2011/06/14

MT4用EA開発時代 - 「OrderSelect問題」仮説検証結果



さて前回は、新たに発見したERR_COMMON_ERROR」発生とその状況からの仮説を書きました。今回は、延び延びになっていた、以前のブログ記事で立てたOrderSelect問題」の仮説検証結果について書いてみたいと思います。


結論から言うと、



仮説は誤りでした。


そもそもどういう仮説だったかと言うと、以前のブログ記事で書いた通り、「OrderSelect()した結果は、1つのMT4で一つの領域に格納されていて、複数チャートでEAを同時実行した場合誤作動してしまう」というモノ。

なので、OrderSelect()した結果の領域は複数あるという結論。


まず、検証方法の概略から。

【OrderSelect問題仮説1検証方法】
--------------------------
1.4つの通貨ペアで同じEAを実行させる
2.EA開始時に発注する
3.発注完了したら、MAGICナンバーと通貨ペアが同じものをOrderSelect()する。
4.OrderSelect()完了したら、一定時間スリープさせた後、以下を比較して異なっていたら、
  その旨のExpertログを出力してstart()関数を抜ける。
  Symbol()とOrderSymbol()
  内部変数に格納したチケット番号とOrderTicket()
5.一回発注したら以降は発注しない。
6.検証終了後は、EAを停止させ、オーダを手動削除
7.対象通貨ペアとSleep時間
    EURUSD:10000ms
    USDCHF:2000ms
    GBPUSD:5000ms
    USDJPY:3000ms
8.利用したMT4
  Forex.com Ver:4.00 Build 229(26 Nov 2010)
--------------------------

【検証に使用したEA-1】
-----------------------------
#property copyright "Copyright  2011, ahaha_fxtrader"
#property link      "http://blog.livedoor.jp/ahaha_fxtrader/"

#include <stdlib.mqh>
#include <stderror.mqh>

//---- input parameters
extern int      Magic = 47982738;
extern int       SleepTime=2000;

int init()
  {
    MathSrand(TimeCurrent());   
   return(0);
  }

int deinit()
  {
   return(0);
  }
int start()
  {
    static int ticket = 0;
    
    if( ticket<=0 )
    {
        int type = MathRand()-(32767.0/2.0);
        if( type >=0 )
        {
            ticket = OrderSend(Symbol(),OP_BUY,MarketInfo(Symbol(),MODE_MINLOT),Ask,10,0,0,NULL,Magic);
            if( ticket>0 ) Print("[[ORDER]] Symbol("+Symbol()+") Ticket("+ticket+")");
        }
        else
        {
            ticket = OrderSend(Symbol(),OP_SELL,MarketInfo(Symbol(),MODE_MINLOT),Bid,10,0,0,NULL,Magic);
            if( ticket>0 ) Print("[[ORDER]] Symbol("+Symbol()+") Ticket("+ticket+")");
        }
    }
    
    // オーダ一覧取得ループ
    for( int i=OrdersTotal()-1 ; i>=0 ; i-- )
    {
        // オーダ情報取得
        if( OrderSelect(i,SELECT_BY_POS , MODE_TRADES)==FALSE ) 
        {
            int Errno = GetLastError();
            Print("[[WARN]] Errno("+Errno+") Description("+ErrorDescription(Errno)+")");
            continue;
        }
         // 対象外であれば次
        if( (OrderMagicNumber() != Magic) || (OrderSymbol() != Symbol()) ) continue;
        
        // 一定時間スリープする
        Sleep(SleepTime);
        
        // チャートのシンボルとOrderSelectのシンボルを出力する
        if( (OrderSymbol()==Symbol()) && (ticket==OrderTicket()) ) Print("[[INFO]] Symbol("+Symbol()+") OrderSymbol("+OrderSymbol()+") Ticket("+ticket+") OrderTicket("+OrderTicket()+")");
        else Print("[[WARN]] Symbol("+Symbol()+") OrderSymbol("+OrderSymbol()+") Ticket("+ticket+") OrderTicket("+OrderTicket()+")");
    }    
    
   return(0);
  }

------------------------------------

これを、1時間強動作させた結果、OrderSymbol()もしくはOrderTicket()が間違えた値になったログは出力されなかった。


