构建蜡烛图趋势约束模型(第7部分):为EA开发优化我们的模型·综合运用
(3/3)·信号有了却不知何时退场?本篇用MA交叉与RRR矩形把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>; <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) { <span class="keyword">if</span> (<span class="functions">ObjectFind</span>(<span class="number">0</span>, name) == -<span class="number">1</span>) { <span class="functions">ObjectCreate</span>(<span class="number">0</span>, name, <span class="macro">OBJ_HLINE</span>, <span class="number">0</span>, time, price); <span class="functions">ObjectSetInteger</span>(<span class="number">0</span>, name, <span class="macro">OBJPROP_COLOR</span>, lineColor); <span class="functions">ObjectSetInteger</span>(<span class="number">0</span>, name, <span class="macro">OBJPROP_WIDTH</span>, <span class="number">2</span>); } <span class="keyword">else</span> { <span class="functions">ObjectMove</span>(<span class="number">0</span>, name, <span class="number">0</span>, time, price); } } <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) { CreatePriceLine(<span class="string">"SignalPriceLine"</span>, <span class="macro">clrBlue</span>, signalPrice, time); CreatePriceLine(<span class="string">"ProfitTargetLine"</span>, <span class="macro">clrGreen</span>, profitTarget, time); CreatePriceLine(<span class="string">"RiskTargetLine"</span>, <span class="macro">clrRed</span>, riskTarget, time); } <span class="keyword">void</span> CheckSignalAndPlaceLines() { <span class="keyword">for</span> (<span class="keyword">int</span> i = rates_total - <span class="number">2</span>; i >= <span class="number">0</span>; i--) { <span class="keyword">if</span> (Buffer6[i] != <span class="number">0.0</span>) { <span class="comment">// Buy Signal Detected</span> <span class="keyword">double</span> signalPrice = Close[i]; <span class="keyword">double</span> profitTarget = signalPrice + profitPoints * <span class="functions">Point</span>; <span class="keyword">double</span> riskTarget = signalPrice - riskPoints * <span class="functions">Point</span>; PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); <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); } <span class="keyword">if</span> (Buffer7[i] != <span class="number">0.0</span>) { <span class="comment">// Sell Signal Detected</span> <span class="keyword">double</span> signalPrice = Close[i]; <span class="keyword">double</span> profitTarget = signalPrice - profitPoints * <span class="functions">Point</span>; <span class="keyword">double</span> riskTarget = signalPrice + riskPoints * <span class="functions">Point</span>; PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); <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); } } } [/CODE] CheckSignalAndPlaceLines 从倒数第二根 K 线往前扫,抓 Buffer6(买)、Buffer7(卖)非零就按信号价算目标,调 PlaceSignalLines 画线并弹 Alert。外汇和贵金属波动大、滑点频繁,这套线只作参考,实际出场可能偏离画线位。 别把画线当止损单 画线只是视觉和警报辅助,不会自动平仓;真要控风险得另挂止损单或用小布盯盘做条件单联动。
<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>; <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) { <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>) { <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); <span class="functions">ObjectSetInteger</span>(<span class="number">class="num">0</span>, name, <span class="macro">OBJPROP_COLOR</span>, lineColor); <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>); } <span class="keyword">else</span> { <span class="functions">ObjectMove</span>(<span class="number">class="num">0</span>, name, <span class="number">class="num">0</span>, time, price); } } <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) { CreatePriceLine(<span class="class="type">class="kw">string">"SignalPriceLine"</span>, <span class="macro">clrBlue</span>, signalPrice, time); CreatePriceLine(<span class="class="type">class="kw">string">"ProfitTargetLine"</span>, <span class="macro">clrGreen</span>, profitTarget, time); 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() { <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i = rates_total - <span class="number">class="num">2</span>; i >= <span class="number">class="num">0</span>; i--) { <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> <span class="keyword">class="type">class="kw">double</span> signalPrice = Close[i]; <span class="keyword">class="type">class="kw">double</span> profitTarget = signalPrice + profitPoints * <span class="functions">Point</span>; <span class="keyword">class="type">class="kw">double</span> riskTarget = signalPrice - riskPoints * <span class="functions">Point</span>; PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); <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); } <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> <span class="keyword">class="type">class="kw">double</span> signalPrice = Close[i]; <span class="keyword">class="type">class="kw">double</span> profitTarget = signalPrice - profitPoints * <span class="functions">Point</span>; <span class="keyword">class="type">class="kw">double</span> riskTarget = signalPrice + riskPoints * <span class="functions">Point</span>; PlaceSignalLines(signalPrice, profitTarget, riskTarget, Time[i]); <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); } } }
◍ 缓冲区声明漏了哪几行
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 数据验证。
<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 脱离调试再迁移绘制层。