//+------------------------------------------------------------------+ //| Dijkstars Algo.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property strict #include CTrade trade; // Input Parameters input int TakeProfit = 1000; input int StopLoss = 385; input double In_Lot = 0.01; input int LeftBars = 3; input int RightBars = 3; input int MaxSwings = 50; input double Lots = 0.1; input double PointBuffer = 10; input int Slippage = 5; ENUM_TIMEFRAMES TimeFrame; // Node Structure struct SwingPoint { int index; datetime time; double price; bool isHigh; bool visited; double distance; bool used; int previous; }; SwingPoint swingPoints[]; //+------------------------------------------------------------------+ //| OnInit | //+------------------------------------------------------------------+ int OnInit() { Print("Dijkstra Swing EA initialized"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| OnTick | //+------------------------------------------------------------------+ void OnTick() { static datetime lastBarTime = 0; datetime currentBarTime = iTime(_Symbol, _Period, 0); if (currentBarTime != lastBarTime) { lastBarTime = currentBarTime; DetectSwings(LeftBars, RightBars); ApplyDijkstra(); VisualizeSwings(); GenerateSignalAndTrade(); FilterAndMarkValidSwings(swingPoints); CleanOldSwingObjects(); } } //+------------------------------------------------------------------+ //| Detect swing highs and lows | //+------------------------------------------------------------------+ void DetectSwings(int left, int right) { ArrayResize(swingPoints, 0); int totalBars = Bars(_Symbol, PERIOD_CURRENT) - right; for (int i = left; i < totalBars; i++) { bool isHigh = true, isLow = true; double high = High(i), low = Low(i); for (int j = 1; j <= left; j++) { if (High(i - j) >= high) isHigh = false; if (Low(i - j) <= low) isLow = false; } for (int j = 1; j <= right; j++) { if (High(i + j) >= high) isHigh = false; if (Low(i + j) <= low) isLow = false; } if (isHigh || isLow) { int idx = ArraySize(swingPoints); ArrayResize(swingPoints, idx + 1); swingPoints[idx].index = i; swingPoints[idx].time = Time(i); swingPoints[idx].price = isHigh ? high : low; swingPoints[idx].isHigh = isHigh; swingPoints[idx].visited = false; swingPoints[idx].distance = DBL_MAX; swingPoints[idx].previous = -1; if (idx >= MaxSwings) break; } } } //+------------------------------------------------------------------+ //| Apply Dijkstra's algorithm | //+------------------------------------------------------------------+ void ApplyDijkstra() { if (ArraySize(swingPoints) == 0) return; swingPoints[0].distance = 0; for (int i = 0; i < ArraySize(swingPoints); i++) { int u = -1; double minDist = DBL_MAX; for (int j = 0; j < ArraySize(swingPoints); j++) { if (!swingPoints[j].visited && swingPoints[j].distance < minDist) { minDist = swingPoints[j].distance; u = j; } } if (u == -1) break; swingPoints[u].visited = true; for (int v = 0; v < ArraySize(swingPoints); v++) { if (!swingPoints[v].visited) { double cost = MathAbs(swingPoints[u].price - swingPoints[v].price); if (swingPoints[u].distance + cost < swingPoints[v].distance) { swingPoints[v].distance = swingPoints[u].distance + cost; swingPoints[v].previous = u; } } } } } //+------------------------------------------------------------------+ //| Visualize Swing Points and Connections | //+------------------------------------------------------------------+ void VisualizeSwings() { for (int i = 0; i < ArraySize(swingPoints); i++) { string objName = "Swing_" + IntegerToString(i); ObjectDelete(0, objName); ObjectCreate(0, objName, OBJ_ARROW, 0, swingPoints[i].time, swingPoints[i].price); ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, swingPoints[i].isHigh ? 233 : 234); ObjectSetInteger(0, objName, OBJPROP_COLOR, swingPoints[i].isHigh ? clrRed : clrBlue); } for (int i = 1; i < ArraySize(swingPoints); i++) { int prev = swingPoints[i].previous; if (prev != -1) { string lineName = "Line_" + IntegerToString(i); ObjectDelete(0, lineName); ObjectCreate(0, lineName, OBJ_TREND, 0, swingPoints[prev].time, swingPoints[prev].price, swingPoints[i].time, swingPoints[i].price); ObjectSetInteger(0, lineName, OBJPROP_COLOR, clrGray); ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 1); } } } double High(int index){return (iHigh(_Symbol, _Period, index));} double Low(int index){return (iLow(_Symbol, _Period, index));} datetime Time(int index){return (iTime(_Symbol, _Period, index));} //+------------------------------------------------------------------+ //| Filter and mark | //+------------------------------------------------------------------+ void FilterAndMarkValidSwings(SwingPoint &points[]) { int count = ArraySize(points); if(count < 2) return; for(int i = 0; i < count; i++) { if(points[i].used) continue; bool isValid = true; double swingPrice = points[i].price; int swingIndex = points[i].index; // Scan forward in time from the swing point for(int j = swingIndex - 1; j >= 0; j--) { double high = iHigh(_Symbol, TimeFrame, j); double low = iLow(_Symbol, TimeFrame, j); // Invalidate swing high if price went higher later if(points[i].isHigh && high > swingPrice) { isValid = false; break; } // Invalidate swing low if price went lower later if(!points[i].isHigh && low < swingPrice) { isValid = false; break; } } if(isValid) { points[i].used = true; // Draw object on chart string objName = points[i].isHigh ? StringFormat("SwingHigh_%d", TimeToString(iTime(_Symbol, TimeFrame, swingIndex))) : StringFormat("SwingLow_%d", TimeToString(iTime(_Symbol, TimeFrame, swingIndex))); color swingColor = points[i].isHigh ? clrRed : clrBlue; ObjectCreate(0, objName, OBJ_HLINE, 0, 0, swingPrice); ObjectSetInteger(0, objName, OBJPROP_COLOR, swingColor); ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_DASH); ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1); } } } //+------------------------------------------------------------------+ //| Cleaning up old swings | //+------------------------------------------------------------------+ void CleanOldSwingObjects(int keepBars = 100) { datetime oldestDate = iTime(_Symbol, TimeFrame, keepBars); int total = ObjectsTotal(0); for(int i = total - 1; i >= 0; i--) { string name = ObjectName(0, i); if(StringFind(name, "SwingHigh_") == 0 || StringFind(name, "SwingLow_") == 0) { datetime swingTime = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME); if(swingTime < oldestDate) { ObjectDelete(0, name); } } } } //+------------------------------------------------------------------+ //| Generate Signal & Trade | //+------------------------------------------------------------------+ void GenerateSignalAndTrade() { if (ArraySize(swingPoints) < 2) return; int last = ArraySize(swingPoints) - 1; int prev = swingPoints[last].previous; if (prev == -1) return; double entry = swingPoints[last].price; double reference = swingPoints[prev].price; double sl, tp; bool isBuy = entry > reference, isSell = entry < reference; SetSLTP(entry, reference, isBuy, sl, tp); if (PositionSelect(_Symbol)) return; if (isBuy) ExecuteTrade(ORDER_TYPE_BUY); else if(isSell) ExecuteTrade(ORDER_TYPE_SELL); } //+------------------------------------------------------------------+ //| Calculate SL and TP based on distance to previous node | //+------------------------------------------------------------------+ void SetSLTP(double entry, double ref, bool isBuy, double &sl, double &tp) { double distance = MathAbs(entry - ref) + PointBuffer * _Point; if (isBuy) { sl = entry - distance; tp = entry + distance; } else { sl = entry + distance; tp = entry - distance; } } //+------------------------------------------------------------------+ //| Execute trade with risk parameters | //+------------------------------------------------------------------+ void ExecuteTrade(ENUM_ORDER_TYPE tradeType){ double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double price = (tradeType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); // Convert StopLoss and TakeProfit from pips to actual price distances double sl_distance = StopLoss * point; double tp_distance = TakeProfit * point; double sl = (tradeType == ORDER_TYPE_BUY) ? price - sl_distance : price + sl_distance; double tp = (tradeType == ORDER_TYPE_BUY) ? price + tp_distance : price - tp_distance; trade.PositionOpen(_Symbol, tradeType, In_Lot, price, sl, tp, NULL); }