//+------------------------------------------------------------------+ //| Forward Simulation_V2.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/johnhlomohang/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/johnhlomohang/" #property version "2.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_label1 "Fast EMA" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #property indicator_label2 "Slow EMA" #property indicator_type2 DRAW_LINE #property indicator_color2 clrOrangeRed #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //+------------------------------------------------------------------+ //| INDICATOR BUFFERS | //+------------------------------------------------------------------+ double FastEMABuffer[]; double SlowEMABuffer[]; //+------------------------------------------------------------------+ //| INPUT PARAMETERS | //+------------------------------------------------------------------+ input int FastEMA_Period = 9; // Fast EMA period input int SlowEMA_Period = 21; // Slow EMA period input int FutureBars = 30; // Number of future candles to project input double SpreadMultiplier = 2.0; // Wick size multiplier input bool AutoAnchor = true; // Auto-move anchor to latest cross bar input string AnchorLineName = "FSE_Anchor"; // Anchor vertical line name input color BullishColor = clrDodgerBlue; // Bullish body color input color BearishColor = clrCrimson; // Bearish body color input color WickColor = clrDimGray; // Wick color input bool ShowZoneLabel = true; // Show projection label input bool ShowSeparatorLine = true; // Show dashed separator at anchor input int InvalidationPips = 10; // Pip distance to trigger invalidation input double CandleGapFraction = 0.08; // Gap between candles as fraction of bar width (0.04–0.20) input int CounterCandleFreq = 4; // Insert 1 counter-trend candle every N candles (min 3) input int AvgLookback = 50; // Bars used to measure average candle size //+------------------------------------------------------------------+ //| STRUCTS | //+------------------------------------------------------------------+ struct PredictedCandle { double open; double high; double low; double close; bool bullish; }; //+------------------------------------------------------------------+ //| GLOBALS | //+------------------------------------------------------------------+ int g_FastHandle = INVALID_HANDLE; int g_SlowHandle = INVALID_HANDLE; int g_LastSignal = 0; // +1 bull, -1 bear, 0 none bool g_SignalActive = false; double g_SignalPrice = 0.0; datetime g_SignalBarTime = 0; datetime g_DrawnAnchor = 0; // anchor time of the last successful draw //--- Measured average candle metrics (refreshed on each new signal) double g_AvgBody = 0.0; // average |close - open| over AvgLookback bars double g_AvgUpperWick = 0.0; // average (high - max(open,close)) double g_AvgLowerWick = 0.0; // average (min(open,close) - low) double g_AvgRange = 0.0; // average (high - low) – full candle height //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Bind and configure the two visible EMA plot buffers SetIndexBuffer(0, FastEMABuffer, INDICATOR_DATA); SetIndexBuffer(1, SlowEMABuffer, INDICATOR_DATA); ArraySetAsSeries(FastEMABuffer, false); ArraySetAsSeries(SlowEMABuffer, false); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, FastEMA_Period); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, SlowEMA_Period); //--- Internal calculation handles g_FastHandle = iMA(_Symbol, _Period, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE); g_SlowHandle = iMA(_Symbol, _Period, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE); if(g_FastHandle == INVALID_HANDLE || g_SlowHandle == INVALID_HANDLE) { Print("ForwardSimEngine [ERROR]: iMA handle creation failed. " "Symbol=", _Symbol, " TF=", EnumToString(_Period)); return INIT_FAILED; } Print("ForwardSimEngine [INIT]: OK FastEMA=", FastEMA_Period, " SlowEMA=", SlowEMA_Period, " FutureBars=", FutureBars, " InvalidationPips=", InvalidationPips, " AvgLookback=", AvgLookback); //--- Pre-compute average candle metrics from history CalcAvgCandleMetrics(); EventSetTimer(3); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); CleanAllObjects(); Print("ForwardSimEngine [DEINIT]: objects cleaned, reason=", reason); } //+-----------------------------------------------------------------------+ //| ON CALCULATE | //+-----------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < SlowEMA_Period + 5) { Print("ForwardSimEngine [WARN]: Not enough bars: ", rates_total); return 0; } //--- How many bars to (re)calculate int limit = (prev_calculated > 1) ? rates_total - prev_calculated + 1 : rates_total; //--- Start index in the buffer (oldest bar that needs updating) int startBar = rates_total - limit; //--- Local arrays for engine logic double tmpFast[], tmpSlow[]; ArraySetAsSeries(tmpFast, false); ArraySetAsSeries(tmpSlow, false); ArrayResize(tmpFast, rates_total); ArrayResize(tmpSlow, rates_total); //--- Copy ALL bars into local arrays (needed by RunEngine for crossover) int copiedFast = CopyBuffer(g_FastHandle, 0, 0, rates_total, tmpFast); int copiedSlow = CopyBuffer(g_SlowHandle, 0, 0, rates_total, tmpSlow); if(copiedFast <= 0 || copiedSlow <= 0) { Print("ForwardSimEngine [WARN]: CopyBuffer returned <=0. fast=", copiedFast, " slow=", copiedSlow); return prev_calculated; } /* Write into plot buffers ONLY within the confirmed copied range and only within what MT5 has allocated (ArraySize guard).*/ int bufSzFast = ArraySize(FastEMABuffer); int bufSzSlow = ArraySize(SlowEMABuffer); int safeFast = MathMin(copiedFast, bufSzFast); int safeSlow = MathMin(copiedSlow, bufSzSlow); for(int i = startBar; i < safeFast; i++) FastEMABuffer[i] = tmpFast[i]; for(int i = startBar; i < safeSlow; i++) SlowEMABuffer[i] = tmpSlow[i]; // ── Run the simulation engine ───────────────────────────────── RunEngine(rates_total, time, close, tmpFast, tmpSlow); return rates_total; } //+------------------------------------------------------------------+ //| ON TIMER | //+------------------------------------------------------------------+ void OnTimer() { // If user moved the anchor manually, force a redraw on next tick if(!AutoAnchor) { datetime curAnchor = GetAnchorTime(); if(curAnchor != g_DrawnAnchor && curAnchor != 0) { g_DrawnAnchor = 0; ChartRedraw(); } } } //+------------------------------------------------------------------+ //| CALC AVERAGE CANDLE METRICS | //+------------------------------------------------------------------+ void CalcAvgCandleMetrics() { int lookback = (AvgLookback < 10) ? 10 : AvgLookback; // minimum 10 bars double hiBuf[], loBuf[], opBuf[], clBuf[]; ArraySetAsSeries(hiBuf, true); ArraySetAsSeries(loBuf, true); ArraySetAsSeries(opBuf, true); ArraySetAsSeries(clBuf, true); //--- Copy starting at shift 1 (skip the live bar), going back lookback bars int copiedH = CopyHigh(_Symbol, _Period, 1, lookback, hiBuf); int copiedL = CopyLow(_Symbol, _Period, 1, lookback, loBuf); int copiedO = CopyOpen(_Symbol, _Period, 1, lookback, opBuf); int copiedC = CopyClose(_Symbol, _Period, 1, lookback, clBuf); int n = MathMin(MathMin(copiedH, copiedL), MathMin(copiedO, copiedC)); if(n <= 0) { Print("ForwardSimEngine [AVG]: CopyPrice failed, keeping previous averages."); return; } double sumBody = 0, sumUWick = 0, sumLWick = 0, sumRange = 0; for(int i = 0; i < n; i++) { double bodyTop = MathMax(opBuf[i], clBuf[i]); double bodyBot = MathMin(opBuf[i], clBuf[i]); sumBody += bodyTop - bodyBot; sumUWick += hiBuf[i] - bodyTop; sumLWick += bodyBot - loBuf[i]; sumRange += hiBuf[i] - loBuf[i]; } double pip = _Point * 10.0; // 1 pip floor g_AvgBody = MathMax(sumBody / n, pip); g_AvgUpperWick = MathMax(sumUWick / n, pip * 0.5); g_AvgLowerWick = MathMax(sumLWick / n, pip * 0.5); g_AvgRange = MathMax(sumRange / n, pip * 2.0); Print("ForwardSimEngine [AVG]: lookback=", n, " AvgBody=", DoubleToString(g_AvgBody / _Point, 1), " pts", " AvgUpperWick=", DoubleToString(g_AvgUpperWick / _Point, 1), " pts", " AvgLowerWick=", DoubleToString(g_AvgLowerWick / _Point, 1), " pts", " AvgRange=", DoubleToString(g_AvgRange / _Point, 1), " pts"); } //+------------------------------------------------------------------+ //| CORE ENGINE | //| All arrays: index 0 = oldest, rates_total-1 = live forming bar | //| rates_total-2 = last fully closed bar (bar index 1) | //| rates_total-3 = bar before that (bar index 2) | //+------------------------------------------------------------------+ void RunEngine(const int rates_total, const datetime &time[], const double &close[], const double &fastBuf[], const double &slowBuf[]) { int barLive = rates_total - 1; // live/forming bar int barClosed = rates_total - 2; // last fully closed bar int barPrev = rates_total - 3; // bar before that if(barPrev < SlowEMA_Period) return; //--- 1. Crossover detection //--- We look at the two most recently CLOSED bars (barPrev and barClosed). //--- Cross occurs when the fast EMA crossed over the slow EMA between them. double fCur = fastBuf[barClosed]; double fPrev = fastBuf[barPrev]; double sCur = slowBuf[barClosed]; double sPrev = slowBuf[barPrev]; int newSignal = 0; if(fPrev <= sPrev && fCur > sCur) newSignal = 1; // bullish if(fPrev >= sPrev && fCur < sCur) newSignal = -1; // bearish //--- Heartbeat log (first 3 ticks + every new signal) static int s_ticks = 0; s_ticks++; if(s_ticks <= 3 || newSignal != 0) { Print("ForwardSimEngine [TICK #", s_ticks, "]", " fCur=", DoubleToString(fCur, _Digits), " sCur=", DoubleToString(sCur, _Digits), " gap=", DoubleToString(fCur - sCur, _Digits), " newSig=", newSignal, " active=", g_SignalActive, " lastSig=",g_LastSignal); } //--- 2. Latch new signal if(newSignal != 0) { g_LastSignal = newSignal; g_SignalActive = true; g_SignalPrice = close[barClosed]; g_SignalBarTime = time[barClosed]; g_DrawnAnchor = 0; // force full redraw /* Refresh measured candle averages at the moment of the signal so the projection uses the most recent volatility context. */ CalcAvgCandleMetrics(); Print("ForwardSimEngine [SIGNAL]: ", (newSignal == 1 ? ">>> BULLISH CROSS <<<" : ">>> BEARISH CROSS <<<"), " bar=", TimeToString(g_SignalBarTime), " px=", DoubleToString(g_SignalPrice, _Digits)); } //--- 3. Invalidation check if(g_SignalActive) { double livePx = close[barLive]; //--- 1 pip = 10 * _Point for a 5-digit broker (covers 3-digit too) double pipSize = _Point * 10.0; double thresh = InvalidationPips * pipSize; bool inv = false; if(g_LastSignal == 1 && livePx < g_SignalPrice - thresh) inv = true; if(g_LastSignal == -1 && livePx > g_SignalPrice + thresh) inv = true; if(inv) { Print("ForwardSimEngine [INVALIDATED]", " signalPx=", DoubleToString(g_SignalPrice, _Digits), " livePx=", DoubleToString(livePx, _Digits), " thresh=", DoubleToString(thresh, _Digits)); g_SignalActive = false; g_LastSignal = 0; g_DrawnAnchor = 0; CleanAllObjects(); DrawInvalidationLabel(g_SignalBarTime, g_SignalPrice); ChartRedraw(); return; } } //--- 4. Only draw/redraw when there is an active signal if(!g_SignalActive || g_LastSignal == 0) return; datetime anchorTime = (AutoAnchor) ? g_SignalBarTime : GetAnchorTime(); if(anchorTime == 0) anchorTime = g_SignalBarTime; //--- Skip if already drawn at this anchor if(anchorTime == g_DrawnAnchor) return; g_DrawnAnchor = anchorTime; //--- 5. Build synthetic candles double emaSlope = fCur - fPrev; PredictedCandle pred[]; ArrayResize(pred, FutureBars); GeneratePrediction(close[barClosed], emaSlope, pred); //--- 6. Render CleanAllObjects(); DrawAllCandles(anchorTime, pred); if(ShowSeparatorLine) DrawSeparator(anchorTime); if(ShowZoneLabel) DrawZoneLabel(anchorTime, close[barClosed]); UpdateAnchorLine(anchorTime); ChartRedraw(); Print("ForwardSimEngine [DRAWN]", " signal=", g_LastSignal, " anchor=", TimeToString(anchorTime), " bars=", FutureBars, " slope=", DoubleToString(emaSlope, _Digits)); } //+------------------------------------------------------------------+ //| PREDICTION ENGINE | //+------------------------------------------------------------------+ void GeneratePrediction(double startPrice, double emaSlope, PredictedCandle &out[]) { MathSrand((int)(TimeLocal() % 32767)); int n = ArraySize(out); int sig = g_LastSignal; // +1 bull, -1 bear double pip = _Point * 10.0; //--- Baseline body size from measured history //--- Guard: if CalcAvgCandleMetrics hasn't run yet use a pip floor double avgBody = (g_AvgBody > pip) ? g_AvgBody : pip * 3.0; double avgUWick = (g_AvgUpperWick > 0) ? g_AvgUpperWick : avgBody * 0.5; double avgLWick = (g_AvgLowerWick > 0) ? g_AvgLowerWick : avgBody * 0.5; //--- EMA-slope momentum scale: 0.5× (weak) … 1.5× (strong) //--- Normalise slope against avgBody so it is always unit-consistent double slopeAbs = MathAbs(emaSlope); double slopeRatio = slopeAbs / avgBody; // 0 = flat, 1 = slope equals avg body //--- Clamp to a ±0.5 band around 1.0 double momentumScale = 0.5 + MathMin(slopeRatio, 1.0); // 0.5 … 1.5 //--- baseStep = what one average trend-direction candle body should be double baseStep = avgBody * momentumScale; //--- Counter-candle frequency guard int ccFreq = (CounterCandleFreq < 3) ? 3 : CounterCandleFreq; double prevClose = startPrice; for(int i = 0; i < n; i++) { //--- Sine envelope: body pulses between 40% and 130% of baseStep double phase = (double)i / (double)n * 2.0 * M_PI; double sinSq = MathSin(phase) * MathSin(phase); // 0 … 1 double envelope = 0.40 + 0.90 * sinSq; // 0.40 … 1.30 //--- Exponential decay: projection flattens toward the tail double decay = MathPow(0.93, i); //--- Body for this candle double bodySize = baseStep * envelope * decay; //--- ±8% random jitter double jitter = 1.0 + ((double)(MathRand() % 160) - 80.0) * 0.001; bodySize *= jitter; //--- Hard floor: at least 0.5 × avgBody so candles are always visible if(bodySize < avgBody * 0.5) bodySize = avgBody * 0.5; //--- Counter-trend injection every ccFreq bars bool isCounter = (i > 0 && (i % ccFreq == 0)); double retracePct = 0.25 + (MathRand() % 21) * 0.01; // 0.25–0.45 double step; if(isCounter) step = -(double)sig * bodySize * retracePct; else step = (double)sig * bodySize; //--- OHLC out[i].open = prevClose; out[i].close = prevClose + step; out[i].bullish = (out[i].close >= out[i].open); double bodyTop = MathMax(out[i].open, out[i].close); double bodyBot = MathMin(out[i].open, out[i].close); double bHeight = bodyTop - bodyBot; if(bHeight < _Point) bHeight = _Point; //--- Wicks anchored to measured avg wick ratios //--- Base ratio = avgWick / avgBody, then add ±25% random spread double uRatioBase = avgUWick / avgBody; double lRatioBase = avgLWick / avgBody; double uJitter = 1.0 + ((double)(MathRand() % 50) - 25.0) * 0.01; // ±25% double lJitter = 1.0 + ((double)(MathRand() % 50) - 25.0) * 0.01; double upWick = bHeight * uRatioBase * uJitter; double dnWick = bHeight * lRatioBase * lJitter; //--- Trend bias: the shadow in the signal direction is slightly longer if(out[i].bullish) upWick *= 1.20; else dnWick *= 1.20; //--- Minimum wick: 20% of body height if(upWick < bHeight * 0.20) upWick = bHeight * 0.20; if(dnWick < bHeight * 0.20) dnWick = bHeight * 0.20; out[i].high = bodyTop + upWick; out[i].low = bodyBot - dnWick; prevClose = out[i].close; } } //+------------------------------------------------------------------+ //| DRAW ALL CANDLES – project one bar-width ahead of anchor | //+------------------------------------------------------------------+ void DrawAllCandles(datetime startTime, PredictedCandle &candles[]) { int barSec = PeriodSeconds(); int total = ArraySize(candles); //--- Gap in seconds on each side of the body (max 45% each side) double gapFrac = CandleGapFraction; if(gapFrac < 0.01) gapFrac = 0.01; if(gapFrac > 0.45) gapFrac = 0.45; int gapSec = (int)(barSec * gapFrac); for(int i = 0; i < total; i++) { //--- Slot boundaries (full bar width) datetime slotStart = startTime + (datetime)((i + 1) * barSec); datetime slotEnd = slotStart + (datetime)barSec; //--- Body boundaries (inset by gap on each side) datetime bodyStart = slotStart + (datetime)gapSec; datetime bodyEnd = slotEnd - (datetime)gapSec; datetime bodyMid = slotStart + (datetime)(barSec / 2); // wick centre DrawSingleCandle(i, bodyStart, bodyEnd, bodyMid, candles[i]); } } //+------------------------------------------------------------------+ //| DRAW ONE CANDLE | //+------------------------------------------------------------------+ void DrawSingleCandle(int idx, datetime t1, datetime t2, datetime tMid, const PredictedCandle &c) { string pfx = "FutureCandle_" + IntegerToString(idx); color bodyCol = c.bullish ? BullishColor : BearishColor; //--- Doji guard double bOpen = c.open; double bClose = c.close; if(MathAbs(bOpen - bClose) < _Point) bClose = bOpen + (c.bullish ? _Point * 2 : -_Point * 2); //--- Filled body string nm = pfx + "_body"; ObjectDelete(0, nm); if(ObjectCreate(0, nm, OBJ_RECTANGLE, 0, t1, bOpen, t2, bClose)) { ObjectSetInteger(0, nm, OBJPROP_COLOR, bodyCol); ObjectSetInteger(0, nm, OBJPROP_FILL, true); ObjectSetInteger(0, nm, OBJPROP_BACK, false); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } //--- Body outline nm = pfx + "_bord"; ObjectDelete(0, nm); if(ObjectCreate(0, nm, OBJ_RECTANGLE, 0, t1, bOpen, t2, bClose)) { ObjectSetInteger(0, nm, OBJPROP_COLOR, bodyCol); ObjectSetInteger(0, nm, OBJPROP_FILL, false); ObjectSetInteger(0, nm, OBJPROP_BACK, false); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } //--- Upper wick (centred on full slot, not the inset body) nm = pfx + "_wU"; ObjectDelete(0, nm); double wTop = MathMax(bOpen, bClose); if(ObjectCreate(0, nm, OBJ_TREND, 0, tMid, wTop, tMid, c.high)) { ObjectSetInteger(0, nm, OBJPROP_COLOR, WickColor); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1); ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } //--- Lower wick nm = pfx + "_wD"; ObjectDelete(0, nm); double wBot = MathMin(bOpen, bClose); if(ObjectCreate(0, nm, OBJ_TREND, 0, tMid, wBot, tMid, c.low)) { ObjectSetInteger(0, nm, OBJPROP_COLOR, WickColor); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1); ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } } //+------------------------------------------------------------------+ //| SEPARATOR | //+------------------------------------------------------------------+ void DrawSeparator(datetime t) { string nm = "FSE_Sep"; ObjectDelete(0, nm); if(ObjectCreate(0, nm, OBJ_VLINE, 0, t, 0)) { ObjectSetInteger(0, nm, OBJPROP_COLOR, clrSilver); ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_DASH); ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1); ObjectSetInteger(0, nm, OBJPROP_BACK, true); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } } //+------------------------------------------------------------------+ //| ZONE LABEL | //+------------------------------------------------------------------+ void DrawZoneLabel(datetime t, double price) { string nm = "FSE_Label"; string txt = (g_LastSignal == 1) ? "[ BULLISH PROJECTION ]" : "[ BEARISH PROJECTION ]"; color col = (g_LastSignal == 1) ? BullishColor : BearishColor; ObjectDelete(0, nm); if(ObjectCreate(0, nm, OBJ_TEXT, 0, t + (datetime)PeriodSeconds(), price)) { ObjectSetString(0, nm, OBJPROP_TEXT, txt); ObjectSetInteger(0, nm, OBJPROP_COLOR, col); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 10); ObjectSetString(0, nm, OBJPROP_FONT, "Courier New"); ObjectSetInteger(0, nm, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } } //+------------------------------------------------------------------+ //| INVALIDATION LABEL | //+------------------------------------------------------------------+ void DrawInvalidationLabel(datetime t, double price) { string nm = "FSE_Invalid"; ObjectDelete(0, nm); if(ObjectCreate(0, nm, OBJ_TEXT, 0, t + (datetime)PeriodSeconds(), price)) { ObjectSetString(0, nm, OBJPROP_TEXT, "[ INVALIDATED - AWAITING NEXT CROSS ]"); ObjectSetInteger(0, nm, OBJPROP_COLOR, clrOrange); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 9); ObjectSetString(0, nm, OBJPROP_FONT, "Courier New"); ObjectSetInteger(0, nm, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, nm, OBJPROP_HIDDEN, false); } } //+------------------------------------------------------------------+ //| ANCHOR LINE HELPERS | //+------------------------------------------------------------------+ void PlaceAnchorLine(datetime t) { ObjectDelete(0, AnchorLineName); if(ObjectCreate(0, AnchorLineName, OBJ_VLINE, 0, t, 0)) { ObjectSetInteger(0, AnchorLineName, OBJPROP_COLOR, clrGold); ObjectSetInteger(0, AnchorLineName, OBJPROP_STYLE, STYLE_DASHDOTDOT); ObjectSetInteger(0, AnchorLineName, OBJPROP_WIDTH, 2); ObjectSetInteger(0, AnchorLineName, OBJPROP_SELECTABLE, true); ObjectSetInteger(0, AnchorLineName, OBJPROP_HIDDEN, false); } } //+------------------------------------------------------------------+ //| Update Anchor Line | //+------------------------------------------------------------------+ void UpdateAnchorLine(datetime t) { if(ObjectFind(0, AnchorLineName) < 0) PlaceAnchorLine(t); else ObjectSetInteger(0, AnchorLineName, OBJPROP_TIME, t); } //+------------------------------------------------------------------+ //| Get Anchor Time | //+------------------------------------------------------------------+ datetime GetAnchorTime() { if(ObjectFind(0, AnchorLineName) >= 0) return (datetime)ObjectGetInteger(0, AnchorLineName, OBJPROP_TIME); return 0; } //+------------------------------------------------------------------+ //| CLEANUP | //+------------------------------------------------------------------+ void CleanAllObjects() { ObjectsDeleteAll(0, "FutureCandle_"); ObjectsDeleteAll(0, "FSE_"); } //+------------------------------------------------------------------+