2011/01/13

バックテスト(自動)時代 - ForexTester2ストラテジプログラミング④(発注ロジックの構造)



さて前回は、ストラテジで独自ログを出力し、スィーニーのMAE/MFE分析や、R期待値を求めれる様にするプログラムの書き方について話しました。

今回は、売買ルールを色々試行錯誤しやすい様な、発注ロジックの構造について記述します。
以下の構造にする事で、特定の手法を追加したり、その後削除したりというのを、一部だけコメントアウトしたり元に戻したりするだけで、色々な組合せを簡単に試せる様になります。

●発注ロジックの構造
 関数呼び出しの流れは以下の様な感じ。
 vOrderTypeは、ロングポジションの場合は1、ショートポジションの場合は-1を指定。
 indexは、どのバーで判断するか指定します。

 GetSingleTick→ToBuy()/ToSell()→ToOrder(vOrderType:Integer)
 →WkToOrder(vOrderType:Integer; index:integer)→各種発注判断関数
  Filter1(vOrderType:Ingeter; index:Integer)
       → 各種フィルタ関数(フィルタ条件を満たしたタイミングで発注)
  Filter2(vOrderType:Integer; index:Integer)
        → 各種フィルタ関数(各種発注判断関数が発注要と判断したタイミングで、満たしていなければならない条件)

  なんだか複雑で、改良の余地ありそうですが、今はこんなロジックにしています。
  以下は、各関数の説明です。

  ①ToBuy()/ToSell()
   ToOrder(1)/ToOrder(-1)を呼び出し、Trueが返却された場合、手仕舞いに向けた変数の
   初期化とストップロス価格計算関数を呼び出し、結果をグローバル変数に設定。
   また、グローバル変数OrderTypeに1/-1を設定。
   わざわざToOrder関数に切り出している理由は、ToOrderをドテン手仕舞いに使用する為です。

{----- Judge to Buy -----------------------------------}
function ToBuy(): Boolean;
begin
    result := False;
    if ToOrder(1) then
    begin
        OrderType := 1;
        OrderSLPrice := CalcSLPrice(OrderPrice);
        result:=True;
    end;
end;
②ToOrder(vOrderType:Integer)
   基本的な発注判断関数と、フィルター用関数を呼び出します。
   ここのミソは、実際の発注判断ロジックを書く時に、前のバーの事は気にせずに、純粋に
   指定されたバーが発注条件を満たしているかどうかだけ書けばよくなる事です。
   (ロジック単純化の為)
   以下のソースでは、2本前のバーでは発注要件を満たしていなかったが、 1本前のバー
   では、発注要件を満たす様になった場合にTrueを返します。

{----- Judge to Order ------------------------------------}
function ToOrder(vOrderType:double) : Boolean;
begin
     result := False;

     if Not(WkToOrder(vOrderType,2) AND Filter1(vOrderType,2))
        AND (WkToOrder(vOrderType,1) AND Filter1(vOrderType,1) AND Filter2(vOrderType,1) )
     then result := True;
end;
③WkToOrder(vOrderType:Integer;index:Integer)
  実際の売買判定用関数を、呼び出します。

  以下の例では、3本の移動平均クロス判定と、2本移動平均クロス判定の関数が用意されており、
  2本移動平均クロスの方はコメントアウトされています。
  つまり、コメントアウトしたり外したりして、仕掛け方法を切り替えます。

  その後、発注要の場合、発注価格を設定する関数を呼び出しています。
    ここも、発注価格の計算方法毎に関数を用意し、コメントアウトで切り替えています。    

{----- Judge to Order Worker -----------------------------}
function WkToOrder(vOrderType:double;index:integer) : Boolean;
begin
     result := False;

     {----------------- Judge to order ----------------------------}
     result := ToOrder2(vOrderType,index); // 3SMA cross
     //result := ToOrder1(vOrderType,index); // 2SMA cross

     {----------------- Call function of setting order price ------------------}
     if result then
     begin
          SetOrderPrice1(vOrderType,0.04,0); // Set OrderPrice from Ask/Bid+ratio
          //SetOrderPrice2(vOrderType,6); // Set OrderPrice from Highest/Lowest last N-Bar
     end;
end;
④ToOrder2(3つの移動平均線クロスの例)
  以下は、3本の移動平均線クロスで発注する場合のロジックです。
  前のバーでは条件を満たしていない事をロジック上書かなくていいところがミソです。

{----- Judge to Order2  3SMA cross ----------------------------------}
function ToOrder2(vOrderType:double;index:integer) : Boolean;
begin
     result := False;

     if vOrderType>0 then
     begin
          if (GetSMA3(index)<GetSMA2(index)) AND (GetSMA2(index)<GetSMA1(index)) then
          begin
               result := True;
          end;
     end;
     if vOrderType<0 then
     begin
          if (GetSMA3(index)>GetSMA2(index)) AND (GetSMA2(index)>GetSMA1(index)) then
          begin
                  result := True;
          end;
     end;
end;
 ⑤Filter1(vOrderType:Ingeter; index:Integer)
  この関数ではフィルタ条件を記載します。ここでも個別のフィルタ判定関数を呼び出す事
  になります。 以下の例では、フィルターAだけが有効になっています。
  ここで書いたフィルタは、売買判定時はフィルタ要件を満たしていなくても、フィルタ要件が満たされ
  次第発注させたい場合に書く場所です。

{----- Filter to Order(System6:Getting satisfy filter condition) --------------}
function Filter1(vOrderType:double;index:integer) : Boolean;
begin
     result := True;

     if result then result := Filter_A(vOrderType,index); // Filter A
     //if result then result := Filter_B(vOrderType,index); // Filter B
end;
⑥Filter2(vOrderType:Ingeter; index:Integer)
  この関数でも、フィルタ条件を記載します。上記⑤との違いは、
  ここで書いたフィルタは、売買判定時はフィルタ要件を満たしていない場合は発注されません。
  以下の例では、そういうフィルタを用意しない場合の例です。
  (いくつか用意したものの、全てコメントアウトしている状態)

{----- Filter to Order(System6:Getting satisfy filter condition) --------------}
function Filter2(vOrderType:double;index:integer) : Boolean;
begin
     result := True;

     //if result then result := Filter_A(vOrderType,index); // Filter A
     //if result then result := Filter_B(vOrderType,index); // Filter B
end;
⑦FilterA(vOrerType:Integer; index:Integer)-個別フィルターロジックです。
    以下のフィルタ例は、DMIと同じ向きの時のみ発注するロジック例です。
    基本はTrueで、発注NGのときだけ、Falseを設定する様になっている事に注意してください。

{----- Filter to Order(DMI) ------------------------------}
function Filter_A(vOrderType:double;index:integer) : Boolean;
begin
     result := True;

     if vOrderType>0 then
     begin
          if Not(GetMDI(index)<GetPDI(index)) then result := False;
     end;
     if vOrderType<0 then
     begin
          if Not(GetPDI(index)<GetMDI(index)) then result := False;
     end;
end;




発注ロジックだけでこんなことになってしまった。。。


説明がイマイチわかりにくくなってしまったので、わからんとこは質問お願いします!!

※参考:「ForexTester2ストラテジの内部設計(GetSingleTick内ロジックの流れ)」

そして、「FXシステムトレード初心者奮闘記」のストラテジプログラミング集がまたまた続くのでした。
次回は手仕舞いです。

0 件のコメント:

コメントを投稿