以上、終わり!!








ちゃうちゃう。



そして次考えた仮説としては、OrderSelect対象となるレコード数が変動した場合にずれるかもしれないというケース。

【OrderSelect問題仮説2検証方法】
--------------------------
乱数で買い/売りを決め、スリープ後決済する。
2時間実行し、スリープ後にチケット番号か、シンボルが不一致になれば"[[WARN]]"を出力する。
他の条件は、前述の「OrderSelect問題仮説1」と同じ。
但し、実行時間は2時間。
--------------------------

【検証に使用したEA-2】
-----------------------------
#property copyright "Copyright  2011, ahaha_fxtrader"
#property link      "http://blog.livedoor.jp/ahaha_fxtrader/"

#include <stdlib.mqh>
#include <stderror.mqh>

//---- input parameters
extern int      Magic = 47982738;
extern int       SleepTime=2000;

int init()
{
    MathSrand(TimeCurrent());   
   return(0);
}

int deinit()
{
   return(0);
}
int start()
{
    static int ticket = 0;
    bool found = FALSE;
    
    if( ticket<=0 )
    {
        int type = MathRand()-(32767.0/2.0);
        if( type >=0 )
        {
            ticket = OrderSend(Symbol(),OP_BUY,MarketInfo(Symbol(),MODE_MINLOT),Ask,10,0,0,NULL,Magic);
            if( ticket>0 ) Print("[[ORDER]] Symbol("+Symbol()+") Ticket("+ticket+")");
        }
        else
        {
            ticket = OrderSend(Symbol(),OP_SELL,MarketInfo(Symbol(),MODE_MINLOT),Bid,10,0,0,NULL,Magic);
            if( ticket>0 ) Print("[[ORDER]] Symbol("+Symbol()+") Ticket("+ticket+")");
        }
    }
    if( ticket<=0 ) return(0);
    
    // オーダ一覧取得ループ
    found = FALSE;
    for( int i=OrdersTotal()-1 ; i>=0 ; i-- )
    {
        // オーダ情報取得
        if( OrderSelect(i,SELECT_BY_POS , MODE_TRADES)==FALSE ) 
        {
            int Errno = GetLastError();
            Print("[[SELECT]] NotFound!");
            RefreshRates();
            continue;
        }
         // 対象外であれば次
        if( (OrderMagicNumber() != Magic) || (OrderSymbol() != Symbol()) ) continue;
        
        // 一定時間スリープする
        Sleep(SleepTime);
        
        // チャートのシンボルとOrderSelectのシンボルを出力する
        if( (OrderSymbol()==Symbol()) && (ticket==OrderTicket()) ) Print("[[INFO]] Symbol("+Symbol()+") OrderSymbol("+OrderSymbol()+") Ticket("+ticket+") OrderTicket("+OrderTicket()+")");
        else Print("[[WARN]] Symbol("+Symbol()+") OrderSymbol("+OrderSymbol()+") Ticket("+ticket+") OrderTicket("+OrderTicket()+")");
        if( OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),100) )
        {
            Print("[[CLOSE]] Symbol("+Symbol()+") OrderSymbol("+OrderSymbol()+") Ticket("+ticket+") OrderTicket("+OrderTicket()+")");
            ticket = 0;
        }
    }
    
   return(0);
}

-------------------------------------





結果、問題なし。
#つまりExpertログ上に"[[WARN]]"は出力されなかった。





というか、ええ加減

自分のプログラムを疑わんかい!









は、はい。。。



仮説間違えていたということは、間違えた仮説に基づいた処置は根本解決になっていないということ。ただ、問題発生後、start()関数を排他利用させた以外にもEAのプログラムもだいぶ変更したけど、事の発端につながる様なバグはなかったし、同様の問題も再発していない。


つまり、仮説は否定されたけど、原因不明な点は変わらず。










ともかく、

お騒がせしましたm(_ _)m





そして、肩身が狭い思いで、「FXシステムトレード初心者奮闘記」の「MT4用EA開発時代」は、OrderSelect問題」の調査を継続するのでした。。多分。。
#先にドキュメント仕上げたいなぁ。。

0 件のコメント:

コメントを投稿