
MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第6回):互いのラインを交差する2つのRSI指標
はじめに
多通貨EAは、1つの銘柄チャートからの複数の銘柄ペアに対して、取引(新規注文、決済注文、トレイリングストップロスとトレイリングプロフィットなどの注文管理など)をおこなうことができるEA(自動売買ロボット)です。この記事では、EAは30ペアを取引します。
この記事では、交差シグナルを持つ2つのRSI指標(高速RSIと低速RSIの交差)を使用します。
これまでの記事で証明されているように、MQL5が提供するパワー、機能、設備があれば、取引端末でもストラテジーテスターでも、多通貨取引がすでに可能であることは誰もが知っています。
効率的かつ効果的な自動売買ロボットを求めるトレーダーの重要なニーズを満たすことを目的として、非常に信頼性の高いMQL5によって提供されるパワー、機能、および設備に依存することにより、シンプルな多通貨EAを作成するための様々なアイデアや戦略を考えることができます。この記事では、互いのラインを交差する2つのRSI指標を使用します。
計画と機能
1.通貨ペアの取引
この多通貨EAは、以下の銘柄またはペアで取引するように計画されています。
外国為替:
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(計28ペア)
追加のメタル2ペア:XAUUSD(金)とXAGUSD(銀)
合計30ペア
この記事のEAでは、接頭辞や接尾辞の付いた銘柄名やペアを自動的に処理する関数を使用しているので、そのような特殊な銘柄名を持つ証券会社からMetaTrader 5上でEAを使用する場合、すべてがスムーズに動作します。
ただし、接頭辞と接尾辞を含む銘柄名を検出する関数は、MetaTrader 5のFXと金属の銘柄ペア名でのみ機能し、特殊な銘柄やインデックスでは機能しません。
前回の記事の多通貨EAについて、多通貨EAを単一通貨EAとしてまたはスタンドアローンEAとして使用する方法を尋ねられる方がいらっしゃいます。
実は、前回の記事で紹介したEAには、単一通貨のみを取引するEAとして使用したり、スタンドアローンEAとして動作させたりする機能やオプションがあります。
今回のEAでも、取引するペアは10種類から選択します。取引される10のオプションペアの1つは「Trader's Desired Pairs」で、このペアはトレーダーがEAの入力プロパティに手動で入力する必要があります。ただし、入力したペア名がすでに30ペアのリストに含まれていなければならないことを常に覚えておく必要があります。
このTrader's Desired Pairsオプションを使用して、希望のペア名を1つだけ入力すれば、EAは単一通貨でのみ取引したり、スタンドアロンEAとして機能したりすることができます。EAはその1つのペアでのみ取引または作業します。
EA入力のパラメータ設定は、下図のように設定する必要があります。
上記の入力プロパティの例では、トレーダーがXAUUSDペアの名前のみを入力すると、EAはXAUUSDペアの取引のみをおこないます。EAがどこに配置されていても、利用可能な30ペアのうち、XAUUSDペアでのみ取引します。
それとは別に、この記事のEAでは、単一通貨で取引するか複数通貨で取引するかの、取引ペアの条件を選択するオプションを追加しました。
EA入力パラメータは下図のように設定する必要があります。
[SP](シングルペア)オプションでは、EAは配置されているペアでのみ取引します。
例えば、EAがEURUSDペアに配置されている場合、EAはEURUSDペアでのみ取引します。
つまり、この記事のEAには、単一通貨を取引する方法と、スタンドアロンのEAとして機能する方法があります。
1.[MP](マルチペア)オプションにこだわり、Trader's Desired Pairsオプションを選択しますが、1つのペア名のみ(例:XAUUSD)を入力します。
このオプションでは、どのペアに配置されていても、EAはTrader Wishes Pairsに入力されたペア名でのみ取引します。
2.[Select Trading Pairs Mode]で、[SP](シングルペア)を選択します。
EURUSDペアに配置されている場合、EAはEURUSDペアでのみ取引します。
さらに、Trade on SpecificTimeグループでは、タイムゾーンで取引したいトレーダーのためのオプションが用意されています。
多分、多くのトレーダーは、タイムゾーンに従って取引したいので、取引するペアは、取引セッションの時間に対応することができます。よって、このEAでは、まだ取引セッション(タイムゾーン)のオプションを使用します。
2.シグナル指標
相対力指数(RSI)は、J.ウェルズ・ワイルダーによって開発され、1978年に出版された書籍「New Concepts in Technical Trading Systems」と、1978年6月号の「Commodities」誌(現在の「Modern Trader」誌)に掲載されました。これは、最も人気のあるオシレーター指標の1つとなっています。
相対力指数(RSI)は、金融市場の分析に用いられるテクニカル指標です。その目的は、最近の取引期間の終値に基づいて、株式や市場の現在および過去の強さや弱さをチャート化することです。
相対力指数(Relative Strength Index、RSIテクニカル指標)は、0から100の間で推移する価格追随型オシレーターです。ワイルダーはRSIを利用する場合、14日を推奨していましたが、その後、9日と25日RSIが一般的になりました。
RSIは最も一般的に14日間の時間枠で使用され、0から100の尺度で測定され、高値と安値のレベルはそれぞれ70と30にマークされます。より短いまたは長い時間枠は、交互に短いまたは長い見通しに使用されます。高水準と低水準(80と20、90と10)は、発生頻度は低いが、勢いが強いことを示します。
さらに、MetaTrader 5には、RSIシグナルがテクニカル分析で次のようなチャート分析に使用されると記載されています。
- トップスとボトムス
- チャートのフォーメーション
- 失敗スイング(支持または抵抗のブレイクアウト)
- 支持と抵抗のレベル
- ダイバージェンス
このように、RSI取引戦略には実に多くのバリエーションがあります。
アナリストであり投資家でもある記事の著者でさえ、Q&Aで次のようにやり取りしています。
Q:「デイ取引に最適なRSIの設定は何ですか?」
A:「残念ながら、RSIは日足バーで最もよく機能します。日中のデータを使用して多くのデータをバックテストしましたが、特に役には立ちませんでした」。
Q:「RSIを使用してどのように取引しますか?」
A:「まず第一に、日足を使いたいです。第二に、設定に短い日数、できれば最大で5日間を使いたいです。第三に、RSIは株式やオーバーナイトのエッジを持つ平均回帰的な資産に最も効果的です。FXでは成功していません。」
ただし、この記事では、高速RSIと低速RSIIの交差、またはFX取引でのRSIとRSIの交差をシグナルに使用します。
成功するかどうかは別として、すべてはまだ実験され、テストされなければなりません。
FastRSIシグナルがSlowRSIラインを横切る様子を図1と図2に示します。
図1
図2
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
- Automatic Calculation Stop LossでYesを選択:ストップロスの計算はEAで自動的におこなわれる
- Automatic Calculation Stop LossでNoを選択:トレーダーはストップロスの値をPipsで入力する必要がある
- Use Order Stop LossがNoの場合:EAは、開かれた各注文について、シグナル状態がまだ良好で利益を得るために注文を維持できるか、または、シグナルが弱まり、利益を保存するために注文を決済する必要がある状態か、または、シグナル状態の方向が逆になっているため、損失状態で注文を決済する必要があるかを確認する
- アクティブ化されていない場合(No)、シグナルが弱まっても注文は維持されるか、利益を保存するために決済されない
- アクティブ化されている場合(Yes)、FastRSIとSlowRSI指標の条件は以下のようになる
買い注文を決済する:
FastRSIがSlowRSIを上回り、現在のバーのFastRSIの値が前のバーのFastRSIの値より小さい場合、買い注文を決済する
売り注文を決済する:
FastRSIがSlowRSIを下回り、現在のバーのFastRSIの値が前のバーのFastRSIの値より大きい場合、売り注文を決済する
ストップロス注文を設定するコードは以下の通りです。
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 bar=3; //-- double rdif=rsidiff; double RSIFast[], RSISlow[]; //-- ArrayResize(RSIFast,bar,bar); ArrayResize(RSISlow,bar,bar); ArraySetAsSeries(RSIFast,true); ArraySetAsSeries(RSISlow,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt); //-- CopyBuffer(hRSIFast[x],0,0,bar,RSIFast); CopyBuffer(hRSISlow[x],0,0,bar,RSISlow); //-- if(exis==down && RSIFast[1]<=RSISlow[1] && RSIFast[1]<RSIFast[2] && RSIFast[0]>RSIFast[1]+rdif) ret=rise; if(exis==rise && RSIFast[1]>=RSISlow[1] && RSIFast[1]>RSIFast[2] && RSIFast[0]<RSIFast[1]-rdif) ret=down; //-- return(ret); //--- } //-end GetCloseInWeakSignal() //---------//
2.テイクプロフィット注文
オプション:Use Order Take Profit:Yes/No
- Use Order Take ProfitでNoを選択:すべての注文はテイクプロフィットなしで発注される
- Use Order Take ProfitがYesの場合:再びオプションが与えられる。Use Automatic Calculation Order Take Profit:Yes/Noオプションを指定することになります。
- Automatic Calculation Order Take ProfitでYesを選択:テイクプロフィット注文の計算はEAで自動的におこなわれる
- 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.トレイリングストップとトレイリングテイクプロフィット
オプション:Use Trailing SL/TP:Yes/No
- Use Trailing SL/TPがNoの場合:EAはトレイリングストップロスおよびおトレイリングテイクプロフィットをおこなわない
- Use Trailing SL/TPがYesの場合:トレーダーは2つのオプションから選ぶことができる
1.価格によるトレーリング
トレイリングストップは、価格の動きと入力プロパティの値を使用してEAによって実行され、同時に変数値TPmin(最小トレイリングプロフィット値)に基づいてトレイリングプロフィットを作ることによって実行される
2.指標によるトレーリング
トレイリングストップは、VIDYA指標を使用してEAによって実行され、同時に変数値TPmin(最小トレイリングプロフィット値)に基づいてトレイリングプロフィットを作る
注意:EAはトレイリングストップと同時にトレイリングテイクプロフィットを実行します。
私の研究と実験によると、VIDYA指標は、Parabolic SARや移動平均指標のいくつかのバリエーションと比較してわずかに優れており、トレイリングストップに理想的です。
VIDYA指標はParabolic SAR指標に比べて値動きに近く、AMA、DEMA、MA指標に比べて値動きからさらに離れています。
そこで今回は、VIDYA指標をベースにしたトレイリングストップ関数を使うことにしました。
トレイリングストップ価格と指標関数のコードは、次の通りです。
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 VIDyAv[]; ArrayResize(VIDyAv,br,br); ArraySetAsSeries(VIDyAv,true); CopyBuffer(hVIDyAv[x],0,0,br,VIDyAv); RefreshPrice(xsymb,TFt,br); //-- if(ptype==POSITION_TYPE_BUY && (VIDyAv[0]<mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip))) pval=VIDyAv[0]; if(ptype==POSITION_TYPE_SELL && (VIDyAv[0]>mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip))) pval=VIDyAv[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=(Close_by_Opps==No && TS_type==1) ? 0 : 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-1.0)*pip)); double modbuysl=vtrsb; double modbuytp=mc_symbol.NormalizePrice(price+TPval*pip); bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>minprofit) { 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+1.0)*pip)); double modselsl=vtrss; double modseltp=mc_symbol.NormalizePrice(price-TPval*pip); bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>minprofit) { modist=mc_trade.PositionModify(symbol,modselsl,modseltp); } } } } //-- return(modist); //--- } //-end ModifySLTP() //---------//
4.手動注文管理
この多通貨EAでは、EAの作業を監視するトレーダーに効率性と有効性を提供するために、いくつかの手動クリックボタンを追加します。
4.1.Set SL / TP All Orders:
Use Order Stop Loss (No)またはUse Order Take Profit (No)というパラメータが入力された後で、全ての注文にストップロスまたはテイクプロフィットを使用したい場合に便利です。
4.2.Close All Orders:
すべての注文を決済したい場合、[Close All Orders]ボタンを1回クリックするだけで、すべての未決済注文が決済されます。
4.3.Close All Orders Profit:
すでに利益が出ている注文をすべて決済したい場合、[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 Autralia 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 }; //--
次は、取引に選択するオプションペアを10組を選択するための列挙です。
//-- 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 mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
以下は、シグナル指標の計算に使用する時間枠を選択するための列挙です。
//-- enum TFUSE { TFM5, // 00_PERIOD_M5 TFM15, // 01_PERIOD_M15 TFM30, // 02_PERIOD_M30 TFH1, // 03_PERIOD_H1 TFH2, // 04_PERIOD_H2 TFH3, // 05_PERIOD_H3 TFH4, // 06_PERIOD_H4 TFH6, // 07_PERIOD_H6 TFH8, // 08_PERIOD_H8 TFH12, // 09_PERIOD_H12 TFD1 // 10_PERIOD_D1 }; //--
TFUSEの列挙では、TF-M5からTF-D1までのEAだけに時間枠計算の使用を制限しています。
以下は、トレイリングストップの計算で使用するタイプを選択するための列挙です。
//-- enum TrType { byprice, // Trailing Stop by Price byindi // Trailing Stop by Indicator }; //--
以下は、EAが取引する取引の種類、単一通貨または複数通貨を選択するための列挙です。
//-- enum MS { SP, // Single Pair MP // Multi Pairs }; //--
以下は、EA入力プロパティです。
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFUSE tfinuse = TFH4; // Select Expert TimeFrame, default PERIOD_H4 input int rsifast = 10; // Input Period for Fast RSI input ENUM_APPLIED_PRICE frsiapp = PRICE_WEIGHTED; // Select Fast RSI Applied Price input int rsislow = 30; // Input Period for Slow RSI input ENUM_APPLIED_PRICE srsiapp = PRICE_WEIGHTED; // Select Slow RSI Applied Price input double rsidiff = 4.56; // Input Differentiation between RSIs //--- input group "=== Select Pairs to Trade ==="; // Selected Pairs to trading input MS trademode = MP; // Select Trading Pairs Mode (Multi or Single) 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 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.0; // 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 = 60.0; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input TrType trlby = byindi; // Select Trailing Stop Type input double TSval = 10.0; // If Use Trailing Stop by Price Input value in Pips input double TSmin = 5.0; // Minimum Pips to start Trailing Stop input double TPmin = 25.0; // 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 = 20240111; // Expert ID (Magic Number) //--- //---------//
注意:EA ID(マジックナンバー)の入力プロパティが空白のままの場合、EAは手動で開かれた注文を管理できます。
Global Strategy EA Parameters Expert Inputプロパティグループで、トレーダーは指標シグナル計算のためのExpertTimeframeを選択し、パラメータを入力するよう指示されます。
- Input Period for RSI FastおよびSelect RSI Fast Applied Price
- Input Period for RSI SlowおよびSelect RSI Slow Applied Price
- RSI間の差別化の入力値
EAのSelect Pairs to Tradeプロパティグループで、トレーダーは提供されている10のオプションから取引するペアを選択する必要があります。デフォルトでは、すべての外国為替30ペアが設定されています。
取引されるペアを設定するには、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); areur=ArraySize(EURs); aretc=ArraySize(JPYs); 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<areur; 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 & Metal 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency "+string(sall)+" 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,areur,areur); 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) { //--- int sym_Lenpre=0; int sym_Lensuf=0; string sym_pre=""; string sym_suf=""; SymbolSelect(Symbol(),true); string insymbol=Symbol(); int inlen=StringLen(insymbol); int toseek=-1; string dep=""; string bel=""; string sym_use =""; int pairx=-1; string xcur[]={"EUR","GBP","AUD","NZD","USD","CAD","CHF"}; // 7 major currency int xcar=ArraySize(xcur); //-- for(int x=0; x<xcar; x++) { toseek=StringFind(insymbol,xcur[x],0); if(toseek>=0) { pairx=x; break; } } if(pairx>=0) { int awl=toseek-3 <0 ? 0 : toseek-3; int sd=StringFind(insymbol,"SD",0); if(toseek==0 && sd<4) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else if(toseek>0) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else { dep=StringSubstr(insymbol,awl,3); bel=StringSubstr(insymbol,awl+3,3); sym_use=dep+bel; } } //-- string sym_nmx=sym_use; int lensx=StringLen(sym_nmx); //-- if(inlen>lensx && lensx==6) { sym_Lenpre=StringFind(insymbol,sym_nmx,0); sym_Lensuf=inlen-lensx-sym_Lenpre; //-- if(sym_Lenpre>0) { sym_pre=StringSubstr(insymbol,0,sym_Lenpre); for(int i=0; i<xcar; i++) if(StringFind(sym_pre,xcur[i],0)>=0) sym_pre=""; } if(sym_Lensuf>0) { sym_suf=StringSubstr(insymbol,sym_Lenpre+lensx,sym_Lensuf); for(int i=0; i<xcar; i++) if(StringFind(sym_suf,xcur[i],0)>=0) sym_suf=""; } } //-- 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を選択します。
Trade on Specific Time ZoneオプションがNoに指定されている場合、EAはMT5の00:15から23:59まで取引します。
Yesの場合は、列挙オプションを選択します。
- カスタムセッションでの取引
- ニュージーランドセッションでの取引
- オーストラリアシドニーセッションでの取引
- アジア東京セッションでの取引
- ヨーロッパロンドンセッションでの取引
- アメリカニューヨークセッションでの取引
デフォルトでは、Trading on Specific Time ZonesはYesに設定され、Trading on Custom Sessionsに設定されています。
カスタムセッションでの取引:
このセッションで、トレーダーは取引を開始する時間または時間と分、取引を停止する時間と分を設定しなければなりません。これは、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 point; 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 GetRSIxx(const string symbol); int PARSAR05(const string symbol); int PARSAR15(const string symbol); int LotDig(const string symbol); //-- bool CheckProfit(const string symbol,ENUM_POSITION_TYPE intype); bool CheckLoss(const string symbol,ENUM_POSITION_TYPE intype); //-- 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: //--- //-- RSIxRSI_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; //-- int hRSIFast[], hRSISlow[]; int hVIDyAv[]; int hPar05[], hPar15[]; int ALO, dgts, arrsar, arrsymbx; int sall, arusd, areur, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; double minprofit; //-- 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, TFT15; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void RSIxRSI_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 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); bool CheckProfitLoss(const string symbol); bool CloseBuyPositions(const string symbol); bool CloseSellPositions(const string symbol); //-- 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 //---------// MCEA mc; //---------//
多通貨EAのワークフロープロセスで、OnInit()から最初に呼び出される最も重要な関数は、RSIxRSI_MCEA_Config()です。
RSIxRSI_MCEA_Config()関数は、使用するすべての銘柄、すべての時間枠、すべてのハンドル指標、およびEAワークフローのインクルードファイルヘッダーのいくつかの重要な機能を設定します。
RSIxRSI_MCEA_Config()関数は、EAワークフローで使用されるすべての指標の時間枠の処理方法と指標ハンドルの作成方法を説明し、実装します。
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::RSIxRSI_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- TFT05=PERIOD_M5; TFT15=PERIOD_M15; 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 //-- //-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hRSISlow[x]=iRSI(DIRI[x],TFt,rsislow,srsiapp); //-- Handle for the Slow RSI indicator hRSIFast[x]=iRSI(DIRI[x],TFt,rsifast,frsiapp); //-- Handle for the Fast RSI indicator hVIDyAv[x]=iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe hPar15[x]=iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe //-- } //-- minprofit=NormalizeDouble(TSmin/100.0,2); //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); if(Close_by_Opps==No) { if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2; else ALO=(int)(mc_account.LimitOrders()/2); } //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end RSIxRSI_MCEA_Config() //---------//
2.EAティック関数
EAのティック関数(OnTick()関数)の中で、多通貨EAのもっとも重要な関数の1つであるExpertActionTrade()を呼び出します。EAが取引に使用されるすべてのプロセスは、この機能に含まれています。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
これは、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++) { //-- switch(trademode) { case SP: { if(mc.DIRI[x]!=Symbol()) continue; symbol=Symbol(); mc.pairs=mc.pairs+" ("+symbol+")"; break; } case MP: { if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; break; } } //-- 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]>mc.minprofit && 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]>mc.minprofit && 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) { mc.ModifySLTP(symbol,trlby); } } //-- mc.CheckOpenPMx(symbol); if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1)) { mc.CheckProfitLoss(symbol); mc.Do_Alerts(symbol,"Close order due stop in loss."); } //-- 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)
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() //---------//
メモ:DayTradingOn/Off条件は、チャートの取引情報に表示されます。
TradingDay()関数によって実行されます。
string MCEA::TradingDay(void) { //--- int trdday=ThisTime(dow); switch(trdday) { case 0: daytrade="Sunday"; break; case 1: daytrade="Monday"; break; case 2: daytrade="Tuesday"; break; case 3: daytrade="Wednesday"; break; case 4: daytrade="Thursday"; break; case 5: daytrade="Friday"; break; case 6: daytrade="Saturday"; break; } return(daytrade); //--- } //-end TradingDay() //---------//
トレーダーは、EAの「TradeatSpecificTime」プロパティグループで、時間帯別に取引するオプションがあります。
メモ:上記で説明したように、ニュージーランドセッションでの取引から米国ニューヨークセッションでの取引の場合、取引開始から取引終了までの時間はEAが計算します。
そのため、EA Entryプロパティでは、トレーダーはカスタムセッションの取引開始時刻と終了時刻を設定するだけでよくなります。
ExpertActionTrade()関数が拡張され、タイムゾーン取引専用のブール値Trade_session()関数が呼び出されるようになりました。
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() //---------//
まずExpertActionTrade()関数がTrade_session()関数を呼び出し、次にTrade_session()関数がSet_Time_Zone()関数を呼び出し、最後にSet_Time_Zone()関数がTime_Zone()関数を呼び出します。
void MCEA::Set_Time_Zone(void) { //--- //-- Server Time==TimeCurrent() datetime TTS=TimeTradeServer(); datetime GMT=TimeGMT(); //-- MqlDateTime svrtm,gmttm; TimeToStruct(TTS,svrtm); TimeToStruct(GMT,gmttm); int svrhr=svrtm.hour; // Server time hour int gmthr=gmttm.hour; // GMT time hour int difhr=svrhr-gmthr; // Time difference Server time to GMT time //-- int NZSGMT=12; // New Zealand Session GMT/UTC+12 int AUSGMT=10; // Australia Sydney Session GMT/UTC+10 int TOKGMT=9; // Asia Tokyo Session GMT/UTC+9 int EURGMT=0; // Europe London Session GMT/UTC 0 int USNGMT=-5; // US New York Session GMT/UTC-5 //-- int NZSStm=8; // New Zealand Session time start: 08:00 Local Time int NZSCtm=17; // New Zealand Session time close: 17:00 Local Time int AUSStm=7; // Australia Sydney Session time start: 07:00 Local Time int AUSCtm=17; // Australia Sydney Session time close: 17:00 Local Time int TOKStm=9; // Asia Tokyo Session time start: 09:00 Local Time int TOKCtm=18; // Asia Tokyo Session time close: 18:00 Local Time int EURStm=9; // Europe London Session time start: 09:00 Local Time int EURCtm=19; // Europe London Session time close: 19:00 Local Time int USNStm=8; // US New York Session time start: 08:00 Local Time int USNCtm=17; // US New York Session time close: 17:00 Local Time //-- int nzo = (NZSStm+difhr-NZSGMT)<0 ? 24+(NZSStm+difhr-NZSGMT) : (NZSStm+difhr-NZSGMT); int nzc = (NZSCtm+difhr-NZSGMT)<0 ? 24+(NZSCtm+difhr-NZSGMT) : (NZSCtm+difhr-NZSGMT); //-- int auo = (AUSStm+difhr-AUSGMT)<0 ? 24+(AUSStm+difhr-AUSGMT) : (AUSStm+difhr-AUSGMT); int auc = (AUSCtm+difhr-AUSGMT)<0 ? 24+(AUSCtm+difhr-AUSGMT) : (AUSCtm+difhr-AUSGMT); //-- int tko = (TOKStm+difhr-TOKGMT)<0 ? 24+(TOKStm+difhr-TOKGMT) : (TOKStm+difhr-TOKGMT); int tkc = (TOKCtm+difhr-TOKGMT)<0 ? 24+(TOKCtm+difhr-TOKGMT) : (TOKCtm+difhr-TOKGMT); //-- int euo = (EURStm+difhr-EURGMT)<0 ? 24+(EURStm+difhr-EURGMT) : (EURStm+difhr-EURGMT); int euc = (EURCtm+difhr-EURGMT)<0 ? 24+(EURCtm+difhr-EURGMT) : (EURCtm+difhr-EURGMT); //-- int uso = (USNStm+difhr-USNGMT)<0 ? 24+(USNStm+difhr-USNGMT) : (USNStm+difhr-USNGMT); int usc = (USNCtm+difhr-USNGMT)<0 ? 24+(USNCtm+difhr-USNGMT) : (USNCtm+difhr-USNGMT); if(usc==0||usc==24) usc=23; //-- //---Trading on Custom Session int _days00=ThisTime(day); int _days10=ThisTime(day); if(stsescuh>clsescuh) _days10=ThisTime(day)+1; tmopcu=ReqDate(_days00,stsescuh,stsescum); tmclcu=ReqDate(_days10,clsescuh,clsescum); //-- //--Trading on New Zealand Session GMT/UTC+12 int _days01=ThisTime(hour)<nzc ? ThisTime(day)-1 : ThisTime(day); int _days11=ThisTime(hour)<nzc ? ThisTime(day) : ThisTime(day)+1; tmop01=ReqDate(_days01,nzo,0); // start: 08:00 Local Time == 20:00 GMT/UTC tmcl01=ReqDate(_days11,nzc-1,59); // close: 17:00 Local Time == 05:00 GMT/UTC //-- //--Trading on Australia Sydney Session GMT/UTC+10 int _days02=ThisTime(hour)<auc ? ThisTime(day)-1 : ThisTime(day); int _days12=ThisTime(hour)<auc ? ThisTime(day) : ThisTime(day)+1; tmop02=ReqDate(_days02,auo,0); // start: 07:00 Local Time == 21:00 GMT/UTC tmcl02=ReqDate(_days12,auc-1,59); // close: 17:00 Local Time == 07:00 GMT/UTC //-- //--Trading on Asia Tokyo Session GMT/UTC+9 int _days03=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; int _days13=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; tmop03=ReqDate(_days03,tko,0); // start: 09:00 Local Time == 00:00 GMT/UTC tmcl03=ReqDate(_days13,tkc-1,59); // close: 18:00 Local Time == 09:00 GMT/UTC //-- //--Trading on Europe London Session GMT/UTC 00:00 int _days04=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; int _days14=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; tmop04=ReqDate(_days04,euo,0); // start: 09:00 Local Time == 09:00 GMT/UTC tmcl04=ReqDate(_days14,euc-1,59); // close: 19:00 Local Time == 19:00 GMT/UTC //-- //--Trading on US New York Session GMT/UTC-5 int _days05=ThisTime(hour)<usc ? ThisTime(day) : ThisTime(day)+1; int _days15=ThisTime(hour)<=usc ? ThisTime(day) : ThisTime(day)+1; tmop05=ReqDate(_days05,uso,0); // start: 08:00 Local Time == 13:00 GMT/UTC tmcl05=ReqDate(_days15,usc,59); // close: 17:00 Local Time == 22:00 GMT/UTC //-- //--Not Use Trading Time Zone if(trd_time_zone==No) { tmopno=ReqDate(ThisTime(day),0,15); tmclno=ReqDate(ThisTime(day),23,59); } //-- Time_Zone(); //-- return; //--- } //-end Set_Time_Zone() //---------//
void MCEA::Time_Zone(void) { //--- //-- tz_ses=""; //-- switch(session) { case Cus_Session: { SesCuOp=StringToTime(tmopcu); SesCuCl=StringToTime(tmclcu); zntm=SesCuOp; znop=SesCuOp; zncl=SesCuCl; tz_ses="Custom_Session"; tz_opn=timehr(stsescuh,stsescum); tz_cls=timehr(clsescuh,clsescum); break; } case New_Zealand: { Ses01Op=StringToTime(tmop01); Ses01Cl=StringToTime(tmcl01); zntm=Ses01Op; znop=Ses01Op; zncl=Ses01Cl; tz_ses="New_Zealand/Oceania"; tz_opn=timehr(ReqTime(Ses01Op,hour),ReqTime(Ses01Op,min)); tz_cls=timehr(ReqTime(Ses01Cl,hour),ReqTime(Ses01Cl,min)); break; } case Australia: { Ses02Op=StringToTime(tmop02); Ses02Cl=StringToTime(tmcl02); zntm=Ses02Op; znop=Ses02Op; zncl=Ses02Cl; tz_ses="Australia Sydney"; tz_opn=timehr(ReqTime(Ses02Op,hour),ReqTime(Ses02Op,min)); tz_cls=timehr(ReqTime(Ses02Cl,hour),ReqTime(Ses02Cl,min)); break; } case Asia_Tokyo: { Ses03Op=StringToTime(tmop03); Ses03Cl=StringToTime(tmcl03); zntm=Ses03Op; znop=Ses03Op; zncl=Ses03Cl; tz_ses="Asia/Tokyo"; tz_opn=timehr(ReqTime(Ses03Op,hour),ReqTime(Ses03Op,min)); tz_cls=timehr(ReqTime(Ses03Cl,hour),ReqTime(Ses03Cl,min)); break; } case Europe_London: { Ses04Op=StringToTime(tmop04); Ses04Cl=StringToTime(tmcl04); zntm=Ses04Op; znop=Ses04Op; zncl=Ses04Cl; tz_ses="Europe/London"; tz_opn=timehr(ReqTime(Ses04Op,hour),ReqTime(Ses04Op,min)); tz_cls=timehr(ReqTime(Ses04Cl,hour),ReqTime(Ses04Cl,min)); break; } case US_New_York: { Ses05Op=StringToTime(tmop05); Ses05Cl=StringToTime(tmcl05); zntm=Ses05Op; znop=Ses05Op; zncl=Ses05Cl; tz_ses="US/New_York"; tz_opn=timehr(ReqTime(Ses05Op,hour),ReqTime(Ses05Op,min)); tz_cls=timehr(ReqTime(Ses05Cl,hour),ReqTime(Ses05Cl,min)); break; } } //-- if(trd_time_zone==No) { SesNoOp=StringToTime(tmopno); SesNoCl=StringToTime(tmclno); zntm=SesNoOp; znop=SesNoOp; zncl=SesNoCl; tz_ses="Not Use Time Zone"; tz_opn=timehr(ReqTime(SesNoOp,hour),ReqTime(SesNoOp,min)); tz_cls=timehr(ReqTime(SesNoCl,hour),ReqTime(SesNoCl,min)); } //-- return; //--- } //-end Time_Zone() //---------//
3.未決済ポジションの取引シグナルの取得
ポジションを建てるシグナルを得るために、ExpertActionTrade()関数はGetOpenPosition()関数を呼び出します。
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int rsix=GetRSIxx(symbol); int par15=PARSAR15(symbol); //-- if(rsix==rise && par15==rise) ret=rise; if(rsix==down && par15==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
そして、GetOpenPosition()関数は2つの関数を呼び出します。
- 2RSIのバッファ値を受け取り、シグナルアルゴリズムを計算するGetRSIxx()関数
- フィルタとしてのPARSAR15()関数
int MCEA::GetRSIxx(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; int bar=3; //-- double rdif=rsidiff; double RSIFast[], RSISlow[]; //-- ArrayResize(RSIFast,bar,bar); ArrayResize(RSISlow,bar,bar); ArraySetAsSeries(RSIFast,true); ArraySetAsSeries(RSISlow,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt); //-- CopyBuffer(hRSIFast[x],0,0,bar,RSIFast); CopyBuffer(hRSISlow[x],0,0,bar,RSISlow); //-- if(RSIFast[1]<=RSISlow[1] && RSIFast[0]>RSISlow[0]+rdif) ret=rise; if(RSIFast[1]>=RSISlow[1] && RSIFast[0]<RSISlow[0]-rdif) ret=down; //-- return(ret); //--- } //-end GetRSIxx() //---------//
int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M5 { //--- int ret=0; int rise=1, down=-1; int br=2; //-- double PSAR[]; ArrayResize(PSAR,br,br); ArraySetAsSeries(PSAR,true); int xx=PairsIdxArray(symbol); CopyBuffer(hPar15[xx],0,0,br,PSAR); //-- RefreshPrice(symbol,TFT15,br); double HIG0=iHigh(symbol,TFT15,0); double LOW0=iLow(symbol,TFT15,0); //-- if(PSAR[0]<LOW0) ret=rise; if(PSAR[0]>HIG0) ret=down; //-- return(ret); //--- } //-end PARSAR15() //---------//
GetRSIxx()関数とPARSAR15()関数の内部では、PairsIdxArray()関数を使用し、1つの関数を呼び出しています。
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()関数は、要求された銘柄の名前とその指標のハンドルを取得するために使用されます。次に、対応する指標ハンドルが呼び出され、その銘柄と時間枠からRSI指標とPSAR指標のバッファ値を取得します。
このEAでは、2つのRSI指標を使用します。
両者には異なる入力パラメータがあります。
高速RSI:
- symbol:要求された銘柄に従う
- timeframe:EAの時間枠で指定
- ma_period=10、高速RSIの入力期間による
- applied_price=PRICE_WEIGHTED、高速RSI適用価格による
低速RSI:
- symbol:要求された銘柄に従う
- timeframe:EAの時間枠で指定
- ma_period=30、低速RSIの入力期間による
- applied_price=PRICE_weighted、低速RSI適用価格による
//-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hRSISlow[x]=iRSI(DIRI[x],TFt,rsislow,srsiapp); //-- Handle for the Slow RSI indicator hRSIFast[x]=iRSI(DIRI[x],TFt,rsifast,frsiapp); //-- Handle for the Fast RSI indicator hVIDyAv[x]=iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe //-- }
そこで、各RSI指標のバッファ値を取得するために、指標ハンドルから各バッファをコピーします。
高速RSIバッファ(バッファ0)を高速RSIハンドルから宛先配列にコピーします。
CopyBuffer(hRSIFast[x],0,0,bar,RSIFast);
低速RSIハンドルから低速RSIバッファ(バッファ0)をデスティネーション配列にコピーします。
CopyBuffer(hRSISlow[x],0,0,bar,RSISlow);
2つの関数GetRSIxx()とPARSAR05()を実行した後、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() //---------//
その他のEAパラメータグループの入力プロパティで、トレーダーは取引情報をチャートに表示するかどうか(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() //---------//
多通貨EARSIxRSI_MCEAのインターフェイスは下図のようになっています。
ご覧のとおり、EAの名前「RSIxRSI_MCEA」の下にボタン[M]、[C]、[R]があります。
[M]ボタンがクリックされると、以下のように手動クリックボタンパネルが表示されます。
手動クリックボタンパネルが表示されている場合、トレーダーは注文を手動で管理できます。
1.Set SL/TP All Orders
上記で説明したように、トレーダーがUse Order Stop Loss(No)やUse Order Take Profit(No)というパラメータを入力し、全ての注文にストップロスまたはテイクプロフィットを使用したい場合、[Set SL / TP All Orders]ボタンをシングルクリックすると、全ての注文が修正され、ストップロスまたはテイクプロフィットが適用されます。
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
すべての注文を決済したい場合、[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 Profits
トレーダーがすでに利益が出ている注文をすべて決済したい場合、[Close All Profits]ボタンを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個の銘柄名またはペアのパネルボタンが表示され、いずれかのペア名または銘柄名をクリックできます。
ペア名または銘柄のいずれかがクリックされると、チャート銘柄は即座にクリックされた名前の銘柄に置き換わります。
void CreateSymbolPanel() { //--- //-- ResetLastError(); DeletePanelButton(); int sydis=83; int tsatu=int(mc.sall/2); //-- CreateButtonTemplate(0,"Template",180,367,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBurlyWood,clrWhite,CORNER_RIGHT_UPPER,187,45,true); CreateButtonTemplate(0,"TempCCS",167,25,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBlue,clrWhite,CORNER_RIGHT_UPPER,181,50,true); CreateButtonClick(0,"X",14,14,"Arial Black",10,BORDER_FLAT,"X",clrWhite,clrWhite,clrRed,ANCHOR_CENTER,CORNER_RIGHT_UPPER,22,48,true,"Close Symbol Panel"); //-- string chsym="Change SYMBOL"; int cspos=int(181/2)+int(StringLen(chsym)/2); CreateButtontLable(0,"CCS","Bodoni MT Black",chsym,11,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,cspos,62,true,"Change Chart Symbol"); //-- for(int i=0; i<tsatu; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,180,sydis+(i*22),true,"Change to "+mc.AS30[i]); //-- for(int i=tsatu; i<mc.sall; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,94,sydis+((i-tsatu)*22),true,"Change to "+mc.AS30[i]); //-- ChartRedraw(0); //-- return; //--- } //-end CreateSymbolPanel() //---------//
この場合、銘柄名のいずれかがクリックされると、OnChartEvent()関数からChangeChartSymbol()関数が呼び出されます。
if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //--- 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]ボタンをクリックすると、多通貨EARSIxRSI_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ストラテジーテスタープラットフォーム上で、RSIxRSI_MCEAMulti-CurrencyEAをテストします。
最初のテストでは、2023.10.01から2024.01.05のカスタム期間で、XAGUSDペアとH4時間枠にRSIxRSI_MCEAを配置した。
テストは2つの異なる入力プロパティ、特にGlobal Strategy EA ParameterグループとTrade & Order Management Parameterグループで実施されました。
1.XAGUSDペアとH4時間枠のRSIxRSI_MCEA
最初のテストの結果は下の画像の通りです。
2.XAGUSDペアとH12時間枠のRSIxRSI_MCEA
2回目のテスト結果は下の画像の通りです。
結論
MQL5を使用し、高速RSIと低速RSIIの交差、またはFX取引でのRSIとRSIの交差をシグナルとする多通貨EAを作成した際の結論は以下の通りです。
- MQL5で複数通貨のEAを作成するのは非常に簡単で、単一通貨のEAを作成するのと大差ないことがわかりました。
- 多通貨EAを作成することで、取引のために多くのチャート銘柄を開く必要がなくなり、トレーダーの効率と有効性が向上します。
- 適切な取引戦略を適用することで、単一通貨のEAを使用するよりも利益の確率が高まります。あるペアの損失が他のペアの利益によってカバーされるためです。
- このRSIxRSI_MCEA多通貨EAは、学習とアイデア創出のための単なるサンプルです。ストラテジーテスターのテスト結果はまだ良くありません。異なる時間枠や指標期間の計算で実験やテストをおこなうことで、より良い戦略やより収益性の高い結果を得ることができます。
- 私の意見では、このRSI-RSI交差戦略は、時間枠、高速期間RSI、低速期間RSI、両方のRSIの差別化値から始まって、様々な異なる実験でさらに研究されるべきです。 私のストラテジーテスターでの実験結果によると、H4以下の時間枠では結果は良くなく、H4以上の時間枠、例えばH8やH12の時間枠では、未決済の取引が少なく結果は良いのですが、未決済の取引が多い小さな時間枠に比べると、損失が出ています。
この記事とMQL5多通貨EAプログラムが、トレーダーの皆さんの学習とアイデアの開発に役立つことを願っています。
ご精読ありがとうございました。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/14051





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