
如何利用 MQL5 创建简单的多币种智能交易系统(第 2 部分):指标信号:多时间帧抛物线 SAR 指标
概述
本文中多币种智能交易系统的定义是一款智能交易系统或交易机器人,它可以从一个品种图表中交易 1 个以上的品种对(开单、平单、及管理订单,例如:尾随止损和止盈),在本文中,智能交易系统将交易 30 个对。这次我们只用 1 个指标,即抛物线 SAR 或 iSAR,将其应用在 PERIOD_M15 到 PERIOD_D1 的多个时间帧。
我们都知道,在交易终端和策略测试器上进行多币种交易,都可以借助 MQL5 提供的强大能力和设施。
因此,我们的目标是满足那些想要高效和有效的交易机器人的交易者的基本需求,故此,依靠高度可靠的 MQL5 提供的能力和设施,我们可以创建一款简单的多币种智能交易系统,在本文中使用指标信号:多时间帧抛物线 SAR 或 iSAR 指标。
计划和功能
1. 交易货币对。
该多币种智能交易系统计划在如下品种或货币对上进行交易:
对于外汇:
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 对。
注意:所有这些交易品种或货币对都是经纪商常用的交易品种或货币对。因此,该多币种智能交易系统不适用于经纪商提供的名称含有前缀或后缀的品种或货币对。
2. 信号指标。
多币种智能交易系统将用 1 个指标信号,但有 5 个时间帧,始自 PERIOD_M15、PERIOD_M30、PERIOD_H1、PERIOD_H4 和 PERIOD_D1。
在该智能交易系统中,它不使用固定的时间帧来计算指标信号,故无需检测信号计算时间帧。
这意味着 FXSAR_MTF_MCEA 智能交易系统可在从 PERIOD_M1 到 PERIOD_MN1 的任何时间帧内使用,并且 FXSAR_MTF_MCEA 仍将基于 iSAR PERIOD_M15、PERIOD_M30、PERIOD_H1、PERIOD_H4 和 PERIOD_D1 计算信号。
这五个抛物线 SAR 时间帧将检测开单的信号。
同时,在订单处于盈利条件下,若 iSAR 指标 PERIOD_M15 的信号疲软时平单。
若要尾随止损和止盈,则用 iSAR 指标的 PERIOD_H1。
iSAR 信号条件策略公式:
上行 =(PRICE_LOW[0] 大于 iSAR 线),或 PRICE_LOW[0] > iSAR[0]
下行 =(PRICE-HIGH[0] 小于 iSAR 线),或 PRICE-HIGH[0] < iSAR[0]
从哪里获得买入信号或卖出信号:
五个 iSAR 指标时间帧,必须总计 5 x 上行是为买入,5 x 下行是为卖出。
iSAR 指标买入和卖出的描绘,参见图例 1
3. 交易和订单管理
该多币种智能交易系统的交易管理有多种选项:
1. 止损单。
- 选项:使用订单止损(是)或(否)
如果选中“使用订单止损(否)”选项,则所有订单在开单时都不带止损。
如果选项“使用订单止损(是)”:再次给出选项:使用自动计算止损(是)或(否)
如果选项是“自动计算止损(是)”,则将由智能系统自动执行止损计算。
如果选项是“自动计算止损(否)”,则交易者必须以点数为单位输入止损值。
如果选项是“使用订单止损(否)”:则智能系统将检查每笔开单,信号条件是否仍然良好,且订单
或许维持盈利,或者信号疲软,需要平单以确保
盈利,或信号条件方向已逆转,持仓亏损也必须平仓。
2. 止盈单。
- 选项:使用订单止盈(是)或(否)
如果选中“使用订单止盈”(否)选项,则所有订单在开单时都不带止盈。
如果选项是“使用订单止盈“(是):再次给出选项:使用自动计算订单止盈(是)或(否)
如果选项是“自动计算订单止盈”(是),则将由智能系统自动执行止盈计算。
如果选项是“自动计算订单止盈“(否),则交易者必须以点数输入订单止盈值。
3. 尾随止损和尾随止盈
- 选项:使用尾随止损/止盈(是)或(否)
如果”使用尾随止损/止盈“选项为(否),则智能系统不会执行尾随止损和尾随止盈。如果选项”使用尾随止损/止盈“(是):再次给出选项:使用自动尾随(是)或(否)如果选项”使用自动尾随“(是),则尾随止损将由智能系统依据抛物线 SAR 的 PERIOD_H1 值执行,同时基于变量值 TPmin(尾随止盈值)进行尾随止盈。如果选项是”使用自动尾随“(否),则智能系统将采用输入属性中的值执行尾随止损。
注意:智能系统将同时执行尾随止盈和尾随止损。
4. 手动订单管理。
为了提高该多币种智能交易系统的效率,将添加若干个手动单击按钮
1. 为所有订单设置止损/止盈
当交易者在输入参数设置”使用订单止损“(否)和/或”使用订单止盈“(否)时
但随后交易者打算针对所有订单使用止损或止盈,然后只需单击“设置止损/止盈所有订单”按钮,所有订单将被修改,止损和/或止盈将被应用。
2. 所有订单平仓
如果交易者想要所有订单平仓,那么只需单击 “所有订单平仓” 按钮,所有持仓将被平仓。
3. 所有盈利订单平仓
如果交易者想把所有盈利订单平仓,那么只需单击“所有盈利订单平仓”按钮即可
把所有盈利持仓都平仓。
5. 管理订单和品种图表。
对于仅从单一品种图表交易 30 对的多币种智能系统,如果为所有品种提供按钮面板,这将非常有效和高效,如此交易者只需单击一下即可更改图表或品种。
在 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; //---
枚举 YN 是智能系统输入属性中的选项(Yes)或(No)
enum YN
{
No,
Yes
};
资金管理手数的枚举
//-- enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
智能系统输入属性
//--- 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 = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 10; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = Yes; // Use Automatic Trailing (Yes) or (No) input double TSval = 5; // If Not Use Automatic Trailing Input Trailing value in Pips input double TSmin = 5; // Minimum Pips to start Trailing Stop input double TPmin = 25; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No) input ulong magicEA = 2023102; // Expert ID (Magic Number) //---
为了声明该多币种智能交易系统所需的所有变量、对象和函数,我们将创建一个类来为智能交易系统指定工作流中的构造和配置。
//+------------------------------------------------------------------+ //| 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; double slv, tpv, pip, xpip; double differ; double floatprofit, fixclprofit; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //------------ int DirectionMove(const string symbol); int GetPSARSignalMTF(string symbol); int PARSAR05(const string symbol); int PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf); 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: //-- FXSAR_MTF_MCEA Config -- string DIRI[], AS30[]; string expname; int hPar05[]; // Handle for the iSAR indicator for M5 Timeframe int hPSAR[][5]; // Handle Indicator, where each Symbol has 5 arrays for Timeframe starting from TF_M15 to TF_D1 int ALO, dgts, arrsar, arrsymbx; int sall, arper; ulong slip; //-- double SARstep, SARmaxi; double profitb[], profits[]; //-- int Buy, Sell; int ccur, psec, xtto, TFArrays, 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, TFSAR[]; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ virtual void FXSAR_MTF_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 TFIndexArray(ENUM_TIMEFRAMES TF); int GetOpenPosition(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); int ThisTime(const int reqmode); //-- string getUninitReasonText(int reasonCode); //------------ //--- }; //-end class MCEA
在多币种智能交易系统工作过程中,自 OnInit() 调用的第一个也是最重要的函数是 FXSAR_MTF_MCEA_Config()。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.FXSAR_MTF_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit()
在 FXSAR_MTF_MCEA_Config() 函数中,配置了所有要用的品种,所有指标的句柄,以及智能交易系统工作流所需的包含头文件的一些重要函数。
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::FXSAR_MTF_MCEA_Config(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 //-- sall=ArraySize(All30); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); //-- arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); for(int x=0; x<arrsymbx; x++) {SymbolSelect(DIRI[x],true);} pairs="Multi Currency 30 Pairs"; //-- TFT05=PERIOD_M5; ENUM_TIMEFRAMES TFA[]={PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1}; TFArrays=ArraySize(TFA); ArrayResize(TFSAR,TFArrays,TFArrays); ArrayCopy(TFSAR,TFA,0,0,WHOLE_ARRAY); //-- TFt=TFSAR[2]; //-- //-- iSAR Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe //-- for(int i=0; i<TFArrays; i++) { hPSAR[x][i]=iSAR(DIRI[x],TFSAR[i],SARstep,SARmaxi); // Handle for iSAR Indicator array sequence of the requested timeframe } } //-- ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders(); //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); //-- return; //--- } //-end FXSAR_MTF_MCEA_Config()
2. 智能系统跳价函数
在智能系统跳价函数(OnTick() 函数)中,我们将调用多币种智能系统中的主要函数之一,即函数 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 //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- int mcsec=mc.ThisTime(mc.sec); //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) { string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday()) { //-- mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions //-- //-- and store in the variable OpOr[x] if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol); //-- if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } } //-- mc.CheckOpenPMx(symbol); //-- if(mc.xtto>0) { //-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>0.02 && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>0.02 && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //-- if(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes) { if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes) if(autotrl==No) mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No) } } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade()
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 parsOp=GetPSARSignalMTF(symbol); //-- if(parsOp==rise && dirmov==rise) ret=rise; if(parsOp==down && dirmov==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition()
GetOpenPosition() 函数将调用 2 个信号函数,并存储在变量 OpOr[] 当中。
1. DirectionMove(symbol); //--函数检查价格在智能系统周期内是否在烛条柱上移动。
2. GetPSARSignalMTF(symbol); //-- 函数在请求的时间帧内计算抛物线 iSAR 公式。
int MCEA::GetPSARSignalMTF(string symbol) // iSAR MTF signal calculation { //--- int mv=0; int rise=1, down=-1; //-- int sarup=0, sardw=0; //-- for(int x=0; x<TFArrays; x++) // The TFArrays variable has a value of 5 which is taken from the number of time frames from TF_M1 to TF_H1. { if(PARSARMTF(symbol,TFSAR[x])>0) sarup++; if(PARSARMTF(symbol,TFSAR[x])<0) sardw++; } //-- if(sarup==TFArrays) mv=rise; if(sardw==TFArrays) mv=down; //-- return(mv); //--- } //- end GetPSARSignalMTF()
GetPSARSignalMTF() 函数将调用一个函数 PARSARMTF(),该函数根据请求的时间帧计算 iSAR 信号。
正如您所看到的,在 PARSARMTF() 函数中,我们使用并调用了 2 个函数:
1. int xx= PairsIdxArray(symbol)
2. int tx=TFIndexArray(mtf).
PairsIdxArray() 函数获取所请求品种的名称,TFIndexArray() 函数获取所请求时间帧的数组序列。
然后调用相应的指标句柄,从所请求时间帧中获取 iSAR 指标的缓冲区值。
int MCEA::PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf) // formula Parabolic iSAR on the requested Timeframe { //--- int ret=0; int rise=1, down=-1; //-- int br=2; //-- double PSAR[]; ArrayResize(PSAR,br,br); ArraySetAsSeries(PSAR,true); int xx=PairsIdxArray(symbol); int tx=TFIndexArray(mtf); CopyBuffer(hPSAR[xx][tx],0,0,br,PSAR); //-- double OPN0=iOpen(symbol,TFSAR[tx],0); double HIG0=iHigh(symbol,TFSAR[tx],0); double LOW0=iLow(symbol,TFSAR[tx],0); double CLS0=iClose(symbol,TFSAR[tx],0); //-- if(PSAR[0]<LOW0 && CLS0>OPN0) ret=rise; if(PSAR[0]>HIG0 && CLS0<OPN0) ret=down; //-- return(ret); //--- } //-end PARSARMTF()
int MCEA::PairsIdxArray(const string symbol) { //--- int pidx=0; //-- for(int x=0; x<arrsymbx; x++) { if(DIRI[x]==symbol) { pidx=x; break; } } //-- return(pidx); //--- } //-end PairsIdxArray()
int MCEA::TFIndexArray(ENUM_TIMEFRAMES TF) { //--- int res=-1; //-- for(int x=0; x<TFArrays; x++) { if(TF==TFSAR[x]) { res=x; break; } } //-- return(res); //--- } //-end TFIndexArray()
//+------------------------------------------------------------------+ //| 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.PairsIdxArray(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- } //-- return; //--- } //-end OnChartEvent()
为了一键更改图表品种,当单击其中一个品种名称时,OnChartEvent() 将调用函数 ChangeChartSymbol()。
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()
如果智能系统属性上的选项“在图表上显示交易信息”选项选择为“是”,则在放置智能交易系统的图表上,调用 TradeInfo() 函数显示交易信息。
void MCEA::TradeInfo(void) // function: write comments on the chart { //---- Pips(Symbol()); double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip; //-- 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 ------------------------------------------------------------"+ "\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()
多币种智能交易系统 FXSAR_MTF_MCEA 界面如下图所示。
如您所见,名为 FXSAR_MTF_MCEA 的智能交易系统有按钮 “M”、“C” 和 “R”
如果单击 “M” 或 “C” 按钮,将显示手动单击按钮面板,如下所示
如果点击 ”M“ 按钮,将显示手动点击按钮面板,然后交易者可以管理订单:
1. 为所有订单设置止损/止盈
2. 所有订单平仓
3. 所有盈利单平仓
如果单击 ”C“ 按钮,将显示一个包含 30 个品种名称或货币对的面板按钮,交易者可以单击其中一个货币对名称或品种名称。如果单击其中一个货币对或品种名称,则图表品种将立即替换为所单击品种名称。
如果单击 ”R“ 按钮,则多币种智能交易系统 FXSAR_MTF_MCEA将 从图表中删除
策略测试器
众所周知,MetaTrader 5 终端策略测试器支持并允许我们测试策略、交易多个品种、或测试所有可用品种及所有可用时间帧的自动交易。
因此,在这种情况下,我们将在 MetaTrader 5 策略测试器平台上测试多时间帧和多币种智能交易系统 FXSAR_MTF_MCEA。
结束语
利用 MQL5 创建多币种和多时间帧智能交易系统的结论如下:
- 事实摆明,在 MQL5 中创建多币种智能交易系统非常简单,与单币种智能交易系统没有太大区别。但对于具有多时间帧的多币种智能交易系统有点特别,它比单一时间帧要复杂一些。
- 创建多币种智能交易系统将提高交易者的效率和有效性,因为交易者无需打开更多品种图表即可进行交易。
- 通过应用正确的交易策略,并计算更佳指标信号,比之单货币智能交易系统,其获利可能性会提升。因为一个品种(货币对)产生的亏损会被其它品种(货币对)的盈利所补偿。
- 这个 FXSAR_MTF_MCEA 多币种智能交易系统只是一个学习和开发思路的例子。
- 在策略测试器当中的测试结果仍然不佳。因此,如果拥有更准确信号计算的更好策略,并添加一些更好的时间帧,我相信结果将比当前策略更好。
注意:
如果您有基于内置 MQL5 标准指标信号创建简单多币种智能交易系统的思路,请在评论中提出。
希望本文和 MQL5 多币种智能交易系统程序能对交易者学习和开发思路有所帮助。感谢您的阅读。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/13470
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。


它当然慢!它的计算量是 "快速 EA "的 30 倍,试着同时运行 30 个快速 EA,看看会发生什么。 我敢打赌,这个 EA 的速度要快得多。 如果测试运行中 75% 以上的胜率保持不变,那么在 4 次交易中赢 3 次的情况下,谁还会在乎速度呢?
对于多币种 EA,手动优化代码是必要的。查看循环以移动静态赋值,在循环和函数中使用局部变量以减少计算,确保同一函数不被多次调用,通过将一次性调用和静态计算移动到全局变量中,在 OnInit 函数中完成尽可能多的工作,等等等等。
要解决符号前缀后缀问题,可以考虑为每个符号使用 2 个变量,一对变量表示 6 chr 名称,另一个变量表示带前缀和后缀的全名。 可以使用字符串函数检查名称,以设置这两个变量。
您可能想创建一个自适应抛物线 止损,更紧密地跟踪柱状图,我认为有几个自适应 PSAR 指标可以作为指导。
不应该低估 Roberto 为这款 EA 所做的工作,它非常重要。
不应该低估 Roberto 为这款 EA 所做的工作,它非常重要。
感谢您的支持。我将撰写一篇文章,添加自动检测和处理具有特殊符号名称、前缀和/或后缀的经纪商的功能。
罗伯托
坏消息,从 2023 年 1 月 1 日到 2023 年 1 月 11 日,我在欧元兑美元 H4 上运行了您的 EA,初始余额为 1000 美元。 EA 在不到 3 个月的时间内就使账户破产。 在有 10,000 美元的情况下,它完全运行,但损失了 8,250 美元。 从图表上看,损失从开始到结束都是一致的,没有急剧的高峰或低谷。
首先,不要绝望!外汇交易是艰难的,而设计一个多货币 EA 则更加艰难。 我知道,我正在将一个 EA 从 MQ4 转变为 MQ5。
现在也许是时候实现可变货币对功能了,这样就可以指定货币对,使您能够只在一个货币对上进行测试。 最简单的方法是将货币对字符串作为输入项,并使用 STRSPLIT 分隔字符串中的每个货币对,以便加载货币对。 更好的方法是使用 30 个货币对显示屏,让用户通过在货币对上计时和改变颜色来选择运行的货币对。 最近有两篇 GUI 文章:GUI:提示和技巧......我使用的是后者,但我认为 "窍门与技巧 "可能更好、更完整。 您还应该使用图形用户界面来显示您的数据,我认为这非常好,而不是使用 "评论 "功能。
我坚信帕累托法则:80% 的特征来自 20% 的元素。 这意味着总体盈利的 80% 来自 6 对交易,相应地,6 对交易造成了 80% 的损失。
在多货币测试中,必须增强策略测试器对单个货币对的统计,以便识别问题领域和帕累托法则。 需要在货币对级别上使用 BackTest 选项卡的元素,即净利润、毛利润、毛损失等等等等。
我仍然认为,SAR 的自适应过程可以提高您的利润。 如果您看一下您的买入/卖出图表,根据条形图大小的增加来提高 SAR 加速速度的自适应功能,可以使 SAR 在图表上前 4 个买入/卖出图中的利润增加。 这种自适应的灵活性有两个好处:更重要的是,它可以让下 一笔交易提前 5 美元至 10美元开仓。 因此,灵活的影响可能会为每笔交易带来 10 美元至 20 美元的总体 利润。 但是,它也可能会导致大量额外的亏损交易,从而相应地减少总体利润。
专注于这些目标和最佳时间框架,你的盈利能力将大幅提高。 我承认我还没有想出一个动态评估流程。
我坚信帕累托定律:80% 的特征来自 20% 的要素。 这意味着总体利润的 80% 来自 6 对组合,相应地,6 对组合造成了 80% 的损失。
谢谢您的意见。
正如我在结论 4 和 5 中所说:
这个 FXSAR_MTF_MCEA 多货币智能交易系统只是一个学习和开发思路的例子。
在策略测试器上的测试结果仍不理想。因此,如果实施一个信号计算更准确的更好的策略,并增加一些更好的时间框架,我相信结果会比当前策略更好。
因此,能否利用你所说的自适应功能进行升级,以获得更好的结果,就取决于你了。
你好,罗伯托、
非常有趣,我喜欢多时间框架系统。
对不起,我不明白如何改变单一 SAR 的时间框架,如果 SAR 有固定值计算。
是否有办法在每个时间框架买入和卖出(而不是等待所有时间框架都在一边)?
在这种情况下,我可以在 1 分钟内卖出,在 5 分钟内买入,假设每隔 0.1 分钟我就会有一个可变数量的多头和空头。
我从 1.1.24 版开始就尝试在黄金 上进行测试,但什么也没发生,没有交易。
有什么建议吗?您也可以私信我。
非常感谢。
马可