検証用EAを一部無料公開します。また簡単な説明を記載します。本ブログ内記事の通貨ペアの傾向確認と同じように確認できると思います。
Table of Contents
ソースファイルの構成
ソースファイルは大きく分けて4つのブロックになっています。
変数宣言
/* 外部変数宣言 */ extern int Magic= 59872465; extern double Lots = 0.1; extern int Slippage = 4; extern int MaxSpread = 5; extern int MaxPosition = 1; extern int Limit = 5000; extern int ProtectiveStop = 5000; // ProtectiveStop 初期Stop extern int TrailingStop = 0; // トレーリングストップ幅 extern int MinimumProfit = 0; // MinimumProfit 0:トレーリングストップしない。0以上:利益到達でトレーリングストップへ extern int Closetime = 20; // Closetime 仕掛けから決済までの経過足数 extern bool ZscoreEnable = true; // シグナルA:ボリンジャーバンド extern int BandsPeriod=20; // シグナルA:ボリンジャーバンド期間 extern int BandsDeviation=1; // シグナルA:ボリンジャーバンド偏差 extern bool ZscoreCounterTrend=false; // シグナルA:カウンターシグナル extern bool DonchanEnable = false; // シグナルB:ドンチャン extern int DonchanPeriod=20; // シグナルB:ドンチャン期間 extern bool DonchanCounterTrend=false; // シグナルB:カウンターシグナル extern bool RSIEnable = false; // シグナルC:RSI extern int RSIPeriod=20; // シグナルC:RSI期間 extern double RSIUpper=55.0; // シグナルC:RSI上ライン extern double RSILower=45.0; // シグナルC:RSI下ライン extern bool RSICounterTrend=false; // シグナルC:カウンターシグナル extern bool MAEnable = false; // シグナルD:MA extern int MAfastPeriod=20; // シグナルD:MA短期 extern int MAslowPeriod=50; // シグナルD:MA長期 MA短期以下でMA短期と終値の比較判定になる extern bool MACounterTrend=false; // シグナルD:カウンターシグナル /* 内部変数宣言 */ int iSlippage; double dPoint; int iSpread;
外部変数宣言はexternを付与することで識別され、EAパラメータから設定することができるようになります。プログラムを変更することなく、下の画像のようにパラメータをMT4から設定できます。

