TradingViewにはすでに単純移動平均(SMA)のインディケーターが用意されているが、それを自作してみる。あえて自作してみることで、計算の工夫の仕方に気付いたり、Pineスクリプトに特有の簡潔な書き方などノウハウを学ぶことができる。
Pineスクリプトで単純移動平均を計算するコードを素直に書くと次のようになる。
//@version=4
study("my sma", overlay=true)
length = input(9)
sum = close
for i = 1 to length - 1
sum := sum + close[i]
ma = sum / length
plot(bar_index >= length - 1 ? ma : na)
sum
を求める処理は、ループ長が length
に比例する for
ループを使うため、計算量はO(n)となる。だが、この計算量は計算を工夫することによって、O(1)へ減らすことができる。
length=9
とした場合、最初から順に sum
の計算を書き出してみると、
sum0 = close0
sum1 = close1 + close0
sum2 = close2 + close1 + close0
...
sum7 = close7 + close6 + close5 + close4 + close3 + close2 + close1 + close0
sum8 = close8 + close7 + close6 + close5 + close4 + close3 + close2 + close1 + close0
sum9 = close9 + close8 + close7 + close6 + close5 + close4 + close3 + close2 + close1
sum10 = close10 + close9 + close8 + close7 + close6 + close5 + close4 + close3 + close2
...
ここで、sum9
に注目してみると、
sum9
= close9 + close8 + close7 + close6 + close5 + close4 + close3 + close2 + close1
= close9 + sum8 - close0
のように変形することができる。
sum10
でも同様に変形できることが分かる。
sum10
= close10 + close9 + close8 + close7 + close6 + close5 + close4 + close3 + close2
= close10 + sum9 - close1
これを踏まえて、下記のようにコードを書き直すことができる。
//@version=4
study("my sma2", overlay=true)
length = input(9)
sum = 0.0
if bar_index < length
sum := close
for i = 1 to bar_index
sum := sum + close[i]
else
sum := sum[1] + close - close[length]
ma = sum / length
plot(bar_index >= length - 1 ? ma : na)
さらに、関数 nz()
を使うことで、このコードは下記のようにシンプルにすることができる。
//@version=4
study("my sma3", overlay=true)
length = input(9)
sum = 0.0
sum := nz(sum[1]) + close - nz(close[length])
ma = sum / length
plot(bar_index >= length - 1 ? ma : na)
最初のコードは、length
に比例する for
ループを使う計算があり計算量はO(n)だったが、書き直したコードでは length
に関わらず計算量は一定でO(1)となる。
Pineスクリプトでは nz()
をうまく利用できると、かなりシンプルなコードになる。Pineスクリプトプログラミングで多用する重要なテクニックの一つである。