564 lines
20 KiB
MQL5
564 lines
20 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| corrStudy.mqh |
|
||
|
|
//| Correlation Study Framework (devKit) |
|
||
|
|
//| |
|
||
|
|
//| PURPOSE |
|
||
|
|
//| ------- |
|
||
|
|
//| Empirically study HOW and WHETHER a set of parameters |
|
||
|
|
//| (of mixed types) correlates with one fixed bool outcome. |
|
||
|
|
//| |
|
||
|
|
//| Use-cases: |
|
||
|
|
//| • What makes a candle's range (H-L) large? |
|
||
|
|
//| • What triggers aggressive consecutive bullish/bearish runs? |
|
||
|
|
//| • Does LastCSID presence / roomToLeft / hour-of-day matter? |
|
||
|
|
//| |
|
||
|
|
//| STATISTICS PRODUCED |
|
||
|
|
//| ------------------- |
|
||
|
|
//| Bool params → Phi coefficient (φ, -1..+1) |
|
||
|
|
//| Lift = P(out|param=T) / P(out) |
|
||
|
|
//| Conditional rate table |
|
||
|
|
//| Numeric params → Point-biserial r (-1..+1) |
|
||
|
|
//| Mean(param | out=T) vs Mean(param | out=F) |
|
||
|
|
//| Ratio of means |
|
||
|
|
//| |
|
||
|
|
//| QUICK-START |
|
||
|
|
//| ----------- |
|
||
|
|
//| // 1. Define your outcome function (zero args, returns bool) |
|
||
|
|
//| bool IsBigRange() { return (crt / atr) >= 1.5; } |
|
||
|
|
//| |
|
||
|
|
//| // 2. Instantiate |
|
||
|
|
//| CCorrelationStudy study("BigRange", IsBigRange); |
|
||
|
|
//| study.StartExport("BigRange_data.csv"); |
|
||
|
|
//| |
|
||
|
|
//| // 3. In OnCalculate / OnTick, set params then observe |
|
||
|
|
//| study.SetBool ("LastCSID", hasCSID); |
|
||
|
|
//| study.SetDouble("PrevRange", prev_h - prev_l); |
|
||
|
|
//| study.SetDouble("RoomToLeft", roomToLeft); |
|
||
|
|
//| study.SetHour ("Hour", TimeCurrent()); |
|
||
|
|
//| study.Observe(); // records one observation |
|
||
|
|
//| |
|
||
|
|
//| // 4. Print report at any time (or on Deinit) |
|
||
|
|
//| study.Report(); |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#pragma once
|
||
|
|
#include <Math\Stat\Math.mqh> // MathSqrt, MathAbs — guaranteed available
|
||
|
|
|
||
|
|
//===================================================================
|
||
|
|
// Function pointer type — the outcome to study
|
||
|
|
// Zero arguments: the developer computes context outside.
|
||
|
|
// Returns true when the outcome of interest occurred.
|
||
|
|
//===================================================================
|
||
|
|
typedef bool (*OutcomeFunc)();
|
||
|
|
|
||
|
|
//===================================================================
|
||
|
|
// Internal statistics structures
|
||
|
|
//===================================================================
|
||
|
|
|
||
|
|
// ---- Bool parameter -----------------------------------------------
|
||
|
|
struct BoolParamStat
|
||
|
|
{
|
||
|
|
string name;
|
||
|
|
bool current_val; // value set this observation
|
||
|
|
|
||
|
|
// 2×2 contingency table
|
||
|
|
// n[param_val][outcome_val]
|
||
|
|
int n[2][2]; // n[0/1][0/1] — total 4 cells
|
||
|
|
int total; // total observations touching this param
|
||
|
|
};
|
||
|
|
|
||
|
|
// ---- Numeric parameter (double, int, hour) ------------------------
|
||
|
|
// Stores running Welford-style accumulators for online mean/variance.
|
||
|
|
struct NumParamStat
|
||
|
|
{
|
||
|
|
string name;
|
||
|
|
double current_val; // value set this observation
|
||
|
|
|
||
|
|
// Global accumulators (all observations)
|
||
|
|
double sum_all;
|
||
|
|
double sum_sq_all;
|
||
|
|
int count_all;
|
||
|
|
|
||
|
|
// Split by outcome
|
||
|
|
double sum_true; // sum of param values when outcome=true
|
||
|
|
double sum_true_sq;
|
||
|
|
int count_true;
|
||
|
|
|
||
|
|
double sum_false;
|
||
|
|
double sum_false_sq;
|
||
|
|
int count_false;
|
||
|
|
};
|
||
|
|
|
||
|
|
//===================================================================
|
||
|
|
// CCorrelationStudy
|
||
|
|
//===================================================================
|
||
|
|
class CCorrelationStudy
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
string m_name; // study label
|
||
|
|
OutcomeFunc m_outcome; // the outcome function
|
||
|
|
int m_total; // total observations recorded
|
||
|
|
int m_outcome_true; // times outcome was true
|
||
|
|
|
||
|
|
// Parameter slots
|
||
|
|
BoolParamStat m_bools[];
|
||
|
|
int m_bool_count;
|
||
|
|
|
||
|
|
NumParamStat m_nums[];
|
||
|
|
int m_num_count;
|
||
|
|
|
||
|
|
// CSV export state
|
||
|
|
int m_file; // file handle (-1 = not open)
|
||
|
|
bool m_exporting;
|
||
|
|
|
||
|
|
//--- Find a bool slot by name, return -1 if absent
|
||
|
|
int FindBool(const string name) const
|
||
|
|
{
|
||
|
|
for(int i = 0; i < m_bool_count; i++)
|
||
|
|
if(m_bools[i].name == name) return i;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Find a numeric slot by name, return -1 if absent
|
||
|
|
int FindNum(const string name) const
|
||
|
|
{
|
||
|
|
for(int i = 0; i < m_num_count; i++)
|
||
|
|
if(m_nums[i].name == name) return i;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Get or create a bool slot
|
||
|
|
int EnsureBool(const string name)
|
||
|
|
{
|
||
|
|
int idx = FindBool(name);
|
||
|
|
if(idx != -1) return idx;
|
||
|
|
ArrayResize(m_bools, m_bool_count + 1);
|
||
|
|
m_bools[m_bool_count].name = name;
|
||
|
|
m_bools[m_bool_count].current_val = false;
|
||
|
|
m_bools[m_bool_count].total = 0;
|
||
|
|
for(int r = 0; r < 2; r++)
|
||
|
|
for(int c = 0; c < 2; c++)
|
||
|
|
m_bools[m_bool_count].n[r][c] = 0;
|
||
|
|
return m_bool_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Get or create a numeric slot
|
||
|
|
int EnsureNum(const string name)
|
||
|
|
{
|
||
|
|
int idx = FindNum(name);
|
||
|
|
if(idx != -1) return idx;
|
||
|
|
ArrayResize(m_nums, m_num_count + 1);
|
||
|
|
m_nums[m_num_count].name = name;
|
||
|
|
m_nums[m_num_count].current_val = 0.0;
|
||
|
|
m_nums[m_num_count].sum_all = 0.0;
|
||
|
|
m_nums[m_num_count].sum_sq_all = 0.0;
|
||
|
|
m_nums[m_num_count].count_all = 0;
|
||
|
|
m_nums[m_num_count].sum_true = 0.0;
|
||
|
|
m_nums[m_num_count].sum_true_sq = 0.0;
|
||
|
|
m_nums[m_num_count].count_true = 0;
|
||
|
|
m_nums[m_num_count].sum_false = 0.0;
|
||
|
|
m_nums[m_num_count].sum_false_sq = 0.0;
|
||
|
|
m_nums[m_num_count].count_false = 0;
|
||
|
|
return m_num_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Compute Phi coefficient from a 2x2 contingency table
|
||
|
|
// phi = (n11*n00 - n10*n01) / sqrt(n1. * n0. * n.1 * n.0)
|
||
|
|
// Returns 0.0 when undefined (zero marginal)
|
||
|
|
double CalcPhi(const BoolParamStat &s) const
|
||
|
|
{
|
||
|
|
double n11 = s.n[1][1]; // param=T, outcome=T
|
||
|
|
double n10 = s.n[1][0]; // param=T, outcome=F
|
||
|
|
double n01 = s.n[0][1]; // param=F, outcome=T
|
||
|
|
double n00 = s.n[0][0]; // param=F, outcome=F
|
||
|
|
|
||
|
|
double row1 = n11 + n10; // total param=T
|
||
|
|
double row0 = n01 + n00; // total param=F
|
||
|
|
double col1 = n11 + n01; // total outcome=T
|
||
|
|
double col0 = n10 + n00; // total outcome=F
|
||
|
|
|
||
|
|
double denom = row1 * row0 * col1 * col0;
|
||
|
|
if(denom <= 0.0) return 0.0;
|
||
|
|
return (n11 * n00 - n10 * n01) / MathSqrt(denom);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Compute Point-Biserial r
|
||
|
|
// r_pb = (M1-M0)/S * sqrt(n1*n0/n^2)
|
||
|
|
// Returns 0.0 when undefined
|
||
|
|
double CalcPointBiserial(const NumParamStat &s) const
|
||
|
|
{
|
||
|
|
if(s.count_all < 2 || s.count_true == 0 || s.count_false == 0)
|
||
|
|
return 0.0;
|
||
|
|
|
||
|
|
double M1 = s.sum_true / s.count_true;
|
||
|
|
double M0 = s.sum_false / s.count_false;
|
||
|
|
|
||
|
|
// Population std dev of the full param series
|
||
|
|
double mean_all = s.sum_all / s.count_all;
|
||
|
|
double var_all = (s.sum_sq_all / s.count_all) - mean_all * mean_all;
|
||
|
|
if(var_all <= 0.0) return 0.0;
|
||
|
|
|
||
|
|
double S = MathSqrt(var_all);
|
||
|
|
double n = (double)s.count_all;
|
||
|
|
|
||
|
|
return (M1 - M0) / S * MathSqrt((double)(s.count_true * s.count_false) / (n * n));
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Write one CSV row (called inside Observe())
|
||
|
|
void WriteCSVRow(bool outcome)
|
||
|
|
{
|
||
|
|
if(!m_exporting || m_file < 0) return;
|
||
|
|
|
||
|
|
string row = TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS) +
|
||
|
|
"," + (outcome ? "1" : "0");
|
||
|
|
|
||
|
|
for(int i = 0; i < m_bool_count; i++)
|
||
|
|
row += "," + (m_bools[i].current_val ? "1" : "0");
|
||
|
|
|
||
|
|
for(int i = 0; i < m_num_count; i++)
|
||
|
|
row += "," + DoubleToString(m_nums[i].current_val, 6);
|
||
|
|
|
||
|
|
FileWrite(m_file, row);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Write CSV header row
|
||
|
|
void WriteCSVHeader()
|
||
|
|
{
|
||
|
|
if(!m_exporting || m_file < 0) return;
|
||
|
|
string hdr = "datetime,outcome";
|
||
|
|
for(int i = 0; i < m_bool_count; i++) hdr += "," + m_bools[i].name;
|
||
|
|
for(int i = 0; i < m_num_count; i++) hdr += "," + m_nums[i].name;
|
||
|
|
FileWrite(m_file, hdr);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Bar separator string
|
||
|
|
string Bar(int len = 64) const
|
||
|
|
{
|
||
|
|
string s = "";
|
||
|
|
for(int i = 0; i < len; i++) s += "-";
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
//=================================================================
|
||
|
|
// Construction / Destruction
|
||
|
|
//=================================================================
|
||
|
|
|
||
|
|
CCorrelationStudy(const string study_name, OutcomeFunc outcome_func)
|
||
|
|
{
|
||
|
|
m_name = study_name;
|
||
|
|
m_outcome = outcome_func;
|
||
|
|
m_total = 0;
|
||
|
|
m_outcome_true = 0;
|
||
|
|
m_bool_count = 0;
|
||
|
|
m_num_count = 0;
|
||
|
|
m_file = INVALID_HANDLE;
|
||
|
|
m_exporting = false;
|
||
|
|
ArrayResize(m_bools, 0);
|
||
|
|
ArrayResize(m_nums, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
~CCorrelationStudy()
|
||
|
|
{
|
||
|
|
StopExport();
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// PARAMETER VALUE SETTERS
|
||
|
|
// Call these each candle/bar before Observe()
|
||
|
|
//=================================================================
|
||
|
|
|
||
|
|
//--- Boolean parameter (e.g. "LastCSID", "PrevBullish")
|
||
|
|
void SetBool(const string name, bool val)
|
||
|
|
{
|
||
|
|
int idx = EnsureBool(name);
|
||
|
|
m_bools[idx].current_val = val;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Continuous real-valued parameter (e.g. "PrevRange", "ATR", "RoomToLeft")
|
||
|
|
void SetDouble(const string name, double val)
|
||
|
|
{
|
||
|
|
int idx = EnsureNum(name);
|
||
|
|
m_nums[idx].current_val = val;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Integer parameter (e.g. "ConsecCandles", "SwingCount")
|
||
|
|
void SetInt(const string name, int val)
|
||
|
|
{
|
||
|
|
SetDouble(name, (double)val);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Datetime → extracts hour-of-day [0..23] as a numeric param.
|
||
|
|
// Use this for session/time-of-day studies.
|
||
|
|
void SetHour(const string name, datetime dt)
|
||
|
|
{
|
||
|
|
MqlDateTime s;
|
||
|
|
TimeToStruct(dt, s);
|
||
|
|
SetDouble(name, (double)s.hour);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Datetime → extracts day-of-week [0=Sun..6=Sat] as numeric.
|
||
|
|
void SetDayOfWeek(const string name, datetime dt)
|
||
|
|
{
|
||
|
|
MqlDateTime s;
|
||
|
|
TimeToStruct(dt, s);
|
||
|
|
SetDouble(name, (double)s.day_of_week);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Raw datetime stored as seconds-since-epoch (for full resolution)
|
||
|
|
void SetDateTime(const string name, datetime dt)
|
||
|
|
{
|
||
|
|
SetDouble(name, (double)(long)dt);
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// OBSERVE — record one data point
|
||
|
|
// Call once per candle / bar after setting all params.
|
||
|
|
// Returns the outcome value so the caller can branch if needed.
|
||
|
|
//=================================================================
|
||
|
|
bool Observe()
|
||
|
|
{
|
||
|
|
if(m_outcome == NULL)
|
||
|
|
{
|
||
|
|
Print("CCorrelationStudy::Observe — outcome function is null.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool out = m_outcome();
|
||
|
|
int ov = out ? 1 : 0;
|
||
|
|
|
||
|
|
m_total++;
|
||
|
|
if(out) m_outcome_true++;
|
||
|
|
|
||
|
|
// --- Update bool param stats
|
||
|
|
for(int i = 0; i < m_bool_count; i++)
|
||
|
|
{
|
||
|
|
int pv = m_bools[i].current_val ? 1 : 0;
|
||
|
|
m_bools[i].n[pv][ov]++;
|
||
|
|
m_bools[i].total++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Update numeric param stats
|
||
|
|
for(int i = 0; i < m_num_count; i++)
|
||
|
|
{
|
||
|
|
double v = m_nums[i].current_val;
|
||
|
|
m_nums[i].sum_all += v;
|
||
|
|
m_nums[i].sum_sq_all += v * v;
|
||
|
|
m_nums[i].count_all++;
|
||
|
|
|
||
|
|
if(out)
|
||
|
|
{
|
||
|
|
m_nums[i].sum_true += v;
|
||
|
|
m_nums[i].sum_true_sq += v * v;
|
||
|
|
m_nums[i].count_true++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_nums[i].sum_false += v;
|
||
|
|
m_nums[i].sum_false_sq += v * v;
|
||
|
|
m_nums[i].count_false++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- CSV
|
||
|
|
WriteCSVRow(out);
|
||
|
|
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// REPORT — print full analysis to Experts log
|
||
|
|
//=================================================================
|
||
|
|
void Report() const
|
||
|
|
{
|
||
|
|
if(m_total == 0)
|
||
|
|
{
|
||
|
|
Print("CCorrelationStudy[", m_name, "] — no observations yet.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
double base_rate = (double)m_outcome_true / m_total;
|
||
|
|
|
||
|
|
Print(Bar(66));
|
||
|
|
PrintFormat(" CORRELATION STUDY: %s", m_name);
|
||
|
|
PrintFormat(" Observations : %d", m_total);
|
||
|
|
PrintFormat(" Outcome=TRUE : %d (base rate = %.1f%%)", m_outcome_true, base_rate * 100.0);
|
||
|
|
Print(Bar(66));
|
||
|
|
|
||
|
|
// ---- BOOL PARAMETERS ------------------------------------------
|
||
|
|
if(m_bool_count > 0)
|
||
|
|
{
|
||
|
|
Print(" [ BOOL PARAMETERS ]");
|
||
|
|
PrintFormat(" %-20s %6s %6s %6s %6s %6s %6s",
|
||
|
|
"Name", "P(o|p=T)", "P(o|p=F)", "Lift", "Phi", "n(T)", "n(F)");
|
||
|
|
Print(" ", Bar(74));
|
||
|
|
|
||
|
|
for(int i = 0; i < m_bool_count; i++)
|
||
|
|
{
|
||
|
|
const BoolParamStat *s = GetPointer(m_bools[i]);
|
||
|
|
|
||
|
|
int nT = s.n[1][1] + s.n[1][0]; // param=true total
|
||
|
|
int nF = s.n[0][1] + s.n[0][0]; // param=false total
|
||
|
|
|
||
|
|
double rate_T = (nT > 0) ? (double)s.n[1][1] / nT : 0.0;
|
||
|
|
double rate_F = (nF > 0) ? (double)s.n[0][1] / nF : 0.0;
|
||
|
|
double lift = (base_rate > 0.0) ? rate_T / base_rate : 0.0;
|
||
|
|
double phi = CalcPhi(m_bools[i]);
|
||
|
|
|
||
|
|
PrintFormat(" %-20s %5.1f%% %5.1f%% %6.2f %+6.3f %6d %6d",
|
||
|
|
s.name, rate_T * 100.0, rate_F * 100.0,
|
||
|
|
lift, phi, nT, nF);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- NUMERIC PARAMETERS ---------------------------------------
|
||
|
|
if(m_num_count > 0)
|
||
|
|
{
|
||
|
|
Print("");
|
||
|
|
Print(" [ NUMERIC PARAMETERS ]");
|
||
|
|
PrintFormat(" %-20s %8s %8s %6s %6s %6s",
|
||
|
|
"Name", "Mean|T", "Mean|F", "Ratio", "r_pb", "n");
|
||
|
|
Print(" ", Bar(74));
|
||
|
|
|
||
|
|
for(int i = 0; i < m_num_count; i++)
|
||
|
|
{
|
||
|
|
const NumParamStat *s = GetPointer(m_nums[i]);
|
||
|
|
if(s.count_all == 0) continue;
|
||
|
|
|
||
|
|
double M1 = (s.count_true > 0) ? s.sum_true / s.count_true : 0.0;
|
||
|
|
double M0 = (s.count_false > 0) ? s.sum_false / s.count_false : 0.0;
|
||
|
|
double ratio = (M0 != 0.0) ? M1 / M0 : 0.0;
|
||
|
|
double rpb = CalcPointBiserial(m_nums[i]);
|
||
|
|
|
||
|
|
PrintFormat(" %-20s %8.4f %8.4f %6.2f %+6.3f %6d",
|
||
|
|
s.name, M1, M0, ratio, rpb, s.count_all);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Print(Bar(66));
|
||
|
|
Print(" INTERPRETATION GUIDE");
|
||
|
|
Print(" Phi: -1=negative, 0=none, +1=positive (bool params)");
|
||
|
|
Print(" Lift: >1 param=T raises outcome rate; <1 lowers it");
|
||
|
|
Print(" r_pb: -1=negative, 0=none, +1=positive (numeric params)");
|
||
|
|
Print(" Ratio: Mean|T / Mean|F (>1 → larger values → more outcome)");
|
||
|
|
Print(Bar(66));
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// CSV EXPORT
|
||
|
|
//=================================================================
|
||
|
|
|
||
|
|
//--- Open a CSV file and start streaming raw observations.
|
||
|
|
// File is created in the MQL5/Files directory.
|
||
|
|
// Returns true on success.
|
||
|
|
bool StartExport(const string filename)
|
||
|
|
{
|
||
|
|
if(m_exporting)
|
||
|
|
{
|
||
|
|
Print("CCorrelationStudy::StartExport — already exporting. Call StopExport() first.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_file = FileOpen(filename, FILE_WRITE | FILE_CSV | FILE_ANSI, ',');
|
||
|
|
if(m_file == INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
PrintFormat("CCorrelationStudy::StartExport — cannot open '%s'. Error: %d",
|
||
|
|
filename, GetLastError());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_exporting = true;
|
||
|
|
WriteCSVHeader();
|
||
|
|
PrintFormat("CCorrelationStudy[%s] — CSV export started: %s", m_name, filename);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Flush and close the CSV file.
|
||
|
|
void StopExport()
|
||
|
|
{
|
||
|
|
if(!m_exporting || m_file == INVALID_HANDLE) return;
|
||
|
|
FileClose(m_file);
|
||
|
|
m_file = INVALID_HANDLE;
|
||
|
|
m_exporting = false;
|
||
|
|
PrintFormat("CCorrelationStudy[%s] — CSV export stopped.", m_name);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsExporting() const { return m_exporting; }
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// QUICK STATS (single param queries without full report)
|
||
|
|
//=================================================================
|
||
|
|
|
||
|
|
//--- Base rate of the outcome across all observations.
|
||
|
|
double BaseRate() const { return (m_total > 0) ? (double)m_outcome_true / m_total : 0.0; }
|
||
|
|
int TotalObs() const { return m_total; }
|
||
|
|
int OutcomeTrue() const { return m_outcome_true; }
|
||
|
|
|
||
|
|
//--- Point-biserial r for one numeric param by name.
|
||
|
|
double GetRpb(const string name) const
|
||
|
|
{
|
||
|
|
int idx = FindNum(name);
|
||
|
|
return (idx == -1) ? 0.0 : CalcPointBiserial(m_nums[idx]);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Phi coefficient for one bool param by name.
|
||
|
|
double GetPhi(const string name) const
|
||
|
|
{
|
||
|
|
int idx = FindBool(name);
|
||
|
|
return (idx == -1) ? 0.0 : CalcPhi(m_bools[idx]);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Mean of a numeric param when outcome was true/false.
|
||
|
|
double MeanWhenTrue(const string name) const
|
||
|
|
{
|
||
|
|
int idx = FindNum(name);
|
||
|
|
if(idx == -1 || m_nums[idx].count_true == 0) return 0.0;
|
||
|
|
return m_nums[idx].sum_true / m_nums[idx].count_true;
|
||
|
|
}
|
||
|
|
|
||
|
|
double MeanWhenFalse(const string name) const
|
||
|
|
{
|
||
|
|
int idx = FindNum(name);
|
||
|
|
if(idx == -1 || m_nums[idx].count_false == 0) return 0.0;
|
||
|
|
return m_nums[idx].sum_false / m_nums[idx].count_false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// RESET
|
||
|
|
//=================================================================
|
||
|
|
|
||
|
|
//--- Wipe all accumulated statistics but keep param slot names.
|
||
|
|
void ResetStats()
|
||
|
|
{
|
||
|
|
m_total = 0;
|
||
|
|
m_outcome_true = 0;
|
||
|
|
|
||
|
|
for(int i = 0; i < m_bool_count; i++)
|
||
|
|
{
|
||
|
|
m_bools[i].total = 0;
|
||
|
|
for(int r = 0; r < 2; r++)
|
||
|
|
for(int c = 0; c < 2; c++)
|
||
|
|
m_bools[i].n[r][c] = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
for(int i = 0; i < m_num_count; i++)
|
||
|
|
{
|
||
|
|
m_nums[i].sum_all = 0; m_nums[i].sum_sq_all = 0; m_nums[i].count_all = 0;
|
||
|
|
m_nums[i].sum_true = 0; m_nums[i].sum_true_sq = 0; m_nums[i].count_true = 0;
|
||
|
|
m_nums[i].sum_false = 0; m_nums[i].sum_false_sq = 0; m_nums[i].count_false = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Wipe everything including param slot definitions.
|
||
|
|
void FullReset()
|
||
|
|
{
|
||
|
|
ResetStats();
|
||
|
|
m_bool_count = 0;
|
||
|
|
m_num_count = 0;
|
||
|
|
ArrayResize(m_bools, 0);
|
||
|
|
ArrayResize(m_nums, 0);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
// END OF FRAMEWORK
|
||
|
|
//+------------------------------------------------------------------+
|