MQLソースチェック項目(新)

MetaTrader 4
GogoJungle
2023/04/13 19:09
735

MQLソースコードチェック項目について

ゴゴジャンで実施しているMQLソースコードチェックの内容について記載します。
EAをご出品する際のチェックリストとして、ご利用いただければ幸いです。


EAチェック全体の流れは下記のとおりです。

  1. ソースコード(mq4)をチェック
  2. Strategy Testerでバックテストを実施してチェック
  3. デモ口座で運用してチェック

※本チェックは、EAの成績について保証しているものではありませんので予めご了承ください


ここでは、ソースコード(mq4)の具体的なチェック内容について、記載します。

1.パラメータ管理

1-1.マジックナンバーの設定確認

  • パラメーターにより任意の値に設定変更が可能であること
【例】
extern int MagicNumber = 123456;
input int MAGIC = 123456;

1-2.マジックナンバーの変更確認(バージョンアップ時)

  • 前回とマジックナンバーが同じであること(externまたはinputで検索して確認)

2.ポジション管理

2-1.ポジションカウント処理の確認

  • 通貨ペアとマジックナンバーを判定し、ポジション数がカウントされていること(OrdersTotal で検索して確認)
【例】
      //-------- 新規ポジションのエントリー --------
      // ポジションの数をカウントする
      for(i=OrdersTotal()-1; i>=0; i--)
      {
         //オーダー選択(エラーを生じた場合、ループから抜け出す)
         if (OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) == false)
         {
            Print("OrderSelect returned the error of ", GetLastError() );
            break;
         }
         
         //オーダー確認(通貨ペアが一致しない場合は、for文の先頭に戻る)
         if (OrderSymbol() != Symbol()) continue;
         
         //マジックナンバー確認(マジックナンバーが一致しない場合は、for文の先頭に戻る)
         if (OrderMagicNumber() != MagicNumber) continue;
   
         if (OrderType() == OP_BUY)
         {
            CountBuy = CountBuy + 1;
         }
         
         if (OrderType() == OP_SELL)
         {
            CountSell = CountSell + 1;
         }
      }     

3.エントリー処理

3-1.最大ポジション数の確認

  • 前提条件として、現在の保有ポジション数と最大ポジション数を比較・判定していること(OrderSend で検索して確認)
