Creation of Atr haldle manger and other methods

This commit is contained in:
Matt Corcoran
2025-07-11 16:30:06 +02:00
parent 7de4cf3cb6
commit ec3fc120ce
9 changed files with 516 additions and 367 deletions
+89 -83
View File
@@ -1,139 +1,145 @@
#include <MyLibs/Utils/MarketDataUtils.mqh>
#include <MyLibs/Utils/AtrHandleManager.mqh>
class AtrBands {
private:
private:
MarketDataUtils market_data_utils;
AtrHandleManager atr_manager;
public:
public:
// Core band accessors
double upper_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1,
color clr = clrDodgerBlue, int width = 1, bool plot = true);
double lower_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1,
color clr = clrDodgerBlue, int width = 1, bool plot = true);
double middle_band(string symbol, double trendline_var, ENUM_TIMEFRAMES tf, int shift = 1, color clr = clrDodgerBlue, int width = 1,
bool plot = true);
double upper_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
double lower_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
double middle_band(string symbol, double trendline_var, ENUM_TIMEFRAMES tf, int shift = 1);
// Band checkers
bool inside_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1, bool plot = true);
bool inside_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
bool inside_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
bool crossed_below_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
bool crossed_above_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1);
bool inside_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1, bool plot = true);
// Plotting
void plot_bands(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int bars = 100, color clr = clrSkyBlue, int width = 1);
bool crossed_below_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1,
bool plot = true);
bool crossed_above_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult = 1.0, int shift = 1,
bool plot = true);
protected:
protected:
double get_atr(string symbol, int atr_period, ENUM_TIMEFRAMES tf, int shift);
void draw_line(string name, double price, color clr, int width);
};
// -------------------
// Public Methods
// -------------------
double AtrBands::upper_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, color clr, int width, bool plot) {
double AtrBands::upper_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double atr = get_atr(symbol, atr_period, tf, shift);
double upper = trendline_var + atr * mult;
if (plot && shift == 1) draw_line("ATRBand_Upper_" + symbol, upper, clr, width); // persistent line
return upper;
return trendline_var + atr * mult;
}
double AtrBands::lower_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, color clr, int width, bool plot) {
double AtrBands::lower_band(string symbol, double trendline_var, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double atr = get_atr(symbol, atr_period, tf, shift);
double lower = trendline_var - atr * mult;
if (plot && shift == 1) draw_line("ATRBand_Lower_" + symbol, lower, clr, width); // persistent line
return lower;
return trendline_var - atr * mult;
}
double AtrBands::middle_band(string symbol, double trendline_var, ENUM_TIMEFRAMES tf, int shift, color clr, int width, bool plot) {
if (plot && shift == 1) draw_line("ATRBand_Mid_" + symbol, trendline_var, clr, width); // persistent line
double AtrBands::middle_band(string symbol, double trendline_var, ENUM_TIMEFRAMES tf, int shift) {
return trendline_var;
}
bool AtrBands::inside_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, bool plot) {
bool AtrBands::inside_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double price = iClose(symbol, tf, shift);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double upper = upper_band(symbol, trendline_var, atr_period, tf, mult, shift, clrDodgerBlue, 1, plot);
double upper = upper_band(symbol, trendline_var, atr_period, tf, mult, shift);
if (price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || upper == EMPTY_VALUE) return false;
return (price > trendline_var && price < upper);
}
bool AtrBands::inside_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, bool plot) {
bool AtrBands::inside_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double price = iClose(symbol, tf, shift);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double lower = lower_band(symbol, trendline_var, atr_period, tf, mult, shift, clrDodgerBlue, 1, plot);
double lower = lower_band(symbol, trendline_var, atr_period, tf, mult, shift);
if (price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || lower == EMPTY_VALUE) return false;
return (price < trendline_var && price > lower);
}
// pull-back inside upper atr band:
bool AtrBands::crossed_below_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, bool plot) {
//--- checked bar
bool AtrBands::crossed_below_upper_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double price = iClose(symbol, tf, shift);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double atr_upper_band = upper_band(symbol, trendline_var, atr_period, tf, mult, shift, clrDodgerBlue, 1, plot);
//--- previous bar
double prev_price = iClose(symbol, tf, shift + 1);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double prev_trendline_var = market_data_utils.get_buffer_value(handle, shift + 1);
double prev_atr_upper_band = upper_band(symbol, prev_trendline_var, atr_period, tf, mult, shift + 1, clrDodgerBlue, 1, plot);
if (price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || atr_upper_band == EMPTY_VALUE || prev_price == EMPTY_VALUE
|| prev_trendline_var == EMPTY_VALUE || prev_atr_upper_band == EMPTY_VALUE) return false;
double upper = upper_band(symbol, trendline_var, atr_period, tf, mult, shift);
double prev_upper = upper_band(symbol, prev_trendline_var, atr_period, tf, mult, shift + 1);
return (prev_price > prev_atr_upper_band && price < atr_upper_band);
if (price == EMPTY_VALUE || prev_price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || prev_trendline_var == EMPTY_VALUE) return false;
return (prev_price > prev_upper && price < upper);
}
// pull-back inside lower atr band:
bool AtrBands::crossed_above_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift, bool plot) {
//--- checked bar
bool AtrBands::crossed_above_lower_band(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int shift) {
double price = iClose(symbol, tf, shift);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double atr_lower_band = lower_band(symbol, trendline_var, atr_period, tf, mult, shift, clrDodgerBlue, 1, plot);
//--- previous bar
double prev_price = iClose(symbol, tf, shift + 1);
double trendline_var = market_data_utils.get_buffer_value(handle, shift);
double prev_trendline_var = market_data_utils.get_buffer_value(handle, shift + 1);
double prev_atr_lower_band = lower_band(symbol, prev_trendline_var, atr_period, tf, mult, shift + 1, clrDodgerBlue, 1, plot);
if (price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || atr_lower_band == EMPTY_VALUE || prev_price == EMPTY_VALUE
|| prev_trendline_var == EMPTY_VALUE || prev_atr_lower_band == EMPTY_VALUE) return false;
double lower = lower_band(symbol, trendline_var, atr_period, tf, mult, shift);
double prev_lower = lower_band(symbol, prev_trendline_var, atr_period, tf, mult, shift + 1);
return (prev_price < prev_atr_lower_band && price > atr_lower_band);
if (price == EMPTY_VALUE || prev_price == EMPTY_VALUE || trendline_var == EMPTY_VALUE || prev_trendline_var == EMPTY_VALUE) return false;
return (prev_price < prev_lower && price > lower);
}
// -------------------
// Internal Helpers
// -------------------
void AtrBands::plot_bands(string symbol, int handle, int atr_period, ENUM_TIMEFRAMES tf, double mult, int bars, color line_color, int width) {
for (int i = bars; i >= 1; i--) {
double trendline = market_data_utils.get_buffer_value(handle, i);
if (trendline == EMPTY_VALUE) continue;
double atr = get_atr(symbol, atr_period, tf, i);
if (atr == EMPTY_VALUE) continue;
double upper = trendline + atr * mult;
double lower = trendline - atr * mult;
datetime time1 = iTime(symbol, tf, i);
datetime time2 = iTime(symbol, tf, i - 1);
string upper_name = "ATR_Upper_" + symbol + "_" + TimeToString(time1, TIME_DATE | TIME_MINUTES);
string lower_name = "ATR_Lower_" + symbol + "_" + TimeToString(time1, TIME_DATE | TIME_MINUTES);
string middle_name = "ATR_middle_" + symbol + "_" + TimeToString(time1, TIME_DATE | TIME_MINUTES);
if (ObjectFind(0, upper_name) < 0) {
ObjectCreate(0, upper_name, OBJ_TREND, 0, time1, upper, time2, upper);
ObjectSetInteger(0, upper_name, OBJPROP_COLOR, line_color);
ObjectSetInteger(0, upper_name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, upper_name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, upper_name, OBJPROP_BACK, true);
ObjectSetInteger(0, upper_name, OBJPROP_SELECTED, false);
}
if (ObjectFind(0, lower_name) < 0) {
ObjectCreate(0, lower_name, OBJ_TREND, 0, time1, lower, time2, lower);
ObjectSetInteger(0, lower_name, OBJPROP_COLOR, line_color);
ObjectSetInteger(0, lower_name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, lower_name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, lower_name, OBJPROP_BACK, true);
ObjectSetInteger(0, lower_name, OBJPROP_SELECTED, false);
}
if (ObjectFind(0, middle_name) < 0) {
ObjectCreate(0, middle_name, OBJ_TREND, 0, time1, trendline, time2, trendline);
ObjectSetInteger(0, middle_name, OBJPROP_COLOR, line_color);
ObjectSetInteger(0, middle_name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, middle_name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, middle_name, OBJPROP_BACK, true);
ObjectSetInteger(0, middle_name, OBJPROP_SELECTED, false);
}
}
ChartRedraw();
}
double AtrBands::get_atr(string symbol, int atr_period, ENUM_TIMEFRAMES tf, int shift) {
int handle = iATR(symbol, tf, atr_period);
if (handle == INVALID_HANDLE) {
Print("Failed to create ATR handle for ", symbol);
return 0.0;
}
double buf[];
ArraySetAsSeries(buf, true);
if (CopyBuffer(handle, 0, shift, 1, buf) == 1 && buf[0] != EMPTY_VALUE) return buf[0];
return 0.0;
}
void AtrBands::draw_line(string name, double price, color clr, int width) {
if (ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
} else {
ObjectSetDouble(0, name, OBJPROP_PRICE, price);
}
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
return atr_manager.get_atr_value(symbol, tf, atr_period, shift);
}
+5 -5
View File
@@ -13,16 +13,16 @@ class TrendlineAnalyser {
// - handle: the indicator handle for the trendline (e.g., iMA handle)
// - cross_long: output bool set to true if a bullish cross is detected
// - cross_short: output bool set to true if a bearish cross is detected
void detect_cross(string symbol, int handle, bool& cross_long, bool& cross_short) {
void detect_cross(string symbol, int handle, bool& cross_long, bool& cross_short, int shift=1) {
cross_long = false;
cross_short = false;
// --- Retrieve prices and trendline values from last 2 closed bars
double price = iClose(symbol, PERIOD_CURRENT, 1); // most recent closed bar
double prev_price = iClose(symbol, PERIOD_CURRENT, 2); // bar before that
double price = iClose(symbol, PERIOD_CURRENT, shift); // most recent closed bar
double prev_price = iClose(symbol, PERIOD_CURRENT, shift + 1); // bar before that
double trendline = market_data_utils.get_buffer_value(handle, 1); // trendline now
double prev_trendline = market_data_utils.get_buffer_value(handle, 2); // trendline before
double trendline = market_data_utils.get_buffer_value(handle, shift); // trendline now
double prev_trendline = market_data_utils.get_buffer_value(handle, shift+1); // trendline before
// --- Exit early if any of the data is missing or invalid
if (price == EMPTY_VALUE || prev_price == EMPTY_VALUE || trendline == EMPTY_VALUE || prev_trendline == EMPTY_VALUE) {