图论:Dijkstra(迪杰斯特拉)算法在交易中的应用·综合运用
(3/3)·把波动点连成图、跑通回测后,这篇把算法落地的最后一块拼图补上
「用节点距离自动算止损止盈」
下面这段逻辑把止损止盈挂在了「入场价与参考节点之间的距离」上,而不是写死多少点。distance 取入场与参考节点差的绝对值,再叠一个 PointBuffer * _Point 的缓冲,避免止损刚好卡在毛刺上被扫。 买卖双向的处理很直接:买单向下的距离当 SL、向上的同距当 TP;卖单反过来。这样盈亏比在数学上是 1:1,实际成交会因点差和滑点偏离,外汇和贵金属属高风险品种,这种对称挂法不代表胜率倾向。 ExecuteTrade 里把 StopLoss、TakeProfit 从「pip 数」乘上 SYMBOL_POINT 转成真实价格距,再按买卖方向加减到挂单价上。注意它直接调 trade.PositionOpen,所以 StopLoss / TakeProfit 这两个外部变量单位必须是 pip,不是点数。 OnTick 只在每根 K 线第一跳跑一次:更新摆动点、跑路径算法、画图、出信号下单、清理旧对象。想验证就开 MT5 把 LeftBars / RightBars / PointBuffer 调小,看小周期下 SLTP 是不是跟着节点距离收缩。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Calculate SL and TP based on distance to previous node | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void SetSLTP(class="type">class="kw">double entry, class="type">class="kw">double ref, class="type">bool isBuy, class="type">class="kw">double &sl, class="type">class="kw">double &tp) { class="type">class="kw">double distance = MathAbs(entry - ref) + PointBuffer * _Point; if (isBuy) { sl = entry - distance; tp = entry + distance; } else { sl = entry + distance; tp = entry - distance; } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Execute trade with risk parameters | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void ExecuteTrade(ENUM_ORDER_TYPE tradeType){ class="type">class="kw">double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); class="type">class="kw">double price = (tradeType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); class=class="str">"cmt">// Convert StopLoss and TakeProfit from pips to actual price distances class="type">class="kw">double sl_distance = StopLoss * point; class="type">class="kw">double tp_distance = TakeProfit * point; class="type">class="kw">double sl = (tradeType == ORDER_TYPE_BUY) ? price - sl_distance : price + sl_distance; class="type">class="kw">double tp = (tradeType == ORDER_TYPE_BUY) ? price + tp_distance : price - tp_distance; trade.PositionOpen(_Symbol, tradeType, In_Lot, price, sl, tp, NULL); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| OnTick | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class="kw">static class="type">class="kw">datetime lastBarTime = class="num">0; class="type">class="kw">datetime currentBarTime = iTime(_Symbol, _Period, class="num">0); if (currentBarTime != lastBarTime) { lastBarTime = currentBarTime; DetectSwings(LeftBars, RightBars); ApplyDijkstra(); VisualizeSwings(); GenerateSignalAndTrade(); FilterAndMarkValidSwings(swingPoints); CleanOldSwingObjects(); } }
两个月窗口下的 1H 回测配置
这套形态识别逻辑在 2025 年 5 月 1 日至 6 月 20 日跑了约 51 个自然日的 1 小时周期回测,用来观察实盘前的行为稳定性。外汇与贵金属杠杆品种波动剧烈,回测仅反映历史窗口特征,不代表后续收益可能。 输入参数里 TP 设 1000 点、SL 固定 385 点,仓位 0.01 手,属于低敞口验证。Left bars 与 Right bars 都是 3,意味着以左右各 3 根 1H K 线确认摆动点;Max swing 50 点限制噪声幅度,Point buffer 10.0 给点位判定留容差,Slippage 5 点模拟常规滑点。 直接把这些数值原样抄进 MT5 的 EA 输入栏,能在同周期同品种上复现测试环境,判断该形态在你常做的货币对上是否也有类似触发频率。
◍ 一点提醒
把波段高低点当图节点、用 Dijkstra 算最省路径这套思路,本质是把价格行为几何化,让进场和止损止盈直接挂在市场自己的支撑阻力骨架上。EA 里每个节点只用一次、被突破就作废,模拟的是价格自然流穿结构而非指标滞后信号。 外汇和贵金属杠杆高、跳空频繁,这种结构路径在流动性突变时可能失效,实盘前务必用 MT5 策略测试器跑 ZIP 里的 Dijkstras_Algo.mq5 做多周期回测。 代码是模块化写的,检测、验证、寻路、执行、画图各管各的,你想换权重算法或加品种,改对应函数即可,不必推倒重来。