finding-average-true-spreads/Average True Spread.mq4

140 lines
11 KiB
MQL4


//+-----------------------------------------------------------------+
//+------------------------------------------------------------------+
//| AverageTrueSpreadLabel.mq4 |
//| Enhanced version with zero errors/warnings|
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
//--- input parameters
input ENUM_TIMEFRAMES SpreadTimeframe = PERIOD_H1; // Timeframe for simulated spread
input int CandlesCount = 20; // Bars for average
input int UpdateIntervalSeconds = 5; // Refresh rate
input color LabelColor = clrWhite; // Text color
input int FontSize = 12; // Font size
input string FontName = "Arial"; // Font type
input bool ShowLiveSpread = true; // Toggle for live spread display
input int LabelCorner = CORNER_LEFT_UPPER; // Chart corner
input int LabelXOffset = 10;
input int LabelYOffset = 20;
input int LabelLineSpacing = 20; // Space between lines
//--- label identifiers
string avgLabel = "AVG_SPREAD_LABEL";
string liveLabel = "LIVE_SPREAD_LABEL";
string warnLabel = "SPREAD_WARN_LABEL";
//+------------------------------------------------------------------+
//| Initialization |
//+------------------------------------------------------------------+
int OnInit()
{
EventSetTimer(UpdateIntervalSeconds);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
ObjectDelete(0, avgLabel);
ObjectDelete(0, liveLabel);
ObjectDelete(0, warnLabel);
}
//+------------------------------------------------------------------+
//| Timer-driven label update |
//+------------------------------------------------------------------+
void OnTimer()
{
int m1Bars = iBars(Symbol(), PERIOD_M1);
if (m1Bars < CandlesCount + 5)
{
DrawLabel(warnLabel, "M1 data missing – load M1 chart!", LabelCorner, LabelXOffset, LabelYOffset, clrRed);
ObjectDelete(0, avgLabel);
ObjectDelete(0, liveLabel);
return;
}
else
{
ObjectDelete(0, warnLabel);
}
double avgSpread = CalculateAverageSpread();
double liveSpread = MarketInfo(Symbol(), MODE_SPREAD) / 10.0;
string avgText = StringFormat("Avg Spread (%s, %d bars): %.1f pips", EnumToString(SpreadTimeframe), CandlesCount, avgSpread);
string liveText = StringFormat("Live Spread: %.1f pips", liveSpread);
DrawLabel(avgLabel, avgText, LabelCorner, LabelXOffset, LabelYOffset, LabelColor);
if (ShowLiveSpread)
DrawLabel(liveLabel, liveText, LabelCorner, LabelXOffset, LabelYOffset + LabelLineSpacing, LabelColor);
else
ObjectDelete(0, liveLabel);
}
//+------------------------------------------------------------------+
//| Calculate average simulated spread via M1 bars |
//+------------------------------------------------------------------+
double CalculateAverageSpread()
{
double totalSpread = 0;
int counted = 0;
datetime startTime = iTime(Symbol(), SpreadTimeframe, 0) - CandlesCount * PeriodSeconds(SpreadTimeframe);
int totalBars = iBars(Symbol(), PERIOD_M1);
for (int i = 0; i < totalBars && counted < CandlesCount; i++)
{
datetime barTime = iTime(Symbol(), PERIOD_M1, i);
if (barTime < startTime || barTime == 0) break;
double high = iHigh(Symbol(), PERIOD_M1, i);
double low = iLow(Symbol(), PERIOD_M1, i);
if (high == 0 || low == 0) continue;
double spread = (high - low) / Point / 10.0;
totalSpread += spread;
counted++;
}
if (counted == 0) return 0;
return totalSpread / counted;
}
//+------------------------------------------------------------------+
//| Draw or update text label |
//+------------------------------------------------------------------+
void DrawLabel(string name, string text, int corner, int x_offset, int y_offset, color clr)
{
if (!ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0))
ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x_offset);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y_offset);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetString(0, name, OBJPROP_FONT, FontName);
ObjectSetString(0, name, OBJPROP_TEXT, text);
}
//+------------------------------------------------------------------+
//| Dummy OnCalculate to fulfill compiler requirement |
//+------------------------------------------------------------------+
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[])
{
return(rates_total); // no action needed
}