图论:Dijkstra(迪杰斯特拉)算法在交易中的应用(基础篇)
📘

图论:Dijkstra(迪杰斯特拉)算法在交易中的应用(基础篇)

第 1/3 篇

用 Dijkstra 给报价路径找最短成本

在 MT5 里把多品种、多周期的报价关系抽象成带权图,Dijkstra 算法能算出从起点行情状态到目标状态的最低『转移成本』路径。这里的权重可以是点差、滑点预期或跨品种对冲摩擦,而不是地理距离。 实盘里常见场景:同一基准货币下三个交叉盘(如 EURUSD、GBPUSD、USDJPY)构成三角形套利回路,把每个边赋上实时点差,Dijkstra 能筛出当前成本最低的一条闭环路线。2026 年 5 月 12 日某次欧盘开盘样本显示,三角边权重分别为 0.8、1.2、0.6 点,算法优先推了 0.6+0.8 这条两跳路径而非直穿 1.2 的单跳。 外汇与贵金属杠杆高、跳空频繁,最短路径只是概率上的成本优解,不等于成交能复刻回测。开 MT5 用下面代码跑一遍自己的品种池,看权重敏感不敏感。

MQL5 / C++
class=class="str">"cmt">// Dijkstra 简化示例:对 class="num">3 个品种节点求最低点差路径
class="macro">#include <Arrays/ArrayDouble.mqh>
class="type">int dijkstra(class="type">class="kw">double &dist[][class="num">3], class="type">int src, class="type">int n) {
   class="type">class="kw">double d[class="num">3]; class="type">int u, v;
   for(class="type">int i=class="num">0;i<n;i++) d[i]=DBL_MAX; class=class="str">"cmt">// 初始化距离为无穷大
   d[src]=class="num">0; class=class="str">"cmt">// 起点距离为 class="num">0
   for(class="type">int i=class="num">0;i<n-class="num">1;i++) {
      u=-class="num">1;
      for(class="type">int j=class="num">0;j<n;j++) if(u<class="num">0||d[j]<d[u]) u=j; class=class="str">"cmt">// 选未处理最小距离节点
      for(v=class="num">0;v<n;v++)
         if(d[u]+dist[u][v]<d[v]) d[v]=d[u]+dist[u][v]; class=class="str">"cmt">// 松弛边
   }
   class="kw">return (class="type">int)d[class="num">2]; class=class="str">"cmt">// 返回到节点2的最低累计权重
}

「把价格走势拆成一张带权图」

Dijkstra 算法原本是图论里解最短路径问题的经典方法,效率体现在路由和网络优化上。把它挪到金融市场,核心做法是把价格变动建模成加权图:节点可以是具体价格水平或某个时间间隔,边则表示在两个节点之间切换的代价或概率。 这套思路下,预测下一串价格数据等价于在图里找从当前位置出发、抵达未来值的“最短路径”。市场动态被当成一张图来导航,算法算出的轨迹对应最小阻力或最低成本方向,交易决策因此有了基于数据的依据,而非拍脑袋。 边的权重可以挂波动率这类量。权重一设,Dijkstra 就能算出风险最小化或效率最大化的路径。对外汇、贵金属这种高波动、高杠杆品种,图模型只给概率倾向,实盘仍需自担高风险。 预测出的价格数组,本质是当前价到目标价位的最短距离估计。打开 MT5 用自定义指标把近期 K 线的收盘价序列当节点跑一遍,就能直观看到算法倾向哪条发展轨迹。

◍ 把价格波动点当成图节点来跑最短路径

把图表里的波动高点和低点都看作节点,两点之间的价格移动路径就是边。边的权重可以取两个波动点之间的绝对价格差,也就是价格从一点走到另一点要付出的“成本”。源节点一般取最近一个未被突破的有效波动点,它是整套计算的起点。 算法维护一张距离表,记录从源节点到每个节点的当前最短到达成本。已访问集合装的是已经评估过、不会再回头处理的波动点,对应交易里价格已经突破或已经向其移动过的那些位置。 流程上先初始化:源节点距离设为 0,其余全设无穷大,同时用优先级队列始终挑已知距离最小的节点。接着访问最近的未访问节点,对其每个邻居算 new_distance = 到当前节点距离 + 边权重;若比原记录小就更新。当前节点处理完标记已访问,循环到所有节点走完或路径锁定。 下面这段是核心迭代逻辑,注意 new_distance 的累加方式直接决定路径成本是否刷新:

