117 lines
No EOL
4.5 KiB
MQL5
117 lines
No EOL
4.5 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Candle Range |
|
|
//| Copyright © 2025 Wolfforex.com|
|
|
//| https://www.wolfforex.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "www.Wolfforex.com, 2024"
|
|
#property version "1.01"
|
|
|
|
#property description "Candle Range - displays candle's pip range on mouseover."
|
|
#property description "Modifiable font parameters, location, and normalization."
|
|
|
|
#property indicator_chart_window
|
|
#property indicator_plots 0
|
|
|
|
input bool ShowBodySize = false; // ShowBodySize: if true, body size will be shown too.
|
|
input bool HavePipettes = false; // HavePipettes: if true, ranges will be divided by 10.
|
|
input bool TrueRange = false; // TrueRange: if true, use true range formula.
|
|
input color font_color = clrLightGray;
|
|
input int font_size = 10;
|
|
input string font_face = "Verdana";
|
|
input ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER;
|
|
input int distance_x = 3;
|
|
input int distance_y = 12;
|
|
input bool DrawTextAsBackground = false; //DrawTextAsBackground: if true, the text will be drawn as background.
|
|
input string ObjectPrefix = "CR-";
|
|
|
|
int n_digits = 0;
|
|
double divider = 1;
|
|
|
|
void OnInit()
|
|
{
|
|
ObjectCreate(ChartID(), ObjectPrefix + "Range", OBJ_LABEL, 0, 0, 0);
|
|
ObjectSetString(ChartID(), ObjectPrefix + "Range", OBJPROP_TEXT, "");
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_FONTSIZE, font_size);
|
|
ObjectSetString(ChartID(), ObjectPrefix + "Range", OBJPROP_FONT, font_face);
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_COLOR, font_color);
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_CORNER, corner);
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_XDISTANCE, distance_x);
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_YDISTANCE, distance_y);
|
|
ObjectSetInteger(ChartID(), ObjectPrefix + "Range", OBJPROP_BACK, DrawTextAsBackground);
|
|
|
|
if (HavePipettes)
|
|
{
|
|
divider = 10;
|
|
n_digits = 1;
|
|
}
|
|
|
|
// Enable mouse move events for the chart.
|
|
ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_MOVE, true);
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
ObjectDelete(ChartID(), ObjectPrefix + "Range");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void OutputRange(double range, double body)
|
|
{
|
|
string text = "Range: " + DoubleToString(Normalize(range), n_digits);
|
|
if (ShowBodySize) text += " Body: " + DoubleToString(Normalize(body), n_digits);
|
|
ObjectSetString(ChartID(), ObjectPrefix + "Range", OBJPROP_TEXT, text);
|
|
ChartRedraw();
|
|
}
|
|
|
|
double Normalize(double distance)
|
|
{
|
|
return NormalizeDouble(distance / _Point / divider, n_digits);
|
|
}
|
|
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
if (id == CHARTEVENT_MOUSE_MOVE)
|
|
{
|
|
int subwindow;
|
|
datetime time;
|
|
double price;
|
|
ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, subwindow, time, price);
|
|
int i = iBarShift(Symbol(), Period(), time, true);
|
|
if (i < 0) return;
|
|
static double prev_range = 0;
|
|
static double prev_body = 0;
|
|
double range = iHigh(Symbol(), Period(), i) - iLow(Symbol(), Period(), i);
|
|
if (TrueRange)
|
|
{
|
|
double range0 = 0;
|
|
if (i < iBars(Symbol(), Period()) - 1) // Otherwise cannot calculate range0.
|
|
{
|
|
range0 = MathMax(MathAbs(iClose(Symbol(), Period(), i + 1) - iHigh(Symbol(), Period(), i)), MathAbs(iClose(Symbol(), Period(), i + 1) - iLow(Symbol(), Period(), i)));
|
|
}
|
|
range = MathMax(range, range0);
|
|
}
|
|
double body = MathAbs(iOpen(Symbol(), Period(), i) - iClose(Symbol(), Period(), i));
|
|
if ((range == prev_range) && (body == prev_body)) return; // Optimization to avoid updating the range object when nothing changed.
|
|
prev_range = range;
|
|
prev_body = body;
|
|
OutputRange(range, body);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |