RSI-Stoch-MA-EA/NNDataLogger.mqh

137 lines
4.2 KiB
MQL5
Raw Permalink Normal View History

2026-01-21 09:23:11 +00:00
//+------------------------------------------------------------------+
//| NNDataLogger.mqh|
//| Logs training samples ONLY when SignalCluster is trade-ready |
//+------------------------------------------------------------------+
#property strict
#include <Files\File.mqh>
#include "NNFeatures.mqh"
// ===================== INPUTS ======================
input bool NN_LogData = true;
input string NN_LogFileName = "nn_dataset_signalready.csv";
input int NN_LabelLookaheadBars = 180; // lookahead window for label
input int NN_MinSecondsBetweenLogs = 10; // avoid spam
// SL/TP mapping (points) — match your bot defaults
input double NN_Cont_SL_Points = 150;
input double NN_Cont_TP_Points = 4000;
input double NN_Counter_SL_Points = 50;
input double NN_Counter_TP_Points = 3000;
// Optional: only log if conflict <= this (extra safety gate)
input double NN_MaxConflictToLog = 40.0;
// ===================== INTERNAL ======================
datetime g_nn_last_log_time = 0;
// Conservative “first hit” label using OHLC of future bars.
// If both TP and SL occur in same bar -> SL wins (tp_first=0).
int NN_LabelTPBeforeSL(bool is_buy, double entry, double tp_pts, double sl_pts, int lookaheadBars)
{
double tp = is_buy ? (entry + tp_pts * _Point) : (entry - tp_pts * _Point);
double sl = is_buy ? (entry - sl_pts * _Point) : (entry + sl_pts * _Point);
for(int i=1; i<=lookaheadBars; i++)
{
double hi = iHigh(_Symbol, PERIOD_CURRENT, i);
double lo = iLow(_Symbol, PERIOD_CURRENT, i);
bool hitTP = false, hitSL = false;
if(is_buy)
{
if(hi >= tp) hitTP = true;
if(lo <= sl) hitSL = true;
}
else
{
if(lo <= tp) hitTP = true; // TP is below entry for sell
if(hi >= sl) hitSL = true; // SL is above entry for sell
}
// Conservative tie-break: SL wins
if(hitSL) return 0;
if(hitTP) return 1;
}
return 0; // no TP within window => treat as fail
}
// Public function: call this ONLY when your cluster is trade-ready.
void NN_LogSignalReadySample(
bool is_buy,
int category, // 0 continuation, 1 counter (use your TRADE_CATEGORY)
double cluster_strength, // 0..100 if you have it
double conflict_score // 0..100 if you have it
)
{
if(!NN_LogData) return;
datetime now = TimeCurrent();
if(g_nn_last_log_time > 0 && (now - g_nn_last_log_time) < NN_MinSecondsBetweenLogs)
return;
if(conflict_score > NN_MaxConflictToLog)
return;
// Feature vector from your existing globals (Indicators/Warn/Praise/State)
double feat[];
int n = BuildNNFeatures(feat);
if(n <= 0) return;
// Use current open price (you can change to bid/ask if you prefer)
double entry = iOpen(_Symbol, PERIOD_CURRENT, 0);
// Pick SL/TP based on category
double sl_pts = (category == 0 ? NN_Cont_SL_Points : NN_Counter_SL_Points);
double tp_pts = (category == 0 ? NN_Cont_TP_Points : NN_Counter_TP_Points);
int tp_first = NN_LabelTPBeforeSL(is_buy, entry, tp_pts, sl_pts, NN_LabelLookaheadBars);
// Write CSV row
int h = FileOpen(NN_LogFileName, FILE_READ|FILE_WRITE|FILE_CSV|FILE_ANSI);
if(h == INVALID_HANDLE) return;
FileSeek(h, 0, SEEK_END);
// Header
if(FileSize(h) == 0)
{
FileWrite(h,
"time","symbol","tf",
"is_buy","category",
"cluster_strength","conflict_score",
"entry","tp_points","sl_points",
"tp_first",
"n_features","features_json"
);
}
// Serialize features
string fjson = "[";
for(int k=0; k<n; k++)
{
fjson += DoubleToString(feat[k], 8);
if(k < n-1) fjson += ",";
}
fjson += "]";
FileWrite(h,
(string)iTime(_Symbol, PERIOD_CURRENT, 0),
_Symbol,
(string)Period(),
(is_buy ? 1 : 0),
category,
DoubleToString(cluster_strength, 2),
DoubleToString(conflict_score, 2),
DoubleToString(entry, _Digits),
DoubleToString(tp_pts, 1),
DoubleToString(sl_pts, 1),
tp_first,
n,
fjson
);
FileClose(h);
g_nn_last_log_time = now;
}