2026-09-15 11:21:44 -05:00 | | | //+------------------------------------------------------------------+
|
2026-09-16 09:57:52 -05:00 | | | //| RBase.mqh |
|
2026-09-15 11:21:44 -05:00 | | | //| Copyright 2026, Leo. |
|
| | | //| https://www.mql5.com |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Leo."
|
| | | #property link "https://www.mql5.com/en/users/nique_372"
|
| | | #property strict
|
| | |
|
2026-09-16 10:10:34 -05:00 | | | #ifndef SCALERBYLEO_SRC_SCALER_RSCALER_RBASE_MQH
|
| | | #define SCALERBYLEO_SRC_SCALER_RSCALER_RBASE_MQH
|
2026-09-15 11:21:44 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-16 09:57:52 -05:00 | | | #include "..\\ScalerBase.mqh"
|
2026-09-15 11:21:44 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
2026-09-15 16:39:51 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #define ROBUSTSCALER_PERCENTILE(vec, l, h, w) ((l == h) ? (vec[l]) : ((vec[l] * (1.0 - w)) + (vec[h] * w)))
|
| | |
|
2026-09-15 11:21:44 -05:00 | | | //+------------------------------------------------------------------+
|
2026-09-16 09:57:52 -05:00 | | | //| Robust Scaler Base |
|
2026-09-15 11:21:44 -05:00 | | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | class RobustScalerBase : public ScalerBase
|
2026-09-15 11:21:44 -05:00 | | | {
|
| | | protected:
|
2026-09-15 16:39:51 -05:00 | | | vector m_medians, m_iqrs, m_iqrs_inv;
|
2026-09-16 09:57:52 -05:00 | | | virtual bool OnLoad() { return true; }
|
2026-09-15 16:39:51 -05:00 | | |
|
| | | //---
|
2026-09-15 22:45:34 -05:00 | | | static __forceinline void MakeValues(const double rank, ulong &l, ulong &h, double &w);
|
2026-09-15 11:21:44 -05:00 | | |
|
| | | public:
|
2026-09-16 09:57:52 -05:00 | | | RobustScalerBase() : ScalerBase() { m_prefix_file = "_median_iqr.csv"; }
|
2026-09-15 11:21:44 -05:00 | | |
|
| | | //---
|
| | | bool Save(string prefix_name, int extra_file_flags = FILE_COMMON);
|
| | | bool LoadByFile(string prefix_name, int extra_file_flags = FILE_COMMON);
|
| | | bool LoadByArr(const string &arr[]) override;
|
| | |
|
| | | //---
|
2026-09-15 22:45:34 -05:00 | | | bool Fit(const matrix<TFlt> &X);
|
2026-09-15 11:21:44 -05:00 | | | };
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | static __forceinline void RobustScalerBase::MakeValues(const double rank, ulong &l, ulong &h, double &w)
|
2026-09-15 16:39:51 -05:00 | | | {
|
| | | l = (ulong)MathFloor(rank);
|
| | | h = (ulong)MathCeil(rank);
|
| | | w = rank - l;
|
| | | }
|
| | |
|
2026-09-15 11:21:44 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Save / Load |
|
| | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | bool RobustScalerBase::Save(string prefix_name, int extra_file_flags = FILE_COMMON)
|
2026-09-15 11:21:44 -05:00 | | | {
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | m_file_name_out = prefix_name + m_prefix_file;
|
| | | FileDelete(m_file_name_out);
|
| | | ResetLastError();
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | const int handle = FileOpen(m_file_name_out, FILE_WRITE | FILE_CSV | extra_file_flags);
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
| | | m_last_err = SCALERBYLEO_ERR_FILE_OPEN;
|
| | | return false;
|
| | | }
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | FileWrite(handle, vector_to_string(m_iqrs));
|
2026-09-15 16:39:51 -05:00 | | | FileWrite(handle, vector_to_string(m_medians));
|
2026-09-15 11:21:44 -05:00 | | | FileWrite(handle, m_i_start);
|
| | | FileWrite(handle, m_i_count);
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | FileClose(handle);
|
| | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | bool RobustScalerBase::LoadByFile(string prefix_name, int extra_file_flags = FILE_COMMON)
|
2026-09-15 11:21:44 -05:00 | | | {
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | m_file_name_out = prefix_name + m_prefix_file;
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | ResetLastError();
|
| | | const int handle = FileOpen(m_file_name_out, FILE_READ | FILE_CSV | extra_file_flags, "\n");
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
| | | m_last_err = SCALERBYLEO_ERR_FILE_OPEN;
|
| | | return false;
|
| | | }
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-16 18:20:12 -05:00 | | | CStringFunc::ToVector<double, CStringConvert>(FileReadString(handle), m_iqrs, ',');
|
| | | CStringFunc::ToVector<double, CStringConvert>(FileReadString(handle), m_medians, ',');
|
2026-09-15 11:21:44 -05:00 | | | m_i_start = ulong(FileReadString(handle));
|
| | | m_i_count = long(FileReadString(handle));
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
| | | m_iqrs_inv = 1.0 / m_iqrs;
|
| | |
|
| | | //---
|
2026-09-15 11:21:44 -05:00 | | | FileClose(handle);
|
2026-09-16 09:57:52 -05:00 | | | return (m_loaded_scaler = OnLoad());
|
2026-09-15 11:21:44 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | bool RobustScalerBase::LoadByArr(const string &arr[])
|
2026-09-15 11:21:44 -05:00 | | | {
|
| | | if(ArraySize(arr) < 4)
|
| | | {
|
| | | m_last_err = SCALERBYLEO_ERR_INVALID_DATA;
|
| | | return false;
|
| | | }
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-15 11:21:44 -05:00 | | | int p = 0;
|
2026-09-16 18:20:12 -05:00 | | | CStringFunc::ToVector<double, CStringConvert>(arr[p++], m_iqrs, ',');
|
| | | CStringFunc::ToVector<double, CStringConvert>(arr[p++], m_medians, ',');
|
2026-09-15 11:21:44 -05:00 | | | m_i_start = ulong(arr[p++]);
|
| | | m_i_count = long(arr[p++]);
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
| | | m_iqrs_inv = 1.0 / m_iqrs;
|
| | |
|
| | | //---
|
2026-09-16 09:57:52 -05:00 | | | return (m_loaded_scaler = OnLoad());
|
2026-09-15 16:39:51 -05:00 | | | }
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Fit |
|
| | | //+------------------------------------------------------------------+
|
2026-09-15 22:45:34 -05:00 | | | template<typename TFlt>
|
2026-09-16 09:57:52 -05:00 | | | bool RobustScalerBase::Fit(const matrix<TFlt> &X)
|
2026-09-15 16:39:51 -05:00 | | | {
|
| | | //---
|
| | | const ulong total_cols = X.Cols();
|
| | | const ulong rows = X.Rows();
|
| | | if(total_cols == 0 || rows == 0)
|
2026-09-15 11:21:44 -05:00 | | | {
|
2026-09-15 16:39:51 -05:00 | | | m_last_err = SCALERBYLEO_ERR_EMPTY_INPUT;
|
| | | return false;
|
2026-09-15 11:21:44 -05:00 | | | }
|
2026-09-15 16:39:51 -05:00 | | | if(m_i_start >= total_cols)
|
2026-09-15 11:21:44 -05:00 | | | {
|
2026-09-15 16:39:51 -05:00 | | | m_last_err = SCALERBYLEO_ERR_INVALID_RANGE;
|
| | | return false;
|
2026-09-15 11:21:44 -05:00 | | | }
|
| | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
| | | const ulong fs = SCALERBYLEO_SIZE(total_cols);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
| | | m_medians.Resize(fs);
|
| | | m_iqrs.Resize(fs);
|
| | | m_iqrs_inv.Resize(fs);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
| | | const double rs_1 = double(rows - 1);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //--- make values
|
| | | ulong l50, h50;
|
| | | double w50;
|
| | | MakeValues(0.50 * rs_1, l50, h50, w50);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | ulong l25, h25;
|
| | | double w25;
|
| | | MakeValues(0.25 * rs_1, l25, h25, w25);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | ulong l75, h75;
|
| | | double w75;
|
| | | MakeValues(0.75 * rs_1, l75, h75, w75);
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //--- iter
|
| | | for(ulong c = 0; c < fs; c++)
|
| | | {
|
2026-09-16 09:57:52 -05:00 | | | //---
|
2026-09-15 16:39:51 -05:00 | | | vector col = X.Col(m_i_start + c);
|
| | | col.Sort(SORT_ASCENDING);
|
| | |
|
| | | //---
|
| | | const double median_v = ROBUSTSCALER_PERCENTILE(col, l50, h50, w50);
|
| | | const double iqr_v = ROBUSTSCALER_PERCENTILE(col, l75, h75, w75) - ROBUSTSCALER_PERCENTILE(col, l25, h25, w25);
|
| | |
|
| | | //---
|
| | | if(fabs(iqr_v) < SCALER_BASE_MIN_VALUE)
|
| | | {
|
| | | m_last_err = SCALERBYLEO_ERR_DEGENERATE_SCALE;
|
| | | return false;
|
| | | }
|
| | |
|
| | | //---
|
| | | m_medians[c] = median_v;
|
| | | m_iqrs[c] = iqr_v;
|
| | | m_iqrs_inv[c] = 1.0 / iqr_v;
|
| | | }
|
2026-09-15 11:21:44 -05:00 | | |
|
2026-09-15 16:39:51 -05:00 | | | //---
|
2026-09-16 09:57:52 -05:00 | | | return (m_loaded_scaler = OnLoad());
|
2026-09-15 11:21:44 -05:00 | | | }
|
| | | }
|
2026-09-16 10:10:34 -05:00 | | | #endif // SCALERBYLEO_SRC_SCALER_RSCALER_RBASE_MQH
|
2026-09-15 11:21:44 -05:00 | | | //+------------------------------------------------------------------+
|