diff --git a/Include/MyIncludes/AccountInfoDisplayInit.mqh b/Include/MyIncludes/AccountInfoDisplayInit.mqh index 7f76d4d..c262090 100644 --- a/Include/MyIncludes/AccountInfoDisplayInit.mqh +++ b/Include/MyIncludes/AccountInfoDisplayInit.mqh @@ -1,78 +1,78 @@ -//+------------------------------------------------------------------+ -//| AccountInfoDisplayInit.mqh | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" - -//--- Enum to define the row index for each piece of information -// This makes the code readable and robust against reordering. -enum ENUM_ACCOUNT_INFO_ROWS - { - ROW_HEADING_BASIC, - ROW_LOGIN, - ROW_NAME, - ROW_SERVER, - ROW_COMPANY, - ROW_CURRENCY, - ROW_CURRENCY_DIGITS, - ROW_HEADING_FINANCIAL, - ROW_BALANCE, - ROW_CREDIT, - ROW_PROFIT, - ROW_EQUITY, - ROW_HEADING_MARGIN, - ROW_MARGIN, - ROW_MARGIN_FREE, - ROW_MARGIN_LEVEL, - ROW_MARGIN_CALL, - ROW_MARGIN_STOPOUT, - ROW_HEADING_RULES, - ROW_TRADE_MODE, - ROW_LEVERAGE, - ROW_MARGIN_MODE, - ROW_STOPOUT_MODE, - ROW_FIFO_CLOSE, - ROW_HEDGE_ALLOWED, - ROW_HEADING_PERMISSIONS, - ROW_TRADE_ALLOWED, - ROW_TRADE_EXPERT, -//--- - ROW_TOTAL_COUNT // Always keep this last to get the total count - }; - -//--- Array of strings for the labels, matching the enum order -const string g_init_labels[ROW_TOTAL_COUNT] = - { - "I. Basic Info", - "Login:", - "Name:", - "Server:", - "Company:", - "Currency:", - "Currency Digits:", - "II. Financials", - "Balance:", - "Credit:", - "Profit:", - "Equity:", - "III. Margin", - "Margin:", - "Free Margin:", - "Margin Level:", - "Margin Call:", - "Margin Stopout:", - "IV. Rules", - "Trade Mode:", - "Leverage:", - "Margin Mode:", - "Stopout Mode:", - "FIFO Close:", - "Hedge Allowed:", - "V. Permissions", - "Trade Allowed:", - "Expert Advisor:", - }; -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| AccountInfoDisplayInit.mqh | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" + +//--- Enum to define the row index for each piece of information +// This makes the code readable and robust against reordering. +enum ENUM_ACCOUNT_INFO_ROWS + { + ROW_HEADING_BASIC, + ROW_LOGIN, + ROW_NAME, + ROW_SERVER, + ROW_COMPANY, + ROW_CURRENCY, + ROW_CURRENCY_DIGITS, + ROW_HEADING_FINANCIAL, + ROW_BALANCE, + ROW_CREDIT, + ROW_PROFIT, + ROW_EQUITY, + ROW_HEADING_MARGIN, + ROW_MARGIN, + ROW_MARGIN_FREE, + ROW_MARGIN_LEVEL, + ROW_MARGIN_CALL, + ROW_MARGIN_STOPOUT, + ROW_HEADING_RULES, + ROW_TRADE_MODE, + ROW_LEVERAGE, + ROW_MARGIN_MODE, + ROW_STOPOUT_MODE, + ROW_FIFO_CLOSE, + ROW_HEDGE_ALLOWED, + ROW_HEADING_PERMISSIONS, + ROW_TRADE_ALLOWED, + ROW_TRADE_EXPERT, +//--- + ROW_TOTAL_COUNT // Always keep this last to get the total count + }; + +//--- Array of strings for the labels, matching the enum order +const string g_init_labels[ROW_TOTAL_COUNT] = + { + "I. Basic Info", + "Login:", + "Name:", + "Server:", + "Company:", + "Currency:", + "Currency Digits:", + "II. Financials", + "Balance:", + "Credit:", + "Profit:", + "Equity:", + "III. Margin", + "Margin:", + "Free Margin:", + "Margin Level:", + "Margin Call:", + "Margin Stopout:", + "IV. Rules", + "Trade Mode:", + "Leverage:", + "Margin Mode:", + "Stopout Mode:", + "FIFO Close:", + "Hedge Allowed:", + "V. Permissions", + "Trade Allowed:", + "Expert Advisor:", + }; +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Include/MyIncludes/HA_Tools.mqh b/Include/MyIncludes/HA_Tools.mqh index 493714d..ea9adf0 100644 --- a/Include/MyIncludes/HA_Tools.mqh +++ b/Include/MyIncludes/HA_Tools.mqh @@ -1,116 +1,116 @@ -//+------------------------------------------------------------------+ -//| HA_Tools.mqh | -//| A toolkit for Heiken Ashi calculations | -//| Copyright 2025, xxxxxxxx | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" - -#include - -//+------------------------------------------------------------------+ -//| Class CHA_Calculator. | -//| Purpose: Encapsulates the logic for calculating Heiken Ashi | -//| candle values from standard OHLC data. This class | -//| manages its own data buffers. | -//+------------------------------------------------------------------+ -class CHA_Calculator : public CObject - { -public: - //--- Public Data Members --- - // These buffers store the calculated Heiken Ashi values and are - // publicly accessible for indicators to use in their calculations. - double ha_open[]; - double ha_high[]; - double ha_low[]; - double ha_close[]; - -public: - //--- Constructor and Destructor - CHA_Calculator(void); - ~CHA_Calculator(void); - - //--- Public Interface - bool Calculate(const int rates_total, - const int prev_calculated, - const double &open[], - const double &high[], - const double &low[], - const double &close[]); - }; - -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CHA_Calculator::CHA_Calculator(void) - { -//--- No specific initialization required in the constructor - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CHA_Calculator::~CHA_Calculator(void) - { -//--- No specific deinitialization required in the destructor - } - -//+------------------------------------------------------------------+ -//| Calculates Heiken Ashi values for the entire history. | -//| INPUT: rates_total - The total number of bars available. | -//| prev_calculated - The number of bars calculated previously.| -//| open[], high[], low[], close[] - Standard price arrays. | -//| RETURN: true if calculation was successful, false otherwise. | -//+------------------------------------------------------------------+ -bool CHA_Calculator::Calculate(const int rates_total, - const int prev_calculated, - const double &open[], - const double &high[], - const double &low[], - const double &close[]) - { -//--- Ensure internal buffers are sized correctly - if(ArrayResize(ha_open, rates_total) < 0 || - ArrayResize(ha_high, rates_total) < 0 || - ArrayResize(ha_low, rates_total) < 0 || - ArrayResize(ha_close, rates_total) < 0) - { - Print("CHA_Calculator: Error resizing Heiken Ashi buffers!"); - return false; - } - -//--- Determine the starting bar for calculation to optimize performance - int start_pos = 0; - if(prev_calculated > 1) - { - // On subsequent calls, only calculate new bars - start_pos = prev_calculated - 1; - } - -//--- Calculate the very first HA bar (index 0) on the first run - if(start_pos == 0) - { - ha_open[0] = (open[0] + close[0]) / 2.0; - ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; - // For the first bar, HA High/Low are the same as the regular High/Low - ha_high[0] = high[0]; - ha_low[0] = low[0]; - start_pos = 1; // Set the starting position for the main loop to the next bar - } - -//--- Main loop to calculate all subsequent HA bars - for(int i = start_pos; i < rates_total; i++) - { - // HA Open is the midpoint of the previous HA bar's body - ha_open[i] = (ha_open[i-1] + ha_close[i-1]) / 2.0; - // HA Close is the average price of the current regular bar - ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; - // HA High is the maximum of the current regular High, HA Open, and HA Close - ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); - // HA Low is the minimum of the current regular Low, HA Open, and HA Close - ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); - } - - return true; - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| HA_Tools.mqh | +//| A toolkit for Heiken Ashi calculations | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" + +#include + +//+------------------------------------------------------------------+ +//| Class CHA_Calculator. | +//| Purpose: Encapsulates the logic for calculating Heiken Ashi | +//| candle values from standard OHLC data. This class | +//| manages its own data buffers. | +//+------------------------------------------------------------------+ +class CHA_Calculator : public CObject + { +public: + //--- Public Data Members --- + // These buffers store the calculated Heiken Ashi values and are + // publicly accessible for indicators to use in their calculations. + double ha_open[]; + double ha_high[]; + double ha_low[]; + double ha_close[]; + +public: + //--- Constructor and Destructor + CHA_Calculator(void); + ~CHA_Calculator(void); + + //--- Public Interface + bool Calculate(const int rates_total, + const int prev_calculated, + const double &open[], + const double &high[], + const double &low[], + const double &close[]); + }; + +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CHA_Calculator::CHA_Calculator(void) + { +//--- No specific initialization required in the constructor + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CHA_Calculator::~CHA_Calculator(void) + { +//--- No specific deinitialization required in the destructor + } + +//+------------------------------------------------------------------+ +//| Calculates Heiken Ashi values for the entire history. | +//| INPUT: rates_total - The total number of bars available. | +//| prev_calculated - The number of bars calculated previously.| +//| open[], high[], low[], close[] - Standard price arrays. | +//| RETURN: true if calculation was successful, false otherwise. | +//+------------------------------------------------------------------+ +bool CHA_Calculator::Calculate(const int rates_total, + const int prev_calculated, + const double &open[], + const double &high[], + const double &low[], + const double &close[]) + { +//--- Ensure internal buffers are sized correctly + if(ArrayResize(ha_open, rates_total) < 0 || + ArrayResize(ha_high, rates_total) < 0 || + ArrayResize(ha_low, rates_total) < 0 || + ArrayResize(ha_close, rates_total) < 0) + { + Print("CHA_Calculator: Error resizing Heiken Ashi buffers!"); + return false; + } + +//--- Determine the starting bar for calculation to optimize performance + int start_pos = 0; + if(prev_calculated > 1) + { + // On subsequent calls, only calculate new bars + start_pos = prev_calculated - 1; + } + +//--- Calculate the very first HA bar (index 0) on the first run + if(start_pos == 0) + { + ha_open[0] = (open[0] + close[0]) / 2.0; + ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; + // For the first bar, HA High/Low are the same as the regular High/Low + ha_high[0] = high[0]; + ha_low[0] = low[0]; + start_pos = 1; // Set the starting position for the main loop to the next bar + } + +//--- Main loop to calculate all subsequent HA bars + for(int i = start_pos; i < rates_total; i++) + { + // HA Open is the midpoint of the previous HA bar's body + ha_open[i] = (ha_open[i-1] + ha_close[i-1]) / 2.0; + // HA Close is the average price of the current regular bar + ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; + // HA High is the maximum of the current regular High, HA Open, and HA Close + ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); + // HA Low is the minimum of the current regular Low, HA Open, and HA Close + ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); + } + + return true; + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Include/MyIncludes/HeikinAshiCalculator.mqh b/Include/MyIncludes/HeikinAshiCalculator.mqh index 24597dd..5200d9c 100644 --- a/Include/MyIncludes/HeikinAshiCalculator.mqh +++ b/Include/MyIncludes/HeikinAshiCalculator.mqh @@ -1,72 +1,72 @@ -//+------------------------------------------------------------------+ -//| HeikinAshiCalculator.mqh | -//| A toolkit for Heikin Ashi calculations | -//| Copyright 2025, xxxxxxxx | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" - -//+------------------------------------------------------------------+ -//| Class CHeikinAshi_Calculator. | -//| Purpose: Encapsulates the logic for calculating Heikin Ashi | -//| candle values from standard OHLC data. This class is | -//| stateless and operates on external buffers. | -//+------------------------------------------------------------------+ -class CHeikinAshi_Calculator - { -public: - //--- Public Interface - void Calculate(const int rates_total, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &ha_open[], - double &ha_high[], - double &ha_low[], - double &ha_close[]); - }; - -//+------------------------------------------------------------------+ -//| Calculates Heikin Ashi values for the entire history. | -//| This method performs a full recalculation for maximum stability. | -//| INPUT: rates_total - The total number of bars available. | -//| open[], high[], low[], close[] - Standard price arrays. | -//| OUTPUT: ha_open[], ha_high[], ha_low[], ha_close[] - Result arrays.| -//+------------------------------------------------------------------+ -void CHeikinAshi_Calculator::Calculate(const int rates_total, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &ha_open[], - double &ha_high[], - double &ha_low[], - double &ha_close[]) - { -//--- Not enough data for calculation - if(rates_total < 1) - return; - -//--- Calculate the very first Heikin Ashi bar (index 0) - ha_open[0] = (open[0] + close[0]) / 2.0; - ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; -// For the first bar, HA High/Low are the same as the regular High/Low - ha_high[0] = high[0]; - ha_low[0] = low[0]; - -//--- Main loop to calculate all subsequent Heikin Ashi bars - for(int i = 1; i < rates_total; i++) - { - // HA Open is the midpoint of the previous HA bar's body - ha_open[i] = (ha_open[i - 1] + ha_close[i - 1]) / 2.0; - // HA Close is the average price of the current regular bar - ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; - // HA High is the maximum of the current regular High, HA Open, and HA Close - ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); - // HA Low is the minimum of the current regular Low, HA Open, and HA Close - ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); - } - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| HeikinAshiCalculator.mqh | +//| A toolkit for Heikin Ashi calculations | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" + +//+------------------------------------------------------------------+ +//| Class CHeikinAshi_Calculator. | +//| Purpose: Encapsulates the logic for calculating Heikin Ashi | +//| candle values from standard OHLC data. This class is | +//| stateless and operates on external buffers. | +//+------------------------------------------------------------------+ +class CHeikinAshi_Calculator + { +public: + //--- Public Interface + void Calculate(const int rates_total, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &ha_open[], + double &ha_high[], + double &ha_low[], + double &ha_close[]); + }; + +//+------------------------------------------------------------------+ +//| Calculates Heikin Ashi values for the entire history. | +//| This method performs a full recalculation for maximum stability. | +//| INPUT: rates_total - The total number of bars available. | +//| open[], high[], low[], close[] - Standard price arrays. | +//| OUTPUT: ha_open[], ha_high[], ha_low[], ha_close[] - Result arrays.| +//+------------------------------------------------------------------+ +void CHeikinAshi_Calculator::Calculate(const int rates_total, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &ha_open[], + double &ha_high[], + double &ha_low[], + double &ha_close[]) + { +//--- Not enough data for calculation + if(rates_total < 1) + return; + +//--- Calculate the very first Heikin Ashi bar (index 0) + ha_open[0] = (open[0] + close[0]) / 2.0; + ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; +// For the first bar, HA High/Low are the same as the regular High/Low + ha_high[0] = high[0]; + ha_low[0] = low[0]; + +//--- Main loop to calculate all subsequent Heikin Ashi bars + for(int i = 1; i < rates_total; i++) + { + // HA Open is the midpoint of the previous HA bar's body + ha_open[i] = (ha_open[i - 1] + ha_close[i - 1]) / 2.0; + // HA Close is the average price of the current regular bar + ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; + // HA High is the maximum of the current regular High, HA Open, and HA Close + ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); + // HA Low is the minimum of the current regular Low, HA Open, and HA Close + ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Include/MyIncludes/HeikinAshi_Tools.mqh b/Include/MyIncludes/HeikinAshi_Tools.mqh index 96becd6..78d7f8c 100644 --- a/Include/MyIncludes/HeikinAshi_Tools.mqh +++ b/Include/MyIncludes/HeikinAshi_Tools.mqh @@ -1,162 +1,162 @@ -//+------------------------------------------------------------------+ -//| HeikinAshi_Tools.mqh | -//| A toolkit for various Heikin Ashi calculations | -//| Copyright 2025, xxxxxxxx | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" - -//+==================================================================+ -//| | -//| CLASS 1: CHeikinAshi_Calculator | -//| | -//+==================================================================+ - -//+------------------------------------------------------------------+ -//| Class CHeikinAshi_Calculator. | -//| Purpose: Encapsulates the logic for calculating Heikin Ashi | -//| candle values from standard OHLC data. This class is | -//| stateless and operates on external buffers. | -//+------------------------------------------------------------------+ -class CHeikinAshi_Calculator - { -public: - //--- Public Interface - void Calculate(const int rates_total, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &ha_open[], - double &ha_high[], - double &ha_low[], - double &ha_close[]); - }; - -//+------------------------------------------------------------------+ -//| Calculates Heikin Ashi values for the entire history. | -//+------------------------------------------------------------------+ -void CHeikinAshi_Calculator::Calculate(const int rates_total, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &ha_open[], - double &ha_high[], - double &ha_low[], - double &ha_close[]) - { - if(rates_total < 1) - return; - - ha_open[0] = (open[0] + close[0]) / 2.0; - ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; - ha_high[0] = high[0]; - ha_low[0] = low[0]; - - for(int i = 1; i < rates_total; i++) - { - ha_open[i] = (ha_open[i - 1] + ha_close[i - 1]) / 2.0; - ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; - ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); - ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); - } - } - - -//+==================================================================+ -//| | -//| CLASS 2: CHeikinAshi_RSI_Calculator | -//| | -//+==================================================================+ - -//+------------------------------------------------------------------+ -//| Class CHeikinAshi_RSI_Calculator | -//| Purpose: Calculates RSI based on Heikin Ashi data. | -//+------------------------------------------------------------------+ -class CHeikinAshi_RSI_Calculator - { -protected: - CHeikinAshi_Calculator m_ha_calculator; // Internal HA calculator - -public: - bool Calculate(const int rates_total, - const int rsi_period, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &rsi_buffer[]); - }; - -//+------------------------------------------------------------------+ -//| Calculates Heikin Ashi based RSI | -//+------------------------------------------------------------------+ -bool CHeikinAshi_RSI_Calculator::Calculate(const int rates_total, - const int rsi_period, - const double &open[], - const double &high[], - const double &low[], - const double &close[], - double &rsi_buffer[]) - { - if(rates_total <= rsi_period) - return false; - -//--- Intermediate buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- Step 1: Calculate Heikin Ashi - m_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- Step 2: Calculate RSI on HA Close - double pos_buffer[], neg_buffer[]; - ArrayResize(pos_buffer, rates_total); - ArrayResize(neg_buffer, rates_total); - - for(int i = 1; i < rates_total; i++) - { - double diff = ha_close[i] - ha_close[i-1]; - double positive_change = (diff > 0) ? diff : 0; - double negative_change = (diff < 0) ? -diff : 0; - - if(i == rsi_period) - { - double sum_pos=0, sum_neg=0; - for(int j=1; j<=rsi_period; j++) - { - double p_diff = ha_close[j] - ha_close[j-1]; - sum_pos += (p_diff > 0) ? p_diff : 0; - sum_neg += (p_diff < 0) ? -p_diff : 0; - } - pos_buffer[i] = sum_pos / rsi_period; - neg_buffer[i] = sum_neg / rsi_period; - } - else - if(i > rsi_period) - { - pos_buffer[i] = (pos_buffer[i-1] * (rsi_period - 1) + positive_change) / rsi_period; - neg_buffer[i] = (neg_buffer[i-1] * (rsi_period - 1) + negative_change) / rsi_period; - } - - if(i >= rsi_period) - { - if(neg_buffer[i] > 0) - { - double rs = pos_buffer[i] / neg_buffer[i]; - rsi_buffer[i] = 100.0 - (100.0 / (1.0 + rs)); - } - else - { - rsi_buffer[i] = 100.0; - } - } - } - return true; - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| HeikinAshi_Tools.mqh | +//| A toolkit for various Heikin Ashi calculations | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" + +//+==================================================================+ +//| | +//| CLASS 1: CHeikinAshi_Calculator | +//| | +//+==================================================================+ + +//+------------------------------------------------------------------+ +//| Class CHeikinAshi_Calculator. | +//| Purpose: Encapsulates the logic for calculating Heikin Ashi | +//| candle values from standard OHLC data. This class is | +//| stateless and operates on external buffers. | +//+------------------------------------------------------------------+ +class CHeikinAshi_Calculator + { +public: + //--- Public Interface + void Calculate(const int rates_total, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &ha_open[], + double &ha_high[], + double &ha_low[], + double &ha_close[]); + }; + +//+------------------------------------------------------------------+ +//| Calculates Heikin Ashi values for the entire history. | +//+------------------------------------------------------------------+ +void CHeikinAshi_Calculator::Calculate(const int rates_total, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &ha_open[], + double &ha_high[], + double &ha_low[], + double &ha_close[]) + { + if(rates_total < 1) + return; + + ha_open[0] = (open[0] + close[0]) / 2.0; + ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0; + ha_high[0] = high[0]; + ha_low[0] = low[0]; + + for(int i = 1; i < rates_total; i++) + { + ha_open[i] = (ha_open[i - 1] + ha_close[i - 1]) / 2.0; + ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0; + ha_high[i] = MathMax(high[i], MathMax(ha_open[i], ha_close[i])); + ha_low[i] = MathMin(low[i], MathMin(ha_open[i], ha_close[i])); + } + } + + +//+==================================================================+ +//| | +//| CLASS 2: CHeikinAshi_RSI_Calculator | +//| | +//+==================================================================+ + +//+------------------------------------------------------------------+ +//| Class CHeikinAshi_RSI_Calculator | +//| Purpose: Calculates RSI based on Heikin Ashi data. | +//+------------------------------------------------------------------+ +class CHeikinAshi_RSI_Calculator + { +protected: + CHeikinAshi_Calculator m_ha_calculator; // Internal HA calculator + +public: + bool Calculate(const int rates_total, + const int rsi_period, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &rsi_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| Calculates Heikin Ashi based RSI | +//+------------------------------------------------------------------+ +bool CHeikinAshi_RSI_Calculator::Calculate(const int rates_total, + const int rsi_period, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &rsi_buffer[]) + { + if(rates_total <= rsi_period) + return false; + +//--- Intermediate buffers + double ha_open[], ha_high[], ha_low[], ha_close[]; + ArrayResize(ha_open, rates_total); + ArrayResize(ha_high, rates_total); + ArrayResize(ha_low, rates_total); + ArrayResize(ha_close, rates_total); + +//--- Step 1: Calculate Heikin Ashi + m_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); + +//--- Step 2: Calculate RSI on HA Close + double pos_buffer[], neg_buffer[]; + ArrayResize(pos_buffer, rates_total); + ArrayResize(neg_buffer, rates_total); + + for(int i = 1; i < rates_total; i++) + { + double diff = ha_close[i] - ha_close[i-1]; + double positive_change = (diff > 0) ? diff : 0; + double negative_change = (diff < 0) ? -diff : 0; + + if(i == rsi_period) + { + double sum_pos=0, sum_neg=0; + for(int j=1; j<=rsi_period; j++) + { + double p_diff = ha_close[j] - ha_close[j-1]; + sum_pos += (p_diff > 0) ? p_diff : 0; + sum_neg += (p_diff < 0) ? -p_diff : 0; + } + pos_buffer[i] = sum_pos / rsi_period; + neg_buffer[i] = sum_neg / rsi_period; + } + else + if(i > rsi_period) + { + pos_buffer[i] = (pos_buffer[i-1] * (rsi_period - 1) + positive_change) / rsi_period; + neg_buffer[i] = (neg_buffer[i-1] * (rsi_period - 1) + negative_change) / rsi_period; + } + + if(i >= rsi_period) + { + if(neg_buffer[i] > 0) + { + double rs = pos_buffer[i] / neg_buffer[i]; + rsi_buffer[i] = 100.0 - (100.0 / (1.0 + rs)); + } + else + { + rsi_buffer[i] = 100.0; + } + } + } + return true; + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Include/MyIncludes/IndicatorExporter.mqh b/Include/MyIncludes/IndicatorExporter.mqh index cf2ca32..4e1ec50 100644 --- a/Include/MyIncludes/IndicatorExporter.mqh +++ b/Include/MyIncludes/IndicatorExporter.mqh @@ -1,140 +1,140 @@ -//+------------------------------------------------------------------+ -//| IndicatorExporter.mqh | -//| A toolkit for exporting indicator buffer data to CSV | -//| Copyright 2025, xxxxxxxx | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" - -#include - -//+------------------------------------------------------------------+ -//| Class CIndicatorExporter. | -//| Purpose: Encapsulates all logic for exporting indicator data | -//| to a CSV file. It handles file opening, writing, and | -//| closing operations. | -//+------------------------------------------------------------------+ -class CIndicatorExporter : public CObject - { -private: - int m_file_handle; // Stores the handle of the currently open file - string m_delimiter; // Stores the delimiter character for the CSV - -public: - //--- Constructor and Destructor - CIndicatorExporter(void); - ~CIndicatorExporter(void); - - //--- Public Interface - bool OpenFile(const string file_name, const string delimiter=","); - void CloseFile(void); - bool WriteHeader(const string &header_fields[]); - bool WriteRow(const datetime time_val, const double &data_values[]); - }; - -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CIndicatorExporter::CIndicatorExporter(void) : m_file_handle(INVALID_HANDLE), m_delimiter(",") - { -//--- Initializes member variables to default states - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIndicatorExporter::~CIndicatorExporter(void) - { -//--- Ensures the file is closed when the object is destroyed - if(m_file_handle != INVALID_HANDLE) - FileClose(m_file_handle); - } - -//+------------------------------------------------------------------+ -//| Opens a file for writing in the MQL5/Files/ directory. | -//| INPUT: file_name - The name of the file to create. | -//| delimiter - The character to use for separating values. | -//| RETURN: true if the file was opened successfully, false otherwise.| -//+------------------------------------------------------------------+ -bool CIndicatorExporter::OpenFile(const string file_name, const string delimiter=",") - { - m_delimiter = delimiter; - ResetLastError(); - -//--- Open the file with write, CSV, and ANSI flags - char separator = (char)StringGetCharacter(m_delimiter, 0); - m_file_handle = FileOpen(file_name, FILE_WRITE | FILE_CSV | FILE_ANSI, separator); - -//--- Check for errors - if(m_file_handle == INVALID_HANDLE) - { - PrintFormat("CIndicatorExporter: Error opening file '%s'. Error code: %d", file_name, GetLastError()); - return false; - } - return true; - } - -//+------------------------------------------------------------------+ -//| Closes the currently open file. | -//+------------------------------------------------------------------+ -void CIndicatorExporter::CloseFile(void) - { - if(m_file_handle != INVALID_HANDLE) - { - FileClose(m_file_handle); - m_file_handle = INVALID_HANDLE; // Reset handle to prevent accidental reuse - } - } - -//+------------------------------------------------------------------+ -//| Writes the header row to the CSV file. | -//| INPUT: header_fields - A string array containing the column names.| -//| RETURN: true on success, false on failure. | -//| NOTE: This version is hardcoded for 4 header fields. | -//+------------------------------------------------------------------+ -bool CIndicatorExporter::WriteHeader(const string &header_fields[]) - { - if(m_file_handle == INVALID_HANDLE) - return false; - -//--- Check array size before writing - if(ArraySize(header_fields) == 4) - { - FileWrite(m_file_handle, header_fields[0], header_fields[1], header_fields[2], header_fields[3]); - } - else - { - Print("CIndicatorExporter: WriteHeader currently supports exactly 4 header fields."); - return false; - } - return true; - } - -//+------------------------------------------------------------------+ -//| Writes a single row of data to the file. | -//| INPUT: time_val - The datetime for the current row. | -//| data_values - A double array with the indicator values. | -//| RETURN: true on success, false on failure. | -//| NOTE: This version is hardcoded for 3 data values. | -//+------------------------------------------------------------------+ -bool CIndicatorExporter::WriteRow(const datetime time_val, const double &data_values[]) - { - if(m_file_handle == INVALID_HANDLE) - return false; - -//--- Convert datetime to a standard string format - string time_str = TimeToString(time_val, TIME_DATE | TIME_MINUTES | TIME_SECONDS); - -//--- Check array size before writing - if(ArraySize(data_values) == 3) - { - FileWrite(m_file_handle, time_str, data_values[0], data_values[1], data_values[2]); - } - else - { - Print("CIndicatorExporter: WriteRow currently supports exactly 3 data values."); - return false; - } - return true; - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| IndicatorExporter.mqh | +//| A toolkit for exporting indicator buffer data to CSV | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" + +#include + +//+------------------------------------------------------------------+ +//| Class CIndicatorExporter. | +//| Purpose: Encapsulates all logic for exporting indicator data | +//| to a CSV file. It handles file opening, writing, and | +//| closing operations. | +//+------------------------------------------------------------------+ +class CIndicatorExporter : public CObject + { +private: + int m_file_handle; // Stores the handle of the currently open file + string m_delimiter; // Stores the delimiter character for the CSV + +public: + //--- Constructor and Destructor + CIndicatorExporter(void); + ~CIndicatorExporter(void); + + //--- Public Interface + bool OpenFile(const string file_name, const string delimiter=","); + void CloseFile(void); + bool WriteHeader(const string &header_fields[]); + bool WriteRow(const datetime time_val, const double &data_values[]); + }; + +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CIndicatorExporter::CIndicatorExporter(void) : m_file_handle(INVALID_HANDLE), m_delimiter(",") + { +//--- Initializes member variables to default states + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CIndicatorExporter::~CIndicatorExporter(void) + { +//--- Ensures the file is closed when the object is destroyed + if(m_file_handle != INVALID_HANDLE) + FileClose(m_file_handle); + } + +//+------------------------------------------------------------------+ +//| Opens a file for writing in the MQL5/Files/ directory. | +//| INPUT: file_name - The name of the file to create. | +//| delimiter - The character to use for separating values. | +//| RETURN: true if the file was opened successfully, false otherwise.| +//+------------------------------------------------------------------+ +bool CIndicatorExporter::OpenFile(const string file_name, const string delimiter=",") + { + m_delimiter = delimiter; + ResetLastError(); + +//--- Open the file with write, CSV, and ANSI flags + char separator = (char)StringGetCharacter(m_delimiter, 0); + m_file_handle = FileOpen(file_name, FILE_WRITE | FILE_CSV | FILE_ANSI, separator); + +//--- Check for errors + if(m_file_handle == INVALID_HANDLE) + { + PrintFormat("CIndicatorExporter: Error opening file '%s'. Error code: %d", file_name, GetLastError()); + return false; + } + return true; + } + +//+------------------------------------------------------------------+ +//| Closes the currently open file. | +//+------------------------------------------------------------------+ +void CIndicatorExporter::CloseFile(void) + { + if(m_file_handle != INVALID_HANDLE) + { + FileClose(m_file_handle); + m_file_handle = INVALID_HANDLE; // Reset handle to prevent accidental reuse + } + } + +//+------------------------------------------------------------------+ +//| Writes the header row to the CSV file. | +//| INPUT: header_fields - A string array containing the column names.| +//| RETURN: true on success, false on failure. | +//| NOTE: This version is hardcoded for 4 header fields. | +//+------------------------------------------------------------------+ +bool CIndicatorExporter::WriteHeader(const string &header_fields[]) + { + if(m_file_handle == INVALID_HANDLE) + return false; + +//--- Check array size before writing + if(ArraySize(header_fields) == 4) + { + FileWrite(m_file_handle, header_fields[0], header_fields[1], header_fields[2], header_fields[3]); + } + else + { + Print("CIndicatorExporter: WriteHeader currently supports exactly 4 header fields."); + return false; + } + return true; + } + +//+------------------------------------------------------------------+ +//| Writes a single row of data to the file. | +//| INPUT: time_val - The datetime for the current row. | +//| data_values - A double array with the indicator values. | +//| RETURN: true on success, false on failure. | +//| NOTE: This version is hardcoded for 3 data values. | +//+------------------------------------------------------------------+ +bool CIndicatorExporter::WriteRow(const datetime time_val, const double &data_values[]) + { + if(m_file_handle == INVALID_HANDLE) + return false; + +//--- Convert datetime to a standard string format + string time_str = TimeToString(time_val, TIME_DATE | TIME_MINUTES | TIME_SECONDS); + +//--- Check array size before writing + if(ArraySize(data_values) == 3) + { + FileWrite(m_file_handle, time_str, data_values[0], data_values[1], data_values[2]); + } + else + { + Print("CIndicatorExporter: WriteRow currently supports exactly 3 data values."); + return false; + } + return true; + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+