【例】
if (countbuy<MaxPos) { 
   int ticket = -1;
   ticket=OrderSend(NULL,OP_BUY,lot,Ask,Slippage,0,0,Com,MagicNumber,0,Blue);

3-2.マジックナンバーの設定確認

  • エントリーをする際(OrderSend関数内の引数9つめに)マジックナンバー(1-1.で指定しているもの)が設定されていること
【例】
OrderSend(NULL,OP_BUY,lot,Ask,Slippage,0,0,Com,『MagicNumber』,0,Blue);

3-3.通貨ペアの設定確認

  • エントリーをする際に(OrderSend関数内に)通貨ペアが Symbol() または NULL であること
    (固定の場合は、USDJPYm, USDJPY_ など、ブローカーによる文字が考慮されていること)
【例】
OrderSend(『Symbol()』,OP_BUY,lot,Ask,Slippage,0,0,Com,MagicNumber,0,Blue);

3-4.ストップロスの設定確認(OrderCloseによるロジック決済がない場合:SL, TPのみ決済の場合)

  • ストップロスの設定がエントリー時に設定されていること(OrderCloseで検索して確認)
  • 5つの引数で確認(※5つ目は省略可)
  • 指値・逆指値ポジションの注文変更を確認

下記は、OrderModify が失敗したら二度とSL, TPが設定されないためNG例

【NG例】
if( EntryPosition == 1 ) //買いの場合のエントリ条件
{
	 res=OrderSend(Symbol(),OP_BUY,Lots ,Ask,SLP,0,0,"TrendLogic",MAGIC,0,Red);
	 if (OrderSelect(res,SELECT_BY_TICKET)==true)
	 {
		 if (Buy_stoploss!=0) SL=OrderOpenPrice()-Buy_stoploss*AdjustPoint(Symbol());
		 if (Buy_takeprofit!=0) TP=OrderOpenPrice()+Buy_takeprofit*AdjustPoint(Symbol());
	 }
	 Modified=OrderModify(OrderTicket(),OrderOpenPrice(),SL,TP,0,Red);
}
else if(EntryPosition == -1 ) //---- 売りエントリ
{
	 res=OrderSend(Symbol(),OP_SELL,Lots,Bid,SLP,0,0,"TrendLogic",MAGIC,0,White);
	 if(OrderSelect(res,SELECT_BY_TICKET)==true)
	 {
		 if(Sell_stoploss!=0) SL=OrderOpenPrice()+Sell_stoploss*AdjustPoint(Symbol());
		 if(Sell_takeprofit!=0) TP=OrderOpenPrice()-Sell_takeprofit*AdjustPoint(Symbol());
	 }
	 Modified=OrderModify(OrderTicket(),OrderOpenPrice(),SL,TP,0,White);
}
  • 証券会社へ提案する場合は、ロジックに関わらずストップロスの設定を確認

下記は、注文時に sl,tp を強制的に設定する方法

【修正前】
ticket=OrderSend(symbol,OP_BUY,Lots,Ask,Slippage,0,0,NULL,MagicNumber,0,Blue);
if(ticket>=0)
	if(OrderModify(ticket,OrderOpenPrice(),sl,tp,0))
	{
		lastTime=now;
		entry_cnt++;
	}
【修正後】
ticket=OrderSend(symbol,OP_BUY,Lots,Ask,Slippage,sl,tp,NULL,MagicNumber,0,Blue);
if(ticket>=0)
	{
		lastTime=now;
		entry_cnt++;
	}

3-5.ロット計算処理の確認(ロットが可変の場合:マーチンゲール、複利など)

  • MT4を再起動すると変数が初期化され(再取得しないため)ロジックに影響のある条件処理となっていないこと

4.決済処理

4-1.マジックナンバーの確認

  • 前提条件として、マジックナンバー、通貨ペアを判定していること
【例】
for( i=OrdersTotal()-1; i>=0; i-- ){
  if( OrderSelect(i, SELECT_BY_POS) == true ){
    if( OrderType() == OP_BUY && OrderMagicNumber() == Magic && OrderSymbol() == Symbol() ){
      if( !(OrderClose(OrderTicket(),OrderLots(),MarketInfo(Symbol(),MODE_BID),Slippage,Green)) ){

4-2.決済対象チケットの確認

  • マジックナンバー、通貨ペア判定後、決済対象のチケットが変化しないこと(OrderSelectが実施されないこと)

下記は決済時のチケットが変わるパターンのためNG

for( i=OrdersTotal()-1; i>=0; i-- ){
  if( OrderSelect(i, SELECT_BY_POS) == true ){
    if( OrderType() == OP_BUY && OrderMagicNumber() == Magic && OrderSymbol() == Symbol() ){
      OrderTicketChange();
      if( !(OrderClose(OrderTicket(),OrderLots(),MarketInfo(Symbol(),MODE_BID),Slippage,Green)) ){
void OrderTicketChange()
  {
   OrderSelect(3, SELECT_BY_POS);   
  }

4-3.リトライ処理の確認

  • 1度決済が失敗しても、決済判定および処理が、ティック毎に再度行われること(決済失敗が考慮されていること)

無限ループ処理の場合はNG

【例】
bool closePosition(int magic, int type = -1) //決済処理を行う関数
{
   int result_count = 0; //挑戦回数
   int close_signal = 0; //0が成功,0以外が失敗

   if(IsTradeAllowed() == true) {
      for(int i = OrdersTotal() - 1; i >= 0; i--) {
         if(OrderSelect(i, SELECT_BY_POS) == false) continue;
         if(OrderSymbol() != Symbol() || OrderMagicNumber() != magic) continue;
         if(type >= 0 && OrderType() != type) continue;
         RefreshRates();

if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, ArrowColor[OrderType()]) == true) {
            continue; //最初のクローズ処理(通常はここで成功する)
         }else{ //ここから決済が失敗した場合の処理
            result_count = 0;
            for(int j = 0; j < RETRY_COUNT; j++) { //リトライカウントに達するまで処理を繰り返す
               Sleep(200);

               if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, ArrowColor[OrderType()]) == true) { 
                  break; //成功したらループから抜ける
               }else{ //失敗した場合
                  int err = GetLastError();
                  if(err > 0){
                     result_count++; //失敗した回数のカウンターを増やす
                     Print("[OrderClose Error] : ", err, " ", ErrorDescription(err));
                  }
               }
               if(result_count == RETRY_COUNT) { //カウンターが指定した挑戦回数に達した場合
                  close_signal++; //決済失敗のシグナルを出す
               }
            }
         }
   }
      if(close_signal == 0) return(true); //成功したので関数を終了する
      Alert("[OrderClose Error] : Close timeout. Check the experts log."); //失敗した場合にタイムアウトのエラーを出す  
   }
   return(false); //アラートを出して終了する
}

4-4.決済条件の確認

  • MT4を再起動すると変数が初期化され(再取得しないため)ロジックに影響のある条件処理となっていないこと

決済条件に使用する変数が再起動で初期化される場合はNG

5.例外処理

5-1.エラーハンドリングの確認

  • ループ処理 while において、無限ループにならないこと(エラーハンドリングのパターンが網羅されていること)
【良い例:タイムアウト処理が記述されている】
while(true)
{
int hoge; //処理上手くいった場合に1となる変数

   //****ここで決済などの処理***//

if(hoge) return(true);

   // タイムアウト処理
   if (GetTickCount() - StartTime > 10 * 1000)
   {
      Alert("OrderSend timeout. Check the experts log.");
      
      return(-1);
   }
【悪い例:タイムアウト処理が記述されていない】
while(true)
{
int hoge; //処理上手くいった場合に1となる変数

   //****ここで決済などの処理***//

if(hoge) return(true);
   }
【その他のループ脱出例】
// リトライしても解消されないエラーなら、ループを脱出
if(err == ERR_INVALID_PRICE) break;
if(err == ERR_INVALID_STOPS) break;
if(err == ERR_LONGS_NOT_ALLOWED) break;
if(err == ERR_SHORTS_NOT_ALLOWED) break;
if(err == ERR_NOT_ENOUGH_MONEY) break;
if(err == ERR_TRADE_TOO_MANY_ORDERS) break;

6.取引制限

6-1.取引制限の確認

  • 複数の証券会社で動作すること(ブローカー、コース、口座番号、ファイル名の縛りがないこと)
【NG例:証券会社(Gaitame)を指定している】
int OnInit()
{
   if(IsTradeAllowed() == false) {
      Alert("Enable the setting 'Allow live trading' in the Expert Properties!");
   }
   if(StringFind(TerminalInfoString(TERMINAL_COMPANY), "Gaitame") == -1) return(INIT_FAILED); //証券会社が"Gaitame"でない場合は初期化が失敗する


   magic_array[0] = Magic1;
   bars1 = getBars(Magic1);

   return(INIT_SUCCEEDED);
}

7.外部処理

7-1.外部通信の確認

  • 外部通信やファイルによる通信が行われていないことを確認(httpで検索して確認)
  • 外部リンクがないことを確認(弊社リンク以外がある場合はNG)

7-2.外部ファイルの確認

  • バックテストの成績を最適化する目的で使用していないこと(hst,dll で検索して確認)

7-3.グローバル変数の確認

  • グローバル変数(GlobalVariableSet, GlobalVariableGet)が使用されていないこと
    (使用する場合は、グローバル変数の特性を理解した上で、問題なく実装されていること)

8.コメント処理

8-1.OrderSend引数コメント確認

  • エントリー処理にて、OrderSend引数8つ目のコメントに「商品ID:商品名」が適応されていること(OrderSendで検索して確認)
    ※半角英数字にて31文字以内とする
    ※31文字以上の場合は省略するなどして、31文字以内に詰めていただく
【例:商品ID 12345,商品名 GogoJungleEAの場合】
int ticket = OrderSend( ①, ②, ③, ④, ⑤, ⑥, ⑦, "12345:GogoJungle_EA", ⑨, ⑩, ⑪);

またEAつくーるで作成の場合は、基本項目「コメント」にて「商品ID:商品名」をご入力後コンパイルいただけますと可能でございます。

9.著作権

9-1.デコンパイルの確認

  • デコンパイルされたコードでないこと
【例】
double Gda_280[30];
int G_digits_192=0;
double G_point_196=0.0;
int Gi_204;
double Gd_208;
double Gd_216;
double Gd_224;
  • 暗号化されているコードの場合も、解読困難のため、著作権の問題を確認
【例】
int  2516972921474835825095 ;
int  919926175214748358129332 ;
int OnInit()
{
    158651616521474836452710  =  945331452214748360523750 ();
    1821361779214748361111350 ( 158651616521474836452710 );
  • ライセンス関連の記述がないこと
【例】
//#include <MT4params.mqh>
//#include <MT4License_1.mqh>
//int group_no = 11,group,a1=1;        // グループ番号 0:使用しない
//bool PC_Check = true;    // true: PC縛りを行う false: 行わない
//datetime PrevTime;
//string ServerURL0 = "http://reapseven.xsrv.jp/license";
//string ServerURL = "http://fxea.xsrv.jp/license";       // サーバーのURL
//string ServerURL2 = "http://fxea.xsrv.jp/license";
//int stp=-1;
//#import "shell32.dll"
//int ShellExecuteW(int hWnd, int lpVerb, string lpFile, string lpParameters, string lpDirectory, int nCmdShow);
//#import
//string DataPath = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL4\\Libraries";

9-2.利用規約違反の確認

  • 複数アカウントで、類似のソースをアップしていないこと(複数アカウントによる出品は、利用規約違反)

10.MT5にてチェックする項目

10-1.証券会社対応

  • 証券会社がもつ1or2に対応する値を取得する必要がある(type_fillingで検索して確認)

1の場合:ORDER_FILLING_FOK ※デフォルト
2の場合:ORDER_FILLING_IOC

【例】
int FillingMode=(int)SymbolInfoInteger(_Symbol,SYMBOL_FILLING_MODE);
if(FillingMode == 2){
      request.type_filling = ORDER_FILLING_IOC;
}

10-2.保有ポジション数の計算

  • 通貨ペアとマジックナンバーを判定して、ポジション数がカウントされていること(PositionsTotalで検索して確認)
【例】
   int pos = 0;
   int posTotal=PositionsTotal();
   for( int posIndex=0; posIndex<posTotal; posIndex++ )
     {
      const ulong ticket=PositionGetTicket(posIndex);
      if(PositionSelectByTicket(ticket) &&
         PositionGetString(POSITION_SYMBOL)==_Symbol &&
         PositionGetInteger(POSITION_MAGIC)==Magic_Number)
        {
            pos++;
        }
     }
  }

10-3.エントリー

  • エントリー時にユーザ任意のマジックナンバーで注文されていること
  • エントリー時の通貨ペアがブローカー考慮の値で注文されていること
  • 決済注文ロジックがない場合、SL/TPがセットされていること
【例】
input int Magic_Number;
MqlTradeRequest request;
MqlTradeResult result;

request.action  = TRADE_ACTION_DEAL;
request.magic  = Magic_Number;
request.symbol  = _Symbol;
request.volume  = 0.1;
request.sl = stoploss;
request.tp = takeprofit;
request.position  =  0;

OrderSend(request,result);

10-4.決済

  • 正しいポジションが決済されること(他EAの取得ポジションを誤って決済しないこと)
    決済注文はチケット番号で行われます。
  • 決済注文の失敗が考慮されていること
  • グローバル変数の初期化が考慮されていること
【例】
   int posTotal=PositionsTotal();
   for( int posIndex=0; posIndex<posTotal; posIndex++ )
     {
      const ulong ticket=PositionGetTicket(posIndex);
      if(PositionSelectByTicket(ticket) &&
         PositionGetString(POSITION_SYMBOL)==_Symbol &&
         PositionGetInteger(POSITION_MAGIC)==Magic_Number)
        {
           MqlTradeRequest request;
           MqlTradeResult result;

           request.action  = TRADE_ACTION_DEAL;
           request.magic  = Magic_Number;
           request.symbol  = _Symbol;
           request.volume  = 0.1;
           request.sl = 0;
           request.tp = 0;
           request.position  =  ticket;

           OrderSend(request,result);
        }
     }
  }

おわりに

ゴゴジャンでは、以上のようなソースチェックを、すべてのEAについて、実施しております。
運用上の不具合や新しい情報などございましたら、ご報告いただければ、幸いでございます。

ご報告いただいた内容に基づき、随時チェック項目をアップデートいたします。

みなさまの優秀なEAのご出品を心からお待ち申し上げております。

コメント

関連トピックス

検索結果がありません。

ノーコードで誰でも簡単EA開発!MQL言語学習にも使える! | GogoJungle

注目トピックス

検索結果がありません。