构建蜡烛图趋势约束模型(第7部分):为EA开发优化我们的模型·综合运用
🤖

构建蜡烛图趋势约束模型(第7部分):为EA开发优化我们的模型·综合运用

(3/3)·信号有了却不知何时退场?本篇用MA交叉与RRR矩形把EA模型收口到可自动化

进阶 第 3/3 篇
很多人在第六部分拿到Telegram信号后就直接手动跟单,却从没问过这些信号是不是最优解。更常见的坑是:有入场没出场,浮盈变浮亏全靠手感。EA若只复刻信号不内置退场,回测再漂亮也只是半套系统。

把出场位画成三条线

Trend Constraint 在 V1.08 把出场逻辑从「只报货币对名字」推进到「给全价格」:信号价、盈利目标、风险目标一并吐出,交易者能直接看价格在哪儿可能撞上阻力或反转。 盈利点和风险点做成可自定义输入,默认 profitPoints=60、riskPoints=20,也就是信号价上下各 60 点、20 点挂线。MT5 里 1 点(Point)随品种小数位变化,外汇欧美对通常是 0.00001,挂线距离要按点值重算。 下面这段是画线的核心。CreatePriceLine 先 ObjectFind 查重,没有就 ObjectCreate 画水平线 OBJ_HLINE,设蓝绿红颜色和宽度 2;已有就用 ObjectMove 挪位置。PlaceSignalLines 一口气把信号线、盈利线、风险线都铺上。 [CODE] <span class="keyword">input</span> <span class="keyword">double</span> profitPoints = <span class="number">60</span>; <span class="comment">// Points for profit target</span> <span class="keyword">input</span> <span class="keyword">double</span> riskPoints = <span class="number">20</span>;&nbsp;&nbsp; <span class="comment">// Points for risk target</span> <span class="keyword">void</span> CreatePriceLine(<span class="keyword">string</span> name, <span class="keyword">color</span> lineColor, <span class="keyword">double</span> price, <span class="datetime">datetime</span> time) { &nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (<span class="functions">ObjectFind</span>(<span class="number">0</span>, name) == -<span class="number">1</span>) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectCreate</span>(<span class="number">0</span>, name, <span class="macro">OBJ_HLINE</span>, <span class="number">0</span>, time, price); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectSetInteger</span>(<span class="number">0</span>, name, <span class="macro">OBJPROP_COLOR</span>, lineColor); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectSetInteger</span>(<span class="number">0</span>, name, <span class="macro">OBJPROP_WIDTH</span>, <span class="number">2</span>); &nbsp;&nbsp;&nbsp;&nbsp;} <span class="keyword">else</span> { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectMove</span>(<span class="number">0</span>, name, <span class="number">0</span>, time, price); &nbsp;&nbsp;&nbsp;&nbsp;} } <span class="keyword">void</span> PlaceSignalLines(<span class="keyword">double</span> signalPrice, <span class="keyword">double</span> profitTarget, <span class="keyword">double</span> riskTarget, <span class="datetime">datetime</span> time) { &nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="string">"SignalPriceLine"</span>, <span class="macro">clrBlue</span>, signalPrice, time); &nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="string">"ProfitTargetLine"</span>, <span class="macro">clrGreen</span>, profitTarget, time); &nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="string">"RiskTargetLine"</span>, <span class="macro">clrRed</span>, riskTarget, time); } <span class="keyword">void</span> CheckSignalAndPlaceLines() { &nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> (<span class="keyword">int</span> i = rates_total - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (Buffer6[i] != <span class="number">0.0</span>) { <span class="comment">// Buy Signal Detected</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> signalPrice = Close[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> profitTarget = signalPrice + profitPoints * <span class="functions">Point</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> riskTarget = signalPrice - riskPoints * <span class="functions">Point</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Alert</span>(<span class="string">"Buy Signal: Signal Price = "</span>, signalPrice, <span class="string">" Profit Target = "</span>, profitTarget, <span class="string">" Risk Target = "</span>, riskTarget); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (Buffer7[i] != <span class="number">0.0</span>) { <span class="comment">// Sell Signal Detected</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> signalPrice = Close[i]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> profitTarget = signalPrice - profitPoints * <span class="functions">Point</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">double</span> riskTarget = signalPrice + riskPoints * <span class="functions">Point</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Alert</span>(<span class="string">"Sell Signal: Signal Price = "</span>, signalPrice, <span class="string">" Profit Target = "</span>, profitTarget, <span class="string">" Risk Target = "</span>, riskTarget); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} } [/CODE] CheckSignalAndPlaceLines 从倒数第二根 K 线往前扫,抓 Buffer6(买)、Buffer7(卖)非零就按信号价算目标,调 PlaceSignalLines 画线并弹 Alert。外汇和贵金属波动大、滑点频繁,这套线只作参考,实际出场可能偏离画线位。 别把画线当止损单 画线只是视觉和警报辅助,不会自动平仓;真要控风险得另挂止损单或用小布盯盘做条件单联动。

