StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | //+------------------------------------------------------------------+
|
| | | //| Atr.mqh|
|
| | | //| Copyright 2026, bandersoft |
|
| | | //| https://www.mql5.com/en/users/fats |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //| Average True Range helper. |
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #ifndef STOPFIRST_ATR_MQH
|
| | | #define STOPFIRST_ATR_MQH
|
| | |
|
| | | //--- GetATRPips reports its result via PriceToPips
|
| | | #include "Symbol.mqh"
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Average True Range on one symbol, timeframe and period |
|
| | | //| |
|
2026-10-16 21:48:01 +03:00 | | | //| Calling iATR, CopyBuffer and IndicatorRelease on every request |
|
| | | //| is expensive once per tick, and a handle created moments earlier |
|
| | | //| usually has no calculated data yet, so CopyBuffer fails and the |
|
| | | //| result is a silent 0 the caller cannot tell from a real reading. |
|
StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | //| |
|
| | | //| The handle is created once and held for the object's lifetime. |
|
| | | //| |
|
| | | //| CAtr atr; |
|
| | | //| int OnInit() { return atr.Init(_Symbol, PERIOD_H1, 14) ? 0 : 1; }|
|
| | | //| void OnTick() { double d = atr.Pips(); } |
|
| | | //+------------------------------------------------------------------+
|
| | | class CAtr
|
| | | {
|
| | | private:
|
| | | string m_symbol;
|
| | | ENUM_TIMEFRAMES m_timeframe;
|
| | | int m_period;
|
| | | int m_handle;
|
| | |
|
| | | public:
|
| | | CAtr(void);
|
| | | ~CAtr(void);
|
| | | bool Init(const string symbol = "",
|
| | | const ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT,
|
| | | const int period = 14);
|
| | | double Value(const int shift = 0);
|
| | | double Pips(const int shift = 0);
|
| | | void Release(void);
|
| | | bool IsReady(void) const { return m_handle != INVALID_HANDLE; }
|
| | | int Handle(void) const { return m_handle; }
|
| | | };
|
| | |
|
| | | CAtr::CAtr(void) : m_symbol(_Symbol),
|
| | | m_timeframe(PERIOD_CURRENT),
|
| | | m_period(14),
|
| | | m_handle(INVALID_HANDLE)
|
| | | {
|
| | | }
|
| | |
|
| | | CAtr::~CAtr(void)
|
| | | {
|
| | | Release();
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Release the handle, if one is held |
|
| | | //| Returns: nothing. |
|
| | | //+------------------------------------------------------------------+
|
| | | void CAtr::Release(void)
|
| | | {
|
| | | if(m_handle != INVALID_HANDLE)
|
| | | {
|
| | | IndicatorRelease(m_handle);
|
| | | m_handle = INVALID_HANDLE;
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Create the indicator handle |
|
| | | //| Parameters: |
|
| | | //| symbol - empty for the current chart symbol |
|
| | | //| timeframe - PERIOD_CURRENT for the chart timeframe |
|
| | | //| period - ATR averaging period, must be positive |
|
| | | //| |
|
| | | //| Returns: true if the handle was created. Safe to call again to |
|
| | | //| repoint the object; the previous handle is released. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CAtr::Init(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period)
|
| | | {
|
| | | Release();
|
| | |
|
| | | if(period <= 0) return false;
|
| | |
|
| | | m_symbol = (symbol == "") ? _Symbol : symbol;
|
| | | m_timeframe = timeframe;
|
| | | m_period = period;
|
| | | m_handle = iATR(m_symbol, m_timeframe, m_period);
|
| | |
|
| | | return m_handle != INVALID_HANDLE;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| ATR in price units |
|
| | | //| Parameters: |
|
| | | //| shift - bar to read, 0 being the forming bar |
|
| | | //| |
|
| | | //| Returns: the ATR, or 0 if Init was never called, the handle |
|
| | | //| failed, or the indicator has not calculated yet. A |
|
| | | //| freshly created handle needs a few ticks; retry rather |
|
| | | //| than treating the 0 as a reading. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CAtr::Value(const int shift)
|
| | | {
|
| | | if(m_handle == INVALID_HANDLE || shift < 0) return 0.0;
|
| | |
|
| | | double buffer[];
|
| | | ArraySetAsSeries(buffer, true);
|
| | |
|
| | | if(CopyBuffer(m_handle, 0, shift, 1, buffer) <= 0) return 0.0;
|
| | |
|
| | | return buffer[0];
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| ATR expressed in pips |
|
| | | //| Returns: the ATR in pips, or 0 - see Value(). |
|
| | | //+------------------------------------------------------------------+
|
| | | double CAtr::Pips(const int shift)
|
| | | {
|
| | | double value = Value(shift);
|
| | | if(value <= 0) return 0.0;
|
| | |
|
| | | return PriceToPips(value, m_symbol);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Cache backing the GetATRPips wrapper |
|
| | | //| |
|
| | | //| Parallel primitive arrays rather than an array of CAtr: MQL5 |
|
| | | //| reports undeleted dynamic objects when a program unloads, and a |
|
| | | //| file-scope cache has no destructor to clean up in. Handles are |
|
| | | //| released by the terminal at unload, or explicitly by |
|
| | | //| ReleaseAtrCache(). |
|
| | | //+------------------------------------------------------------------+
|
| | | string g_atrKeys[];
|
| | | int g_atrHandles[];
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Release every handle the GetATRPips cache holds |
|
| | | //| Returns: nothing. Call from OnDeinit if you want them gone early. |
|
| | | //+------------------------------------------------------------------+
|
| | | void ReleaseAtrCache(void)
|
| | | {
|
| | | int total = ArraySize(g_atrHandles);
|
| | | for(int i = 0; i < total; i++)
|
| | | if(g_atrHandles[i] != INVALID_HANDLE)
|
| | | IndicatorRelease(g_atrHandles[i]);
|
| | |
|
| | | ArrayResize(g_atrKeys, 0);
|
| | | ArrayResize(g_atrHandles, 0);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Cached iATR handle for one symbol, timeframe and period |
|
| | | //| Returns: the handle, or INVALID_HANDLE if it could not be made. |
|
| | | //+------------------------------------------------------------------+
|
| | | int CachedAtrHandle(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period)
|
| | | {
|
| | | string key = symbol + "|" + IntegerToString(timeframe) + "|" + IntegerToString(period);
|
| | |
|
| | | int total = ArraySize(g_atrKeys);
|
| | | for(int i = 0; i < total; i++)
|
| | | if(g_atrKeys[i] == key)
|
| | | return g_atrHandles[i];
|
| | |
|
| | | int handle = iATR(symbol, timeframe, period);
|
| | | if(handle == INVALID_HANDLE) return INVALID_HANDLE;
|
| | |
|
| | | ArrayResize(g_atrKeys, total + 1);
|
| | | ArrayResize(g_atrHandles, total + 1);
|
| | | g_atrKeys[total] = key;
|
| | | g_atrHandles[total] = handle;
|
| | |
|
| | | return handle;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Get ATR value in pips |
|
| | | //| Parameters: |
|
| | | //| period - ATR averaging period |
|
| | | //| timeframe - PERIOD_CURRENT for the chart timeframe |
|
| | | //| symbol - empty for the current chart symbol |
|
| | | //| |
|
| | | //| Kept as a wrapper over the cache so existing callers do not have |
|
| | | //| to hold a CAtr. Prefer CAtr in new code - it makes the handle's |
|
| | | //| lifetime visible. |
|
| | | //| |
|
| | | //| Returns: the ATR in pips, or 0 if the handle could not be made |
|
| | | //| or the indicator has not calculated yet. |
|
| | | //+------------------------------------------------------------------+
|
| | | double GetATRPips(int period = 14, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT,
|
| | | string symbol = "")
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | | if(period <= 0) return 0;
|
| | |
|
| | | int handle = CachedAtrHandle(symbol, timeframe, period);
|
| | | if(handle == INVALID_HANDLE) return 0;
|
| | |
|
| | | double atr[];
|
| | | ArraySetAsSeries(atr, true);
|
| | |
|
| | | if(CopyBuffer(handle, 0, 0, 1, atr) <= 0) return 0;
|
| | |
|
| | | return PriceToPips(atr[0], symbol);
|
| | | }
|
| | |
|
| | | #endif // STOPFIRST_ATR_MQH
|
| | | //+------------------------------------------------------------------+
|