forked from mnbvc188199/Warrior_EA
Warrior's defaults are now the validated book: DIP_ZSCORE alone, long only, H4, risk 0.25%, one chart per index with a shared Magic. - System/BarCache.mqh: whole-history closed bars, Wilder ATR, GK sigma and the expanding vol percentile (no 1024-bar stdlib ceiling) - System/AccountGuard.mqh: open-risk cap, kill switch, cross-chart lock and Friday flat, shared through terminal globals by Magic - CWarriorExpert: guard on every tick; a transient open failure retries the bar - CWarriorSignal::SetupStop: the dip owns its 3 x Wilder ATR stop from the bid - SignalDipBuy: no entry vote while holding (a still-dipping time exit never closed, and Processing re-entered on the exit bar); no entry on a stop bar - WarriorMoney sizes on equity; WARRIOR_RISK allows fractional risk - TradeLog + research/compare_ea.py: trade-for-trade check vs WarriorDipZ - SP500/US30/DAX40 identical to the cent, NAS100 96.9% (stale-quote timer fills) - research/nn_cross_index.py: pre-registered cross-index NN meta-label - FAIL (AUC 0.564, CI [0.498, 0.630]); DipMetaCut stays off Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
3.1 KiB
MQL5
63 lines
3.1 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| TradeLog.mqh |
| |
//| AnimateDread |
| |
//| |
| |
//| ONE ROW PER CLOSED POSITION of this symbol and magic, written to |
| |
//| the common folder at deinit: <prefix>_trades_<SYMBOL>.csv. The |
| |
//| columns are WarriorDipZ's journal, so research/reconcile.py and |
| |
//| grid_summary.py read either EA's output - which is how Warrior |
| |
//| was checked trade for trade against the reference implementation. |
| |
//+------------------------------------------------------------------+
| |
#ifndef WARRIOR_TRADELOG_MQH
| |
#define WARRIOR_TRADELOG_MQH
| |
| |
void WriteTradeLog(const string prefix, const string symbol, const long magic)
| |
{
| |
if(!HistorySelect(0, TimeCurrent() + 86400))
| |
return;
| |
const int h = FileOpen(prefix + "_trades_" + symbol + ".csv",
| |
FILE_WRITE | FILE_CSV | FILE_ANSI | FILE_COMMON, ',');
| |
if(h == INVALID_HANDLE)
| |
return;
| |
FileWrite(h, "position", "symbol", "entry_time", "entry_price", "volume",
| |
"exit_time", "exit_price", "net_profit", "exit_reason",
| |
"gross_profit", "swap", "commission");
| |
const int deals = HistoryDealsTotal();
| |
for(int i = 0; i < deals; i++)
| |
{
| |
const ulong d = HistoryDealGetTicket(i);
| |
if(HistoryDealGetInteger(d, DEAL_MAGIC) != magic ||
| |
HistoryDealGetInteger(d, DEAL_ENTRY) != DEAL_ENTRY_OUT ||
| |
HistoryDealGetString(d, DEAL_SYMBOL) != symbol)
| |
continue;
| |
const long pos = HistoryDealGetInteger(d, DEAL_POSITION_ID);
| |
datetime et = 0;
| |
double ep = 0, vol = 0, gross = 0, swp = 0, com = 0;
| |
for(int j = 0; j < deals; j++)
| |
{
| |
const ulong e = HistoryDealGetTicket(j);
| |
if(HistoryDealGetInteger(e, DEAL_POSITION_ID) != pos)
| |
continue;
| |
gross += HistoryDealGetDouble(e, DEAL_PROFIT);
| |
swp += HistoryDealGetDouble(e, DEAL_SWAP);
| |
com += HistoryDealGetDouble(e, DEAL_COMMISSION);
| |
if(HistoryDealGetInteger(e, DEAL_ENTRY) == DEAL_ENTRY_IN)
| |
{
| |
et = (datetime)HistoryDealGetInteger(e, DEAL_TIME);
| |
ep = HistoryDealGetDouble(e, DEAL_PRICE);
| |
vol = HistoryDealGetDouble(e, DEAL_VOLUME);
| |
}
| |
}
| |
const long rsn = HistoryDealGetInteger(d, DEAL_REASON);
| |
const string why = (rsn == DEAL_REASON_SL ? "stop" : (rsn == DEAL_REASON_SO ? "stopout" : "expert"));
| |
FileWrite(h, (string)pos, symbol,
| |
TimeToString(et, TIME_DATE | TIME_MINUTES), DoubleToString(ep, 5),
| |
DoubleToString(vol, 2),
| |
TimeToString((datetime)HistoryDealGetInteger(d, DEAL_TIME), TIME_DATE | TIME_MINUTES),
| |
DoubleToString(HistoryDealGetDouble(d, DEAL_PRICE), 5),
| |
DoubleToString(gross + swp + com, 2), why, DoubleToString(gross, 2),
| |
DoubleToString(swp, 2), DoubleToString(com, 2));
| |
}
| |
FileClose(h);
| |
}
| |
#endif // WARRIOR_TRADELOG_MQH
|