MQL5 / C++
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">class="kw">double</span> profitPoints = <span class="number">class="num">60</span>; <span class="comment">class=class="str">"cmt">// Points for profit target</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">class="kw">double</span> riskPoints = <span class="number">class="num">20</span>;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Points for risk target</span>
<span class="keyword">class="type">void</span> CreatePriceLine(<span class="keyword">class="type">class="kw">string</span> name, <span class="keyword">class="type">color</span> lineColor, <span class="keyword">class="type">class="kw">double</span> price, <span class="class="type">class="kw">datetime">class="type">class="kw">datetime</span> time) {
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (<span class="functions">ObjectFind</span>(<span class="number">class="num">0</span>, name) == -<span class="number">class="num">1</span>) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectCreate</span>(<span class="number">class="num">0</span>, name, <span class="macro">OBJ_HLINE</span>, <span class="number">class="num">0</span>, time, price);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectSetInteger</span>(<span class="number">class="num">0</span>, name, <span class="macro">OBJPROP_COLOR</span>, lineColor);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectSetInteger</span>(<span class="number">class="num">0</span>, name, <span class="macro">OBJPROP_WIDTH</span>, <span class="number">class="num">2</span>);
&nbsp;&nbsp;&nbsp;&nbsp;} <span class="keyword">else</span> {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ObjectMove</span>(<span class="number">class="num">0</span>, name, <span class="number">class="num">0</span>, time, price);
&nbsp;&nbsp;&nbsp;&nbsp;}
}
<span class="keyword">class="type">void</span> PlaceSignalLines(<span class="keyword">class="type">class="kw">double</span> signalPrice, <span class="keyword">class="type">class="kw">double</span> profitTarget, <span class="keyword">class="type">class="kw">double</span> riskTarget, <span class="class="type">class="kw">datetime">class="type">class="kw">datetime</span> time) {
&nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="class="type">class="kw">string">"SignalPriceLine"</span>, <span class="macro">clrBlue</span>, signalPrice, time);
&nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="class="type">class="kw">string">"ProfitTargetLine"</span>, <span class="macro">clrGreen</span>, profitTarget, time);
&nbsp;&nbsp;&nbsp;&nbsp;CreatePriceLine(<span class="class="type">class="kw">string">"RiskTargetLine"</span>, <span class="macro">clrRed</span>, riskTarget, time);
}
<span class="keyword">class="type">void</span> CheckSignalAndPlaceLines() {
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> (<span class="keyword">class="type">int</span> i = rates_total - <span class="number">class="num">2</span>; i &gt;= <span class="number">class="num">0</span>; i--) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (Buffer6[i] != <span class="number">class="num">0.0</span>) { <span class="comment">class=class="str">"cmt">// Buy Signal Detected</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> signalPrice = Close[i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> profitTarget = signalPrice + profitPoints * <span class="functions">Point</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> riskTarget = signalPrice - riskPoints * <span class="functions">Point</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Alert</span>(<span class="class="type">class="kw">string">"Buy Signal: Signal Price = "</span>, signalPrice, <span class="class="type">class="kw">string">" Profit Target = "</span>, profitTarget, <span class="class="type">class="kw">string">" Risk Target = "</span>, riskTarget);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (Buffer7[i] != <span class="number">class="num">0.0</span>) { <span class="comment">class=class="str">"cmt">// Sell Signal Detected</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> signalPrice = Close[i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> profitTarget = signalPrice - profitPoints * <span class="functions">Point</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> riskTarget = signalPrice + riskPoints * <span class="functions">Point</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Alert</span>(<span class="class="type">class="kw">string">"Sell Signal: Signal Price = "</span>, signalPrice, <span class="class="type">class="kw">string">" Profit Target = "</span>, profitTarget, <span class="class="type">class="kw">string">" Risk Target = "</span>, riskTarget);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}

◍ 缓冲区声明漏了哪几行

V1.09 编译一度报错,排查错误日志后发现是移动平均线交叉模块缺了新缓冲区的声明。除了已有的变量,必须补上 MA8、MA9、MA_handle8、MA_handle9 以及 Open2,否则 EA 在初始化阶段就会因数组未绑定而失败。 下方代码里高亮的部分就是当时漏写、补回后得以通过编译的声明。注意这些都是指标句柄与数组的成对定义,少一个 double 数组或对应 handle,终端都会在编译期直接抛错。 int MA_handle8; // 8号均线的指标句柄 double MA8[]; // 8号均线数值缓冲 int MA_handle9; // 9号均线的指标句柄 double MA9[]; // 9号均线数值缓冲 double Open2[]; // 辅助用的开盘价数组 V1.10 加了矩形对象后能编译,但图表不画任何东西,说明逻辑跑通了、渲染层还有坑,只能逐行跟。V1.11 又出编译错误,留到下一期拆。 顺手把已用的 8 个缓冲区用途理了一遍:Buffer1 抓 RSI 穿超买且开盘≥某 K 收盘、双 MA 均大于对照 MA 的买入区;Buffer2 是对称卖出区;Buffer3/4 记 MA5 与 MA6 的上下穿摆动点;Buffer5/8 分别跟 MA3 与 MA7 的>R7A5C和<关系;Buffer6/7 标 MA8 与 MA9 的死叉与金叉信号。外汇与贵金属波动大、滑点凶,这类多缓冲 EA 上线前务必在 MT5 策略测试器跑至少 3 个月 Tick 数据验证。

MQL5 / C++
<span class="keyword">class="type">int</span> RSI_handle;
<span class="keyword">class="type">class="kw">double</span> RSI[];
<span class="keyword">class="type">class="kw">double</span> Open[];
<span class="keyword">class="type">class="kw">double</span> Close[];
<span class="keyword">class="type">int</span> MA_handle;
<span class="keyword">class="type">class="kw">double</span> MA[];
<span class="keyword">class="type">int</span> MA_handle2;
<span class="keyword">class="type">class="kw">double</span> MA2[];
<span class="keyword">class="type">int</span> MA_handle3;
<span class="keyword">class="type">class="kw">double</span> MA3[];
<span class="keyword">class="type">int</span> MA_handle4;
<span class="keyword">class="type">class="kw">double</span> MA4[];
<span class="keyword">class="type">class="kw">double</span> Low[];
<span class="keyword">class="type">class="kw">double</span> High[];
<span class="keyword">class="type">int</span> MA_handle5;
<span class="keyword">class="type">class="kw">double</span> MA5[];
<span class="keyword">class="type">int</span> MA_handle6;
<span class="keyword">class="type">class="kw">double</span> MA6[];
<span class="keyword">class="type">int</span> MA_handle7;
<span class="keyword">class="type">class="kw">double</span> MA7[];
<span style="background-class="type">color:rgb(class="num">255, class="num">242, class="num">153);"><span class="keyword">class="type">int</span> MA_handle8;
<span class="keyword">class="type">class="kw">double</span> MA8[];
<span class="keyword">class="type">int</span> MA_handle9;
<span class="keyword">class="type">class="kw">double</span> MA9[];
<span class="keyword">class="type">class="kw">double</span> Open2[];</span>

「别急着下结论」

Trend Constraint 从 V1.09 到 V1.10 的迭代,核心是把移动平均线交叉信号和对象绘制拆成了两层:前者管触发,后者管可视化。V1.09 文件 20.95 KB,已带交叉信号;V1.10 涨到 24.09 KB,加了对象绘制却仍标着调试阶段,直接上实盘有踩坑概率。 外汇和贵金属本身高杠杆、高波动,这类指标再顺手也只是辅助框定止损止盈位置,替代不了你自己对风险敞口的控制。拿 ZIP 里的两个 mq5 去 MT5 里分别编译跑一遍,对比两者在 EURUSD 一小时图上的重绘表现,比看任何说明都实在。 作者留了社区协作的口子,剩余 bug 大概率还会在 V1.11 动刀。你要是自己改参数,建议先锁死 V1.09 的逻辑,等 V1.10 脱离调试再迁移绘制层。

让小布替你跑这套诊断
这些信号质量与RRR分布的诊断,小布盯盘的AIGC已内置,打开对应品种页即可看到历史触发与盈亏区间,你只需判断是否接入EA自动化。

常见问题

验证系统找不到EA依赖的自定义指标文件就会报错,只能本地运行;若要发布需把条件编进EA或合并为单一程序。
可能在大周期共振时更稳,但在震荡段交叉频繁会提高假信号概率,建议用趋势约束缓冲做前置过滤。
目前小布盯盘展示的是同逻辑的RRR区间与信号历史,EA自动化执行仍需你在MT5侧部署,小布负责看盘口与回溯。
用前高前低或结构止损实测,不要用理想目标价反推,否则回测盈利会虚高、实盘倾向失效。
V1.08只合并信号推送,本篇补了出场点位与测试验证,关于信号合并完整讨论见《构建蜡烛图趋势约束模型·基础篇》。