MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第1回):ADXとパラボリックSARの組み合わせによる指標シグナル
Roberto Jacobs | 10 10月, 2023
はじめに
本記事における多通貨EAは、1つの銘柄チャートから複数の銘柄ペアの取引(新規注文、決済注文、注文管理など)が可能なEA(自動売買ロボット)として定義されます。
多通貨システムを搭載した取引自動化システム(自動売買ロボット)に対するニーズと関心は現在非常に高くなっていますが、MQL5自動売買ロボットへの多通貨システムプログラムの実装は広く公表されていないか、多くのプログラマーによってまだ秘密にされています。
そのため、この記事では、効率的で効果的な自動売買ロボットを求めるトレーダーの本質的なニーズを満たすことを目的とし、信頼性の高いMQL5が提供する長所、能力、機能に頼ることで、指標シグナルを使用するシンプルな多通貨EAを作成します。パラボリックSAR指標と組み合わせたADX(Average Directional Movement、平均方向性移動)です。
計画と特徴
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ペア。
これらの銘柄やペアはすべて、ブローカーが一般的に使用するものです。この多通貨EAは、接頭辞または接尾辞を持つ銘柄またはペア名を持つブローカーでは動作しません。
2. シグナル指標
多通貨EAは2つの指標シグナルを使用します。1.ADX (Average Directional Movement)指標、期間7、メインシグナル用、2.パラボリックSAR指標、トレンドシグナル確認用。
2つの主要な指標は、EAプロパティで指定されているのと同じ時間枠を使用します。トレンドの強さまたは弱さを検出することに加えて、パラボリックSAR指標はM15およびM5時間枠でも使用されます。
ADXシグナル条件ストラテジー公式:iADX
UP = (+DI[2] <= -DI[2]) && (+DI[1] > -DI[1]+difference) && (+DI[0] > +DI[1]) && ((+DI[0]/-DI[0]) > (+DI[1]/-DI[1]))
DOWN = (+DI[2] >= -DI[2]) && (+DI[1] < -DI[1]-difference) && (+DI[0] < +DI[1]) && ((+DI[0]/-DI[0]) < (+DI[1]/-DI[1]))
ここで、差は0.34です。
(+DI[1] > -DI[1]+0.34) = Signal Buy true;
(+DI[1] < -DI[1]-0.34) = Signal Sell true;
PLUSDI_LINEの現在のバーをMINUSDI_LINEの現在のバーで割った割合
と
前バーのPLUSDI_LINEを前バーのMINUSDI_LINEで割った割合の比較
(+DI[0]/-DI[0]) = V0 = (現在のバーのPLUSDI_LINE / 現在のバーのMINUSDI_LINE x 100) - 100;
(+DI[1]/-DI[1]) = V1 = (前のバーのPLUSDI_LINE / 前のバーのMINUSDI_LINE x 100) - 100;
この場合、次のようになります。
V0 > V1の場合、ADX条件パーセント値 = 上昇
V0 < V1の場合、ADX条件パーセント値 = 下降
パラボリックSARシグナル条件戦略:パラボリックストップ&リバースシステム(iSAR)
iSAR UP = PRICE_LOW[0] > iSAR[0]
iSAR DOWN = PRICE_HIGH[0] < iSAR[0]
iSARと組み合わせたiADXシグナルの図を図1に示します。
3.取引と注文管理
この多通貨EAの取引管理には、いくつかのオプションが与えられています。
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で、開かれた注文ごとに、シグナル状態がまだ良好で注文が利益を維持できるかどうか、
またはシグナルが弱まって注文を決済する必要があるかどうか、
または利益を保存するためやシグナル状態が方向を反転したために、注文を損失ポジションで決済する必要があるかどうかが確認されます。
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で入力する必要があります。
3.トレーリングストップとトレーリングテイクプロフィット
オプション:Use Trailing SL/TP:Yes/No
Use Trailing SL/TPがNoの場合、EAはトレーリングストップロスおよびトレーリングテイクプロフィットをおこないません。
Use Trailing SL/TPがYesの場合、さらにオプションUse Automatic Trailing:Yes/Noを指定することになります。
Use Automatic TrailingでYesを選択すると、トレーリングストップはパラボリックSARの値を使用してEAによって実行されます。
Use Automatic TrailingでNoを選択すると、トレーリングストップは入力プロパティの値を使用してEAが実行します。
注意:EAはトレーリングストップと同時にトレーリングテイクプロフィットを実行します。
4.手動による注文管理
この多通貨EAの効率をサポートするために、いくつかの手動クリックボタンが追加されます。
1.Set SL / TP All Orders
トレーダー入力パラメータが、Use Order Stop Loss:Noおよび/またはUse Order Take Profit:Noに設定されている場合
トレーダーがすべての注文にストップロスまたはテイクプロフィットを使用する場合、[Set SL / TP All Orders]ボタンをクリックするだけで、すべての注文が
変更され、ストップロスやテイクプロフィットが適用されます。
2.Close All Orders
トレーダーがすべての注文を決済したい場合、[Close All Orders]ボタンを1回クリックするだけで、すべての未決注文が決済されます。
3.Close All Orders Profit
トレーダーがすでに利益が出ている注文をすべて決済したい場合、[Close All Orders Profit]ボタンを1回クリックするだけで、
すでに利益が出ているすべての未決注文が決済されます。
5.管理注文と銘柄チャート
1つのチャート銘柄から30ペアを取引する多通貨EAの場合、すべての銘柄にボタンパネルが用意されていれば、トレーダーはワンクリックでチャートや銘柄を変更でき、非常に効果的かつ効率的です。
MQL5プログラムでの実装計画
1. プログラムヘッダとEA入力プロパティ
ヘッダーファイル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; //---
列挙YNは、EA入力プロパティのオプション(Yes/No)に使用されます。
enum YN { No, Yes }; //--
資金管理ロットサイズを使用する列挙
enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
EAシグナル計算のための時間枠の列挙
enum TFX { TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
EA入力プロパティ
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFX TimeFrames = TFH4; // Select Expert TimeFrame, default PERIOD_H4 input int ADXPeriod = 7; // Input ADX Period 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 //--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 = No; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 50; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = No; // 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 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 = 202307; // Expert ID (Magic Number) //---
この多通貨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; int posCur1, posCur2; //-- double LotPS, difDi; double slv, tpv, pip, xpip; double floatprofit, fixclprofit; double ADXDIp[]; double ADXDIm[]; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ int iADXCross(const string symbol); int iADXpct(const string symbol,const int index); int PARSAR05(const string symbol); int PARSAR15(const string symbol); int PARSAROp(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: //--- //-- ADXPSAR_MCEA Config -- string DIRI[], AS30[]; string expname; int handADX[]; int hParOp[], hPar15[], hPar05[]; int ALO, dgts, arrsymbx; int sall, arper; ulong slip; ENUM_TIMEFRAMES TFt, TFT15, TFT05; //-- double SARstep, SARmaxi; 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) //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void ADXPSAR_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 GetOpenPosition(const string symbol); int DirectionMove(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); int CheckToCloseInWeakSignal(const string symbol,int exis); int ThisTime(const int reqmode); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------//
OnInit()から呼び出される多通貨EAの作業プロセスで、最も最初で最も重要な関数はADXPSAR_MCEA_Config()です。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.ADXPSAR_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit() //---------//
ADXPSAR_MCEA_Config()関数では、使用されるすべての銘柄が設定され、使用されるすべての指標と、EAワークフローのインクルードファイルヘッダーのいくつかの重要な関数が設定されます。
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::ADXPSAR_MCEA_Config(void) { //--- //-- Here we will register all the symbols or pairs that will be used on the Multi-Currency Expert Advisor //-- 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 //-- sall=ArraySize(All30); ArrayResize(AS30,sall,sall); //-- These AS30[] arrays will be used in the symbol list panel and for the buttons to change symbols and charts ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); //-- arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); //-- The "DIRI[]" array containing the symbol or pair name will be used //-- in all trading activities of the multi-currency expert //-- //-- This function is for Select all symbol in the Market Watch window for(int x=0; x<arrsymbx; x++) { SymbolSelect(DIRI[x],true); } pairs="Multi Currency 30 Pairs"; //--- //-- Here we will provide a Period Timeframe value which will be used for signal calculations according //-- to the Timeframe option on the expert input property. ENUM_TIMEFRAMES TFs[]= {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(x==TimeFrames) { TFt=TFs[x]; break; } } //-- //-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { handADX[x]=iADX(DIRI[x],TFt,ADXPeriod); //-- Handle for the iADX indicator according to the selected Timeframe hParOp[x]=iSAR(DIRI[x],TFt,SARstep,SARmaxi); //-- Handle for the iSAR indicator according to the selected Timeframe hPar15[x]=iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe } //-- //-- Since this expert advisor is a multi-currency expert, we must check the maximum number //-- of account limit orders allowed by the broker. //-- This needs to be checked, so that when the expert opens an order there will be //-- no return codes of the trade server error 10040 = TRADE_RETCODE_LIMIT_POSITIONS ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders(); //-- //-- The LotPS variable will later be used for the proportional distribution of Lot sizes for each symbol LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); //-- Set Magic Number as expert ID mc_trade.SetDeviationInPoints(slip); //-- Set expert deviation with slip variable value mc_trade.SetMarginMode(); //-- Set the Margin Mode expert to the value of Account Margin Mode //-- return; //--- } //-end ADXPSAR_MCEA_Config() //---------//
2.EAティック関数
EAのティック関数(OnTick()関数)の中で、多通貨EAのメイン関数の1つである関数ExpertActionTrade()を呼び出します。
//+------------------------------------------------------------------+ //| 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 //-- //-- The functions below will be displayed on the expert chart according to //-- the Select Display Trading Info on Chart (Yes) or (No) option on expert property. //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //-- //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- Because the current prices of a specified symbol (SymbolInfoTick) will occur differently //-- for each symbol, we reduce the tick update frequency to only every 5 seconds. //-- So, looping to check the signal for all trading activity of all symbols will only be done every 5 seconds. //-- int mcsec=mc.ThisTime(mc.sec); //-- With the function ThisTime(mc.sec), we will retrieve the current seconds value to mcsec variable. //-- //-- MathMod is a formula that gives the (modulus) real remainder after the division of two numbers. //-- By dividing the value of seconds with the value of 5.0, if the result is 0, it means that 5 seconds //-- have been reached from the previous psec variable seconds value. //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) //-- So, if the seconds value in the ccur variable is not the same as the psec variable value { //-- (then the psec variable value already 5 seconds before) string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor //-- Here we start with the rotation of the name of all symbol or pairs to be traded //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- After the symbol or pair name is set, we declare or notify the symbol to MarketWatch //-- and the trade server by calling the CurrentSymbolSet(symbol) function. mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday()) //-- The TradingToday() function checks whether today is allowed for trading { //-- If today is not allowed for trading, then the Expert will only perform management //-- orders such as trailing stops or trailing profits and closing orders. //-- according to the expert input property Day Trading On/Off group //-- If TradingToday() == Yes, then the next process is to call the function ThisTime(mc.sec) //-- 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 it turns out that the "Sell Order" has been opened, //-- and Close Trade By Opposite Signal according to the input property is (Yes), //-- then call the function CloseSellPositions(symbol) to close the sell order on that 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); //-- Open BUY order for this symbol else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(mc.xtto>=mc.ALO) { //-- If the total number of orders is greater than or equal //-- to the account limit orders allowed by the broker, then turn on alerts //-- 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); //-- Call the CheckOpenPMx(symbol) function //-- //-- If it turns out that the "Sell Order" has been opened, //-- and the condition of the Sell order has lost more than 1.02 USD, //-- and the "Buy Order" has not been opened, then call CloseSellPositions(symbol) //-- to close "Sell order" and open "Buy order". if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) { mc.CloseSellPositions(symbol); mc.OpenBuy(symbol); } else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(SaveOnRev==Yes) mc.CloseAllProfit(); } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- //-- Call the CheckOpenPMx(symbol) function to check whether there are //-- already open "Buy" or "Sell" orders or no open orders. //-- mc.CheckOpenPMx(symbol); //-- //-- If it turns out that the "Buy Order" has been opened, //-- and Close Trade By Opposite Signal according to the input property is (Yes), //-- then call the function CloseBuyPositions(symbol) to close the buy order on that symbol. //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- //-- The algorithm below means that the expert will only open 1 order per symbol, //-- provided that the total number of orders is still less than //-- the account limit orders allowed by the broker. //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); //-- Open SELL order for this symbol else if(mc.xtto>=mc.ALO) { //-- If the total number of orders is greater than or equal //-- to the account limit orders allowed by the broker, then turn on alerts //-- 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); //-- Call the CheckOpenPMx(symbol) function //-- //-- If it turns out that the "Buy Order" has been opened, //-- and the condition of the Buy order has lost more than 1.02 USD, //-- and the "Sell Order" has not been opened, then call CloseBuyPositions(symbol) //-- to close "Buy order" and open "Sell order". if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) { mc.CloseBuyPositions(symbol); mc.OpenSell(symbol); } else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(SaveOnRev==Yes) mc.CloseAllProfit(); } } //-- mc.CheckOpenPMx(symbol); //-- The algorithm block below will check whether there is a weakening of the signal on Buy or Sell positions. //-- If it is true that there is a weakening signal and the iSAR indicator has reversed direction, //-- then close the losing order and immediately opened an order in the opposite direction. //-- if(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) {mc.CloseSellPositions(symbol); mc.OpenBuy(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(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) mc.CloseBuyPositions(symbol); if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) mc.CloseSellPositions(symbol); } //-- 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) } } //-- //-- Check if there are orders that were closed in the last 6 seconds. //-- If there are give alerts. mc.CheckClose(symbol); } //-- replace the value of the psec variable with the value of the ccur variable. mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
3.ポジションの開閉の売買シグナルを得る方法
指標のシグナルを取得するには、GetOpenPosition(symbol)関数を呼び出して、ポジションの売買シグナルを取得します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int dirmov=DirectionMove(symbol); int pars15=PARSAR15(symbol); int parsOp=PARSAROp(symbol); int sigADX=iADXCross(symbol); //-- if(sigADX==rise && parsOp==rise && dirmov==rise && pars15==rise) ret=rise; if(sigADX==down && parsOp==down && dirmov==down && pars15==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
GetOpenPosition()関数は4つのシグナル関数を呼び出し、変数OpOr[]に格納します。
1.DirectionMove(symbol); //-- EA期間中のローソク足上の価格であるかどうかを確認する関数
2.PARSAR15(symbol); //-- 期間M15でiSAR指標の状態が上昇するか下降するかを確認する関数
3.PARSAROp(symbol); //-- EA期間中にiSAR指標の状態が上昇するか下降するかを確認する関数
4. iADXCross(symbol); //-- EA期間中にiADX指標の状態が上昇するか下降するかを確認する関数
次に、iADXCross(symbol)関数の中で、iADXpct() 関数が呼び出され、シグナル指標のセクションで説明したように、+DIと-DIの間のパーセンテージの動きを確認します。
指標の条件を取得するには、PARSAR15(symbol)、PARSAROP(symbol)、iADXCross(symbol)、iADXpct()の4つの関数で、必要な指標ハンドルのインデックス番号を取得する必要があります。
指標ハンドルのインデックス番号を取得するために、PairsIdxArray(symbol)関数を呼び出します。
int x=PairsIdxArray(symbol);
x値は、当該銘柄の指標ハンドルのインデックス番号の配列です。
PARSAR15()関数の例では、問題の銘柄のiSAR指標ハンドルを呼び出す方法を見ることができます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M15 { //--- 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() //---------//
4.ChartEvent関数
多通貨EAの使用における有効性と効率性をサポートするために、注文の管理やチャートまたは銘柄の変更において、いくつかの手動ボタンを作成する必要があると考えられます。
//+------------------------------------------------------------------+ //| 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/TP 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); //-- Button state (depressed button) ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); //-- Button state (depressed button) ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); //-- Button state (depressed button) ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol name button is click if(lensparam==lensymbol) { int sx=mc.PairsIdxArray(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
多通貨EAのインターフェイスは下図のようになっています。
手動EAボタン
Mボタンがクリックされると、以下のように手動クリックボタンパネルが表示されます。
そして、トレーダーは注文を管理することができます。
1.Set SL/TP All Orders
2.Close All Orders
3.Close All Profits
[C]ボタンをクリックすると、以下のように30の銘柄名またはペアのパネルボタンが表示されます。
ペア名または銘柄のいずれかがクリックされると、チャート銘柄は即座にクリックされた名前の銘柄に置き換わります。
[R]ボタンをクリックすると、多通貨EA ADXPSAR_MCEAがチャートから削除されます。
ストラテジーテスター
MetaTrader 5ターミナルのストラテジーテスターはすでにサポートされており、ストラテジーのテスト、複数銘柄取引、または利用可能なすべての銘柄での自動取引のテストを実行できることが知られています。
取引戦略のテスト - 多通貨テスト
そこで今回は、ADXPSAR_MCEA Multi-Currency EAをMetaTrader 5プラットフォームのストラテジーテスターでテストしてみます。
結論
上に書いたように、MQL5を使って多通貨EAを作り、次の結論に達しました。
- MQL5で多通貨EAを作成するのは非常に簡単で、単一通貨のEAと大差ないことがわかりました。
- 多通貨EAを作成すると、トレーダーは取引のために多くのチャート銘柄を開く必要がないため、トレーダーの効率と有効性が向上します。
- 適切な取引戦略を適用し、より優れた指標シグナルを計算することで、単一通貨EAを使用する場合と比較して、利益を得る確率が高まります。あるペアで発生した損失は、他のペアの利益でカバーされるからです。
- このADXPSAR_MCEA多通貨EAは、学習し、アイデアを開発するための単なる例です。ストラテジーテスターのテスト結果もまだ良くありません。従って、より正確なシグナル計算をおこなうより良い戦略が実装されれば、結果は現在のものよりも良くなると思います。
この記事とMQL5多通貨EAプログラムが、トレーダーの皆さんの学習とアイデアの開発に役立つことを願っています。
ご精読ありがとうございました。