MQL4两步改仓法:稳健跟踪止损实战
基于Demark系数的双阶段头寸修改EA解析
一、两步修改头寸技术的背景与价值
在MetaTrader 4的自动交易开发中,如何管理已打开头寸的止损与止盈一直是核心问题。传统跟踪止损往往在价格小幅回撤时就频繁修改止损,导致邻近趋势时不必要的关闭和重新打开头寸,增加交易成本与滑点风险。Genkov在2016年介绍的“已打开头寸的两步修改”方法,源自T.DeMark技术分析中的修正长度系数(0.382和0.618),通过在建仓后分两个阶段调整止损和止盈,显著减少了无效操作。
该方法的实用价值在于:当市场出现偏离或震荡时,第一阶段用常规TrailingStop锁定基础安全垫;第二阶段引入修正系数,让止损跟随趋势回撤比例移动,同时逐步上移止盈。这种结构尤其适合无法持续盯盘、又希望捕捉“有利”趋势的交易者。原文图1和图2展示了在偏离情况下,该方法如何检测趋势并保护利润。
二、功能算法与核心参数定义
两步修改的算法逻辑非常明确。第一步:由指定的TrailingStop值执行初始止损移动,随后将StopLoss设置在比可能修正水平低1-2个点的位置(修正系数Coeff_取0.382)。在每个步长上,按照TrailingStop的一半(可自定义)增加TakeProfit值。第二步:当止损已进入保本或盈利区(S/L大于等于开仓价),利用价格与开仓价差乘以0.382计算动态止损线,并继续偏移止盈。
关键外部参数包括:March(止盈递增步长倍数,0表示不增)、StopLoss(初始止损点数)、TrailingStop(初始跟踪距离)、TakeProfit(初始止盈,用于测试拟合)。在程序开头设置extern double March = 0可实现止盈不动;若设为正值,则每阶段按half_Trail×March点数推高止盈。
- MagicNumber:区分EA自身订单的标识,需嵌入开仓与修改函数
- point:当前品种点值,通过MarketInfo获取
- half_Trail:TrailingStop的一半,作为止盈步长基准
- Coeff_up / Coeff_down:基于0.382的修正系数计算出的动态止损缓冲
三、MagicNumber与地址支持操作
原文强调,喜欢在交易时直接执行特定程序地址分析支持操作的交易者,最好将MagicNumber变量转移到Expert Advisor自身打开头寸的代码中。这意味着修改函数只处理特定Magic的订单,避免干扰手动单或其他EA单。关于具体的地址支持,可在MQL4.com网站发布的S. Kovalyov书籍中阅读更多。实践中,我们应为每种类型的头寸打开条件(按Magic=N)编写独立的跟踪与关闭逻辑,因为市场不可预测,通用修饰符难以覆盖所有情况。
在v6版本中,作者考虑了预测和幻数的地址支持,使函数可精准绑定到某策略实例。对于中文交易者,建议将Magic设为易读数字(如3090),并在开仓OrderSend时传入相同Magic,确保TrailingStop()循环内能用OrderMagicNumber()!=Magic来continue过滤。
四、EA代码结构与start函数改造
原始文章提供v4(按止损关闭)、v5(按获利预测关闭)、v6(含幻数地址支持)。要将修改逻辑变为可调用函数,需对程序开头的int start()添加注释,并用TrailingStop()函数描述替换;在程序末尾取消函数调用注释。若保留建仓示例,则可整体作为测试EA运行。
下面片段展示了v5中核心参数与start框架(已精简注释)。注意:实际使用时若作为纯函数库,应将TrailingStop()置于experts/include扩展名.mqh或libraries下.mq4。
extern double March = 1; // step of increasing TakeProfit
extern double StopLoss = 15;
extern double TrailingStop = 16;
extern double TakeProfit = 60; // fitting with the tester
int start()
{
int point = MarketInfo(Symbol(),MODE_POINT);
int StopLev= MarketInfo(Symbol(),MODE_STOPLEVEL);
double half_Trail = MathRound(TrailingStop/2);
double Step = March*half_Trail;
if (TrailingStop<0) return;
{
for (int i=0; i<OrdersTotal(); i++)
{
if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if (OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
if (OrderType()==OP_BUY)
{
五、BUY头寸的两步修改代码详解
第一阶段BUY修改:若S/L小于开仓价(仍在风险区),且当前Bid与开仓价差大于TrailingStop*Point,同时原S/L小于Bid-TrailingStop*Point,则直接将S/L上移TrailingStop点,T/P增加Step点。这确保初始安全垫快速建立。第二阶段:当S/L>=开仓价(保本),计算Coeff_up=(Bid-Open)*0.382,若价差大于该系数,则新S/L=Bid-Coeff_up-2*Point;仅当新S/L高于原S/L超3点才修改,同时T/P再推Step点。
以下为v5中BUY两阶段核心代码(节选),展示条件分支与OrderModify调用。注意颜色参数仅为可视化,不影响逻辑。
if(OrderStopLoss()<OrderOpenPrice())
{ if(Bid-OrderOpenPrice()>TrailingStop*Point)
{ if(OrderStopLoss()<Bid-TrailingStop*Point)
{ OrderModify(OrderTicket(),OrderOpenPrice(),
OrderStopLoss()+TrailingStop*Point,
OrderTakeProfit()+Step*Point,0,Aqua); return; } } }
if(Bid-OrderOpenPrice()>=TakeProfit*Point && (Pr_Op_1-Pr_Op_0)>2*Point)
{ OrderClose(OrderTicket(),Lots,Bid,2,Red); }
if(OrderStopLoss()>=OrderOpenPrice())
{ double Coeff_up = NormalizeDouble((Bid-OrderOpenPrice())*0.382,Digits);
if(Bid-OrderOpenPrice()>Coeff_up)
{ double New_S_Loss = Bid-Coeff_up-2*Point;
if(New_S_Loss-OrderStopLoss()>3*Point)
{ OrderModify(OrderTicket(),OrderOpenPrice(),New_S_Loss,OrderTakeProfit()+Step*Point,0,Yellow); } return; } }
六、SELL头寸的对称逻辑与差异
SELL头寸逻辑与BUY完全对称。第一阶段:若S/L大于开仓价且开仓价-Ask>TrailingStop*Point,则S/L下移至Ask+TrailingStop*Point,T/P减少Step点。第二阶段:当S/L<=开仓价,计算Coeff_down=(Open-Ask)*0.382,新S/L=Ask+Coeff_down+2*Point,当新值低于原S/L超3点才修改。此外,预测关闭条件为Open-Ask>=TakeProfit*Point且(Pr_Op_0-Pr_Op_1)>2*Point时市价平仓。
这种对称设计保证多空双向均有相同的风险控制节奏。但在实际品种上,点差与停止水平可能导致SELL修改比BUY更难触发,建议在测试器中分别优化TrailingStop与StopLoss参数。
else if(OrderType()==OP_SELL)
{ if(OrderStopLoss()>OrderOpenPrice())
{ if(OrderOpenPrice()-Ask>TrailingStop*Point && OrderStopLoss()>Ask+TrailingStop*Point)
{ OrderModify(OrderTicket(),OrderOpenPrice(),Ask+TrailingStop*Point,OrderTakeProfit()-Step*Point,0,SkyBlue); return; } }
if(OrderOpenPrice()-Ask>=TakeProfit*Point && (Pr_Op_0-Pr_Op_1)>2*Point)
{ OrderClose(OrderTicket(),Lots,Bid,2,Red); }
if(OrderStopLoss()<=OrderOpenPrice())
{ double Coeff_down = NormalizeDouble((OrderOpenPrice()-Ask)*0.382,Digits);
if(OrderOpenPrice()-Ask>Coeff_down)
{ double New_S_Loss = Ask+Coeff_down+2*Point;
if(New_S_Loss-OrderStopLoss()>3*Point)
{ OrderModify(OrderTicket(),OrderOpenPrice(),New_S_Loss,OrderTakeProfit()-Step*Point,0,Khaki); return; } } } }
七、与典型跟踪止损方案的对比
Sergey Kravchuk在“一种跟踪止损和退出市场的模式”中描述的典型跟踪止损,通常每 tick 或固定距离移动止损,逻辑单一。本文两步法与之相比更容易理解,且在模拟账户实测中对激进与稳健跟踪均有效。典型方案在震荡市中容易被扫损;两步法因第二阶段引入Demark系数,允许价格回撤幅度随盈利扩大而增加,更像“盈利后放宽回撤容忍度”的弹性风控。
但两步法代码更复杂,需处理两个阶段的条件跳转与未定义变量问题;典型方案则易于封装为通用模块。中文交易者若追求快速部署,可先用典型方案,再逐步迁移到两步法以获取更高曲线平滑度。
八、部署步骤与文件管理建议
要将本文函数用于自己的EA,步骤如下:1)从原文链接下载Modify_2step_v4/v5/v6.mq4;2)移除详细注释形成可执行函数,保存至Terminal_folder\experts\include(.mqh)或libraries(.mq4);3)在主EA的start()中调用TrailingStop(),并确保开仓时写入相同Magic;4)在策略测试器用MACD示例逻辑(或自有信号)验证。v5附带了基于iMACD的简易开仓代码,可直接测试函数有效性。
注意:MetaQuotes保留原文材料权利,禁止整篇转载,但学习者可基于思路重写。实际运行时,必须处理MODE_STOPLEVEL,否则修改失败。另外,原文v6才完整支持幻数地址,若需多策略共存,优先用v6思路。