diff --git a/OrdersEA_Smart_Grid_BO.mq5 b/OrdersEA_Smart_Grid_BO.mq5 index c4cc9b4..30ed502 100755 --- a/OrdersEA_Smart_Grid_BO.mq5 +++ b/OrdersEA_Smart_Grid_BO.mq5 @@ -5,12 +5,12 @@ //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Garfield Heron" #property link "https://fetcherpay.com" -#property version "5.5" +#property version "5.6" #include #include -#define VERSION "Version 5.5 Smart Grid Breakout BO MT5" +#define VERSION "Version 5.6 Smart Grid Breakout BO MT5" #define MAX_TRADES 600 #define MAX_LOG_TRADES 1200 @@ -118,6 +118,14 @@ input bool InpCloseBeforeWeekend = true; input int InpWeekendCloseHour = 17; input bool InpCancelPendingBeforeWeekend = true; input int InpMondayStartHour = 7; // Monday: no new grids before this server hour (0 = off) +//--- Thursday Wind-Down (5.6): approach the weekend close algorithmically — +// stop taking new risk Thursday afternoon and let tight trails walk +// positions out at their natural end; the hard close stays as backstop. +input string WinddownSettings = "=== Thursday Wind-Down ==="; +input bool InpUseWinddown = true; +input int InpWinddownStartHour = 19; // Server hour Thursday: no new grids from here (Thu 12:00 ET) +input int InpWinddownTrailStart = 200; // Wind-down trail activation (points) +input int InpWinddownTrailStop = 150; // Wind-down trail distance (points) //--- Trade Object CTrade trade; @@ -171,6 +179,8 @@ datetime lastWeeklyScan = 0; //--- Weekend Protection bool weekendCloseExecuted = false; bool mondayStandDownLogged = false; +bool winddownLogged = false; +bool winddownPendingsCancelled = false; //--- Master one-shot (1.4) bool masterShutdownDone = false; @@ -456,6 +466,73 @@ bool CheckWeekendProtection() return true; } +//+------------------------------------------------------------------+ +//| Thursday Wind-Down window (5.6) | +//| Server Thursday >= InpWinddownStartHour through the Friday weekend | +//| close: no new grids, pendings cancelled, tight trails take over. | +//+------------------------------------------------------------------+ +bool InWinddown() + { + if(!InpUseWinddown) return false; + MqlDateTime dt; + TimeToStruct(TimeCurrent(), dt); + if(dt.day_of_week == THURSDAY && dt.hour >= InpWinddownStartHour) return true; + if(dt.day_of_week == FRIDAY && dt.hour < InpWeekendCloseHour) return true; + return false; + } + +//+------------------------------------------------------------------+ +//| Friday shadow metric (5.6) | +//| First tick of the new trading week: report what each position | +//| flattened at the weekend close would have done through Friday — | +//| mark-to-market at Friday's last H1 close plus worst adverse | +//| excursion. Pure telemetry: quantifies what the flatten policy | +//| costs (or saves) for the weekly analysis. | +//+------------------------------------------------------------------+ +void ReportFridayShadow() + { + datetime monday = WeekStartBroker(); + datetime friStart = monday - 3*86400 + InpWeekendCloseHour*3600; + datetime friEnd = monday - 2*86400; + + MqlRates bars[]; + int n = CopyRates(_Symbol, PERIOD_H1, friStart, friEnd, bars); + if(n < 1) return; + double friClose = bars[n-1].close; + double hi = bars[0].high, lo = bars[0].low; + for(int i = 1; i < n; i++) + { + if(bars[i].high > hi) hi = bars[i].high; + if(bars[i].low < lo) lo = bars[i].low; + } + + double tickVal = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); + double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); + if(tickSize <= 0 || tickVal <= 0) return; + + if(!HistorySelect(friStart - 300, friStart + 900)) return; + for(int i = 0; i < HistoryDealsTotal(); i++) + { + ulong d = HistoryDealGetTicket(i); + if(d == 0) continue; + if(HistoryDealGetString(d, DEAL_SYMBOL) != _Symbol) continue; + if(HistoryDealGetInteger(d, DEAL_MAGIC) != MagicNum) continue; + if((ENUM_DEAL_ENTRY)HistoryDealGetInteger(d, DEAL_ENTRY) != DEAL_ENTRY_OUT) continue; + // a SELL deal closes a long position + int dir = ((ENUM_DEAL_TYPE)HistoryDealGetInteger(d, DEAL_TYPE) == DEAL_TYPE_SELL) ? 1 : -1; + double vol = HistoryDealGetDouble(d, DEAL_VOLUME); + double closeP = HistoryDealGetDouble(d, DEAL_PRICE); + double mtm = (friClose - closeP) * dir / tickSize * tickVal * vol; + double worstP = (dir > 0) ? lo : hi; + double worst = (worstP - closeP) * dir / tickSize * tickVal * vol; + PrintS("SHADOW " + (dir > 0 ? "long" : "short") + " " + DoubleToString(vol, 2) + + " flattened@" + DoubleToString(closeP, _Digits) + + " friClose=" + DoubleToString(friClose, _Digits) + + " mtm=$" + DoubleToString(mtm, 2) + + " worst=$" + DoubleToString(worst, 2)); + } + } + //+------------------------------------------------------------------+ //| Monday Morning Stand-Down (5.3) | //| Sunday-evening ET liquidity is thin and the pivots/ATR are built | @@ -864,13 +941,17 @@ void ApplyBreakeven() void ApplyTrailingStop() { if(!InpUseTrailingStop) return; - if(InpTrailStartPoints <= 0 || InpTrailStop <= 0) return; + // Wind-down (5.6): much tighter trail so positions walk themselves out + // ahead of the weekend close instead of being chopped at the deadline + int effStartPts = InWinddown() ? InpWinddownTrailStart : InpTrailStartPoints; + int effDistPts = InWinddown() ? InpWinddownTrailStop : InpTrailStop; + if(effStartPts <= 0 || effDistPts <= 0) return; double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); - double trailStart = InpTrailStartPoints * point; - double trailDist = InpTrailStop * point; + double trailStart = effStartPts * point; + double trailDist = effDistPts * point; for(int i = PositionsTotal() - 1; i >= 0; i--) { @@ -1332,6 +1413,20 @@ void OnTick() lastHeartbeat = TimeCurrent(); } + // --- Friday shadow report (5.6) — once per week on the first tick of the + // new server week (Sunday evening ET), before any gate can block it --- + MqlDateTime shdt; + TimeToStruct(TimeCurrent(), shdt); + if(shdt.day_of_week == MONDAY) + { + datetime wk = WeekStartBroker(); + if((datetime)GlobalVariableGet(GvKey("shadowWk")) != wk) + { + GlobalVariableSet(GvKey("shadowWk"), (double)wk); + ReportFridayShadow(); + } + } + // --- Per-EA daily drawdown (3.1B) --- if(!CheckDailyDrawdown()) { @@ -1398,6 +1493,36 @@ void OnTick() if(currentBarTime == lastBarTime) return; lastBarTime = currentBarTime; + // --- Thursday wind-down (5.6): no new risk into the shortened week. + // Trailing/breakeven keep running in the 5s block above; only new grid + // placement (and existing entry pendings) are shut off. + if(InWinddown()) + { + if(!winddownLogged) + { + PrintS("🌙 WIND-DOWN — no new grids; trail tightened to " + + IntegerToString(InpWinddownTrailStart) + "/" + + IntegerToString(InpWinddownTrailStop) + "pts until weekend close"); + winddownLogged = true; + } + if(!winddownPendingsCancelled) + { + CancelAllOrders("Wind-down — no new risk"); + winddownPendingsCancelled = true; + if(gridPlaced) + { + gridPlaced = false; + SaveGridState(); + } + } + return; + } + if(winddownLogged || winddownPendingsCancelled) + { + winddownLogged = false; + winddownPendingsCancelled = false; + } + // --- Update adaptive-filter state each bar --- UpdateFilterRelaxation(); diff --git a/bo-audnzd.set b/bo-audnzd.set index 5ac0618..b773f48 100644 --- a/bo-audnzd.set +++ b/bo-audnzd.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444012 diff --git a/bo-audusd.set b/bo-audusd.set index f2630b5..7c4e70d 100644 --- a/bo-audusd.set +++ b/bo-audusd.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444005 diff --git a/bo-eurchf.set b/bo-eurchf.set index 38f492e..21604c9 100644 --- a/bo-eurchf.set +++ b/bo-eurchf.set @@ -56,6 +56,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444010 diff --git a/bo-eurgbp.set b/bo-eurgbp.set index a4f36b4..632b331 100644 --- a/bo-eurgbp.set +++ b/bo-eurgbp.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444011 diff --git a/bo-eurjpy.set b/bo-eurjpy.set index 174edac..ad28f89 100644 --- a/bo-eurjpy.set +++ b/bo-eurjpy.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444009 diff --git a/bo-eurusd.set b/bo-eurusd.set index f3ae42e..0be8696 100644 --- a/bo-eurusd.set +++ b/bo-eurusd.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444001 diff --git a/bo-gbpjpy.set b/bo-gbpjpy.set index 1692c28..32a9310 100644 --- a/bo-gbpjpy.set +++ b/bo-gbpjpy.set @@ -55,6 +55,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444004 diff --git a/bo-gbpusd.set b/bo-gbpusd.set index 5e9b9ad..3143695 100644 --- a/bo-gbpusd.set +++ b/bo-gbpusd.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444002 diff --git a/bo-major.set b/bo-major.set index b68fe72..723af9f 100644 --- a/bo-major.set +++ b/bo-major.set @@ -56,6 +56,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === Session Notes === ; BO fires on breakout of daily pivot range (ATR-scaled) ; Best: London open (07:00-09:00 GMT), NY open (13:30-15:00 GMT) diff --git a/bo-nzdusd.set b/bo-nzdusd.set index 9767451..cabd97b 100644 --- a/bo-nzdusd.set +++ b/bo-nzdusd.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444006 diff --git a/bo-steady.set b/bo-steady.set index 77edef1..73ed434 100644 --- a/bo-steady.set +++ b/bo-steady.set @@ -57,6 +57,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === Session Notes === ; Lower volatility = smaller moves but more frequent breakouts of ATR range ; Tight SL important — false breakouts common on these pairs diff --git a/bo-usdcad.set b/bo-usdcad.set index 1a2db3a..fdee4f0 100644 --- a/bo-usdcad.set +++ b/bo-usdcad.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444007 diff --git a/bo-usdchf.set b/bo-usdchf.set index 1b8ea45..248960a 100644 --- a/bo-usdchf.set +++ b/bo-usdchf.set @@ -55,6 +55,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444008 diff --git a/bo-usdjpy.set b/bo-usdjpy.set index 2a7cb53..084aeb2 100644 --- a/bo-usdjpy.set +++ b/bo-usdjpy.set @@ -54,6 +54,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=10 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444003 diff --git a/bo-volatile.set b/bo-volatile.set index 0ec08c1..d864cd5 100644 --- a/bo-volatile.set +++ b/bo-volatile.set @@ -56,6 +56,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === Session Notes === ; GBPJPY/XAUUSD can gap 200+ pts — BO suits them well but cut losses fast ; Monitor DiagnosticMode output on first few trades diff --git a/bo-xagusd.set b/bo-xagusd.set index bfae760..7cbd3ab 100644 --- a/bo-xagusd.set +++ b/bo-xagusd.set @@ -60,6 +60,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444014 diff --git a/bo-xauusd.set b/bo-xauusd.set index 4031a88..7cb06ff 100644 --- a/bo-xauusd.set +++ b/bo-xauusd.set @@ -55,6 +55,12 @@ InpWeekendCloseHour=7 InpCancelPendingBeforeWeekend=true InpMondayStartHour=7 +; === Thursday Wind-Down === +InpUseWinddown=true +InpWinddownStartHour=19 +InpWinddownTrailStart=200 +InpWinddownTrailStop=150 + ; === EA Settings === MagicNum=444013