ScalerByLeo/Src/Scaler/RScaler/RBase.mqh

221 lines
6.5 KiB
MQL5

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
//+------------------------------------------------------------------+
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
//---
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;
//---
bool Fit(const matrix<TFlt> &X);
2026-09-15 11:21:44 -05:00
};
2026-09-15 16:39:51 -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 |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
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
}
//+------------------------------------------------------------------+
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 |
//+------------------------------------------------------------------+
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
//+------------------------------------------------------------------+