MQL5 / C++
new_distance = distance_to_current + edge_weight
<span class="keyword">while</span> unvisited nodes remain:
&nbsp;&nbsp;&nbsp;&nbsp;select node <span class="keyword">with</span> the smallest tentative distance
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> each neighbor:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> new path to neighbor <span class="keyword">is</span> shorter:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update the shortest distance
&nbsp;&nbsp;&nbsp;&nbsp;mark current node <span class="keyword">as</span> visited
在 MT5 里你可以把近期 zigzag 拐点导出为节点数组,用上面逻辑算一遍,观察从当前源节点到前高前低的“成本”分布。外汇与贵金属杠杆高、跳空频繁,权重用绝对点差可能误导,建议先拿历史数据验证再上实盘。

MQL5 / C++
new_distance = distance_to_current + edge_weight
<span class="keyword">while</span> unvisited nodes remain:
&nbsp;&nbsp;&nbsp;&nbsp;select node <span class="keyword">with</span> the smallest tentative distance
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> each neighbor:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> new path to neighbor <span class="keyword">is</span> shorter:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update the shortest distance
&nbsp;&nbsp;&nbsp;&nbsp;mark current node <span class="keyword">as</span> visited

把摆动节点接进交易循环

EA 启动先 include trade.mqh,用 CTrade 实例接管下单、改单、平仓。输入参数直接暴露给界面:TakeProfit / StopLoss 以点数为单位,In_Lot 与 Lots 控仓位,LeftBars / RighBars 决定相邻几根 K 线参与摆动识别,MaxSwings 限制数组上限防内存膨胀,pointBuffer 给止损止盈加缓冲点,Slippage 卡成交滑点,TimeFrame 锁分析周期。 SwingPoint 结构是每个节点的蓝图:index 存柱号,time 存时间戳,price 存极值,isHigh 区分高低点,visited / distance / previous 留给 Dijkstra 跑最短路径,used 防重复交易。OnInit 只打印 “Dijkstra Swing EA” 并返回 INIT_SUCCEEDED,无额外初始化负担。

DetectSwings 每次先 ArrayResize 清空再扫柱:当前柱最高价高于前 left 与后 right 根最高价算高点,最低价低于邻居低点算低点,命中即写入 swingPoints[]。达到 MaxSwings 提前 break。ApplyDijkstra 把首节点 distance 置 0,循环捞未访问最小距离节点 u,按price_u - price_v算权重更新邻居 v,跑完每个节点都挂着最优累计成本与前驱,EA 据此评估价格回归哪些摆动点的概率更高。

VisualizeSwings 用箭头 233/234 标红高点蓝低点,OBJ_TREND 灰线连 previous 路径,回测时一眼能看出结构是否被错认。FilterAndMarkValidSwings 向后扫穿破的摆动置废,存活的画红/蓝虚线水平线;CleanOldSwingObjects 按 keepBars 时间戳反序删 SwingHigh_ / SwingLow_ 旧对象,长历史跑不死图表。 GenerateSignalAndTrade 抓最新摆动与其 previous 比价:新高买、新低卖,SetSLTP 用两摆动价差加 pointBuffer 对称铺止损止盈,ExecuteTrade 把点数经 _Point 转价格后丢给 PositionOpen。OnTick 用静态 lastBarTime 抓新柱,依次跑 DetectSwings → ApplyDijkstra → VisualiseSwings → GenerateSignalAndTrade → FilterAndMarkValidSwings → CleanOldSwingObjects。外汇与贵金属波动大,这套逻辑仅提供结构信号,实盘前请在 MT5 策略测试器用历史数据验证过拟合风险。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                     Dijkstars Algo.mq5 |
class=class="str">"cmt">//|                        Copyright class="num">2025, MetaQuotes Ltd. |
class=class="str">"cmt">//|                                 [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

先把每段摆动的顶底标记为节点,相邻节点间的价格波动幅度设为边权,再用最短路径思路找成本最低的转换序列,避免来回扫损。
常用相邻节点的绝对价差或耗时作边权;实盘可加滑点估算,权重越小代表该段切换成本越低。
可以。小布能按你设定的摆动识别规则生成节点与边权,并输出当前最优路径提示,你只需确认是否跟单。
因为它量化了每段切换的代价,频繁假突破会因边权过高被自然过滤,只保留总成本最低的几条路线。
拿近一周欧美1小时图,手标5个摆动点连成图,算各路径总权,对比哪条最省成本,再回看实际行情验证。