交易员之活学活用: "平静" 优化或绘制交易分布·综合运用
(3/3)· 把盈利按开仓时间摊开看,优化前先避开那些被平均掩盖的入场陷阱
挂脚本让账户历史在图上自己摊开
想直接看当前账户的交易分布,最省事的办法是丢一个脚本到图表上。脚本启动后会按每笔入场时间顺序扫历史成交,并把分析图绘出来。 跑之前有个硬前提:必须给脚本开 DLL 导入权限,因为它依赖的 DistributionOfProfits.mqh 会调用系统 DLL,不然直接报错起不来。 脚本只有一个输入参数 start,用来圈定从哪天开始绘分析图。下面这段是核心骨架,输入默认设在 2010.05.11 12:05:00,你改这个日期就能换分析窗口。 代码逐行拆解: #property script_show_inputs 让参数面板弹出,方便改 start; input datetime start=D'2010.05.11 12:05:00' 是分析起点,类型用 datetime 而非 string; #include <DistributionOfProfits.mqh> 把分析类拉进来,DLL 调用藏在这头文件里; CDistributionOfProfits Analysis 声明一个分析对象实例; OnStart 里两行:AnalysisTradingHistory(start) 按起点捞历史,ShowDistributionOfProfits() 把利润分布画到图上。 外汇和贵金属杠杆高、滑点跳空频繁,这类分布图只是历史剖面,对后续走势只有概率层面的参考,别当成下单依据。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| test_report.mq5 | class=class="str">"cmt">//| 版权所有 class="num">2016, MetaQuotes 软件公司| class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "版权所有 class="num">2016, MetaQuotes 软件公司" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property script_show_inputs class=class="str">"cmt">//--- input class="type">class="kw">datetime start=D&class="macro">#x27;class="num">2010.05.class="num">11 class="num">12:class="num">05:class="num">00&class="macro">#x27;; class="macro">#include <DistributionOfProfits.mqh> class=class="str">"cmt">//--- CDistributionOfProfits Analysis; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 脚本程序开始函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//--- Analysis.AnalysisTradingHistory(start); Analysis.ShowDistributionOfProfits(); } class=class="str">"cmt">//+------------------------------------------------------------------+
「在测试器里拆开MACD的时段盈亏」
拿 MT5 标准分发里的 MACD Sample 做底本,复制到独立文件夹并改名 MACD Sample report.mq5,这样改动不会污染原文件。先在终端设置里勾选允许 DLL 调用,再于 EA 尾部补一个 OnTester() 函数,把每笔平仓的时段与盈亏喂给分析模块。 跑完回测后生成的页面里,有一张按小时统计的盈利/亏损分布直方图。图上能直接看出哪些钟点开仓倾向赚钱、哪些钟点持续失血——原文里就标出了两个明显的亏损时间间隔。 顺手做两个实验就很有意思:一是在那两段亏损时段硬性禁交易,二是把信号反接成反向开仓。外汇与贵金属杠杆高、滑点跳空频繁,这种时段反转只是概率上的修正,不是稳赢。 多货币 EA 也能如法炮制。在头部加 #include <DistributionOfProfits.mqh> 并声明 CDistributionOfProfits ExtDistribution,结尾挂上 OnTester(),一次运行后产出 TestAnalysis.htm。所有图表皆可交互,悬停直方图列就能看具体品种合计盈亏;饼图拆出每个品种的利润贡献占比;剩余图表按仓位入场时间排开逐品种盈亏。 别把正态当圣经 那张按小时的分布图只是样本内的切片,换品种或拉长时间窗,亏损时段很可能移位。动手前先在自己 MT5 用 2020–2024 的 H1 数据重跑一遍再下结论。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| MACD Sample report.mq5 | class=class="str">"cmt">//| 版权所有 class="num">2009-class="num">2016, MetaQuotes 软件公司| class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "版权所有 class="num">2009-class="num">2016, MetaQuotes 软件公司" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">5.50" class="macro">#class="kw">property description "重要的是确认智能程序可在一般的" class="macro">#class="kw">property description "图表上工作, 且在我们的情况里, 用户不能在输入变量" class="macro">#class="kw">property description "设置理有任何错误 (手数, 止盈, 尾随停止)," class="macro">#class="kw">property description "我们会在图表上超过 class="num">2*trend_period 根柱线上检查止盈" class="macro">#define MACD_MAGIC class="num">1234502 class=class="str">"cmt">//--- class="macro">#include <Trade\Trade.mqh> class="macro">#include <Trade\SymbolInfo.mqh> class="macro">#include <Trade\PositionInfo.mqh> class="macro">#include <Trade\AccountInfo.mqh> class="macro">#include <DistributionOfProfits.mqh> class=class="str">"cmt">//--- input class="type">class="kw">double InpLots =class="num">0.1; class=class="str">"cmt">// 手数 input class="type">int InpTakeProfit =class="num">50; class=class="str">"cmt">// 止盈 (点数) input class="type">int InpTrailingStop =class="num">30; class=class="str">"cmt">// 尾随停止级别 (点数) input class="type">int InpMACDOpenLevel =class="num">3; class=class="str">"cmt">// MACD 开盘级别 (点数) input class="type">int InpMACDCloseLevel=class="num">2; class=class="str">"cmt">// MACD 平仓级别 (点数) input class="type">int InpMATrendPeriod =class="num">26; class=class="str">"cmt">// MA 趋势周期 class=class="str">"cmt">//--- class="type">int ExtTimeOut=class="num">10; class=class="str">"cmt">// 在交易操作之间的超时秒数 CDistributionOfProfits ExtDistribution; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| MACD 示例智能程序类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CSampleExpert { class="kw">protected: class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 测试器函数 | class=class="str">"cmt">//+------------------------------------------------------------------+
◍ 在 OnTester 里跑分布分析
做 EA 回测时,想顺手看盈利分布,可以把分析逻辑塞进 OnTester。这是 MT5 优化器每跑完一组参数会调用的函数,返回啥不重要,关键是副作用。 上面这段代码只做三件事:先给 ret 赋 0.0,再调用 ExtDistribution.AnalysisTradingHistory(0) 把当前品种(0 即当前图表品种)的历史交易喂给分布对象,最后 ShowDistributionOfProfits 把利润分布画出来。回测完直接在结果里翻就行。 注意外汇和贵金属杠杆高、滑点跳空频繁,历史分布只是样本,对实盘只具概率参考意义,别当成仓位依据。
class="type">class="kw">double OnTester() { class=class="str">"cmt">//--- class="type">class="kw">double ret=class="num">0.0; ExtDistribution.AnalysisTradingHistory(class="num">0); ExtDistribution.ShowDistributionOfProfits(); class=class="str">"cmt">//--- class="kw">return(ret); }
用分布图做不跑测试的时段筛选
交易分布绘制完后,历史成交会先并成仓位,再按入场时刻拆成三类来看:小时、周内天数、月份。这套拆法不依赖策略测试器重跑,直接拿已有成交记录就能出图。 源文件里附带了合并仓位并画图的实现,挂在任意品种上就能检查自己的策略在哪些小时或哪几天胜率偏薄。亚洲、欧洲、美国时段里,可能有一两个段根本不值得盯,图上会直接显出来。 外汇和贵金属波动受时段流动性影响大,这种‘平静优化’只是帮你看清分布,不等于过滤后就能避开亏损,实盘仍有较高风险。打开 MT5 加载附带的脚本,选一个你常做的品种跑一遍,重点看亏损仓位扎堆的小时区间。
「类库迭代后如何避开优化器坑」
DistributionOfProfits.mqh 从 v1.027 到 v1.033 做了两处实质改动:v1.027 引入优化期保护,构造器内嵌名为 "Non File" 的文件标识,并加入对 MQL_OPTIMIZATION 常量的检查;v1.033 则把仓位分析维度扩到按资金、按点数、以及资金+点数混合三种模式。 在 MT5 里跑回测时,若勾选了「遗传优化 / 全部优化」,优化器会反复调用分析类。原版代码若在优化期写文件或绘图,可能拖慢速度甚至报错。v1.027 之后直接在构造和分析入口拦掉优化上下文,是务实的写法。 外汇与贵金属保证金交易杠杆高、滑点跳空频繁,任何历史分析工具都只能描述过去分布,不能推导未来盈亏概率。 下面这段是 v1.027 防护的核心片段,注意高亮部分:构造器把 m_name_file 硬设为 "Non File",AnalysisTradingHistory 一进来就判 MQL_OPTIMIZATION,为真直接 return false,优化进程里不会触碰文件逻辑。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 构造器 | class=class="str">"cmt">//+------------------------------------------------------------------+ CDistributionOfProfits::CDistributionOfProfits(class="type">void) : m_name_file("Non File"), m_color_loss("ed7d31"), m_color_profit("5b9bd5"), m_width("class="num">440"), m_height("class="num">400"), m_data_number(class="num">1) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 分析交易历史 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CDistributionOfProfits::AnalysisTradingHistory(const class="type">class="kw">datetime start_time=class="num">0) { class=class="str">"cmt">//--- if(MQLInfoInteger(MQL_OPTIMIZATION)) class="kw">return(false);
◍ 把这条线请下神坛
上面的脚本把盈利分布从 EA 里拆出来单独跑:OnStart 里先 SetTypeOfAnalysis 选定按资金、点数还是两者都要,再 AnalysisTradingHistory 拉起止时间的历史成交,最后 ShowDistributionOfProfits 把直方图丢给浏览器。注意 ShowDistributionOfProfits 开头那句,若 MQLInfoInteger(MQL_OPTIMIZATION) 为真就直接 return——也就是说在策略测试器做遗传优化时它压根不画,只在普通回测或手动跑脚本时才出图。 report_type 默认 MONEY_AND_POINTS,start 写死 2016.06.28 09:10:00,这俩都是 input,你换品种前至少把起点日期改成自己账户的实际入金日,否则分布里会混进无关的历史单。外汇与贵金属杠杆高,历史盈利分布只是样本描述,对未来亏损概率没有任何担保。 正态拟合在推销话术里常被说成「系统健康证明」,但真实交易序列的肥尾和跳空会让均值方差同时失真。拿这段代码跑完自己的成交记录,看见钟形图也别松风控——它只是告诉你过去怎么亏过,不是明天不会亏。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 显示盈利分布 (浏览器开始) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CDistributionOfProfits::ShowDistributionOfProfits(class="type">void) { class=class="str">"cmt">//--- if(MQLInfoInteger(MQL_OPTIMIZATION)) class="kw">return; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| test_report.mq5 | class=class="str">"cmt">//| 版权所有 class="num">2016, MetaQuotes 软件公司| class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "版权所有 class="num">2016, MetaQuotes 软件公司" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property script_show_inputs class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 报告类型 | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ANALYSIS_TYPE { ONLY_MONEY=class="num">0, class=class="str">"cmt">// 按资金 ONLY_POINTS=class="num">1, class=class="str">"cmt">// 按点数 MONEY_AND_POINTS=class="num">2, class=class="str">"cmt">// 按资金和点数 }; class=class="str">"cmt">//--- input class="type">class="kw">datetime start=D&class="macro">#x27;class="num">2016.06.class="num">28 class="num">09:class="num">10:class="num">00&class="macro">#x27;; input ANALYSIS_TYPE report_type=MONEY_AND_POINTS; class=class="str">"cmt">//--- class="macro">#include <DistributionOfProfits.mqh> class=class="str">"cmt">//--- CDistributionOfProfits Analysis; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 脚本程序开始函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//--- Analysis.SetTypeOfAnalysis(report_type); Analysis.AnalysisTradingHistory(start); Analysis.ShowDistributionOfProfits(); }