現在様々な手法でバックテストを実施しているのですが、移動平均線のパラメータ(日数)を期間の途中で切り替えるようなロジックを作りたくてストラテジーを書いてみたら、AverageFC関数の計算結果がおかしくなりましたorz
原因と解決策をメモしておきますので、参考にしていただければと思います。
発生した現象
日足チャートにおいて、期間ごとに移動平均線の日数を変更してテストしたいと思いました。2010年は5日移動平均線、2011年は10日平均線、・・といった感じ。それで、期間ごとにAverageFC関数のパラメータを変更すればいいやと思いました。
(書いてみたコード:これは間違いです)
If Date < 1170101 and Date < 1020101 then Begin varAvg = AverageFC( Close, 5 ); End Else If Date >= 1020101 and Date < 1030101 then Begin varAvg = AverageFC( Close, 10 ); { 以下、期間ごとに続く・・ } End;
しかし、いざやってみると売買サインがうまく表示されません。
はて・・?と思って以下のようなコードを書いてデバッグ用の出力をしてみたところ、ちょうどパラメータの値が変わる所でAverageFC関数の計算結果がおかしくなっていました。
Vars: varAvgLength(0); If Date <= 1170101 then Begin varAvgLength = 5; End Else Begin varAvgLength = 100; End; Print( Date:7:0, Spaces(2), AverageFC( Close, varAvgLength );
出力結果
1170104(=2017年01月04日)以降から、明らかに数値がおかしい(苦笑)
原因
AverageFC関数に限らず、”FC”付きの関数は「高速計算方法を使用する」とマニュアルに記載されています。
このシリーズ関数は、Average とまったく同じ値を返しますが、高速計算方法を使用するため、使用するメモリーが非 FC バージョンよりわずかに多い点が異なります。
(トレードステーション:AverageFC関数のページより)
で、関数のEasyLanguageコードは「ストラテジー」や「インジケーター」と同様に、『EasyLanguage開発環境』からファイルを開いて確認できるので、「関数」のAverage関数とAverageFC関数のEasyLanguageコードを見てました。すると、それぞれSummation関数とSummationFC関数という値の総和を求める関数を呼び出していました。
この2つはどちらも、指定した足数の指定した値の総和(合計値)を求める関数で、この計算結果を足数で割る事で平均値を計算しています。例えば過去10足の終値の総和を求めるなら Summation( Close, 10 ) といった感じです。
Average関数もAverageFC関数も、それぞれこの総和を求める関数以外はほとんど同じコードなので、今回の原因はSummation関数とSummationFC関数の違いにあるようです。
それで、このSummation関数とSummationFC関数のコードも確認してみたところ、Summation関数では毎回すべての計算を行なうのに対して、SummationFC関数では前回の計算結果に「新しい値を加えて」「最も古い値を引く」という処理をしています。
つまり例えば100日移動平均線を計算する場合、Summation関数の場合は各足ごとに、現在の足から100日前までの足をすべて足す計算処理をしているのに対して・・
SummationFC関数の場合は、最初の足だけ100日分計算して、次の足からは前の計算結果に現在の足を足して、最も古い100日前の値を引くことで、過去100日分の総和を求めているわけです。
Summation関数のコード(一部)
>||
for Value1 = 0 to Length – 1
begin
Sum = Sum + Price[Value1] ;
end ;
||<
SummationFC関数のコード(一部)
>||
Sum = Sum[1] + Price – Price[Length] ;
||<
Summation関数の方が、forで繰り返し処理を行なっている分、計算速度が遅くなってしまうというわけです。
で、今回急に計算値が小さくなってしまったのは、それまで5足分の価格の総和を保持していたSum変数が、パラメータを100に変更した後もそのままの値だったため、「 ( 過去5本の足の総和 ) + ( 現在の足の価格 ) - ( 100本前の足の価格 ) / 100」という意味のない計算をしてしまうため、計算がおかしくなってしまったのでした。
SummationFC関数の入力パラメータLengthのコメントにも「このパラメータは一定値であるとする」と但し書きがありますので、SummationFC関数は「関数のパラメータが途中で変わる事はない」前提で、計算を大幅に減らすような工夫がなされている、ということです。
解決策
この動作の解決策については、単純にFC無しの標準関数(Average関数など)を使えばOKです。
計算処理は遅くなってしまいますが、FC系関数の仕様がこうなってる以上仕方ないですね。
処理速度など気になるなら、SummationFC関数のコードを改造して独自の計算関数を作ってみると良いかもしれません。
以上、AverageFC関数の挙動に関するメモでした。