2011/01/11

バックテスト(自動)時代 - ForexTester2ストラテジプログラミング②(インジケータの利用)



さて、前回は、ForexTester2でのストラテジプログラミングの苦労した点と共通部品について書きました。今回は、ストラテジでインジケータを利用する方法について書いてみたいと思います。

これもまた意外と苦労しました。

●インジケータの利用について一言
 ストラテジのプログラムを組む際、ForexTester2に組み込んだインジケータ(テクニカル指標)の値
 を取得することができます。

  実は、単純な様で、苦労します。

 ふつーに考えれば、ヘルプ通りに使えばいいんですが、


          甘かった!!!


 まず、チャート上に表示可能なインジケータがヘルプで網羅されていない!!!
 あと、ヘルプに掲載されているパラメータが実際と異なる!!!
 
 だから、英語でもいいから、正しく不足無く書いてくれ!!!

 
 英語でいいから!!


 ゼイゼイ。。。 。。。。気を取り直して。。。。
 

●基本的な使い方の流れ(例として、単純移動平均を使います)

 1.ソースファイル頭のvarセクション(グローバル変数領域) - インジケータ用変数の定義
  まず、インジケータにアクセスする為の変数を定義します。
SMA1Ind : integer; // Indicator handle for SMA1
  これは、インジケータの値を取得する際に使用するAPI(GetIndicatorValue)の第一引数 になります。

 2.InitStrategy関数内(※必須ではありません) - インジケータのパラメータを外部パラメータ化する
  移動平均を例にした場合、何バー分の移動平均にするかを決める必要があります。

  固定長で、バー数をプログラム内に埋め込むのも一つの手ですが、外部パラメータとして
  定義することにより、「Strategy optimizer」で最適化を図れます。その為には、以下のコード
  をInitStrategy関数内に記載します。
  ※ただし、冒頭のvarセクションに、SMA1PeriodをInteger型として定義しておく必要があります。
RegOption('SMA1Period', ot_Integer, SMA1Period);
SetOptionRange('SMA1Period', 1, MaxInt);
SMA1Period := 6;
  これで、移動平均線の初期値を「6」とした整数値が、「Strategy properties」に表示される
  様になります。

 3.ResetStrategy関数内 - インジケータを生成する
インジケータを生成し、その後インジケータにアクセスする為のハンドルを、「1.」で定義した変数
に格納します。
SMA1Ind := CreateIndicator(Currency , TimeFrame ,'MovingAverage' , format('%d;0;0;Simple (SMA);Close',[SMA1Period]));
  ・第1引数(Currency):PCHAR型で通貨ペア('USDJPY'等)を指定します。これは単純。
  ・第2引数(TimeFrame)
      どの時間足を使うのかを指定します。
      ここで問題!!一体どんな選択肢があって、希望する時間足を指定するには
     なんと書けばいいのか、ヘルプに無い!!
     簡単に言うと分数をIntegerで指定することになります(1H足であれば60を指定)。
     しかし、通常はForexTester2で指定した定義を使うべきです
     (1H足であれば"60"ではなく、PERIOD_H1)。
     で、その一覧がHelpに無い!!! で、どうするかというと、プロジェクトフォルダ内の
     「StrategyInterfaceUnit.pas」をNotepadで開いてみましょう。
     「// timeframes」を文字列検索すると、指定可能な時間足毎の定義が出てきます。
  ・第3引数('MovingAverage')
    インジケータの名称を指定します。
    これも、単純な様でいて面倒。Helpに載っているものはそれでいいかもしれないですが、
    チャートに表示できるくせに、ヘルプに載っていないインジケータがある!!
    (例えば、Parabolic-SAR)
    で、結局わかったのは、「ForexTester2\Indicators」ディレクトリ内で、DLL形式ファイル
     の中から使いたいインジケータを探し、拡張子を除いたファイル名の文字列を指定する
     みたいです。
    (例:"XXX.dll"というファイル名であれば、"XXX"を指定)
  ・第4引数(format(....)) : インジケータのパラメータを文字列で渡します。
    チャートにインジケータを表示させた時、の「Data」ウィンドウに表示されている
    インジケータ名の横の文字列( XXX(123,456)であれば、 '123;456')を指定するのが
    てっとり早いです。
    ちなみに、format文の構文はDELPHI Users' forum」を参考にしました。

 4.ResetStrategy関数の後ろ - インジケータのデータを取得する共通関数を用意する
    これはあくまでも私の好みですが、インジケータのデータにアクセスする為だけの関数を用意
    します。以下が例です。
    こういった類の関数の事をラッパー関数と呼びますが、プログラムの保守性を高めたり、視認性
    を高めたりする効果があります。
    ここで、GetIndicatorValueというAPIを使いますが、これもクセ者!!
{-----MovingAverage Calculate  SMA1---------------------------------}
 function GetSMA1(index: integer): double;
 begin
     result :=GetIndicatorValue(SMA1Ind, index , 0 );    
 end;
       さて、ここで「GetIndicatorValue」というAPIを使用して、インジケータの実際の値を
    取得します。
   第一引数は、上記「1.」で定義したグローバル変数、第二引数は、indexなので、1本前の
   バーであれば1、2本前のバーであれば2を指定します。
   (実はこのindexの考え方も当初混乱しました。トレード以外の一般的なプログラムでは最初1
   (もしくは0)から始まって、新しい情報程、数字が増えていく)
   
   問題は、この3番目の引数の「0」、ここがクセ者なんです。
   SMAの場合、とりうる値が一つなので、通常は0でシンプルなのですが、ボリンジャーバンド等の
   1インジケータで複数の値がある場合、何を指定すればいいのかが問題になってきます。
   ADXのヘルプ間違ってました(0:ADX,1:PDI,2:MDIが正解)

   ここもヘルプが正しく、全て網羅されていればなんの問題も無いところです。
   でも、ヘルプ間違えている箇所があり、信用できないのです。


   だから、英語でいいから正しいのを書いてくれ!!


  これを解決するには、インジケータのソースから読み解く必要が出てきます。
  まず、「ForexTester2\Examples\Indicators\Delphi\IndicatorsSrc」ディレクトリ配下に、
  インジケータ毎のソースファイルがあるのですが、この3番目の引数(BufferIndex)、
  Init関数内のCreateIndexBufferを呼び出す順序で0から始まり、1づつ増えていきます。

  例:
AParam := CreateIndexBuffer;
BParam :=CreateIndexBuffer;
CParam:= CreateIndexBuffer;
DParam:= CreateIndexBuffer;
と書かれていた場合、AParamの値を取得する場合は「0」、BParamの値を取得する
  場合は「1」、DParamの値を取得する場合は「3」を指定します。

  もうこの根拠は、実際独自インジケータを作った時の経験則以外の何者でもありません。
  正しい事しっている人いれば教えて欲しいです。


 5.実際にインジケータのデータを使う
  上記「4.」の関数を使う場合、以下の様になります。
  以下のプログラム例は、移動平均が上昇しているかどうかの判定です。
if GetSMA1(2)<GetSMA1(1) then
begin
    いろいろ
end;

ふーっ!!!ストラテジ作る時に、インジケータの利用がこれほど大変だとは。。。


オレは一体何を信じればいいんや!!


そして、「FXシステムトレード初心者奮闘記」のストラテジプログラミング集がまたまた続くのでした。
P.S.そうは言ってもForexTester2気に入っています。

0 件のコメント:

コメントを投稿