
MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第5回): ケルトナーチャネルのボリンジャーバンド—指標シグナル
はじめに
この記事における多通貨EAの定義は、1つの銘柄チャートからのみ複数の銘柄ペアの取引(注文を出す、注文を決済する、注文を管理するなど)ができるEAまたは自動売買ロボットです。この記事では、EAは30ペアを取引します。
この記事では、2つの指標、この場合はケルトナーチャネルのボリンジャーバンド®からのシグナルを使用します。
古いプラットフォーム(MetaTrader 4)では、このようなシグナルの使用はiBandsOnArray関数として知られていました。
MQL4リファレンスのiBandsOnArray関数の説明では、次のように述べられています。注:iBands(...)とは異なり、iBandsOnArray()関数は銘柄名、時間枠、適用価格によるデータを受け取りません。価格データは事前に準備する必要があります...
MQL5フォーラムのディスカッションを読むと、MQL5にはiBandOnArray()が存在しないと主張するトレーダーやユーザーさえいます。
確かに、iBandOnArray()はMQL5関数リストにはありませんが、iBands()指標ハンドルを使用することで、実際にはMQL5でiBandOnArray()を簡単に作成できます。実際、私の意見では、MQL5で指標ハンドルを使用する方が、MetaTrader 4でiBandsOnArray()関数を使用するよりも簡単で便利です。
以前の記事で証明したように、MQL5が提供するパワー、能力、機能を使用して、取引ターミナルとストラテジーテスターの両方で複数通貨取引が可能であることは誰もが知っています。
そのため、この記事では、効率的で効果的な自動売買ロボットを求めるトレーダーの本質的なニーズを満たすことを目的とし、信頼性の高いMQL5が提供する長所、能力、機能に頼ることで、開かれた注文に対して2つの指標シグナルを使用するシンプルな多通貨EAを作成します。ケルトナーチャネルのボリンジャーバンド®。ボリンジャーバンド指標はケルトナーチャネル指標からの価格データを使用します。一方、トレーリングストップの場合は、引き続きパラボリックSAR (iSAR)指標を使用します。
計画と機能
1.通貨ペアの取引
この多通貨EAは、以下の銘柄またはペアで取引するように設定されています。
28ペア:EURUSD、GBPUSD、AUDUSD、NZDUSD、USDCAD、USDCHF、USDJPY、EURGBP、EURAUD、EURNZD、EURCAD、EURCHF、EURJPY、GBPAUD、GBPNZD、GBPCAD、GBPCHF、GBPJPY、AUDNZD、AUDCAD、AUDCHF、AUDJPY、NZDCAD、NZDCHF、NZDJPY、CADCHF、CADJPY、CHFJPY
メタル2ペア:XAUUSD(金)とXAGUSD(銀)
合計30ペア
前回の記事と同様に、この記事でもペア名のプレフィックスとペア名のサフィックスに特別な入力プロパティを追加することで作業を簡単にします。次に、簡単な関数を使用して、ペア名のプレフィックスおよび/またはサフィックスを、登録されている30個のペア名と組み合わせて処理します。これにより、このような特殊な銘柄名を持つブローカーのEAをMetaTrader 5で使用するときに、すべてがスムーズに機能します。
プレフィックスとサフィックスを持つ銘柄名を検出する関数の弱点は、この関数がMT5の外国為替および金属銘柄のペアまたは名前に対してのみ機能し、特殊な銘柄やインデックスに対しては機能しないことです。それとは別に、この方法のもう1つの弱点は、トレーダーがペアのプレフィックスおよび/またはサフィックスの名前にタイプミス(大文字と小文字は区別されるなど)をした場合です。この記事のEAを使用するトレーダーには、ペア名のプレフィックスおよび/またはサフィックスを入力する際に正確さと精度が期待されます。
前回の記事と同様に、このEAでも、現時点で取引されるペアのオプションを10個追加しました。取引される10のオプションペアの1つは「トレーダー希望ペア」で、取引されるペアはトレーダーがEA入力プロパティに手動で入力する必要があります。ただし、入力するペアの名前がすでに30ペアのリストに含まれている必要があることに常に留意する必要があります。
このバージョンのEAでは、取引セッション(タイムゾーン)のオプションも追加したため、取引されるペアは取引セッションの時間に対応する可能性があります。
2.シグナル指標
このバージョンのEAでは、2つの指標のシグナル、この場合はケルトナーチャネルのボリンジャーバンド®を使用します。ボリンジャーバンド®指標の価格データとして、ケルトナーチャネル指標を使用します。
2.1.ケルトナーチャネル指標
ケルトナーチャネルは、1960年代にチェスター・ケルトナーによって初めて導入されました。元の計算式では、単純移動平均(SMA)と高値/安値の価格帯を使用してバンドを計算していました。 1980年代に、Average True Range (ATR)を使用する新しい計算式が導入されました。ATR法は現在一般的に使用されています。
この記事のEAに使用されるケルトナーチャネル指標は、現在一般的な手法、つまりATR指標の期間20を使用した上下のバンドを持つ指数移動平均(EMA)期間20を使用して特に作成しました。
ケルトナーチャネル指標の入力プロパティは次のとおりです。
2.2.ボリンジャーバンド®指標
ボリンジャーバンド®は、80年代にジョン・ボリンジャーによって作成され、すぐにテクニカル分析分野で最も広く使用される指標の1つになりました。ボリンジャーバンド®は、市場の短期的な極端な価格を強調するために使用される、上部、中間、下部の3つのバンドで構成されています。上部のバンドは買われすぎの状態を示し、下部のバンドは売られすぎの状態を示します。ほとんどの金融アナリストは、ボリンジャーバンド®を使用し、他の指標と組み合わせて、市場の状態をより適切に分析的に把握します。
この記事のEAでは、ケルトナーチャネル指標からの価格データを使用する期間38のボリンジャーバンド®指標を使用します。
ボリンジャーバンド®指標の入力プロパティは次のとおりです。
買いまたは売りシグナルのボリンジャーバンド®指標の価格データとしてのケルトナーチャネル指標の図を図1および図2に示します。
図1:買いシグナル
図2:売りシグナル
上の図では、ケルトナーチャネルの中央線がボリンジャーバンド®の上側線またはボリンジャーバンド®の下側線の上または下を横切った場合にのみシグナルが表示されます。しかし、この記事のEAの場合、指標シグナルは実際にはケルトナーチャネル指標の中央線とボリンジャーバンド®指標の上部、中間、下部のライン間のクロスオーバーです。
- 買いシグナルの場合
- 最初のシグナル:ケルトナーチャネル指標の中央線がボリンジャーバンド®指標の下限線と交差したとき。または
- 2番目のシグナル:ケルトナーチャネル指標の中間線がボリンジャーバンド®指標の中間線を超えたとき。または
- 3番目のシグナル:ケルトナーチャネル指標の中央線がボリンジャーバンド®指標の上部線と交差したとき。
- 売りシグナルの場合:
- 最初のシグナル:ケルトナーチャネル指標の中央線がボリンジャーバンド®指標の上部線を下降したとき。または
- 2番目のシグナル:ケルトナーチャネル指標の中央線がボリンジャーバンド®指標の中央線を下降したとき。または
- 3番目のシグナル:ケルトナーチャネル指標の中央線がボリンジャーバンド®指標の下側の線をクロスダウンしたとき。
3.取引と注文管理
この多通貨EAは、取引を管理するためのいくつかのオプションを備えています。
3.1.ストップロス注文
オプション:Use Order Stop Loss:Yes/No
- Use Order Stop LossでNoを選択すると、すべての注文はストップロスなしで発注されます。
- Use Order Stop LossがYesの場合:再びオプションが与えられます。Use Automatic Calculation Stop LossでYes/Noを指定することになります。
- Use Automatic Calculation Stop LossがYesの場合、ストップロスの計算はEAによって自動的に実行されます。
- Use Automatic Calculation Stop LossでNoを選択すると、トレーダーはストップロスの値をPipsで入力する必要があります。
- Use Order Stop LossがNoの場合:EAは、開かれた各注文について、シグナル状態がまだ良好で利益を得るために注文を維持できるか、または、シグナルが弱まり、利益を保存するために注文を閉じる必要がある状態か、または、シグナル状態の方向が逆になっているため、損失状態で注文を閉じる必要があるかを確認します。
注:特に弱いシグナルによる取引決済と利益の保存については、それをアクティブにするかどうかのオプションが与えられます。
アクティブ化されていない場合(No)、シグナルが弱まっても注文は維持されるか、利益を保存するために決済されません。
有効化された場合(Yes)、ケルトナーチャナー指標とボリンジャーバンド®指標の条件は次のとおりです。
- 買い注文を閉じるには:ケルトナーチャネル指標の下側の線がボリンジャーバンド®の上側の線を下回ると、買い注文は閉じられます。
- 売り注文を閉じるには:ケルトナーチャネル指標の上の線がボリンジャーバンド®の下の線と交差すると、売り注文は閉じられます。
ストップロス注文を設定するコードは次のとおりです。
double MCEA::OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- slv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice-38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice-SLval*pip); else slv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice+38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice+SLval*pip); else slv=0.0; } } //--- return(slv); //--- } //-end OrderSLSet() //---------//
弱いシグナルによる取引を終了して利益を保存するコードは次のとおりです。
int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit { //--- int ret=0; int rise=1, down=-1; //-- int br=3; Pips(symbol); double difud=mc_symbol.NormalizePrice(1.5*pip); //-- double KCub[], KClb[]; double BBub[], BBlb[]; //-- ArrayResize(KCub,br,br); ArrayResize(KClb,br,br); ArrayResize(BBub,br,br); ArrayResize(BBlb,br,br); ArraySetAsSeries(KCub,true); ArraySetAsSeries(KClb,true); ArraySetAsSeries(BBub,true); ArraySetAsSeries(BBlb,true); //-- int xx=PairsIdxArray(symbol); //-- CopyBuffer(hKC[xx],1,0,br,KCub); CopyBuffer(hKC[xx],2,0,br,KClb); CopyBuffer(hBB[xx],1,0,br,BBub); CopyBuffer(hBB[xx],2,0,br,BBlb); //-- int dirmove=DirectionMove(symbol,TFt); bool closebuy=(KClb[1]>=BBub[1] && KClb[0]<BBub[0]-difud); bool closesel=(KCub[1]<=BBlb[1] && KCub[0]>BBlb[0]+difud); //-- if(exis==down && closesel && dirmove==rise) ret=rise; if(exis==rise && closebuy && dirmove==down) ret=down; //-- return(ret); //--- } //-end GetCloseInWeakSignal() //---------//
3.2.テイクプロフィット注文
オプション:UseOrderTakeProfit:Yes/No
- UseOrderTakeProfitでNoを選択した場合、すべての注文はテイクプロフィットなしで発注されます。
- Use Order Take ProfitがYesの場合:再びオプションが与えられます。UseAutomaticCalculationOrderTakeProfit:Yes/Noオプションを指定することになります。
- Use Automatic Calculation Order Take ProfitでYesを選択すると、テイクプロフィット注文の計算はEAで自動的におこなわれます。
- Use Automatic Calculation Order Take ProfitでNoを選択した場合、トレーダーは注文のテイクプロフィット値をPipsで入力する必要があります。
テイクプロフィット注文を設定するコードは次のとおりです。
double MCEA::OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- tpv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice+50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice+TPval*pip); else tpv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice-50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice-TPval*pip); else tpv=0.0; } } //--- return(tpv); //--- } //-end OrderTPSet() //---------//
3.3.トレーリングストップとトレーリングテイクプロフィット
オプション:UseTrailingSL/TP:Yes/No
- UseTrailingSL/TPがNoの場合、EAはトレーリングストップロスおよびトレーリングテイクプロフィットをおこないません。
- Use Trailing SL/TPがYesの場合:再びオプションが与えられます。Use Automatic Trailing:Yes/Noを指定することになります。
- Use Automatic TrailingがYesの場合、トレーリングストップは、EAが時間枠シグナル計算と同時にパラボリックSAR (iSAR)値を使用し、同時に変数値TPmin(最小トレーリング利益値)に基づいてトレーリング利益を得ることで実行されます。
- Use Automatic TrailingがNoの場合、EAによってトレーリングストップが入力プロパティの値を使用して実行されます。
注:EAはトレーリングストップと同時にトレーリングテイクプロフィットを実行します。
トレーリングストップ価格関数:
double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type) { //--- int br=2; double pval=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); //-- switch(TS_type) { case 0: { RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY) pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip); if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip); break; } case 1: { double PSAR[]; ArrayResize(PSAR,br,br); ArraySetAsSeries(PSAR,true); CopyBuffer(hParIU[x],0,0,br,PSAR); RefreshPrice(xsymb,TFt,br); //-- if(ptype==POSITION_TYPE_BUY && (PSAR[0]<iLow(xsymb,TFt,0))) pval=PSAR[0]; if(ptype==POSITION_TYPE_SELL && (PSAR[0]>iHigh(xsymb,TFt,0))) pval=PSAR[0]; break; } } //-- return(pval); //--- } //-end TSPrice() //---------//
SL/TP機能の変更:
bool MCEA::ModifySLTP(const string symbx,int TS_type) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int TRSP=TS_type; bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrsb+TSmin*pip); double modbuysl=vtrsb; double modbuytp=mc_symbol.NormalizePrice(price+TPmin*pip); bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>0.05) { modist=mc_trade.PositionModify(symbol,modbuysl,modbuytp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrss-TSmin*pip); double modselsl=vtrss; double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip); bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>0.05) { modist=mc_trade.PositionModify(symbol,modselsl,modseltp); } } } } //-- return(modist); //--- } //-end ModifySLTP() //---------//
4.手動による注文管理
この多通貨EAの効率をサポートするために、いくつかの手動クリックボタンが追加されます。
4.1.SetSL/TPAllOrders
トレーダーの入力パラメータがOrderStopLossがNoおよび/またはUseOrderTakeProfitがNoの場合
すべての注文でストップロスまたはテイクプロフィットを使用する場合、
[Set SL / TP All Orders]ボタンを1回クリックするだけで済みます。すべての注文が変更され、ストップロスやテイクプロフィットが適用されます。
4.2.すべての注文を決済したい場合、[Close All Orders]ボタンを1回クリックするだけで、すべての未決注文が決済されます。
4.3.すでに利益が出ている注文をすべて決済したい場合、[Close All Orders Profit]ボタンを1回クリックするだけで、すべてのすでに利益が得られている未処理の注文が決済されます。
5.注文管理とチャート銘柄
1つのチャート銘柄から30ペアを取引する多通貨EAの場合、すべての銘柄にボタンパネルがあれば、トレーダーがワンクリックでチャートや銘柄を変更して、EAが注文を開閉するときに指標シグナルの精度を確認できるようになり、非常に効果的かつ効率的になります。
MQL5プログラムでの実装計画
1.プログラムヘッダーと入力プロパティ
ヘッダーファイルMQL5をインクルードします。
//+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\AccountInfo.mqh> //-- CTrade mc_trade; CSymbolInfo mc_symbol; CPositionInfo mc_position; CAccountInfo mc_account; //---
使用するタイムゾーンの列挙
//-- enum tm_zone { Cus_Session, // Trading on Custom Session New_Zealand, // Trading on New Zealand Session Australia, // Trading on Australia Sydney Session Asia_Tokyo, // Trading on Asia Tokyo Session Europe_London, // Trading on Europe London Session US_New_York // Trading on US New York Session }; //--
時間を選択するための列挙
//-- enum swhour { hr_00=0, // 00:00 hr_01=1, // 01:00 hr_02=2, // 02:00 hr_03=3, // 03:00 hr_04=4, // 04:00 hr_05=5, // 05:00 hr_06=6, // 06:00 hr_07=7, // 07:00 hr_08=8, // 08:00 hr_09=9, // 09:00 hr_10=10, // 10:00 hr_11=11, // 11:00 hr_12=12, // 12:00 hr_13=13, // 13:00 hr_14=14, // 14:00 hr_15=15, // 15:00 hr_16=16, // 16:00 hr_17=17, // 17:00 hr_18=18, // 18:00 hr_19=19, // 19:00 hr_20=20, // 20:00 hr_21=21, // 21:00 hr_22=22, // 22:00 hr_23=23 // 23:00 }; //--
時間、分を選択するための列挙
//-- enum inmnt { mn_00=0, // Minute 0 mn_05=5, // Minute 5 mn_10=10, // Minute 10 mn_15=15, // Minute 15 mn_20=20, // Minute 20 mn_25=25, // Minute 25 mn_30=30, // Minute 30 mn_35=35, // Minute 35 mn_40=40, // Minute 40 mn_45=45, // Minute 45 mn_50=50, // Minute 50 mn_55=55 // Minute 55 }; //--
取引するオプションペアを選択するための列挙
//-- enum PairsTrade { All30, // All Forex 30 Pairs TrdWi, // Trader Wishes Pairs Usds, // Forex USD Pairs Eurs, // Forex EUR Pairs Gbps, // Forex GBP Pairs Auds, // Forex AUD Pairs Nzds, // Forex NZD Pairs Cads, // Forex CDD Pairs Chfs, // Forex CHF Pairs Jpys // Forex JPY Pairs }; //--
列挙YNは、EA入力プロパティのオプション(Yes/No)に使用されます。
資金管理ロットサイズを使用する列挙
//-- enum YN { No, Yes }; //--
計算シグナル指標で使用される時間枠を選択するための列挙体
//-- enum TFUSE { TFM5, // PERIOD_M5 TFM15, // PERIOD_M15 TFM30, // PERIOD_M30 TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
注:TFUSE列挙体では、EAの時間枠計算の使用をTF-M5からTF-D1までに制限します。
EA入力プロパティ
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFUSE tfinuse = TFH1; // Select Expert TimeFrame, default PERIOD_H1 input int KCPeriod = 20; // Input Keltner Channel Period, default 20 input ENUM_MA_METHOD KCMethod = MODE_EMA; // Select Keltner Channel MA Method, default EMA input ENUM_APPLIED_PRICE KCMAAP = PRICE_TYPICAL; // Select Keltner Channel MA Applied Price, default Price Typical input int KCATRPer = 20; // Input Keltner Channel ATR Period, default 20 input double KCATRBandsMulti = 1.0; // Input Keltner Channel ATR bands multiplier input int BBPeriod = 38; // Input Bollinger Bands® Indicator period, default 38 input double BBDevi = 1.0; // Input Bollinger Bands® Indicator Deviations, default 1.00 //--- input group "=== Select Pairs to Trade ==="; // Selected Pairs to trading input PairsTrade usepairs = All30; // Select Pairs to Use input string traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma input string sym_prefix = ""; // Input the symbol prefix in case sensitive (if any) input string sym_suffix = ""; // Input the symbol suffix in case sensitive (if any) //-- input group "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter input mmt mmlot = DynamLot; // Money Management Type input double Risk = 10.0; // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%) input double Lots = 0.01; // Input Manual Lot Size FixedLot //--Trade on Specific Time input group "=== Trade on Specific Time ==="; // Trade on Specific Time input YN trd_time_zone = Yes; // Select If You Like to Trade on Specific Time Zone input tm_zone session = Cus_Session; // Select Trading Time Zone input swhour stsescuh = hr_00; // Time Hour to Start Trading Custom Session (0-23) input inmnt stsescum = mn_15; // Time Minute to Start Trading Custom Session (0-55) input swhour clsescuh = hr_23; // Time Hour to Stop Trading Custom Session (0-23) input inmnt clsescum = mn_55; // Time Minute to Stop Trading Custom Session (0-55) //--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No) //--Trade & Order management Parameter input group "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter input YN use_sl = No; // Use Order Stop Loss (Yes) or (No) input YN autosl = Yes; // Use Automatic Calculation Stop Loss (Yes) or (No) input double SLval = 30; // If Not Use Automatic SL - Input SL value in Pips input YN use_tp = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 100; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = Yes; // Use Automatic Trailing (Yes) or (No) input double TSval = 5; // If Not Use Automatic Trailing Input Trailing value in Pips input double TSmin = 5; // Minimum Pips to start Trailing Stop input double TPmin = 25; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No) input ulong magicEA = 20231204; // Expert ID (Magic Number) //---
注:EA ID(マジックナンバー)の入力プロパティが空白のままの場合、EAは手動で開かれた注文を管理できます。
EA入力プロパティグループの[Global Strategy EA Parameters]では、トレーダーは指標シグナル計算のEA時間枠を選択し、ケルトナーチャネルおよびボリンジャーバンド®指標のパラメータを入力するように指示されます。
この記事のEAを作成する場合、EAのケルトナーチャネル指標の入力プロパティは、指標の入力プロパティとまったく同じ入力プロパティを使用します。
//-- input int period_kc = 20; // Input Keltner Channel Period input ENUM_MA_METHOD ma_method = MODE_EMA; // Select MA Type of smoothing input ENUM_APPLIED_PRICE ma_price = PRICE_TYPICAL; // Select MA Applied Price input int atr_period = 20; // Input ATR Period (typically over 10 or 20) input double band_multi = 1.00; // Input the Band Multiplier ATR Desired //--
EA入力プロパティグループの[Select Pairs to Trade]では、提供される10のオプションから取引するペアを選択します。デフォルトでは[All Forex 30 Pairs]が決定されます。
取引されるペアを設定するには、HandlingSymbolArrays()関数を呼び出します。HandlingSymbolArrays()関数を使用して、取引されるすべてのペアを処理します。
void MCEA::HandlingSymbolArrays(void) { //--- string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP", "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD", "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF", "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs //-- sall=ArraySize(All30); arusd=ArraySize(USDs); aretc=ArraySize(EURs); ArrayResize(VSym,sall,sall); ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); //-- if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0) { string to_split=traderwishes; // A string to split into substrings pairs name string sep=","; // A separator as a character ushort u_sep; // The code of the separator character //--- Get the separator code u_sep=StringGetCharacter(sep,0); //--- Split the string to substrings int p=StringSplit(to_split,u_sep,SPC); if(p>0) { for(int i=0; i<p; i++) StringToUpper(SPC[i]); //-- for(int i=0; i<p; i++) { if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1); } } arspc=ArraySize(SPC); } //-- SetSymbolNamePS(); // With this function we will detect whether the Symbol Name has a prefix and/or suffix //-- if(inpre>0 || insuf>0) { if(usepairs==TrdWi && arspc>0) { for(int t=0; t<arspc; t++) { SPC[t]=pre+SPC[t]+suf; } } //-- for(int t=0; t<sall; t++) { All30[t]=pre+All30[t]+suf; } for(int t=0; t<arusd; t++) { USDs[t]=pre+USDs[t]+suf; } for(int t=0; t<aretc; t++) { EURs[t]=pre+EURs[t]+suf; } for(int t=0; t<aretc; t++) { GBPs[t]=pre+GBPs[t]+suf; } for(int t=0; t<aretc; t++) { AUDs[t]=pre+AUDs[t]+suf; } for(int t=0; t<aretc; t++) { NZDs[t]=pre+NZDs[t]+suf; } for(int t=0; t<aretc; t++) { CADs[t]=pre+CADs[t]+suf; } for(int t=0; t<aretc; t++) { CHFs[t]=pre+CHFs[t]+suf; } for(int t=0; t<aretc; t++) { JPYs[t]=pre+JPYs[t]+suf; } } //-- ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);} if(ValidatePairs(Symbol())>=0) symbfix=true; if(!symbfix) { Alert("Expert Advisors will not trade on pairs "+Symbol()); Alert("-- "+expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(usepairs) { case 0: // All Forex 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency 30 Pairs"; //-- break; } case 1: // Trader wishes pairs { ArrayResize(DIRI,arspc,arspc); arrsymbx=arspc; ArraySymbolResize(); ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY); pairs="("+string(arspc)+") Trader Wishes Pairs"; //-- break; } case 2: // USD pairs { ArrayResize(DIRI,arusd,arusd); arrsymbx=arusd; ArraySymbolResize(); ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY); pairs="("+string(arusd)+") Multi Currency USD Pairs"; //-- break; } case 3: // EUR pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex EUR Pairs"; //-- break; } case 4: // GBP pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex GBP Pairs"; //-- break; } case 5: // AUD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex AUD Pairs"; //-- break; } case 6: // NZD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex NZD Pairs"; //-- break; } case 7: // CAD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CAD Pairs"; //-- break; } case 8: // CHF pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CHF Pairs"; //-- break; } case 9: // JPY pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex JPY Pairs"; //-- break; } } //-- return; //--- } //-end HandlingSymbolArrays() //---------//
HandlingSymbolArrays()関数内でSetSymbolNamePS()関数を呼び出します。SetSymbolNamePS()関数を使用すると、プレフィックスやサフィックスを持つ銘柄名を処理できるようになります。
void MCEA::SetSymbolNamePS(void) { //--- symbfix=false; int ptriml; int ptrimr; string insymbol=Symbol(); int sym_Lenpre=StringLen(prefix); int sym_Lensuf=StringLen(suffix); if(sym_Lenpre>0) { ptriml=StringTrimLeft(suffix); ptriml=StringTrimRight(suffix); } if(sym_Lensuf>0) { ptrimr=StringTrimLeft(suffix); ptrimr=StringTrimRight(suffix); } string sym_pre=prefix; string sym_suf=suffix; //-- pre=sym_pre; suf=sym_suf; inpre=StringLen(pre); insuf=StringLen(suf); posCur1=inpre; posCur2=posCur1+3; //-- return; //--- } //-end SetSymbolNamePS() //---------//
注:EAがペアを検証します。トレーダーがペア名、ペアプレフィックス名やペアサフィックス名の入力を間違えた場合(タイプミス)、またはペアの検証に失敗した場合、EAには警告が表示され、EAはチャートから削除されます。
EA入力プロパティグループの[Trade on Specific Time]では、[Trade on Specific Time Zone]でYesまたはNoを選択します。Yesの場合は、次の列挙体オプションを選択します。
- カスタムセッションでの取引
- ニュージーランドセッションでの取引
- オーストラリアシドニーセッションでの取引
- アジア東京セッションでの取引
- ヨーロッパロンドンセッションでの取引
- アメリカニューヨークセッションでの取引
カスタムセッションでの取引:このセッションでは、トレーダーは取引を開始する時刻、または取引を終了する時間と分を設定する必要があります。これは、EAが開始から終了までの指定された期間中にのみアクティビティを実行することを意味します。
ニュージーランドのセッション取引からニューヨークの米国セッション取引までの時間は、取引の開始から取引終了までの時間はEAによって計算されます。
EAを作業するためのクラス
EAのワークフローの構造と構成を決定するには、この多通貨EAに必要なすべての変数、オブジェクト、および関数を宣言するクラスを作成します。
//+------------------------------------------------------------------+ //| Class for working Expert Advisor | //+------------------------------------------------------------------+ class MCEA { //--- private: //---- int x_year; // Year int x_mon; // Month int x_day; // Day of the month int x_hour; // Hour in a day int x_min; // Minutes int x_sec; // Seconds //-- int oBm, oSm, ldig; //--- Variables used in prefix and suffix symbols int posCur1, posCur2; int inpre, insuf; bool symbfix; string pre,suf; string prefix,suffix; //--- Variables are used in Trading Time Zone int ishour, onhour; int tftrlst, tfcinws; datetime rem, znop, zncl, zntm; datetime SesCuOp, SesCuCl, Ses01Op, Ses01Cl, Ses02Op, Ses02Cl, Ses03Op, Ses03Cl, Ses04Op, Ses04Cl, Ses05Op, Ses05Cl, SesNoOp, SesNoCl; //-- string tz_ses, tz_opn, tz_cls; //-- string tmopcu, tmclcu, tmop01, tmcl01, tmop02, tmcl02, tmop03, tmcl03, tmop04, tmcl04, tmop05, tmcl05, tmopno, tmclno; //---------------------- //-- double LotPS; double slv, tpv, pip, xpip; double SARstep, SARmaxi; double floatprofit, fixclprofit; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ void SetSymbolNamePS(void); void HandlingSymbolArrays(void); void Set_Time_Zone(void); void Time_Zone(void); bool Trade_session(void); string PosTimeZone(void); int ThisTime(const int reqmode); int ReqTime(datetime reqtime,const int reqmode); //-- int DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf); int BBOnKeltnerChannel(const string symbol); int PARSAR05(const string symbol); int LotDig(const string symbol); //-- double MLots(const string symbx); double NonZeroDiv(double val1,double val2); double OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type); //-- string ReqDate(int d,int h,int m); string TF2Str(ENUM_TIMEFRAMES period); string timehr(int hr,int mn); string TradingDay(void); string AccountMode(); string GetCommentForOrder(void) { return(expname); } //------------ public: //--- //-- BBOnKeltnerChannel_MCEA Config -- string DIRI[], AS30[], VSym[]; string SPC[]; string USD[]; string EUR[]; string GBP[]; string AUD[]; string NZD[]; string CAD[]; string CHF[]; string JPY[]; //-- string expname; string indiname; //-- int hKC[]; int hBB[]; int hParIU[], hPar05[]; int ALO, dgts, arrsar, arrsymbx; int sall, arusd, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; //-- int Buy, Sell; int ccur, psec, xtto, checktml; int OpOr[],xob[],xos[]; //-- int year, // Year mon, // Month day, // Day hour, // Hour min, // Minutes sec, // Seconds dow, // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) doy; // Day number of the year (January 1st is assigned the number value of zero) //-- ENUM_TIMEFRAMES TFt, TFT05; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void BBOnKeltnerChannel_MCEA_Config(void); virtual void ExpertActionTrade(void); //-- void ArraySymbolResize(void); void CurrentSymbolSet(const string symbol); void Pips(const string symbol); void TradeInfo(void); void Do_Alerts(const string symbx,string msgText); void CheckOpenPMx(const string symbx); void SetSLTPOrders(void); void CloseBuyPositions(const string symbol); void CloseSellPositions(const string symbol); void CloseAllOrders(void); void CheckClose(const string symbx); void TodayOrders(void); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf); void RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars); //-- bool RefreshTick(const string symbx); bool TradingToday(void); bool OpenBuy(const string symbol); bool OpenSell(const string symbol); bool ModifyOrderSLTP(double mStop,double ordtp); bool ModifySLTP(const string symbx,int TS_type); bool CloseAllProfit(void); bool ManualCloseAllProfit(void); //-- int PairsIdxArray(const string symbol); int ValidatePairs(const string symbol); int GetOpenPosition(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------//
OnInit()によって呼び出される、多通貨EAワークプロセスの最初の最も重要な関数は、BBOnKeltnerChannel_MCEA_Config()です。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.BBOnKeltnerChannel_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit() //---------//
BBOnKeltnerChannel_MCEA_Config()関数は、使用されるすべての銘柄、使用されるすべてのハンドル指標、およびEAワークフローのインクルードファイルヘッダーのいくつかの重要な関数を構成します。
関数行468~484では、時間枠を処理し、使用されるすべての指標の指標ハンドルを作成する方法が説明されています。
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::BBOnKeltnerChannel_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- TFT05=PERIOD_M5; ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; int arTFs=ArraySize(TFs); //-- for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x]; // TF for calculation signal //-- //-- Keltner Channel and Bollinger Bands® Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hKC[x]=iCustom(DIRI[x],TFt,indiname,KCPeriod,KCMethod,KCMAAP,KCATRPer,KCATRBandsMulti); //-- Handle for the Keltner Channel indicator hParIU[x]=iSAR(DIRI[x],TFt,SARstep,SARmaxi); //-- Handle for the iSAR indicator according to the selected Timeframe hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe //-- } //-- for(int x=0; x<arrsymbx; x++) hBB[x]=iBands(DIRI[x],TFt,BBPeriod,0,BBDevi,hKC[x]); //-- Handle for the iBands On Keltner Channel Indicator handle //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end BBOnKeltnerChannel_MCEA_Config() //---------//
2.EAティック関数
EAのティック関数(OnTick()関数)の中で、多通貨EAのもっとも重要な関数の1つであるExpertActionTrade()を呼び出します。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
この関数内のEAワークプロセスのシーケンスは次の通りです。
ExpertActionTrade()関数は、オープン注文、クローズ注文、トレーリングストップまたは取引利益、その他の追加アクティビティから始まるすべてのアクティビティを実行し、自動取引を管理します。
void MCEA::ExpertActionTrade(void) { //--- //--Check Trading Terminal ResetLastError(); //-- if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit { mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting."); mc.checktml=1; //-- Variable checktml is given a value of 1, so that the alert is only done once. return; } //-- if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- int mcsec=mc.ThisTime(mc.sec); //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) { string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday() && mc.Trade_session()) { //-- mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions //-- //-- and store in the variable OpOr[x] if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol); //-- if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } } //-- mc.CheckOpenPMx(symbol); //-- if(mc.xtto>0) { //-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>0.02 && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>0.02 && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //-- if(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes) { if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes) if(autotrl==No) mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No) } } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
[Day Trading On/Off]プロパティグループは、日曜日から土曜日までの指定された日に取引するオプションをトレーダーに提供します。このようにして、トレーダーは、Yes/Noのオプションを使用して、指定した日のEA取引をアクティブ化または非アクティブ化できます。
//--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No)
Execution for Day Trading On/Offは次のとおりです。
bool MCEA::TradingToday(void) { //--- bool tradetoday=false; int trdday=ThisTime(dow); hariini="No"; //-- int ttd[]; ArrayResize(ttd,7); ttd[0]=ttd0; ttd[1]=ttd1; ttd[2]=ttd2; ttd[3]=ttd3; ttd[4]=ttd4; ttd[5]=ttd5; ttd[6]=ttd6; //-- if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";} //-- return(tradetoday); //--- } //-end TradingToday() //---------//
メモ:Day Trading On/Off条件は、チャートの取引情報に表示されます。
EAの[Trade on Specific Time]プロパティグループでは、トレーダーはタイムゾーンごとに取引するオプションがあります。
input group "=== Trade on Specific Time ==="; // Trade on Specific Time input YN trd_time_zone = Yes; // Select If You Like to Trade on Specific Time Zone input tm_zone session = Cus_Session; // Select Trading Time Zone input swhour stsescuh = hr_00; // Time Hour to Start Trading Custom Session (0-23) input inmnt stsescum = mn_15; // Time Minute to Start Trading Custom Session (0-55) input swhour clsescuh = hr_23; // Time Hour to Stop Trading Custom Session (0-23) input inmnt clsescum = mn_55; // Time Minute to Stop Trading Custom Session (0-55)
メモ:上で説明したように、ニュージーランドセッションでの取引から米国ニューヨークセッションでの取引の場合、取引開始から取引終了までの時間がEAによって計算されます。したがって、EAエントリプロパティでは、トレーダーはカスタムセッションの取引開始時の時と分、および取引終了時の時と分を設定するだけで済みます。
特にタイムゾーン取引の場合、ブール型Trade_session()関数の呼び出しがExpertActionTrade()関数に追加されます。
Trade_session()がtrueの場合、EAの作業プロセスは終了するまで続行されますが、falseの場合、EAは[Close Trade and Save Profit due to Weak Signal if it is (Yes)]および[Trailing Stop if it is (Yes)]タスクのみを実行します。
bool MCEA::Trade_session(void) { //--- bool trd_ses=false; ishour=ThisTime(hour); if(ishour!=onhour) Set_Time_Zone(); datetime tcurr=TimeCurrent(); // Server Time //-- switch(session) { case Cus_Session: { if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true; break; } case New_Zealand: { if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true; break; } case Australia: { if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true; break; } case Asia_Tokyo: { if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true; break; } case Europe_London: { if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true; break; } case US_New_York: { if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true; break; } } //-- if(trd_time_zone==No) { if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true; } //-- onhour=ishour; //-- return(trd_ses); //--- } //-end Trade_session() //---------//
3.オープンポジションの取引シグナルの取得
シグナルを取得するには、ExpertActionTrade()関数はGetOpenPosition()関数を呼び出します。
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int BBOnKC=BBOnKeltnerChannel(symbol); //-- if(BBOnKC==rise) ret=rise; if(BBOnKC==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
GetOpenPosition()関数は、シグナル計算を実行するBBOnKeltnerChannel()関数を呼び出します。
int MCEA::BBOnKeltnerChannel(const string symbol) // Fungction of Bollinger Bands® On Keltner Channel Indicator { //--- int ret=0; int rise=1, down=-1; int br=3; Pips(symbol); double difud=mc_symbol.NormalizePrice(1.5*pip); //-- double KCmb[], // Destination array for Keltner Channel Middle Line buffer KCub[], // Destination array for Keltner Channel Upper Band buffer KClb[]; // Destination array for Keltner Channel Lower Band buffer double BBmb[], // Destination array for Bollinger Bands® BASE_LINE buffer BBub[], // Destination array for Bollinger Bands® UPPER_BAND buffer BBlb[]; // Destination array for Bollinger Bands® LOWER_BAND buffer //-- ArrayResize(KCmb,br,br); ArrayResize(KCub,br,br); ArrayResize(KClb,br,br); ArrayResize(BBmb,br,br); ArrayResize(BBub,br,br); ArrayResize(BBlb,br,br); ArraySetAsSeries(KCmb,true); ArraySetAsSeries(KCub,true); ArraySetAsSeries(KClb,true); ArraySetAsSeries(BBmb,true); ArraySetAsSeries(BBub,true); ArraySetAsSeries(BBlb,true); //-- int xx=PairsIdxArray(symbol); //-- CopyBuffer(hKC[xx],0,0,br,KCmb); CopyBuffer(hKC[xx],1,0,br,KCub); CopyBuffer(hKC[xx],2,0,br,KClb); CopyBuffer(hBB[xx],0,0,br,BBmb); CopyBuffer(hBB[xx],1,0,br,BBub); CopyBuffer(hBB[xx],2,0,br,BBlb); //-- bool BBKCrise1=(KCmb[1]<=BBlb[1] && KCmb[0]>BBlb[0]+difud); bool BBKCrise2=(KCmb[1]<=BBmb[1] && KCmb[0]>BBmb[0]+difud); bool BBKCrise3=(KCmb[1]<=BBub[1] && KCmb[0]>BBub[0]+difud); //-- bool BBKCdown1=(KCmb[1]>=BBub[1] && KCmb[0]<BBub[0]-difud); bool BBKCdown2=(KCmb[1]>=BBmb[1] && KCmb[0]<BBmb[0]-difud); bool BBKCdown3=(KCmb[1]>=BBlb[1] && KCmb[0]<BBlb[0]-difud); //-- if(BBKCrise1 || BBKCrise2 || BBKCrise3) ret=rise; if(BBKCdown1 || BBKCdown2 || BBKCdown3) ret=down; //-- return(ret); //--- } //-end BBOnKeltnerChannel() //---------//
ご覧のとおり、BBOnKeltnerChannel()関数内では、1つの関数(PairsIdxArray())を使用して呼び出しています。
int xx=PairsIdxArray(symbol);
int MCEA::PairsIdxArray(const string symbol) { //--- int pidx=-1; //-- for(int x=0; x<arrsymbx; x++) { if(DIRI[x]==symbol) { pidx=x; break; } } //-- return(pidx); //--- } //-end PairsIdxArray() //---------//
PairsIdxArray()関数は、要求された銘柄の名前とその指標のハンドルを取得するために使用されます。次に、対応する指標ハンドルが呼び出され、その時間枠からケルトナーチャネルとボリンジャーバンド®シグナルのバッファ値が取得されます。
次に、ケルトナーチャネル指標のバッファ番号を知る必要があります。ケルトナーチャネル指標では、OnInit()関数でバッファ番号が次のとおりであることがわかります。0-中央線、1-上部バンド、2-下部バンド
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //-- assignment of array to indicator buffer SetIndexBuffer(0,KC_Middle,INDICATOR_DATA); SetIndexBuffer(1,KC_UpperB,INDICATOR_DATA); SetIndexBuffer(2,KC_LowerB,INDICATOR_DATA); SetIndexBuffer(3,KC_ATRtemp,INDICATOR_CALCULATIONS); //-- handleMA=iMA(Symbol(),Period(),period_kc,0,MODE_EMA,ma_price); //-- if(handleMA==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the Moving Average indicator for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //-- handleATR=iATR(Symbol(),Period(),atr_period); //-- if(handleATR==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the ATR indicator for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //-- short_name=StringFormat("Keltner Channel(%d, %s, %.2f)",period_kc,EnumToString(ma_method),band_multi); IndicatorSetString(INDICATOR_SHORTNAME,short_name); IndicatorSetInteger(INDICATOR_DIGITS,Digits()); //-- return(INIT_SUCCEEDED); //--- } //---------//
この場合、ボリンジャーバンド®指標のバッファの数も知る必要があります。
一方、iBands®関数で説明されているように
「メモ:バッファ番号は次のとおりです。0 - BASE_LINE、1 - UPPER_BAND、2 - LOWER_BAND」
applied_price
[in] 使用された価格。価格定数ENUM_APPLIED_PRICEのいずれか、または別の指標のハンドルを指定できます。
この記事では、EAはケルトナーチャネル指標ハンドルからボリンジャーバンド®に適用された価格を使用します。
したがって、ケルトナーチャネルおよびボリンジャーバンド®指標の各ラインのバッファ値を取得するには、指標ハンドルから各バッファをコピーします。
中央線バッファ(バッファ0)をケルトナーチャネル指標ハンドルから宛先配列にコピーするには、次の手順を実行します。
CopyBuffer(hKC[xx],0,0,br,KCmb);
上バンドバッファ(バッファ1)をケルトナーチャネル指標ハンドルから宛先配列にコピーするには、次の手順を実行します。
CopyBuffer(hKC[xx],1,0,br,KCub);
下バンドバッファ(バッファ2)をケルトナーチャネル指標ハンドルから宛先配列にコピーするには、次の手順を実行します。
CopyBuffer(hKC[xx],2,0,br,KClb);
BASE_LINEバッファ(バッファ0)をボリンジャーバンド®指標ハンドルからコピー先の配列にコピーするには、次の手順を実行します。
CopyBuffer(hBB[xx],0,0,br,BBmb);
UPPER_BANDバッファ(バッファ1)をボリンジャーバンド®指標ハンドルからコピー先の配列にコピーするには、次の手順を実行します。
CopyBuffer(hBB[xx],1,0,br,BBub);
LOWER_BANDバッファ(バッファ2)をボリンジャーバンド®指標ハンドルからコピー先の配列にコピーするには、次の手順を実行します。
CopyBuffer(hBB[xx],2,0,br,BBlb);
次に、GetOpenPosition()関数によって次の結果が返されます。
- 値0:シグナルは不明
- 値1:オープン買い注文シグナル
- 値-1:オープン売り注文シグナル
GetOpenPosition()関数が値1を返した場合、EAはOpenBuy()関数を呼び出します。
bool MCEA::OpenBuy(const string symbol) { //--- ResetLastError(); //-- bool buyopen = false; string ldComm = GetCommentForOrder()+"_Buy"; double ldLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Bid()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Ask()); //-- if(RefreshTick(symbol)) buyopen=mc_trade.Buy(ldLot,symbol,mc_symbol.Ask(),SL,TP,ldComm); //-- int error=GetLastError(); if(buyopen||error==0) { string bsopen="Open BUY Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open BUY order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(buyopen); //-- //--- } //-end OpenBuy //---------//
その間、GetOpenPosition()関数が-1の値を返した場合、EAはOpenSell()関数を呼び出します。
bool MCEA::OpenSell(const string symbol) { //--- ResetLastError(); //-- bool selopen = false; string sdComm = GetCommentForOrder()+"_Sell"; double sdLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Ask()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Bid()); //-- if(RefreshTick(symbol)) selopen=mc_trade.Sell(sdLot,symbol,mc_symbol.Bid(),SL,TP,sdComm); //-- int error=GetLastError(); if(selopen||error==0) { string bsopen="Open SELL Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open SELL order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(selopen); //-- //--- } //-end OpenSell //---------//
4.ChartEvent関数
多通貨EAの使用における有効性と効率性をサポートするには、注文の管理およびチャートまたは銘柄の変更において1つ以上の手動ボタンを作成する必要があると考えられます。
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- //--- handling CHARTEVENT_CLICK event ("Clicking the chart") ResetLastError(); //-- ENUM_TIMEFRAMES CCS=mc.TFt; //-- if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //-- //--- if "Set SL All Orders" button is click if(sparam=="Set SL/TP All Orders") { mc.SetSLTPOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders"); //--- unpress the button ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false); ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Order" button is click if(sparam=="Close All Order") { mc.CloseAllOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders"); //--- unpress the button ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Profit" button is click if(sparam=="Close All Profit") { mc.ManualCloseAllProfit(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit"); //--- unpress the button ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "X" button is click if(sparam=="X") { ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //--- unpress the button ObjectSetInteger(0,"X",OBJPROP_STATE,false); ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateSymbolPanel(); } //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
[Other Expert Advisor Parameters]入力プロパティグループでは、トレーダーには、チャート上に取引情報を表示するかどうかを選択するYes/Noオプションが与えられます。
このオプションが選択されている場合(Yes)、TradeInfo()関数を呼び出すことによって、EAが接続されているチャートに取引情報が表示されます。
TradeInfo()関数の一部として、取引タイムゾーン条件に従って時間を記述する関数も追加しました。
string MCEA::PosTimeZone(void) { //--- string tzpos=""; //-- if(ReqTime(zntm,day)>ThisTime(day)) { tzpos=tz_opn+ " Next day to " +tz_cls + " Next day"; } else if(TimeCurrent()<znop) { if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; //else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; } else if(TimeCurrent()>=znop && TimeCurrent()<zncl) { if(ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; else if(ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; } else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) { tzpos=tz_opn+" Today to " +tz_cls+ " Next day"; } //-- return(tzpos); //---- } //-end PosTimeZone() //---------//
void MCEA::TradeInfo(void) // function: write comments on the chart { //---- Pips(Symbol()); double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip; rem=zntm-TimeCurrent(); string postime=PosTimeZone(); string eawait=" - Waiting for active time..!"; //-- string comm=""; TodayOrders(); //-- comm="\n :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ " "+TimeToString(TimeCurrent(),TIME_SECONDS)+ "\n ------------------------------------------------------------"+ "\n :: Broker : "+ TerminalInfoString(TERMINAL_COMPANY)+ "\n :: Expert Name : "+ expname+ "\n :: Acc. Name : "+ mc_account.Name()+ "\n :: Acc. Number : "+ (string)mc_account.Login()+ "\n :: Acc. TradeMode : "+ AccountMode()+ "\n :: Acc. Leverage : 1 : "+ (string)mc_account.Leverage()+ "\n :: Acc. Equity : "+ DoubleToString(mc_account.Equity(),2)+ "\n :: Margin Mode : "+ (string)mc_account.MarginModeDescription()+ "\n :: Magic Number : "+ string(magicEA)+ "\n :: Trade on TF : "+ EnumToString(TFt)+ "\n :: Today Trading : "+ TradingDay()+" : "+hariini+ "\n :: Trading Session : "+ tz_ses+ "\n :: Trading Time : "+ postime; if(TimeCurrent()<zntm) { comm=comm+ "\n :: Time Remaining : "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait; } comm=comm+ "\n ------------------------------------------------------------"+ "\n :: Trading Pairs : "+pairs+ "\n :: BUY Market : "+string(oBm)+ "\n :: SELL Market : "+string(oSm)+ "\n :: Total Order : "+string(oBm+oSm)+ "\n :: Order Profit : "+DoubleToString(floatprofit,2)+ "\n :: Fixed Profit : "+DoubleToString(fixclprofit,2)+ "\n :: Float Money : "+DoubleToString(floatprofit,2)+ "\n :: Nett Profit : "+DoubleToString(floatprofit+fixclprofit,2); //-- Comment(comm); ChartRedraw(0); return; //---- } //-end TradeInfo() //---------//
他通貨EA BBOnKeltnerChannel_MCEAのインターフェイスは、次の図のようになります。
ご覧のとおり、EA名BBOnKeltnerChannel_MCEAの下に[M]、[C]、[R]ボタンがあります。
[M]ボタンをクリックすると、下図に示すように、手動クリック用のボタンのパネルが表示されます。
手動クリックボタンパネルが表示されている場合、トレーダーは注文を手動で管理できます。
1.すべての注文でSL/TPを設定する上で説明したように、パラメータ[Use Order Stop Loss]や[Use Order Take Profit]でNoを入力したが、すべての注文でストップロスまたはテイクプロフィットを使用するつもりである場合、[Set SL / TP All Orders]ボタンを1回クリックすると、すべての注文が変更され、ストップロスやテイクプロフィットが適用されます。
void MCEA::SetSLTPOrders(void) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- double modbuysl=0; double modselsl=0; double modbuytp=0; double modseltp=0; string position_symbol; int totalorder=PositionsTotal(); //-- for(int i=totalorder-1; i>=0; i--) { string symbol=PositionGetSymbol(i); position_symbol=symbol; if(mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modbuysl=SetOrderSL(symbol,opstype,pos_open); if(price<modbuysl) modbuysl=mc_symbol.NormalizePrice(price-slip*pip); modbuytp=SetOrderTP(symbol,opstype,pos_open); if(price>modbuytp) modbuytp=mc_symbol.NormalizePrice(price+slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modbuysl,modbuytp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } if(opstype==POSITION_TYPE_SELL) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modselsl=SetOrderSL(symbol,opstype,pos_open); if(price>modselsl) modselsl=mc_symbol.NormalizePrice(price+slip*pip); modseltp=SetOrderTP(symbol,opstype,pos_open); if(price<modseltp) modseltp=mc_symbol.NormalizePrice(price-slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modselsl,modseltp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } } } //-- return; //--- } //-end SetSLTPOrders //---------//
2.すべての注文を決済したい場合、[Close All Orders]ボタンを1回クリックするだけで、すべての未決注文が決済されます。
void MCEA::CloseAllOrders(void) //-- function: close all order { //---- ResetLastError(); //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int total=PositionsTotal(); // number of open positions //--- iterate over all open positions for(int i=total-1; i>=0; i--) { //--- if the MagicNumber matches if(mc_position.Magic()==magicEA) { //-- string position_Symbol = PositionGetSymbol(i); // symbol of the position ulong position_ticket = PositionGetTicket(i); // ticket of the the opposite position ENUM_POSITION_TYPE type = mc_position.PositionType(); RefreshTick(position_Symbol); bool closepos = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); //--- } } //--- return; //---- } //-end CloseAllOrders() //---------//
3.すでに利益が出ている注文をすべて決済したい場合、[Close All Orders Profit]ボタンを1回クリックするだけで、すべてのすでに利益が得られている未処理の注文が決済されます。
bool MCEA::ManualCloseAllProfit(void) { //---- ResetLastError(); //-- bool orclose=false; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; orclose=false; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double cur_profit = NormalizeDouble(pos_profit+pos_swap+pos_comm,2); ulong position_ticket = PositionGetTicket(i); //--- if(type==POSITION_TYPE_BUY && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } if(type==POSITION_TYPE_SELL && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //-- return(orclose); //---- } //-end ManualCloseAllProfit() //---------//
[C]ボタンをクリックすると、30個の銘柄名またはペアのパネルボタンが表示され、いずれかのペア名または銘柄名をクリックできます。ペア名または銘柄のいずれかがクリックされると、チャート銘柄は即座にクリックされた名前の銘柄に置き換わります。
この場合、銘柄名の1つがクリックされると、OnChartEvent()関数がChangeChartSymbol()関数として呼び出されます。
//--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //--
void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf) { //--- //--- unpress the button ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false); ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0); ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //-- ChartSetSymbolPeriod(0,c_symbol,cstf); //-- ChartRedraw(0); //-- return; //--- } //-end ChangeChartSymbol() //---------//
[R]ボタンをクリックすると、多通貨EA BBOnKeltnerChannel_MCEAがチャートから削除されるため、EAを手動で切断する必要がありません。
if(id==CHARTEVENT_OBJECT_CLICK) { //-- //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- }
ストラテジーテスター
知られているように、MetaTrader 5ターミナルのストラテジーテスターは、ストラテジーのテスト、複数の銘柄の取引、または利用可能なすべての銘柄と利用可能なすべての時間枠の自動取引のテストをサポートしており、これを可能にします。したがって、MetaTrader 5ストラテジーテスタープラットフォームでは、BBOnKeltnerChannel_MCEAを多通貨EAとしてテストします。
このテストでは、BBOnKeltnerChannel_MCEAをXAGUSDペアとH1時間枠に配置し、カスタム期間を2023.09.04から2023.12.02に設定しました。
テストは、2つの異なる入力プロパティ、特に[Trade & Order Management]パラメータグループを使用して実行されました。
1.デフォルトの入力プロパティ
2.カスタム入力プロパティ
結論
MQL5を使用してケルトナーチャネル指標上のボリンジャーバンド®指標からのシグナルを使用して多通貨EAを作成した結論は次のとおりです。
- MQL5で多通貨EAを作成するのは非常に簡単で、単一通貨のEAと大差ないことがわかりました。
- 古いプラットフォーム(MetaTrader4)と比較して、MQL5の指標ハンドルを使用して指標の値とシグナルを取得する方が簡単で便利です。
- 多通貨EAを作成すると、取引のために多くのチャート銘柄を開く必要がないため、トレーダーの効率と有効性が向上します。
- 適切な取引戦略を適用することにより、単一通貨EAを使用する場合と比較して利益の確率が増加します。これは、あるペアの損失が他のペアの利益によってカバーされるためです。
- このBBOnKeltnerChannel_MCEA多通貨EAは、学習とアイデア生成のための単なるサンプルです。ストラテジーテスターのテスト結果はまだ良くありません。したがって、異なる時間枠や異なる指標期間の計算で実験やテストをおこなうことで、より良い、より収益性の高い結果を得ることが可能です。
- BBOnKeltnerChannel_MCEAのストラテジーテスターでのテスト結果は、カスタム入力パラメータプロパティの結果が既定の入力パラメータプロパティよりも優れていることを示しています。
この記事とMQL5多通貨EAプログラムが、トレーダーの皆さんの学習とアイデアの開発に役立つことを願っています。
ご精読ありがとうございました。
注:組み込みのMQL5標準指標シグナルに基づいてシンプルな複数通貨EAを作成するアイデアをお持ちの方は、コメントでご提案ください。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/13861





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索