在我的上一篇标题为“Lite_EXPERT2.mqh: Expert Advisor 开发人员的功能套件”的文章中,我让读者熟悉了 Lite_EXPERT2.mqh 函数。 在本文中,我将提供使用这些函数的实际 Expert Advisor 实现示例。 我认为,以下交易函数的操作
OpenBuyOrder1_() OpenSellOrder1_() OpenBuyOrder2_() OpenSellOrder2_() OpenBuyLimitOrder1_() OpenBuyStopOrder1_() OpenSellLimitOrder1_() OpenSellStopOrder1_() Make_BuyTrailingStop_() Make_SellTrailingStop_()
与 Lite_EXPERT1.mqh 文件中提供的类似函数的操作并无本质上的不同。
它们包含的几个额外的外部变量的初始化不大可能会造成任何混淆(参见 Exp_0_1.mq4、Exp_0.mq4、Exp_1.mq4 和 EXP_1_1.mq4)。 因此,完全不需要再返回去介绍它们。 我将直接介绍使用交易函数构建的示例,它们将价格图表位的绝对值用作挂单的外部变量。
ddOpenBuyOrder1_() dOpenSellOrder1_() dOpenBuyOrder2_() dOpenSellOrder2_() dOpenBuyLimitOrder1_() dOpenBuyStopOrder1_() dOpenSellLimitOrder1_() dOpenSellStopOrder1_() dModifyOpenBuyOrder_() dModifyOpenSellOrder_() dModifyOpenBuyOrderS() dModifyOpenSellOrderS() dMake_BuyTrailingStop_() dMake_SellTrailingStop_()
本文将进一步讨论的交易策略是基于平均真实波动范围指标的,因此本文将从此指标开始展开。
平均真实波动范围指标(下文称为 - ATR 或平均真实波动范围)是由韦尔斯·王尔德发明的,1978 年在其著作《技术交易系统新概念 (New Concepts in Technical Trading Systems)》首次提到。 此指标后来相当受欢迎,现在仍纳入很多技术分析软件套件中。 ATR 指标本身并不指出当前趋势方向,但提供有关市场的波动性或活动的图形图像。
基本上,此指标可以两种形式用于机械交易系统:
1. 过滤交易系统的信号以识别市场趋势和非趋势条件。
在这种情况下,趋势方向和进场信号是从其他指标接收的,而 ATR 指标仅提供其他进场条件。 例如,这种其他条件可以是指标本身突破平均指标值。 要获得平均 ATR 值,使用基于 ATR 的信号平均线非常方便。
2. 自适应挂单。
此指标的绝对值确定与条柱开盘价格之间的距离,在此距离之外很可能会开始出现剧烈的价格波动。 因此,使用这些位来为挂单设置建仓位和止损位非常便捷。 在这种情况下,我们有机会在每个交易中使用 ATR 指标在与可适应当前市场波动性的价格相距一定距离处设置订单。 在实际市场状况中设置固定距离,就像是战争早已远去,而老将始终处于 战备 状态。 在不断变换的实际市场状况中,这往往会带来非常有利的交易系统绩效。 通过非常相似的方式,你可以使用 ATR 距离将跟踪止损位移至每次条柱发生变化时所处的价格。
现在,我们可以介绍如何使用 Lite_EXPERT2.mqh 文件开发 Expert Advisor。 最好的方式是,首先对基于 Lite_EXPERT1.mqh 构建的 Expert Advisor 进行现代化,以为它们在交易中提供更好的灵活性。
我已经在我的一篇标题为“基于大众交易系统和交易机器人优化点金术的 Expert Advisor”的文章中提供了有关这种系统的详细说明,这篇文章专门介绍非常基本的交易系统。
是时候让它复杂化了。 在 Exp_1_1.mq4 Expert Advisor(原始 Exp_1.mq4)中开发了一个几乎相近的基于 Lite_EXPERT2.mqh 函数的交易系统。 我们只需要将固定的止损位和获利位替换为在 ATR 单元中重新计算的止损位和获利位,并添加类似的跟踪止损位,此跟踪止损位在每次条柱变化之后都会出现偏移。 此操作最好分两个阶段实现。 我们首先替换止损位和获利位(Exp_17_A.mq4 Expert Advisor),在检查代码没有错误且符合选定的交易策略之后,我们添加跟踪止损位(Exp_17.mq4 Expert Advisor)。 在本文中,我将仅提供最后版本以及对代码做出更改的详细说明。
//+X================================================================X+ //| Exp_17.mq4 | //| Copyright © 2009, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+X================================================================X+ #property copyright "Copyright © 2009, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //+--------------------------------------------------------+ //| INPUT PARAMETERS OF THE EXPERT ADVISOR FOR BUY DEALS | //+--------------------------------------------------------+ extern bool Test_Up = true; // filter of direction of deal calculations extern int Timeframe_Up = 240; extern double Money_Management_Up = 0.1; extern int Length_Up = 4; // depth of smoothing extern int Phase_Up = 100; // parameter varying within the range (-100..+100), impacts the transitional process quality; extern int IPC_Up = 0; extern int ATR_Period_Up = 14; // True Range averaging period extern int LevMinimum_Up = 40; // Minimum value in points below // which pending order values cannot fall extern int STOPLOSS_Up = 100; // Stop Loss expressed as percentage of ATR extern int TAKEPROFIT_Up = 200; // Take Profit expressed as percentage of ATR extern int TRAILINGSTOP_Up = 100; // Trailing Stop expressed as percentage of ATR extern bool ClosePos_Up = true; // permission to forcibly close a position //+--------------------------------------------------------+ //| INPUT PARAMETERS OF THE EXPERT ADVISOR FOR SELL DEALS | //+--------------------------------------------------------+ extern bool Test_Dn = true; // filter of direction of deal calculations extern int Timeframe_Dn = 240; extern double Money_Management_Dn = 0.1; extern int Length_Dn = 4; // depth of smoothing extern int Phase_Dn = 100; // parameter varying within the range (-100..+100), impacts the transitional process quality; extern int IPC_Dn = 0; extern int ATR_Period_Dn = 14; // True Range averaging period extern int LevMinimum_Dn = 40; // Minimum value in points below // which pending order values cannot fall extern int STOPLOSS_Dn = 100; // Stop Loss expressed as percentage of ATR extern int TAKEPROFIT_Dn = 200; // Take Profit expressed as percentage of ATR extern int TRAILINGSTOP_Dn = 100; // Trailing Stop expressed as percentage of ATR extern bool ClosePos_Dn = true; // permission to forcibly close a position //+---------------------------------------------+ //---- declaration of integer variables for the minimum calculation bars int MinBar_Up, MinBar_Dn; //---- declaration of integer variables for chart time frames in seconds int Period_Up, Period_Dn; //---- declaration of floating point variables for pending orders double _STOPLOSS_Up, _TAKEPROFIT_Up, _LevMinimum_Up, _TRAILINGSTOP_Up; double _STOPLOSS_Dn, _TAKEPROFIT_Dn, _LevMinimum_Dn, _TRAILINGSTOP_Dn; //+X================================================================X+ //| Custom Expert functions | //+X================================================================X+ #include <Lite_EXPERT2.mqh> //+X================================================================X+ //| Custom Expert initialization function | //+X================================================================X+ int init() { //---- Checking correctness of the Timeframe_Up variable value TimeframeCheck("Timeframe_Up", Timeframe_Up); //---- Checking correctness of the Timeframe_Dn variable value TimeframeCheck("Timeframe_Dn", Timeframe_Dn); //---- Initialization of variables MinBar_Up = 4 + 39 + 30;// four bars for entry signals + FATL filter length + JMA filter length MinBar_Up = MathMax(MinBar_Up, ATR_Period_Up + 1); MinBar_Dn = 4 + 39 + 30;// four bars for entry signals + FATL filter length + JMA filter length MinBar_Dn = MathMax(MinBar_Dn, ATR_Period_Dn + 1); //---- Period_Up = Timeframe_Up * 60; // chart time frame for long positions in seconds Period_Dn = Timeframe_Dn * 60; // chart time frame for short positions in seconds //---- Conversion of percent to fraction _STOPLOSS_Up = STOPLOSS_Up / 100.0; _TAKEPROFIT_Up = TAKEPROFIT_Up / 100.0; _TRAILINGSTOP_Up = TRAILINGSTOP_Up / 100.0; //---- Conversion of percent to fraction _STOPLOSS_Dn = STOPLOSS_Dn / 100.0; _TAKEPROFIT_Dn = TAKEPROFIT_Dn / 100.0; _TRAILINGSTOP_Dn = TRAILINGSTOP_Dn / 100.0; //---- Conversion of the minimum points to the price distance minimum _LevMinimum_Up = LevMinimum_Up * Point; _LevMinimum_Dn = LevMinimum_Dn * Point; //---- initialization complete return(0); } //+X================================================================X+ //| expert deinitialization function | //+X================================================================X+ int deinit() { //----+ Deleting global variables after testing and optimizations TimeLevelGlobalVariableDel(Symbol(), 1); TimeLevelGlobalVariableDel(Symbol(), 2); //---- Expert Advisor deinitialization complete return(0); //----+ } //+X================================================================X+ //| Custom Expert iteration function | //+X================================================================X+ int start() { //----+ //----+ Declaration of local variables int bar; double Mov[3], dMov12, dMov23, ATR, Level, open; //----+ Declaration of static variables static datetime TradeTimeLevel_Up, TradeTimeLevel_Dn; //---- static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop; static bool TrailSignal_Up, TrailSignal_Dn; //---- static double dStopLoss_Up, dTakeProfit_Up, dTrailingStop_Up; static double dStopLoss_Dn, dTakeProfit_Dn, dTrailingStop_Dn; //+---------------------------+ //| CODE FOR LONG POSITIONS | //+---------------------------+ if (Test_Up) if (MinBarCheck(Symbol(), Timeframe_Up, MinBar_Up)) { if (IsNewBar(0, Symbol(), Timeframe_Up)) { //----+ Zeroing out trading signals BUY_Sign = false; BUY_Stop = false; //---- Getting the time limit for disabling // the next trading operation TradeTimeLevel_Up = iTime(NULL, Timeframe_Up, 0); if (TradeTimeLevel_Up == 0) return(-1); TradeTimeLevel_Up += Period_Up; //----+ CALCULATING AND LOADING INDICATOR VALUES TO BUFFERS for(bar = 1; bar <= 3; bar++) Mov[bar - 1]= iCustom(NULL, Timeframe_Up, "JFatl", Length_Up, Phase_Up, 0, IPC_Up, 0, bar); //----+ DETERMINING SIGNALS FOR DEALS dMov12 = Mov[0] - Mov[1]; dMov23 = Mov[1] - Mov[2]; //---- Getting a signal for opening a position if (dMov23 < 0) if (dMov12 > 0) BUY_Sign = true; //---- Getting a signal for closing a position if (dMov12 < 0) if (ClosePos_Up) BUY_Stop = true; //----+ CALCULATION OF PENDING ORDERS FOR LONG POSITIONS // Make order calculation only if the trading signal is available if (BUY_Sign) { //---- Getting the initial ATR value ATR = iATR(NULL, Timeframe_Up, ATR_Period_Up, 1); //---- Getting the current price open = iOpen(Symbol(), Timeframe_Up, 0); //---- Calculating the distance to the Stop Loss Level = ATR * _STOPLOSS_Up; //---- Checking the distance to the Stop Loss against the minimum value if (Level < _LevMinimum_Up) Level = _LevMinimum_Up; //---- Determining the absolute Stop Loss value dStopLoss_Up = open - Level; //---- Calculating the distance to the Take Profit Level = ATR * _TAKEPROFIT_Up; //---- Checking the distance to the Take Profit against the minimum value if (Level < _LevMinimum_Up) Level = _LevMinimum_Up; //---- Determining the absolute Take Profit value dTakeProfit_Up = open + Level; //---- Correcting values of pending // orders, given the direction of the trade dGhartVelueCorrect(OP_BUY, dStopLoss_Up); dGhartVelueCorrect(OP_BUY, dTakeProfit_Up); } //----+ CALCULATION OF TRAILING STOPS FOR LONG POSITIONS dTrailingStop_Up = 0; TrailSignal_Up = false; //---- if (TRAILINGSTOP_Up > 0) // Calculate the Trailing Stop only if the necessary position exists if (OrderSelect_(Symbol(), OP_BUY, 1, MODE_TRADES)) // Move Trailing Stop if the position is opened on a non-zero bar if (iBarShift(NULL, Timeframe_Up, OrderOpenTime(), false) > 0) { TrailSignal_Up = true; //---- Getting the initial ATR value ATR = iATR(NULL, Timeframe_Up, ATR_Period_Up, 1); //---- Getting the current price open = iOpen(Symbol(), Timeframe_Up, 0); //---- Calculating the distance to the Stop Loss Level = ATR * _TRAILINGSTOP_Up; //---- Checking the distance to the Stop Loss against the minimum value if (Level < _LevMinimum_Up) Level = _LevMinimum_Up; //---- Getting the absolute Trailing Stop value dTrailingStop_Up = open - Level; //---- Correcting the absolute Trailing Stop value, // given the direction of the trade (for position // modification functions the value of the cmd variable is inverse!) dGhartVelueCorrect(OP_SELL, dTrailingStop_Up); } } //----+ DEAL EXECUTION if (!dOpenBuyOrder1_(BUY_Sign, 1, TradeTimeLevel_Up, Money_Management_Up, 5, dStopLoss_Up, dTakeProfit_Up)) return(-1); //---- if (!CloseBuyOrder1_(BUY_Stop, 1)) return(-1); //---- if (!dMake_BuyTrailingStop_(TrailSignal_Up, 1, TradeTimeLevel_Up, dTrailingStop_Up)) return(-1); } //+---------------------------+ //| CODE FOR SHORT POSITIONS | //+---------------------------+ if (Test_Dn) if (MinBarCheck(Symbol(), Timeframe_Dn, MinBar_Dn)) { if (IsNewBar(1, Symbol(), Timeframe_Dn)) { //----+ Zeroing out trading signals SELL_Sign = false; SELL_Stop = false; //---- Getting the time limit for disabling // the next trading operation TradeTimeLevel_Dn = iTime(NULL, Timeframe_Dn, 0); if (TradeTimeLevel_Dn == 0) return(-1); TradeTimeLevel_Dn += Period_Dn; //----+ CALCULATING AND LOADING INDICATOR VALUES TO BUFFERS for(bar = 1; bar <= 3; bar++) Mov[bar - 1]= iCustom(NULL, Timeframe_Dn, "JFatl", Length_Dn, Phase_Dn, 0, IPC_Dn, 0, bar); //----+ DETERMINING SIGNALS FOR DEALS dMov12 = Mov[0] - Mov[1]; dMov23 = Mov[1] - Mov[2]; //---- Getting a signal for opening a position if (dMov23 > 0) if (dMov12 < 0) SELL_Sign = true; //---- Getting a signal for closing a position if (dMov12 > 0) if (ClosePos_Dn) SELL_Stop = true; //----+ CALCULATION OF PENDING ORDERS FOR SHORT POSITIONS // Make order calculation only if the trading signal is available if (SELL_Sign) { //---- Getting the initial ATR value ATR = iATR(NULL, Timeframe_Dn, ATR_Period_Dn, 1); //---- Getting the current price open = iOpen(Symbol(), Timeframe_Dn, 0); //---- Calculating the distance to the Stop Loss Level = ATR * _STOPLOSS_Dn; //---- Checking the distance to the Stop Loss against the minimum value if (Level < _LevMinimum_Dn) Level = _LevMinimum_Dn; //---- Determining the absolute Stop Loss value dStopLoss_Dn = open + Level; //---- Calculating the distance to the Take Profit Level = ATR * _TAKEPROFIT_Dn; //---- Checking the distance to the Take Profit against the minimum value if (Level < _LevMinimum_Dn) Level = _LevMinimum_Dn; //---- Determining the absolute Take Profit value dTakeProfit_Dn = open - Level; //---- Correcting values of pending orders, given the direction of the trade dGhartVelueCorrect(OP_SELL, dStopLoss_Dn); dGhartVelueCorrect(OP_SELL, dTakeProfit_Dn); } //----+ CALCULATION OF TRAILING STOPS FOR SHORT POSITIONS dTrailingStop_Dn = 0; TrailSignal_Dn = false; //---- if (TRAILINGSTOP_Dn > 0) // Calculate the Trailing Stop only if the necessary position exists if (OrderSelect_(Symbol(), OP_SELL, 2, MODE_TRADES)) // Move Trailing Stop if the position is opened on a non-zero bar if (iBarShift(NULL, Timeframe_Dn, OrderOpenTime(), false) > 0) { TrailSignal_Dn = true; //---- Getting the initial ATR value ATR = iATR(NULL, Timeframe_Dn, ATR_Period_Dn, 1); //---- Getting the current price open = iOpen(Symbol(), Timeframe_Dn, 0); //---- Calculating the distance to the Stop Loss Level = ATR * _TRAILINGSTOP_Dn; //---- Checking the distance to the Stop Loss against the minimum value if (Level < _LevMinimum_Dn) Level = _LevMinimum_Dn; //---- Getting the absolute Trailing Stop value dTrailingStop_Dn = open + Level; //---- Correcting the absolute Trailing Stop value, // given the direction of the trade (for position // modification functions the value of the cmd variable is inverse!) dGhartVelueCorrect(OP_BUY, dTrailingStop_Dn); } } //----+ DEAL EXECUTION if (!dOpenSellOrder1_(SELL_Sign, 2, TradeTimeLevel_Dn, Money_Management_Dn, 5, dStopLoss_Dn, dTakeProfit_Dn)) return(-1); //---- if (!CloseSellOrder1_(SELL_Stop, 2)) return(-1); //---- if (!dMake_SellTrailingStop_(TrailSignal_Dn, 2, TradeTimeLevel_Dn, dTrailingStop_Dn)) return(-1); } return(0); //----+ } //+X----------------------+ <<< The End >>> +-----------------------X+
因此,我们在 Expert Advisor 的外部变量块中有一对新变量 - ATR_Period_Up 和 ATR_Period_Dn,它们可用于更改挂单计算中涉及的 ATR 指标值。 现在,止损位、获利位和跟踪止损位的外部变量的值的逻辑含义有所不同。 这些值之前用于表示订单价格与当前价格之间相对距离(以点数为单位)。 它们现在表示 ATR 指标值在第一个条柱中的百分比。 换言之,要计算订单,我们取得 ATR 指标的百分比并将此百分比添加至零条柱开盘价的值。 因此,将百分比转换成浮点值的最好方法是,使用 Expert Advisor 的 init() 块,在此块中,这些计算将仅执行一次,而且计算值将保存到声明具有全局范围的变量。
由于有新的 ATR 指标可用,init() 块中的 LevMinimum_Up 和 LevMinimum_Dn 变量的初始化公式发生了更改。 Expert Advisor 的 start() 块具有声明为静态的新变量,用于存储终端价格变动之间的值。 用于计算挂单和跟踪止损位的代码已被安排到用于获取交易信号的块内部的小模块中。 现在,要执行交易,我们使用不同的函数,其中,在 Margin_Mode 变量初始化之后,值 5 将被用作为浮点止损位条件中的一个更具逻辑的值。
为了展示使用 IndicatorCounted_() 和 ReSetAsIndexBuffer() 函数所带来的机会,在此 Expert Advisor 中,我们使用了插入在 Expert Advisor 代码中的 JFATL() 函数替换自定义指标 Jfatl.mq4。
bool JFATL(int Number, string symbol, int timeframe, int Length, int Phase, int IPC, double& Buffer[])
此函数获取此指标的输入参数和 Buffer[] 数组。 如果计算成功,此函数将返回 true,否则返回 false。 此数组通过引用被转换成类似的指标缓冲区,填充有 JFATL 指标值。 在此函数中,JJMASeries() 函数被替换为 JJMASeries1() 函数,后者在零条柱上不执行任何计算。 我们还使用 iPriceSeries() 函数替换了 PriceSeries() 函数。 指标初始化块还被移至“零初始化”块。 请注意,JJMASeries1() 函数仅在 Expert Advisor 中的此函数内部使用,因此 Number 变量值不会重新计算,将被直接传递给 JJMASeries1()。 这同样适用于 IndicatorCounted_() 函数。
我已经讨论了使用其他专门针对此主题的文章中的函数替换指标。 1、2、3。 使用了此替换的 Expert Advisor 由 Exp_17_.mq4 文件表示。 我们应注意,JFatl.mq4 指标中采用的 JMA 平滑算法相当耗费资源,而且,与之前的版本相比,这种用指标函数替换指标的操作会显著提升此 Expert Advisor 中的优化速度。 最后,对于最懒惰的人而言,开发同一个 Expert Advisor (Exp_17R.mq4) 时,可以在代码中包含所有必要的函数,而无需任何其他包括文件或指标来用于编译和运行。 此 Expert Advisor 的所有三个类似项的运行完全相同! 唯一例外的情况是,最后一个 Expert Advisor 中的 IPC_Up 和 IPC_Dn 变量值在一个相对较小的范围 (0-10) 内波动,因为没有调用 Heiken Ashi#.mq4 指标。
在论坛中,你偶尔会看到一些 MQL4 编程大师不赞成编写此类指标函数的观点,在他们看来,这就像把裤衩往头上套。 我个人仅仅是花费十五分钟时间基于相当易于理解的代码编写此函数。 因此,如果能够通过这种方式以快六倍的速度运行漫长的优化过程,我会继续坚持这种选择!
基于新闻事件交易的突破系统
我的文章中已经以 Exp_10.mq4 Expert Advisor 的形式提供了此交易系统版本以供你思考。 基于 Lite_EXPERT2.mqh 函数的 Exp_10_1.mq4 Expert Advisor 完全类似。 它比原始版本略微复杂,但更加可靠,因为它不受 Expert Advisor、终端或操作系统重启等各种情况的影响。 为了确定在此之后应关闭未平仓位的时间,此 Expert Advisor 使用了 TradeTimeLevelCheck() 函数:
此函数返回 true,在此时间点之后,其值将被作为输入参数传递给用于下挂单或建仓的函数。 此函数从全局变量中获得该值。
现在,我们需要更改挂单计算的算法。 但在这种情况下,除止损位和获利位以外,还应动态计算止损单。 本质上,这不会为我们更改任何内容,一切按相同的方式实施。 而且,原始 Expert Advisor 中的跟踪止损位在每次价格变动时都会进行处理,我们需要在每次条柱发生变化时对其进行移动。 Expert Advisor (Exp_18.mq4) 的最终代码当然不像原始 Expert Advisor 的代码一样简单,但程序逻辑非常简洁明了。 Exp_18R.mq4 完全类似于最后一个 Expert Advisor,以完善的独立文件的形式实现。
我相信,与 Lite_EXPERT1.mqh 函数相比,Lite_EXPERT2.mqh 自定义函数在编程方法方面没有任何新东西。
它们只是增强了编程功能,在应用方面基本保持不变。 因此,在仔细分析 Lite_EXPERT1.mqh 函数之后,在快速轻松地了解 Lite_EXPERT2.mqh 功能的过程中,应该不会有任何困难之处。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程