MT4模式交易法测跟踪止损
用理想线条复现订单以公平对比退出算法
为什么需要模式交易测试工具
开发订单修改与关闭算法时,最大痛点在于如何公平比较不同方法的结果。策略测试器虽是标准检查机制,但复杂EA若自行计算进场、跟踪与退出,几乎无法获得可重复且相互可比的模式。假设某进场信号持续较长时间,价格在预测方向波动时跟踪止损启动;止损过近会过早平仓,若信号仍有效EA又开新单,便把正确订单收益与提前关闭后其他订单收益混杂,无法隔离评估跟踪算法本身优劣。
本文提出的思路是:将进场与出场点标记在图表,把时间与方向存入文件,再用一个只执行文件命令的EA严格重放。这样所有测试都在同一组数学正确的订单流上进行,不同跟踪止损逻辑的差异才能被干净地度量。
问题说明与线条标记逻辑
在图表中用两种线条代表交易:紫线为理想进出场,用于计算理论最大收益;蓝线为实际特点,如进场延迟、保本位附近平仓,用来测试真实跟踪。蓝线在跟踪后可能出现多个止损触发点:最近距价触发激进跟踪、常规触发耐心跟踪、理想触发最大化收益,也可能因急躁在反转区误触发。
标记原则:进场点应选历史中明显的市场反转处;出场点不要在反转瞬间而是之后,让算法自行完成操作,即使亏损也暴露重设必要。通过这种标记,我们获得可重复的理想区域,后续仅需完善之。
- 紫线:理论最优,仅作基准参考
- 蓝线:含延迟与保守平仓,用于实测
- 出场点延后于反转,容错算法空间
- 多触发点区分激进/常规/理想跟踪
标记工具脚本组详解
为方便标记,作者提供一组脚本:TL_Buy与TL_Sell分别在拖放点创建买/卖趋势线段;TL_Write将所有TL_前缀线条坐标写入文件;TL_Read从文件重绘;TL_Clear清空。线条命名规则统一为前缀TL_+方向字符(B/S)+编号,如TL_B1、TL_S3,便于选择删除与程序识别。
使用方式:把绘制脚本拖到图表,出现线段后拖动端点对齐理想蓝线;运行TL_Write输入文件名保存;测试前用TL_Read可重建编辑。脚本代码透明带注释,算法不复杂但严格依赖对象命名约定。
// TL_Buy 片断 (MQL4)
#include <WinUser32.mqh>
#define _prefix_ "TL_"
int start(){
int MaxNo=0,i,No;
if(WindowOnDropped()!=0) { MessageBox("Script should be dropped in the main window","ERROR", IDOK + MB_ICONERROR); return(1); }
for(i=0;i<ObjectsTotal();i++) {
if(StringFind(ObjectName(i),_prefix_)==0) {
No=StrToInteger(StringSubstr(ObjectName(i),StringLen(_prefix_)+1));
if(MaxNo<No) MaxNo=No;
}
}
datetime t0=WindowTimeOnDropped(); double p0=WindowPriceOnDropped();
int width = 5*Period()*60;
double height = 20*MarketInfo(Symbol(),MODE_TICKSIZE);
string LineName = _prefix_+"B"+(MaxNo+1);
ObjectCreate(LineName,OBJ_TREND,0,t0-width,p0-height, t0+width,p0+height);
ObjectSet(LineName,OBJPROP_RAY,False);
ObjectSet(LineName,OBJPROP_WIDTH,2);
ObjectSet(LineName,OBJPROP_COLOR,Blue);
}
// TL_Write 片断 (MQL4)
#include <WinUser32.mqh>
#define _prefix_ "TL_"
#property show_inputs
extern string FileNameForWrite = "TL_DATA.TXT";
int start(){
int LinesCNT=0,i; string Operation;
int fh=FileOpen(FileNameForWrite,FILE_CSV|FILE_WRITE,';');
for(i=0;i<ObjectsTotal();i++) {
if(StringFind(ObjectName(i),_prefix_)==0) {
string LineName = ObjectName(i);
datetime t1=ObjectGet(LineName,OBJPROP_TIME1);
datetime t2=ObjectGet(LineName,OBJPROP_TIME2);
double p1=ObjectGet(LineName,OBJPROP_PRICE1);
double p2=ObjectGet(LineName,OBJPROP_PRICE2);
LinesCNT++;
Operation = StringSubstr(ObjectName(i),StringLen(_prefix_),1);
FileWrite(fh,Operation,TimeToStr(t1),DoubleToStr(p1,Digits),TimeToStr(t2),DoubleToStr(p2,Digits));
}
}
FileClose(fh);
MessageBox("Stored sections "+(LinesCNT)+" pcs.","Done", IDOK + MB_ICONINFORMATION);
}
文件定位与测试器目录陷阱
文件目录是极易出错点。普通脚本只能在 experts\files 下创建文件,但策略测试器运行时访问的是 tester\files 同名文件夹。因此每次用TL_Write生成或更新文件后,必须手动从 experts\files 复制到 tester\files,否则EA读不到而报错退出。
测试EA TL_Trader工作机制
TL_Trader读取模式文件,在每次价格变动遍历所有线条段,核心三块:到达段首的开仓块、到达段尾的平仓块、跟踪止损处理块。订单注释写入起止时间标记(如t1=t2),避免同段重复开仓;若跟踪提前平仓,段结束仍按注释时间强制关闭,保证不多次开同段单。
参数ProcedTrailing可关跟踪,得到最悲观基线,与优化结果对比。因线条无先后,每tick全扫,用内部时间格式比对。代码展示开仓前查历史与现单防重,平仓按段尾时间执行。
// TL_Trader 片断 (MQL4)
extern string FileNameForRead = "TL_DATA.TXT";
extern double Lots = 0.1;
extern double StopLoss = 0;
extern double TrailingStop = 30;
extern bool ProcedTrailing=true;
int start(){
int fh=FileOpen(FileNameForRead,FILE_CSV|FILE_READ,';');
if(fh<0) { MessageBox("Error opening file","ERROR",IDOK+MB_ICONERROR); return(1); }
while(true){
string Operation=FileReadString(fh);
if(FileIsEnding(fh)) break;
string st1=FileReadString(fh); string sp1=FileReadString(fh);
string st2=FileReadString(fh); string sp2=FileReadString(fh);
datetime t1=StrToTime(st1); double p1=StrToDouble(sp1);
datetime t2=StrToTime(st2); double p2=StrToDouble(sp2);
if(t1>t2) { /* swap */ }
string MarkComent = t1+"="+t2;
for(int i=0;i<OrdersTotal();i++){
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue;
if(OrderComment()==MarkComent && TimeCurrent()>=t2) {
if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);
else OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);
}
}
bool OrderNotPresent=true;
if(t1<=TimeCurrent() && TimeCurrent()<t2){
for(int i=0;i<OrdersTotal();i++){
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue;
if(OrderComment()==MarkComent) { OrderNotPresent=false; break; }
}
if(OrderNotPresent) {
if(Operation=="B") { if(StopLoss<=0) SL=0; else SL=Ask-StopLoss*Point;
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,SL,0,MarkComent,1235,0,Blue); }
else { if(StopLoss<=0) SL=0; else SL=Bid+StopLoss*Point; /* sell */ }
}
}
}
FileClose(fh);
}
实例结果与优化解读
作者用14行集合TL_DATA.txt测试。禁跟踪时结果糟糕;简单优化跟踪止损大小得出95点最佳,与时段柱统计98%分位吻合。启用优化后收益显著提升,且所有订单精确在段首建立。需注意:若让订单留至段尾可能获'无与伦比'收益,但那来自重复开仓而非跟踪机制。本工具目标是评跟踪有效性,故同开同清、不长持是关键。
扩展方向与社区协作
进一步可在同图测多跟踪算法:段首开多单各跟各算法,重叠比较数量与质量。亦可换进场战术线条比战术。作者作为程序员寻交易员合作实盘化。本文为'裸版'研究工具,后续拟发算法对比篇。原文链接 https://www.mql5.com/zh/articles/1527 提供ZIP下载TL_Trader.zip。
- 多算法同图重叠测试
- 进场/退场战术对比
- 与专业交易员协作调战术
- 后续文章做算法横向评测