568 lines
22 KiB
MQL5
568 lines
22 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| ForwardSimEngine.mq5 |
|
|
//| Forward Simulation Engine – EMA Crossover |
|
|
//| Visualized as Predicted Future Candles (M15) |
|
|
//| Git, Copyright 2025, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com/en/users/johnhlomohang/ |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Git, Copyright 2025, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com/en/users/johnhlomohang/"
|
|
#property version "1.00"
|
|
#property indicator_chart_window
|
|
#property indicator_buffers 2
|
|
#property indicator_plots 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 = 10; // 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
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| STRUCTS |
|
|
//+------------------------------------------------------------------+
|
|
struct PredictedCandle
|
|
{
|
|
double open;
|
|
double high;
|
|
double low;
|
|
double close;
|
|
bool bullish;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GLOBAL VARS |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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);
|
|
|
|
EventSetTimer(3);
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
EventKillTimer();
|
|
CleanAllObjects();
|
|
Print("ForwardSimEngine [DEINIT]: objects cleaned, reason=", reason);
|
|
}
|
|
|
|
//+-----------------------------------------------------------------------+
|
|
//| ON CALCULATE |
|
|
//| NOTE: time[], close[] (and all price arrays) passed in here are |
|
|
//| NOT set as series – index 0 = oldest bar, rates_total-1 = newest |
|
|
//+-----------------------------------------------------------------------+
|
|
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 – we own these, safe to size freely
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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
|
|
|
|
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[])
|
|
{
|
|
//--- Wick size in price: 1 pip × multiplier × 3
|
|
double pipVal = _Point * 10.0;
|
|
double wickSz = pipVal * SpreadMultiplier * 3.0;
|
|
if(wickSz < _Point * 5)
|
|
wickSz = _Point * 5;
|
|
|
|
//--- Step direction: preserve sign from signal, floor at 3 points minimum
|
|
double direction = (g_LastSignal == 1) ? MathAbs(emaSlope) : -MathAbs(emaSlope);
|
|
if(MathAbs(direction) < _Point * 3)
|
|
direction = (g_LastSignal == 1 ? 1.0 : -1.0) * _Point * 3;
|
|
|
|
double decayBase = 0.91; // each bar's move is 91% of the previous
|
|
double prevClose = startPrice;
|
|
|
|
MathSrand((int)(TimeLocal() % 32767));
|
|
|
|
for(int i = 0; i < FutureBars; i++)
|
|
{
|
|
double decay = MathPow(decayBase, i);
|
|
double step = direction * decay;
|
|
|
|
//--- ±15% noise relative to wickSz
|
|
double noise = ((double)(MathRand() % 200) - 100.0) / 100.0 * wickSz * 0.15;
|
|
step += noise;
|
|
|
|
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);
|
|
|
|
//--- Wick: 30%–120% of wickSz
|
|
double upWk = wickSz * (0.3 + (double)(MathRand() % 90) * 0.01);
|
|
double dnWk = wickSz * (0.3 + (double)(MathRand() % 90) * 0.01);
|
|
|
|
out[i].high = bodyTop + upWk;
|
|
out[i].low = bodyBot - dnWk;
|
|
|
|
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);
|
|
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
//--- +1 so first projected candle starts ONE bar after the anchor
|
|
datetime t1 = startTime + (datetime)((i + 1) * barSec);
|
|
DrawSingleCandle(i, t1, candles[i]);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| DRAW ONE CANDLE |
|
|
//+------------------------------------------------------------------+
|
|
void DrawSingleCandle(int idx, datetime t1, const PredictedCandle &c)
|
|
{
|
|
int barSec = PeriodSeconds();
|
|
string pfx = "FutureCandle_" + IntegerToString(idx);
|
|
datetime t2 = t1 + (datetime)barSec;
|
|
datetime tMid = t1 + (datetime)(barSec / 2);
|
|
|
|
color bodyCol = c.bullish ? BullishColor : BearishColor;
|
|
|
|
//--- Doji guard: ensure body has at least 1 point height
|
|
double bOpen = c.open;
|
|
double bClose = c.close;
|
|
if(MathAbs(bOpen - bClose) < _Point)
|
|
bClose = bOpen + (c.bullish ? _Point : -_Point);
|
|
|
|
//--- 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 (unfilled rectangle)
|
|
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
|
|
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);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateAnchorLine(datetime t)
|
|
{
|
|
if(ObjectFind(0, AnchorLineName) < 0)
|
|
PlaceAnchorLine(t);
|
|
else
|
|
ObjectSetInteger(0, AnchorLineName, OBJPROP_TIME, t);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
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_");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|