- Magic:どのEAが注文を出したのか識別するために設定します。他のEAのMagicナンバーと被らないようにします。
- Lots:注文数量になります。0.1とすると10,000通貨であることが多いです。口座の種類によっても変わるため、実際の運用では事前に確認します。本EAではロットはこのパラメータに設定した値で注文が出されます。
- Slippage:注文時に市場の価格とずれが発生したときにどこまで許容するか設定します。注文時にSlippage以上の価格差があると注文は執行されません。
- MaxSpread:買いと売りの価格差をどこまで許容するかを示す値です。取引が少ないときや、指標発表時にspreadが拡大したときに注文を抑えるために使用します。
- MaxPosition:EAからのオーダー数を制限します。シグナルが発生しポジションを持った後、再度シグナルが発生したときにMaxPosition未満であれば追加オーダーをします。
- Limit:ポジションの利益がLimitに達するとポジションをクローズし利益を確定します。pips単位で設定します。
- ProtectiveStop:ポジションの損益がProtectiveStopに達するとポジションをクローズします。pips単位で設定します。下のトレーリングストップを設定した場合はトレーリングストップ動作が始まるまでのストップとして働きます。pips単位で設定します。
- TrailingStop:トレーリングストップ動作が始まった後のストップをpips単位で設定します。
- MinimumProfit:オーダーを持った後、利益がMinimumProfitに達するとトレーリングストップ動作を開始します。pips単位で設定します。
その他の外部変数はシグナル発生の条件を切り替えるためのものになりますのでシグナル関数で説明します。残りの内部変数はプログラム内で使用されるもので外部変数のようにパラメータ入力から変更することはできません。プログラム上必要な変数の宣言を行っています。
オーダー制御
オーダー制御ではエキスパートアドバイザ(EA)に必要な3つの関数を作成します。
初期化関数
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- int CDigits = (int)MarketInfo(Symbol(),MODE_DIGITS); if(CDigits == 2 || CDigits == 3){ // 小数点2桁又は3桁の通貨 USD/JPYなど dPoint = 0.01; // ディーラー毎のPipsを揃える }else if(CDigits == 4 || CDigits == 5){ // 小数点4桁又は5桁の通貨 EUR/USDなど dPoint = 0.0001; // ディーラー毎のPipsを揃える } if(CDigits == 2 || CDigits == 4){ // USD/JPYなどが小数点2桁またはEUR/USDなどが4桁のディーラー iSlippage = Slippage; // スリッページ算出 iSpread = MaxSpread; // スプレッド算出 計算式はスリッページと同じ }else if(CDigits == 3 || CDigits == 5){ // USD/JPYなどが小数点3桁またはEUR/USDなどが5桁のディーラー iSlippage = Slippage * 10; // スリッページ算出 iSpread = MaxSpread * 10; // スプレッド算出 計算式はスリッページと同じ } //--- return(INIT_SUCCEEDED); }
初期化関数はOnInit関数です。これはEAがセットアップ後に動作を開始するときに呼び出されます。動作を開始するときとは、EAをMT4にセットアップし、最初に動かすときや、セットアップ後の再セットアップやMT4を再起動した場合です。
ディーラーごとに通貨ペアの桁数は決まっていて、プログラム内で取得できるスプレッドやスリッページの最小値が異なります。EAでは外部変数でストップやスリッページ許容値、スプレッド許容値を設定可能にしています。これらの値はpips単位として指定しますので、この関数によって指定した値を同じ価値として扱うように調整しています。
終了関数
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- }
終了関数はOnDeinit関数です。EAが動作中の状態からチャートから削除されるときや再セットアップ時に初期化関数が呼び出される前に呼び出されます。本EAでは特に使用していませんが、EA停止後、再開するときに何らかの変数を記憶しておくときに利用します。終了関数で記憶し、初期化関数で復元します。
Tick関数
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- int i; int iTicket; double iLots; int iBuyCnt=0; int iSellCnt=0; static int iOrderCheckBuy; static datetime tOrderTimeBuy; static int iOrderCheckSell; static datetime tOrderTimeSell; static int iCloseCheck; static datetime tCloseTime; datetime comptime; iLots = Lots; /* オーダーの確認 */ if( OrdersTotal() > 0){ for( i=0; i<OrdersTotal(); i++ ){ if( OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == Magic && OrderSymbol() == Symbol() ){ if( OrderType() == OP_BUY ){ iBuyCnt++; }else if( OrderType() == OP_SELL ){ iSellCnt++; } } } } /* 足一つに対し1オーダーの制限 */ if( iOrderCheckBuy >= 1 ){ if( tOrderTimeBuy != iTime(NULL,0,1) ){ iOrderCheckBuy = 0; } } if( iOrderCheckSell >= 1 ){ if( tOrderTimeSell != iTime(NULL,0,1) ){ iOrderCheckSell = 0; } } if( iCloseCheck >= 1 ){ if( tCloseTime != iTime(NULL,0,1) ){ iCloseCheck = 0; } } /* オーダー処理 */ if( iBuyCnt < MaxPosition && (MarketInfo(Symbol(),MODE_SPREAD) < iSpread) && iOrderCheckBuy == 0 ){ // 買いポジション数、スプレッドの確認 if(signalchk(0) == 1) // セットアップの確認 { CloseAllSellOrders(Symbol(), Magic, iSlippage); // 売り注文クローズ if( iOrderCheckBuy == 0 ){ // オーダーコントロール double AskPrice = MarketInfo(Symbol(),MODE_ASK); // 価格セット double BuyStopLoss = 0; if(ProtectiveStop > 0){ BuyStopLoss = AskPrice - (ProtectiveStop * dPoint); // ストップロスセット } double BuyTakeProfit = 0; if( Limit > 0 ){ BuyTakeProfit = AskPrice + (Limit * dPoint); // テイクプロフィットセット } iTicket = OrderSend( Symbol(),OP_BUY,iLots * 1,AskPrice,iSlippage,BuyStopLoss,BuyTakeProfit,"",Magic,0,Blue); // 買い注文 if( iTicket < 0 ){ // エラーチェック Print( "Error opening BuyStopOrder" ); } else { } iOrderCheckBuy = iOrderCheckBuy + 1; // オーダーカウント更新 tOrderTimeBuy = iTime(NULL,0,1); }else{ iOrderCheckBuy = iOrderCheckBuy + 1; // オーダーカウント更新 tOrderTimeBuy = iTime(NULL,0,1); } } } if( iSellCnt < MaxPosition && (MarketInfo(Symbol(),MODE_SPREAD) < iSpread) && iOrderCheckSell == 0 ){ // 売りポジション数、スプレッドの確認 if(signalchk(1) == 1) // セットアップの確認 { CloseAllBuyOrders(Symbol(), Magic, iSlippage); // 買い注文クローズ if( iOrderCheckSell == 0 ){ // オーダーコントロール double BidPrice = MarketInfo(Symbol(),MODE_BID); // 価格セット double SellStopLoss = 0; if(ProtectiveStop > 0){ SellStopLoss = BidPrice + (ProtectiveStop * dPoint); // ストップロスセット } double SellTakeProfit = 0; if( Limit > 0 ){ SellTakeProfit = BidPrice - (Limit * dPoint); // テイクプロフィットセット } iTicket = OrderSend( Symbol(),OP_SELL,iLots * 1,BidPrice,iSlippage,SellStopLoss,SellTakeProfit,"",Magic,0,Red); // 売り注文 if( iTicket < 0 ){ // エラーチェック Print( "Error opening SellStopOrder" ); } else { } iOrderCheckSell = iOrderCheckSell + 1; // オーダーカウント更新 tOrderTimeSell = iTime(NULL,0,1); }else{ iOrderCheckSell = iOrderCheckSell + 1; // オーダーカウント更新 tOrderTimeSell = iTime(NULL,0,1); } } } if( iCloseCheck == 0 ){ /* トレイリングストップ */ if(BuyMarketCount(Symbol(),Magic) > 0 && MinimumProfit > 0) { BuyTrailingStop(Symbol(),TrailingStop,MinimumProfit,Magic); } if(SellMarketCount(Symbol(),Magic) > 0 && MinimumProfit > 0) { SellTrailingStop(Symbol(),TrailingStop,MinimumProfit,Magic); } /* 時間によるクローズ */ for( i=OrdersTotal()-1; i>=0; i-- ){ // 保持期間を過ぎたポジションをクローズする if( OrderSelect(i, SELECT_BY_POS) == true ){ if( (OrderType() == OP_BUY || OrderType() == OP_SELL)&& OrderMagicNumber() == Magic && OrderSymbol() == Symbol() ){ // 買いポジションを確認 comptime = OrderOpenTime(); // ポジションを建てた時間の取得 /* 必ずクローズする時間 */ if( (iBarShift(NULL,0,comptime,false)*Period()) >= (Closetime*Period()) ){ // ポジション時間からバー経過数へ変換し、クローズ時間と比較 if( OrderType() == OP_BUY ){ CloseAllBuyOrders(Symbol(), Magic, iSlippage); // 買い注文クローズ }else if( OrderType() == OP_SELL ){ CloseAllSellOrders(Symbol(), Magic, iSlippage); // 売り注文クローズ } } } } } iCloseCheck = iCloseCheck + 1; // オーダーカウント更新 tCloseTime = iTime(NULL,0,1); } }
Tick関数はOnTick関数です。EA稼働中に価格変動が起きるたびに呼び出されます。1分に何回などと決まってはおらず、価格データが受信されなければ実行はされません。
- ローカル変数宣言部:本関数内で使用する変数を宣言しています。static修飾子が付与された変数はOnTickが再度呼び出されたときに初期化をせずに、前回のOnTick終了時の値を使用します。
- オーダーの確認:現在持っているポジションを確認します。Magicナンバーが一致したポジションの買いと売りをカウントしています。
- 足一つに対し1オーダーの制限:本EAでは注文を1つのバーに対し1つに制限しています。注文時に記憶した バー のオープン時間をここで確認し、更新があった場合にフラグiOrderCheckXXXを操作し再度注文可能にします。
- またクローズ判定も同様の仕組みを利用しています。クローズ判定を1つのバー に対し1回としているのは本EAは高速解析するため、オープンプライスでのバックテストを前提としています。その結果を実際の運用や、everytickで動かすと1つの バー の中では価格変動が多数あり、オープンプライスとはかけ離れた結果となります。クローズ判定を1つのバー で1回とすることでバックテスト精度を高めます。
- オーダー処理:オーダー条件の確認を行い、成立していた場合に買い又は売りのオーダーを出します。条件にはポジション数、スプレッド幅、シグナル 、iOrderCheckXXX があります。オーダー前には反対ポジション(買いであれば売り)をクローズします。その後、注文価格、リミット、ストップを設定しオーダーを出します。注文成立でiOrderCheckXXXを操作し、オーダー制限をします。
- トレイリングストップ:買い注文、売り注文それぞれにトレイリングストップを行います。 ( バー1つにつき1回のみ )
- 時間によるクローズ:CloseTimeで指定したバー本数が経過したらクローズするようにポジションの取得時間から経過足数へ変換しています。マーケットが動いていない時間はカウントされません。の数になります。( バー1つにつき1回のみ )
シグナル関数
int signalchk(int sel) { int ret = 1; double dIndiVal[INDIVAL_CNT]; ArrayInitialize(dIndiVal,0); /* ボリンジャーバンド */ if( ZscoreEnable == true ){ if( ZscoreCounterTrend == 0 ){ dIndiVal[0] = iBands(NULL, 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1); // UPPER dIndiVal[1] = iClose(NULL,0,1); dIndiVal[3] = iBands(NULL, 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1); // LOWER dIndiVal[2] = iClose(NULL,0,2); }else{ dIndiVal[3] = iBands(NULL, 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1); // UPPER dIndiVal[2] = iClose(NULL,0,1); dIndiVal[0] = iBands(NULL, 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1); // LOWER dIndiVal[1] = iClose(NULL,0,2); } if( sel == 0 ){ if(dIndiVal[0] < dIndiVal[1] && dIndiVal[0] > dIndiVal[2]){ // 買いセットアップの確認 ret &= 1; }else{ ret = 0; } }else{ if(dIndiVal[1] < dIndiVal[3] && dIndiVal[2] > dIndiVal[3]){ // 売りセットアップの確認 ret &= 1; }else{ ret = 0; } } } /* ドンチャン */ if( DonchanEnable == true ){ if( DonchanCounterTrend == 0 ){ dIndiVal[0] = High[iHighest(NULL, 0, MODE_HIGH, DonchanPeriod, 1)]; dIndiVal[1] = High[iHighest(NULL, 0, MODE_HIGH, DonchanPeriod, 2)]; dIndiVal[2] = Low[iLowest(NULL, 0, MODE_LOW, DonchanPeriod, 1)]; dIndiVal[3] = Low[iLowest(NULL, 0, MODE_LOW, DonchanPeriod, 2)]; }else{ dIndiVal[3] = High[iHighest(NULL, 0, MODE_HIGH, DonchanPeriod, 1)]; dIndiVal[2] = High[iHighest(NULL, 0, MODE_HIGH, DonchanPeriod, 2)]; dIndiVal[1] = Low[iLowest(NULL, 0, MODE_LOW, DonchanPeriod, 1)]; dIndiVal[0] = Low[iLowest(NULL, 0, MODE_LOW, DonchanPeriod, 2)]; } if( sel == 0 ){ if(dIndiVal[0] > dIndiVal[1]){ // 買いセットアップの確認 ret &= 1; }else{ ret = 0; } }else{ if(dIndiVal[2] < dIndiVal[3]){ // 売りセットアップの確認 ret &= 1; }else{ ret = 0; } } } /* RSI */ if( RSIEnable == true ){ if( RSICounterTrend == 0 ){ dIndiVal[1] = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,1); // RSI dIndiVal[0] = RSIUpper; dIndiVal[2] = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,2); // RSI dIndiVal[3] = RSILower; }else{ dIndiVal[2] = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,1); // RSI dIndiVal[3] = RSIUpper; dIndiVal[1] = iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,2); // RSI dIndiVal[0] = RSILower; } if( sel == 0 ){ if(dIndiVal[0] < dIndiVal[1] && dIndiVal[0] > dIndiVal[2]){ // 買いセットアップの確認 ret &= 1; }else{ ret = 0; } }else{ if(dIndiVal[1] < dIndiVal[3] && dIndiVal[2] > dIndiVal[3] ){ // 売りセットアップの確認 ret &= 1; }else{ ret = 0; } } } /* 移動平均 */ if( MAEnable == true ){ if( MACounterTrend == 0 ){ dIndiVal[0] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,1); // fast MA dIndiVal[1] = iClose(NULL,0,1); dIndiVal[2] = iClose(NULL,0,2); dIndiVal[3] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,1); // fast MA dIndiVal[4] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,2); // fast MA dIndiVal[5] = iMA(NULL,0,MAslowPeriod,0,MODE_SMA,PRICE_CLOSE,1); // slow MA dIndiVal[6] = iMA(NULL,0,MAslowPeriod,0,MODE_SMA,PRICE_CLOSE,2); // slow MA }else{ dIndiVal[0] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,1); // fast MA dIndiVal[2] = iClose(NULL,0,1); dIndiVal[1] = iClose(NULL,0,2); dIndiVal[5] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,1); // fast MA dIndiVal[6] = iMA(NULL,0,MAfastPeriod,0,MODE_SMA,PRICE_CLOSE,2); // fast MA dIndiVal[3] = iMA(NULL,0,MAslowPeriod,0,MODE_SMA,PRICE_CLOSE,1); // slow MA dIndiVal[4] = iMA(NULL,0,MAslowPeriod,0,MODE_SMA,PRICE_CLOSE,2); // slow MA } if( sel == 0 ){ if( MAfastPeriod > MAslowPeriod ){ // fast MAと価格の比較 if(dIndiVal[0] < dIndiVal[1] && dIndiVal[0] >= dIndiVal[2]){ // 買いセットアップの確認 ret &= 1; }else{ ret = 0; } }else{ if(dIndiVal[5] < dIndiVal[3] && dIndiVal[6] >= dIndiVal[4]){ // 買いセットアップの確認 ret &= 1; }else{ ret = 0; } } }else{ if( MAfastPeriod > MAslowPeriod ){ // fast MAと価格の比較 if(dIndiVal[0] > dIndiVal[1] && dIndiVal[0] <= dIndiVal[2]){ // 売りセットアップの確認 ret &= 1; }else{ ret = 0; } }else{ if(dIndiVal[5] > dIndiVal[3] && dIndiVal[6] <= dIndiVal[4]){ // 売りセットアップの確認 ret &= 1; }else{ ret = 0; } } } } return(ret); }
シグナル関数では外部変数で設定したパラメータに応じてオーダー条件を判定し結果を返します。外部変数XXXEnable=trueの場合のみ判定します。またXXXCounterTrend=trueとした場合はシグナルが反転します。
- ボリンジャーバンド:BandsPeriodに算出期間、BandsDeviationに偏差を設定します。買いシグナルは2つ前のバーでは終値がアッパーレベルを超えておらず、1つ前のバーで終値がアッパーレベルを超えた場合をシグナル発生としています。売りシグナルはロワーレベルを利用し2つ前のバーでは終値がロワーレベルを上回っており、1つ前のバーで終値がロワーレベルを下回った場合にシグナル発生します。
- ドンチャン:DonchanPeriodに算出期間を設定します。算出期間内の最高値、最安値を算出します。買いシグナルは2つ前のバーの最高値より1つ前のバーの最高値が上回った場合シグナル発生します。売りシグナルは2つ前の最安値より1つ前の最安値が下回った場合にシグナル発生します。
- RSI:RSIPeriodに算出期間、RSIUpperに上ライン、RSILowerに下ラインを設定します。算出したRSI値を上ラインを2つ前のバーでは下回り、1つ前のバーで上回った場合に買いシグナルが発生します。下ラインを2つ前のバーで上回り、1つ前のバーで下回った場合に売りシグナルが発生します。
- 移動平均:MAfastPeriodへ短期移動平均算出期間を、MAslowPeriodへ長期移動平均算出期間を設定します。2つ前の足と1つ前の足を使い移動平均線がクロスした場合にシグナルが発生します。長期を短期が上抜いた場合は買い、下抜いた場合は売りです。
注文関数
/*-------------------------------------------------------------------------*/ // 注文関数 /*-------------------------------------------------------------------------*/ /* 全ての買いポジションをクローズ */ void CloseAllBuyOrders(string argSymbol, int argMagicNumber, int argSlippage) { bool result; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if(result == true && OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_BUY) { // 決済注文 int CloseTicket = OrderTicket(); double CloseLots = OrderLots(); double ClosePrice = MarketInfo(argSymbol,MODE_BID); bool Closed = OrderClose(CloseTicket,CloseLots,ClosePrice,argSlippage,Red); // エラー処理 if(Closed == false) { } else Counter--; } } } /* 全ての売りポジションをクローズ */ void CloseAllSellOrders(string argSymbol, int argMagicNumber, int argSlippage) { bool result; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if(result == true && OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_SELL) { // 決済注文 int CloseTicket = OrderTicket(); double CloseLots = OrderLots(); double ClosePrice = MarketInfo(argSymbol,MODE_ASK); bool Closed = OrderClose(CloseTicket,CloseLots,ClosePrice,argSlippage,Red); // エラー処理 if(Closed == false) { } else Counter--; } } } /* 買いポジショントレイリングストップ設定 */ void BuyTrailingStop(string argSymbol, int argTrailingStop, int argMinProfit, int argMagicNumber) { bool result; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if( result == true ) { // 最大損切り価格と最小利食い価格の計算 double MaxStopLoss = MarketInfo(argSymbol,MODE_BID) - (argTrailingStop * dPoint); MaxStopLoss = NormalizeDouble(MaxStopLoss,(int)MarketInfo(OrderSymbol(),MODE_DIGITS)); double CurrentStop = NormalizeDouble(OrderStopLoss(),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)); double PipsProfit = MarketInfo(argSymbol,MODE_BID) - OrderOpenPrice(); double MinProfit = argMinProfit * dPoint; // 損切り価格の変更 if(OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_BUY && CurrentStop < MaxStopLoss && PipsProfit >= MinProfit) { bool Trailed = OrderModify(OrderTicket(),OrderOpenPrice(),MaxStopLoss,OrderTakeProfit(),0); // エラー処理 if(Trailed == false) { } } } } } /* 売りポジショントレイリングストップ設定 */ void SellTrailingStop(string argSymbol, int argTrailingStop, int argMinProfit, int argMagicNumber) { bool result; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if( result == true ) { // 最大損切り価格と最小利食い価格の計算 double MaxStopLoss = MarketInfo(argSymbol,MODE_ASK) + (argTrailingStop * dPoint); MaxStopLoss = NormalizeDouble(MaxStopLoss,(int)MarketInfo(OrderSymbol(),MODE_DIGITS)); double CurrentStop = NormalizeDouble(OrderStopLoss(),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)); double PipsProfit = OrderOpenPrice() - MarketInfo(argSymbol,MODE_ASK); double MinProfit = argMinProfit * dPoint; // 損切り価格の変更 if(OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_SELL && (CurrentStop > MaxStopLoss || CurrentStop == 0) && PipsProfit >= MinProfit) { bool Trailed = OrderModify(OrderTicket(),OrderOpenPrice(),MaxStopLoss,OrderTakeProfit(),0); // エラー処理 if(Trailed == false) { } } } } } /* 買いポジション数を確認 */ int BuyMarketCount(string argSymbol, int argMagicNumber) { bool result; int OrderCount = 0; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if(result == true && OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_BUY) { OrderCount++; } } return(OrderCount); } /* 売りポジション数を確認 */ int SellMarketCount(string argSymbol, int argMagicNumber) { bool result; int OrderCount= 0; for(int Counter = 0; Counter <= OrdersTotal()-1; Counter++) { result = OrderSelect(Counter,SELECT_BY_POS); if(result == true && OrderMagicNumber() == argMagicNumber && OrderSymbol() == argSymbol && OrderType() == OP_SELL) { OrderCount++; } } return(OrderCount); }
注文関数はEA内でよく使用する機能を関数化しているものです。各関数ではMagicナンバーとシンボルを判定し本EAによるポジションか確認しています。
- CloseAllBuyOrders:買いポジションを全てクローズします。
- CloseAllSellOrders:売りポジションを全てクローズします。
- BuyTrailingStop:買いポジションがargMinProfitに指定したpips以上の利益が出るとargTrailingStopのpips値にストップを移動します。
- SellTrailingStop: 売りポジションがargMinProfitに指定したpips以上の利益が出るとargTrailingStopのpips値にストップを移動します。
- BuyMarketCount:買いポジション数をカウントします。
- SellMarketCount:売りポジション数をカウントします。
参考書籍
本EAには以下の書籍を参考としている箇所があります。オーダー周りの処理はMT4ならではの知識が必要となりますが、自作する際の情報収集に大変有用でした。
![]() |
FXメタトレーダー4 MQLプログラミング 堅牢なEA構築のための総合ガイド (ウィザードブックシリーズ) [ アンドリュー・R.ヤング ] 価格:3,024円 |
![]() |
FXメタトレーダー実践プログラミング 高機能システムトレードソフト超活用術 (現代の錬金術師シリーズ) [ 豊嶋久道 ] 価格:3,024円 |