//+------------------------------------------------------------------+ //| MarketContext.mqh | //| AnimateDread | //| | //| WHAT THE TRADER SAW WHEN THEY PRESSED THE BUTTON. | //| | //| One fixed-width record of every modality's reading at the signal | //| bar. It is the single source of truth for three consumers that | //| used to be three hand-kept lists: the modalities WRITE it, the | //| trade book PERSISTS it (header and row both come from CtxName()), | //| and the reviewer BUCKETS it. Add a field once, here, and all | //| three follow; nothing else spells a column name. | //| | //| CTX_NA marks a reading the modality could not produce. It is | //| never zero: a missing Wyckoff read must not look like "phase 0". | //+------------------------------------------------------------------+ #ifndef WARRIOR_MARKETCONTEXT_MQH #define WARRIOR_MARKETCONTEXT_MQH #define CTX_NA (-999.0) enum ENUM_CTX { //--- price shape (ModalityPrice) CTX_Z = 0, // z-score(20) of the close CTX_DIST_ATR, // (close - SMA20) / ATR CTX_RET1_ATR, // last bar's return, in ATR CTX_DROP5_ATR, // 5-bar return, in ATR CTX_RANGE_ATR, // bar range, in ATR CTX_CLOSE_LOC, // where the close sat in its own range, 0..1 CTX_ER, // efficiency ratio (20) CTX_VR, // variance ratio (60, 5) CTX_REGIME, // 0 chop / 1 trend / 2 mean-revert //--- volatility (ModalityPrice) CTX_VOL_PCT, // expanding-window percentile of Garman-Klass sigma(30) CTX_ATR_RATIO, // ATR / mean ATR of the last 100 bars //--- volume, clock removed (ModalityVolume) CTX_RVOL, // ln(tick volume / same-hour median), level-detrended CTX_RVOL_RAW, // the same without the detrend CTX_ABSORB, // effort minus result: rvol - ln(range/ATR). High = volume without progress //--- Wyckoff structure (ModalityWyckoff) CTX_WYK_OK, // 1 when the indicators answered CTX_WYK_PHASE, // phase * direction: +-1..5 = A..E CTX_WYK_EVENT, // last event within the look-back, signed code (+-1..9) CTX_WYK_AGE, // bars since that event CTX_WYK_SPRING, // strongest spring/UTAD grade within the look-back, signed CTX_WYK_CHAR, // +1 accumulation / -1 distribution / 0 not anchored CTX_WYK_RANGEPOS, // close inside the open range, 0..1 (NA when no range is open) CTX_WYK_FAIL, // failed-structure quality, signed CTX_WYK_BIAS, // the reader's verdict for a LONG, -1..+1 //--- cross-index breadth (ModalityBreadth) CTX_BREADTH_N, // peers that answered CTX_BREADTH, // fraction of them at z(20) <= -1 //--- calendar (ModalityCalendar) CTX_DOW, CTX_HOUR, CTX_DOM, // day of month CTX_TO_MONTH_END, // calendar days to month end CTX_N }; string CtxName(const int i) { switch(i) { case CTX_Z: return "z20"; case CTX_DIST_ATR: return "dist_sma_atr"; case CTX_RET1_ATR: return "ret1_atr"; case CTX_DROP5_ATR: return "ret5_atr"; case CTX_RANGE_ATR: return "range_atr"; case CTX_CLOSE_LOC: return "close_loc"; case CTX_ER: return "er20"; case CTX_VR: return "vr60_5"; case CTX_REGIME: return "regime"; case CTX_VOL_PCT: return "vol_pct"; case CTX_ATR_RATIO: return "atr_ratio"; case CTX_RVOL: return "rvol_tod"; case CTX_RVOL_RAW: return "rvol_tod_raw"; case CTX_ABSORB: return "absorb"; case CTX_WYK_OK: return "wyk_ok"; case CTX_WYK_PHASE: return "wyk_phase"; case CTX_WYK_EVENT: return "wyk_event"; case CTX_WYK_AGE: return "wyk_event_age"; case CTX_WYK_SPRING: return "wyk_spring"; case CTX_WYK_CHAR: return "wyk_char"; case CTX_WYK_RANGEPOS: return "wyk_range_pos"; case CTX_WYK_FAIL: return "wyk_fail"; case CTX_WYK_BIAS: return "wyk_bias"; case CTX_BREADTH_N: return "breadth_n"; case CTX_BREADTH: return "breadth"; case CTX_DOW: return "dow"; case CTX_HOUR: return "hour"; case CTX_DOM: return "dom"; case CTX_TO_MONTH_END: return "to_month_end"; } return "?"; } struct SMarketContext { datetime bar; // open time of the signal bar double v[CTX_N]; string story; // the same reading, as a trader would say it void Reset(const datetime t) { bar = t; story = ""; for(int i = 0; i < CTX_N; i++) v[i] = CTX_NA; } bool Has(const int f) const { return v[f] != CTX_NA; } }; //--- The CSV columns for a context, in field order. Header and row are built from the same loop, //--- so they cannot disagree about width or order. string CtxHeader(void) { string h = ""; for(int i = 0; i < CTX_N; i++) h += (i > 0 ? "," : "") + CtxName(i); return h; } string CtxRow(const SMarketContext &c) { string r = ""; for(int i = 0; i < CTX_N; i++) r += (i > 0 ? "," : "") + DoubleToString(c.v[i], 5); return r; } #endif // WARRIOR_MARKETCONTEXT_MQH