
基于大众交易系统和交易机器人优化点金术的Expert Advisor(续)
简介
我收到上一篇文章的一位读者的提议,对回测过程稍加自动化,以实现同时获得所有优化结果的可能性。此外,手动改变测试周期不是很方便,该过程也应该自动化。这个想法非常棒。而且,MQL4 完全可以实现。所以,我将从问题的解决方法开始讲述。
回测自动化
要完成该任务我们需要:
1.在所需的 Expert Advisor 标头下面写入一行,内容如下:
//+==================================================================+ //| Custom BackTesting function | //+==================================================================+ #include <IsBackTestingTime.mqh>
使用该指令,将 IsBackTestingTime() 函数加入 EA 代码。不要忘记将 IsBackTestingTime.mqh 文件放入 INCLUDE 文件夹。该函数:
bool IsBackTestingTime()
{
}
用于定义时间周期,在该时间内进行回测优化或回测。在该时间周期内,函数始终返回‘真’,在其他时间则返回‘假’。除了这个函数,通过以下指令将外部 EA 变量添加到 EA 代码:
//---- Declaration of external variables for backtesting extern datetime Start_Time = D'2007.01.01'; // start time of zero optimization extern int Opt_Period = 3; // optimization period in months, if less than zero, parameters are in days extern int Test_Period = 2; // testing period in months extern int Period_Shift = 1; // step of optimization period shift in months extern int Opt_Number = 0; // optimization number
希望这些变量的含义对于读了我上一篇文章的人都很清楚,这里就不再解释。
2.在 EA 代码前的开始函数程序块设置调用 IsBackTestingTime() 函数的最简单的通用代码,根据回测优化的数量将 EA 运行限制在特定的时间范围。
//----+ Execution of backtesting conditions if (!IsBackTestingTime()) return(0);
它的示意图如下:
//+==================================================================+ //| Exp_BackTest.mq4 | //| Copyright © 2008, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+==================================================================+ #property copyright "Copyright © 2008, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //+==================================================================+ //| Custom BackTesting function | //+==================================================================+ #include <IsBackTestingTime.mqh> //---- INPUT PARAMETERS OF THE EA //---- GLOBAL VARIABLES OF THE EA //+==================================================================+ //| USER-DEFINED FUNCTIONS OF THE EA | //+==================================================================+ //+==================================================================+ //| Custom Expert initialization function | //+==================================================================+ int init() { //----+ +------------------------------------------------------------+ //---- CODE FOR THE EA INITIALIZATION //----+ +------------------------------------------------------------+ //---- end of initialization return(0); } //+==================================================================+ //| Custom Expert iteration function | //+==================================================================+ int start() { //----+ Execution of backtesting conditions if (!IsBackTestingTime()) return(0); //----+ +---------------------------------------------------------+ //----+ CODE OF THE EA ALGORITHM //----+ +---------------------------------------------------------+ //----+ return(0); } //+------------------------------------------------------------------+
如果你对现成 EA 示例上的详细问题解决方案感兴趣,查看 EA 代码 Exp_5_1.mq4,源于上一篇文章中的 Exp_5.mq4,经修改后用于回测。实际上,与简单的 Expert Advisor 相比,这种 EA 的优化没有多大不同。但是,我认为除了 Opt_Number 变量外,回测变量应该进行优化,不过你可能有不同的看法。
重要的是记住:在测试优化后,我们得到的不是优化期间的结果,而是在其之后(右侧边界之外)的结果。使用遗传算法在一次运行内进行所有的回测优化并非最好的决定,在没有优化输入变量 Opt_Number 的情况下,单独深入分析每个回测优化更加有趣。
但即使在这种情况下,这种方法也促进了对 EA 行为的理解。应该记住,外部变量 Opt_Number 的值可以从零变化到某个最大值,该最大值可以使用以下方式定义:从执行所有回测优化的总周期(月数)减去回测优化周期的月数(Opt_Period)和减去回测周期(Test_Period)。获得的值加一。如果 Period_Shift 等于一,获得的结果将是 Opt_Number 变量的最大值。
基于两条移动线交叉的交易系统
这种交易系统的变体非常普遍。现在我们来分析奠定这种策略的算法。对于做多头寸,输入的算法如下:
对于做空头寸,则如下:
可以使用在指标中定义平均线的具有不同参数的两条相同移动线。假设定义 MovA 移动平均线的参数始终小于 MovB 移动平均线的同一参数。这样,在该交易系统中,MovA 是快速移动线,MovB 是慢速线。下面是基于两条 JMA 移动线的交易系统的实现变体:
//+==================================================================+ //| Exp_6.mq4 | //| Copyright © 2007, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+==================================================================+ #property copyright "Copyright © 2007, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //----+ +-------------------------------------------------------------------------------+ //---- EA INPUT PARAMETERS FOR BUY TRADES extern bool Test_Up = true;//filter of trade calculations direction extern int Timeframe_Up = 240; extern double Money_Management_Up = 0.1; extern int LengthA_Up = 4; // smoothing depth of the quick moving extern int PhaseA_Up = 100; // parameter changing in the range //-100 ... +100, influences the quality of transient process of quick moving extern int IPCA_Up = 0;/* Selecting prices, on which the indicator will be calculated by the quick moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */ extern int LengthB_Up = 4; // smoothing depth increment of slow moving to quick one extern int PhaseB_Up = 100; // parameter changing in the range //-100 ... +100, influences the quality of transient process of slow moving; extern int IPCB_Up = 0;/* Selecting prices, on which the indicator will be calculated by the slow moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */ extern int STOPLOSS_Up = 50; // stop loss extern int TAKEPROFIT_Up = 100; // take profit extern bool ClosePos_Up = true; // forced position closing allowed //----+ +-------------------------------------------------------------------------------+ //---- EA INPUT PARAMETERS FOR SELL TRADES extern bool Test_Dn = true;//filter of trade calculations direction extern int Timeframe_Dn = 240; extern double Money_Management_Dn = 0.1; extern int LengthA_Dn = 4; // smoothing depth of the quick moving extern int PhaseA_Dn = 100; // parameter changing in the range // -100 ... +100, influences the quality of transient process of quick moving; extern int IPCA_Dn = 0;/* Selecting prices, on which the indicator will be calculated by the quick moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */ extern int LengthB_Dn = 4; // smoothing depth increment of slow moving to quick one extern int PhaseB_Dn = 100; // parameter changing in the range // -100 ... +100, influences the quality of transient process of slow moving; extern int IPCB_Dn = 0;/* Selecting prices, on which the indicator will be calculated by the slow moving(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */ extern int STOPLOSS_Dn = 50; // stop loss extern int TAKEPROFIT_Dn = 100; // take profit extern bool ClosePos_Dn = true; // forced position closing allowed //----+ +-------------------------------------------------------------------------------+ //---- Integer variables for the minimum of calculation bars int MinBar_Up, MinBar_Dn; //+==================================================================+ //| Custom Expert functions | //+==================================================================+ #include <Lite_EXPERT1.mqh> //+==================================================================+ //| Custom Expert initialization function | //+==================================================================+ int init() { //---- Checking the correctness of Timeframe_Up variable value if (Timeframe_Up != 1) if (Timeframe_Up != 5) if (Timeframe_Up != 15) if (Timeframe_Up != 30) if (Timeframe_Up != 60) if (Timeframe_Up != 240) if (Timeframe_Up != 1440) Print(StringConcatenate("Parameter Timeframe_Up cannot ", "be equal to ", Timeframe_Up, "!!!")); //---- Checking the correctness of Timeframe_Dn variable value if (Timeframe_Dn != 1) if (Timeframe_Dn != 5) if (Timeframe_Dn != 15) if (Timeframe_Dn != 30) if (Timeframe_Dn != 60) if (Timeframe_Dn != 240) if (Timeframe_Dn != 1440) Print(StringConcatenate("Parameter Timeframe_Dn cannot ", "be equal to ", Timeframe_Dn, "!!!")); //---- Initialization of variables MinBar_Up = 4 + 30; MinBar_Dn = 4 + 30; //---- end of initialization return(0); } //+==================================================================+ //| expert deinitialization function | //+==================================================================+ int deinit() { //----+ //---- End of EA deinitialization return(0); //----+ } //+==================================================================+ //| Custom Expert iteration function | //+==================================================================+ int start() { //----+ Declaring local variables int bar; double MovA[2], MovB[2]; //----+ Declaring static variables static int LastBars_Up, LastBars_Dn; static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop; //----++ CODE FOR LONG POSITIONS if (Test_Up) { int IBARS_Up = iBars(NULL, Timeframe_Up); if (IBARS_Up >= MinBar_Up) { if (LastBars_Up != IBARS_Up) { //----+ Initialization of variables BUY_Sign = false; BUY_Stop = false; LastBars_Up = IBARS_Up; //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS for(bar = 1; bar < 3; bar++) MovA[bar - 1] = iCustom(NULL, Timeframe_Up, "JJMA", LengthA_Up, PhaseA_Up, 0, IPCA_Up, 0, bar); for(bar = 1; bar < 3; bar++) MovB[bar - 1] = iCustom(NULL, Timeframe_Up, "JJMA", LengthA_Up + LengthB_Up, PhaseB_Up, 0, IPCB_Up, 0, bar); //----+ DEFINING SIGNALS FOR TRADES if ( MovA[1] < MovB[1]) if ( MovA[0] > MovB[0]) BUY_Sign = true; if ( MovA[0] > MovB[0]) BUY_Stop = true; } //----+ EXECUTION OF TRADES if (!OpenBuyOrder1(BUY_Sign, 1, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up)) return(-1); if (ClosePos_Up) if (!CloseOrder1(BUY_Stop, 1)) return(-1); } } //----++ CODE FOR SHORT POSITIONS if (Test_Dn) { int IBARS_Dn = iBars(NULL, Timeframe_Dn); if (IBARS_Dn >= MinBar_Dn) { if (LastBars_Dn != IBARS_Dn) { //----+ Initialization of variables SELL_Sign = false; SELL_Stop = false; LastBars_Dn = IBARS_Dn; //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS for(bar = 1; bar < 3; bar++) MovA[bar - 1] = iCustom(NULL, Timeframe_Dn, "JJMA", LengthA_Dn, PhaseA_Dn, 0, IPCA_Dn, 0, bar); for(bar = 1; bar < 3; bar++) MovB[bar - 1] = iCustom(NULL, Timeframe_Dn, "JJMA", LengthA_Dn + LengthB_Dn, PhaseB_Dn, 0, IPCB_Dn, 0, bar); //----+ DEFINING SIGNALS FOR TRADES if ( MovA[1] > MovB[1]) if ( MovA[0] < MovB[0]) SELL_Sign = true; if ( MovA[0] < MovB[0]) SELL_Stop = true; } //----+ EXECUTION OF TRADES if (!OpenSellOrder1(SELL_Sign, 2, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn)) return(-1); if (ClosePos_Dn) if (!CloseOrder1(SELL_Stop, 2)) return(-1); } } //----+ return(0); } //+------------------------------------------------------------------+
基于两个震荡指标交叉的交易系统
这种交易策略不仅可以使用移动线,还可以使用震荡指标,但对于后者,根据上一篇文章所写,最好设置挂单,而不是在收到信号后立即进入市场。可以使用 NACD 图表作为生动的示例。
要设置 BuyLimit 挂单,算法如下:
下面是用于 SellLimit 类型订单的算法:
该 EA 的代码跟之前 EA 的代码类似:
//+==================================================================+ //| Exp_7.mq4 | //| Copyright © 2007, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+==================================================================+ #property copyright "Copyright © 2007, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //----+ +---------------------------------------------------------------------------+ //---- EA INPUT PARAMETERS FOR BUY TRADES extern bool Test_Up = true; //filter of trade calculations direction extern int Timeframe_Up = 240; extern double Money_Management_Up = 0.1; extern int FST_period_Up = 12; // period of the quick moving extern int SLO_period_Up = 22; // period increment of slow moving to quick one extern int SIGN_period_Up = 8; // period of the signal line extern int Price_Up = 0; // selecting prices, upon which MACD is calculated extern int STOPLOSS_Up = 50; // stop loss extern int TAKEPROFIT_Up = 100; // take profit extern int PriceLevel_Up =40; // difference between the current price and // price of pending order triggering extern bool ClosePos_Up = true; // forced position closing allowed //----+ +---------------------------------------------------------------------------+ //---- EA INPUT PARAMETERS FOR SELL TRADES extern bool Test_Dn = true; //filter of trade calculations direction extern int Timeframe_Dn = 240; extern double Money_Management_Dn = 0.1; extern int FST_period_Dn = 12; // period of the quick moving extern int SLO_period_Dn = 22; // period increment of slow moving to quick one extern int SIGN_period_Dn = 8; // period of the signal line extern int Price_Dn = 0; // selecting prices, upon which MACD is calculated extern int STOPLOSS_Dn = 50; // stop loss extern int TAKEPROFIT_Dn = 100; // take profit extern int PriceLevel_Dn =40; // difference between the current price and // price of pending order triggering extern bool ClosePos_Dn = true; // forced position closing allowed //----+ +---------------------------------------------------------------------------+ //---- Integer variables for the minimum of calculation bars int MinBar_Up, MinBar_Dn; //+==================================================================+ //| Custom Expert functions | //+==================================================================+ #include <Lite_EXPERT1.mqh> //+==================================================================+ //| Custom Expert initialization function | //+==================================================================+ int init() { //---- Checking the correctness of Timeframe_Up variable value if (Timeframe_Up != 1) if (Timeframe_Up != 5) if (Timeframe_Up != 15) if (Timeframe_Up != 30) if (Timeframe_Up != 60) if (Timeframe_Up != 240) if (Timeframe_Up != 1440) Print(StringConcatenate("Parameter Timeframe_Up cannot ", "be equal to ", Timeframe_Up, "!!!")); //---- Checking the correctness of Timeframe_Dn variable value if (Timeframe_Dn != 1) if (Timeframe_Dn != 5) if (Timeframe_Dn != 15) if (Timeframe_Dn != 30) if (Timeframe_Dn != 60) if (Timeframe_Dn != 240) if (Timeframe_Dn != 1440) Print(StringConcatenate("Parameter Timeframe_Dn cannot ", "be equal to ", Timeframe_Dn, "!!!")); //---- Initialization of variables MinBar_Up = 4 + FST_period_Up + SLO_period_Up + SIGN_period_Up; MinBar_Dn = 4 + FST_period_Dn + SLO_period_Dn + SIGN_period_Dn; //---- end of initialization return(0); } //+==================================================================+ //| expert deinitialization function | //+==================================================================+ int deinit() { //----+ //---- End of the EA deinitialization return(0); //----+ } //+==================================================================+ //| Custom Expert iteration function | //+==================================================================+ int start() { //----+ Declaring local variables int bar; double MovA[2], MovB[2]; //----+ Declaring static variables static int LastBars_Up, LastBars_Dn; static datetime StopTime_Up, StopTime_Dn; static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop; //----++ CODE FOR LONG POSITIONS if (Test_Up) { int IBARS_Up = iBars(NULL, Timeframe_Up); if (IBARS_Up >= MinBar_Up) { if (LastBars_Up != IBARS_Up) { //----+ Initialization of variables BUY_Sign = false; BUY_Stop = false; LastBars_Up = IBARS_Up; StopTime_Up = iTime(NULL, Timeframe_Up, 0) + 60 * Timeframe_Up; //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS for(bar = 1; bar < 3; bar++) MovA[bar - 1] = iMACD(NULL, Timeframe_Up, FST_period_Up, FST_period_Up + SLO_period_Up, SIGN_period_Up, Price_Up, 0, bar); for(bar = 1; bar < 3; bar++) MovB[bar - 1] = iMACD(NULL, Timeframe_Up, FST_period_Up, FST_period_Up + SLO_period_Up, SIGN_period_Up, Price_Up, 1, bar); //----+ DEFINING SIGNALS FOR TRADES if ( MovA[1] < MovB[1]) if ( MovA[0] > MovB[0]) BUY_Sign = true; if ( MovA[0] > MovB[0]) BUY_Stop = true; } //----+ EXECUTION OF TRADES if (!OpenBuyLimitOrder1(BUY_Sign, 1, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up, PriceLevel_Up, StopTime_Up)) return(-1); if (ClosePos_Up) if (!CloseOrder1(BUY_Stop, 1)) return(-1); } } //----++ CODE FOR SHORT POSITIONS if (Test_Dn) { int IBARS_Dn = iBars(NULL, Timeframe_Dn); if (IBARS_Dn >= MinBar_Dn) { if (LastBars_Dn != IBARS_Dn) { //----+ Initialization of variables SELL_Sign = false; SELL_Stop = false; LastBars_Dn = IBARS_Dn; StopTime_Dn = iTime(NULL, Timeframe_Dn, 0) + 60 * Timeframe_Dn; //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS for(bar = 1; bar < 3; bar++) MovA[bar - 1] = iMACD(NULL, Timeframe_Dn, FST_period_Dn, FST_period_Dn + SLO_period_Dn, SIGN_period_Dn, Price_Dn, 0, bar); for(bar = 1; bar < 3; bar++) MovB[bar - 1] = iMACD(NULL, Timeframe_Dn, FST_period_Dn, FST_period_Dn + SLO_period_Dn, SIGN_period_Dn, Price_Dn, 1, bar); //----+ DEFINING SIGNALS FOR TRADES if ( MovA[1] > MovB[1]) if ( MovA[0] < MovB[0]) SELL_Sign = true; if ( MovA[0] < MovB[0]) SELL_Stop = true; } //----+ EXECUTION OF TRADES if (!OpenSellLimitOrder1(SELL_Sign, 2, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn, PriceLevel_Dn, StopTime_Dn)) return(-1); if (ClosePos_Dn) if (!CloseOrder1(SELL_Stop, 2)) return(-1); } } //----+ return(0); } //+------------------------------------------------------------------+
总结
另一篇文章也已完成。在 Expert Advisor 中基于绝对不同的指标变体实现了另一个交易系统。希望本文能够对 EA 编程新手有用,以进一步培养将正确形式化的算法转化为 Expert Advisor 可用和绝对有效的代码。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1521
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
