203 Commits
Author SHA1 Message Date
Luke Mosoti 01e6e5e0a5 fix: use as_unit('ns') to normalise DatetimeIndex resolution before reindex
The previous astype() cast did not resolve the pandas 2.0 all-NaN reindex
issue. Using DatetimeIndex.as_unit('ns') (the pandas-2.0 canonical API)
on both the USDCHF series index and the target idx before calling reindex
ensures exact nanosecond-level timestamp matching regardless of whether
the source was read from CSV (datetime64[s]) or stripped from a UTC-aware
MT5 sync index via tz_localize(None) (datetime64[ns]).
2026-04-12 22:34:25 +03:00
Luke Mosoti a24c37c36f fix: resolve all-NaN USDCHF merge in sync_validate due to pandas 2.0 dtype mismatch
- map_usdchf_to_bars: intraday path now casts idx to match series.index dtype
  before reindex (datetime64[ns] from tz_localize vs datetime64[s] from CSV read
  caused reindex to return all-NaN, wiping all rows after dropna)
- _apply_features (validator): use _USDCHF_PATH_BY_TF for TF-specific USDCHF
  master path; add WARNING log listing any entirely-NaN columns before dropna
  to aid future diagnosis
2026-04-12 22:30:00 +03:00
Luke Mosoti b6b058927e feat: per-TF USDCHF consolidation + H1 optimizer recovery + MT5 data guide
- data_consolidator: add consolidate_usdchf_m15/m5 producing USDCHF_master_M15.csv
  and USDCHF_master_M5.csv; H1 legacy fallback now excludes M5/M15 filenames
- processor: _USDCHF_PATH_BY_TF lookup so each TF loads its matching-frequency
  USDCHF master (H1→master.csv, M15→master_M15.csv, M5→master_M5.csv)
- main: cmd_consolidate runs all three TF consolidations in one pass with per-TF summary
- optimizer: H1 n_states reverted [3,4], obs_cov floor raised 0.1→0.5,
  MIN_OOS_TRADES_BY_TF["H1"] lowered 200→75
- risk_manager: H1 headway_cent small-account daily cap raised 1→2 trades
- README: per-TF USDCHF filename/master table; dedicated "Getting deep history from MT5"
  section (any symbol, any TF) with MetaQuotes-Demo Pro Tip
2026-04-12 21:40:54 +03:00
Luke Mosoti 29d42b44fd feat: add Walk-Forward Analysis and model staleness checks to enhance trading strategy evaluation 2026-04-12 17:57:50 +03:00
Luke Mosoti d6fb72de59 feat: implement forced lot sizing for $15 accounts in MT5 trader 2026-04-11 22:42:39 +03:00
Luke Mosoti 0ecb17e2cd feat: H1 ultra-low-capital optimizer hardening for $15 accounts
Three changes to reduce Risk of Ruin on H1 with a $15 balance:

1. _score_result: doubled DD penalty for H1+small tier (5.0 → 10.0)
   — forces optimizer to prefer low-drawdown entries over raw Sharpe on
   hourly bars where a single swing can consume the 15% daily DD limit.

2. H1 search space tightened in make_objective:
   - n_states locked to 3 (Bull/Bear/Chop) — n_states=4 adds micro-regime
     noise on hourly bars without OOS benefit
   - max_depth reduced 3–5 → 2–4 (less IS memorisation on limited H1 data)
   - min_child_weight raised 1–15 → 15–30 (requires statistically
     significant split nodes, discourages noise-driven branches)
   M15 search space unchanged.

3. risk_manager: H1 small cent accounts capped at 1 trade/day, 1
   position/signal — forces the optimizer and live loop to select the
   single highest-conviction daily setup rather than averaging into losers.

USDCHF feature: already conditionally included in prepare_features when
USDCHF_master.csv is present — no change needed, graceful 4-feature
fallback preserved.

Action required: delete models/study_headway_cent.db before re-running
optimize --tf H1 so Optuna builds a fresh surrogate without stale
n_states=4 / min_child_weight<15 trials biasing the model.
2026-04-11 20:55:04 +03:00
Luke Mosoti 10e9f39e5b fix: pass Optuna thresholds to plot_equity_curve to fix Max DD 0.0% bug
plot_equity_curve was calling compute_signals with the hardcoded default
threshold (0.65). For M5 where Optuna tunes thresholds to 0.50–0.60, almost
no signals fired → near-zero strategy returns → drawdown annotation showed
"Max DD: 0.0%".

• plot_equity_curve now accepts prob_threshold / short_threshold params
• generate_full_report threads them through
• cmd_report passes params.get("prob_threshold") and params.get("short_threshold")
  so the equity curve uses the same Optuna-tuned thresholds as vectorized_backtest
2026-04-11 20:40:30 +03:00
Luke Mosoti 236a85270b feat: broker-specific report directories + add --mode report to all TF workflows
- visualizer.py: _tf_dir now uses reports/<TF>_<broker>/ so M5_headway_cent
  and M5_standard charts save to separate folders and never overwrite each other
- All 5 plot functions + generate_full_report accept broker= param and pass it through
- main.py cmd_report: passes broker= to generate_full_report; print updated to
  show reports/<TF>_<broker>/ path
- README.md: --mode report added to all four per-TF workflows (H1, M15, M5 cent,
  M5 standard); Step 6 updated with correct broker-specific folder tree; command
  reference table updated with broker-specific path description
2026-04-11 20:30:49 +03:00
Luke Mosoti 3e233481d7 fix: improve logging for USDCHF fallback and indicate data staleness 2026-04-11 12:55:59 +03:00
Luke MosotiandClaude Sonnet 4.6 d21069d958 docs: add Chop_Low/Chop_High state labels for n_states=4 (M5)
- State Labels section rewritten: shows Chop (n_states=3), Chop_Low=2
  and Chop_High=3 (n_states=4) with mean-return rank explanation
- Added explanation of why M5 uses two Chop sub-states and what
  distinguishes them (log-return rank, not volatility)
- Signal logic table updated: "Chop state (2 or 3)" blocked
- Regime-aligned filter note updated to reference both state 2 and 3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 21:47:09 +03:00
Luke MosotiandClaude Sonnet 4.6 57cc1d30f6 docs: update README for hybrid scalp protection, pos_per_trade, and TP3
- Hybrid Scalp Protection section: fixed scalp target ($4/position),
  trailing guard ($2 activation, 50% drawdown), both per-position
- Staged TPs: M5 growth accounts (>$50) now have TP3 at 3.0x SL;
  small accounts (<=$50) use TP1+TP2 only (clamped by min(pos_per_trade, len(tps)))
- Risk Management table: pos_per_trade=2 for <=$50, pos_per_trade=3 for >$50;
  removed outdated standard account guard row
- Timeframe Configurations: added pos_per_trade rows, TP3, trailing guard params
- Command Reference: added --profit_target option
- Standard account section: removed $500 minimum recommendation and old guard note
- Troubleshooting: updated EA conflict entry to mention startup CONFLICT warning
- Step 9: updated EA conflict note with accurate description of what goes wrong

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 21:40:29 +03:00
Luke Mosoti 55f49e3a9d feat: add profit target and trailing stop features for M5 scalping 2026-04-10 21:35:53 +03:00
Luke MosotiandClaude Sonnet 4.6 5b2a5ccefd fix: clearer no-signal reason + cp1252 unicode crash in logger
- mt5_trader: replace generic "No signal (need >X or <Y)" with an
  explicit reason that names the actual block — regime mismatch vs
  probability not cleared (e.g. "Bear state but prob=0.521 not <0.480")
  so users can see at a glance whether the HMM or XGBoost gated the bar
- main: replace U+2192 arrow in migration log message with ASCII '->'
  to avoid UnicodeEncodeError on Windows cp1252 terminals

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 21:51:34 +03:00
Luke Mosoti 3e566301f1 feat: update m5_meta.json scores and add new meta files for headway and standard models 2026-04-09 21:37:18 +03:00
Luke MosotiandClaude Sonnet 4.6 0cc1553d9a fix: m5_meta.json migration fallback for broker-specific path
If models/m5_meta_<broker>.json is not found, fall back to the legacy
models/m5_meta.json and copy it to the broker-specific path automatically.
Same migration pattern as the study.db fallback added earlier.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 21:35:07 +03:00
Luke MosotiandClaude Sonnet 4.6 6f296adb3b docs: full README.md rewrite — cent/standard accounts, new modes, broker-specific models
- Add Cent vs Standard account section with P&L conversion tables
  (explains that +$2.40 cent = $0.024 real USD, standard is 1:1)
- Remove all paper trading / --account demo|live references;
  replace with --mode demo (real orders, no prompt) and --mode live (real orders, YES prompt)
- Update model file references to broker+TF naming convention
  (hmm_model_H1_headway_cent.pkl etc.)
- Update study DB references to per-broker files (study_headway_cent.db / study_standard.db)
- Add M5 standard account workflow with prob_threshold 0.55-0.60 rationale
- Signal logic table updated: regime-aligned filter (Bull=BUY only, Bear=SELL only, Chop=blocked)
- Probability threshold table per TF per broker with search ranges
- Spread viability guard: cent M5-only 1.5x vs standard all-TFs 3.0x
- Standard account guard documented in risk management table
- Data freshness section explaining IS/OOS split dates and sync_validate scope
- Degenerate HMM training abort guard documented
- Troubleshooting table updated; removed dry_run/--account demo row
- State labels table updated with signal eligibility notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 11:26:31 +03:00
Luke Mosoti 4dd9c6fe1f Refactor code structure for improved readability and maintainability 2026-04-09 11:24:22 +03:00
Luke MosotiandClaude Sonnet 4.6 53aa01f9c1 docs: full README rewrite for broker-specific models and mode changes
README_LIVE.md:
- Cent vs Standard account explanation with real-USD P&L conversion table
  (shows that +$2.40 on cent = $0.024 real, standard is 1:1)
- Removed all paper trading / --account demo|live references
- --mode demo and --mode live documented (both send real orders, demo skips prompt)
- Added broker-specific model file tree (hmm_model_H1_headway_cent.pkl etc.)
- Probability threshold table per TF per broker with rationale
- M5 standard account workflow (prob_threshold 0.55-0.60 vs cent 0.50-0.53)
- Updated risk management table with standard account pos_per_trade guard
- Updated troubleshooting entries; removed dry_run reference
- Added Data Requirement section explaining IS/OOS split and sync_validate scope

README_REMOTE.md:
- Study DB references updated to per-broker files (study_headway_cent.db etc.)
- Explain that --trials N is a total target, not additional
- Instructions to delete only the target broker DB, not the shared study.db
- START TRADING button note (uses --mode live + --yes via subprocess)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 11:20:40 +03:00
Luke MosotiandClaude Sonnet 4.6 1c62499071 fix: study.db migration fallback + degenerate HMM training guard
- optimizer.get_best_params: if study_<broker>.db not found, fall back to
  legacy models/study.db so optimization runs before the per-broker split
  are not silently discarded (prevents 'using defaults' fallback)
- main.cmd_train: abort and sys.exit(1) before saving if HMM min state
  persistence < 0.70 — prevents deploying a garbage degenerate model when
  Optuna params were not loaded; prints clear remediation steps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 00:27:20 +03:00
Luke MosotiandClaude Sonnet 4.6 59085649ee feat: broker-specific model files and study DB separation
Cent and standard account models now live in separate files so
optimizing/training one account never overwrites the other:

- engine_hmm.py: get_model_path(tf, broker) → hmm_model_H1_headway_cent.pkl
- engine_xgb.py: get_ensemble_path(tf, broker) → xgb_ensemble_H1_standard.pkl
- optimizer.py: STUDY_DB replaced by _study_db(broker) →
  models/study_headway_cent.db + models/study_standard.db (fully isolated)
- main.py: _M5_META_PATH → _m5_meta_path(broker); thread broker through
  all model path calls, cmd_export, cmd_report, _check_m5_readiness
- validator.py: pass broker to hmm_model_path + get_ensemble_path
- mt5_trader.py: pass broker to hmm_model_path + get_ensemble_path

Backward-compat fallback to generic MODEL_PATH / ENSEMBLE_PKL_PATH
preserved if broker-specific file absent (e.g. models not yet retrained).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 00:16:46 +03:00
Luke MosotiandClaude Sonnet 4.6 cea8b3bab4 feat: multi-account architecture (Cent & Standard Hybrid)
- AdaptiveRiskManager: add broker param; standard guard forces pos_per_trade=1
  for growth accounts with balance<$50 to prevent unsafe dual-lot margin
- backtester: thread broker through apply_session_limits + ARM instantiations
- mt5_trader: broker-aware MIN_SPREAD_RATIO dict (cent=1.5, standard=3.0);
  spread viability guard now applies to all TFs on standard accounts;
  pass broker= to both ARM instantiations in live loop
- optimizer: broker-aware M5 prob thresholds (cent: 0.50-0.53, standard: 0.55-0.60)
  to account for higher per-trade costs on standard accounts
- main.py: pass broker= to ARM display calls in cmd_optimize/train/report

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 23:44:05 +03:00
Luke MosotiandClaude Opus 4.6 47edb1866e fix: H1/M15 degenerate HMM guard + tighten trans_cov ceiling
Two guards against the Bull/Chop state-collapse pattern (49K transitions,
identical state means, sub-0.01 persistence):

1. HMM quality gate: any state with self-transition prob < 0.80 → trial
   scored -100.0 immediately, before wasting time on XGBoost training.

2. trans_cov ceiling for H1/M15 lowered from 0.1 to 0.03.  Values above
   0.03 make Kalman noisy and typically cause state collapse with n_states=3.
   M5 keeps 0.001-0.1 (different bar structure and obs_cov range).

These fix the case where an optimizer run with n_states=3 returned
OOS Sharpe=2.117 but sync_validate showed Sharpe=-2.67 across all periods
due to degenerate HMM state assignments at inference time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 23:27:35 +03:00
Luke MosotiandClaude Opus 4.6 66d710057e feat: --mode demo/live split + P&L cent fix + pips + remove paper trading
Demo vs Live:
- New --mode demo: sends real orders to MT5 demo, no confirmation prompt
- --mode live: sends real orders, keeps WARNING + YES confirmation
- Removed --account argument (demo/live distinction now done via --mode)
- Removed dry_run feature entirely — all execution modes send real orders
- remote_control.py START commands use --mode live --yes (no --account)

P&L fixes:
- Cent account detection: raw MT5 balance > 10 000 → divide by CENT_MULTIPLIER
  to convert cUSD → real USD in all P&L logs and Telegram messages
- Pips added: price movement shown as "+X.XX pts" / "-X.XX pts" in log
  and Telegram after every closed position

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 22:52:56 +03:00
Luke MosotiandClaude Opus 4.6 776967d86e fix: H1/M15 n_states>=3 + warn when hmm_state importance=0
n_states=2 combined with the regime-aligned signal filter has no Chop
state, forcing every bar into Bull or Bear.  In a strongly trending
market (e.g. Q1-2026 gold bull run) the HMM mislabels many bullish bars
as Bear, firing SELL signals counter to the trend (WR dropped to 36.6%).

Requiring n_states>=3 for H1/M15 ensures there is always a Chop/neutral
state so ambiguous bars generate no signal instead of a wrong-direction
trade.  M5 keeps its [2,4] restriction since n_states=3 is degenerate
on 5-min data.

Added WARNING in train_xgb when hmm_state feature importance=0 — this
indicates XGBoost ignores the HMM while the regime filter still gates on
it, a contradictory setup that should be caught at training time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 22:00:33 +03:00
Luke MosotiandClaude Opus 4.6 7829fa9b28 feat: regime-aligned signals + fix P&L exit-deal wait
Regime-aligned signal filter (all TFs, backtester + live trader):
- BUY fires only when hmm_state == Bull (0)
- SELL fires only when hmm_state == Bear (1)
- Chop (2) never generates a signal
Mirrors compute_signals() in backtester exactly so live behaviour
matches what Optuna optimised against.

P&L history fix:
- Retry loop extended from 5s to 20s
- Loop now requires DEAL_ENTRY_OUT (entry==1) to be present before
  accepting results — fixes 0.00 P&L caused by only the opening deal
  appearing within the original 5-second window

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 21:02:35 +03:00
Luke MosotiandClaude Opus 4.6 33844143b6 fix: handle break-even P&L display (0.0 > 0 is False but shows +0.00)
When profit guard closes a position exactly at entry the P&L rounds to
0.00 but pnl==0.0 triggered the LOSS tag. Now shows BREAK-EVEN / ➡️
emoji so the log is no longer contradictory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 18:08:37 +03:00
Luke MosotiandClaude Opus 4.6 0b28cf196d feat: raise M15 daily trade cap to 4 to match M5
M15 generates ~96 bars/day vs M5's 288 — both now get a 4-trade/day
cap for small accounts so the optimizer can clear MIN_OOS_TRADES=200
thresholds during the coming re-optimization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 18:00:23 +03:00
Luke MosotiandClaude Sonnet 4.6 b5106860f7 feat: M5 scalping refinements — profit guard, tighter TPs, threshold tuning
Align H1 TP config with M15 — reduce over-ambitious targets:
- H1 trending: [1.5, 3.0] -> [1.0, 2.0]  (TP2=3.0 rarely filled; 2.0 is
  achievable in a strong H1 trend day; mirrors M15 ratio)
- M15/H1: profit guard (70% to TP1 -> SL to entry+2×spread), break-even
  (TP1 hit -> runner SL to entry), chop-exit (regime shift closes runner)
  were already all-TF — confirmed in code comments and loop logic
- README: update staged TP table with per-TF values and profit protection
  chain; fix Timeframe Configurations table with correct TP1/TP2 values
  and Min OOS trades updated to reflect M15=200/H1=200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 17:49:37 +03:00
Luke MosotiandClaude Sonnet 4.6 f7d12d06eb feat: M5 scalping refinements — profit guard, tighter TPs, threshold tuning
Trade open/close Telegram notifications + P&L history retry fix:
- _log_closed_pnl: retry history_deals_get up to 5× with 1s gap — fixes
  'P&L unavailable — not yet in history' (MT5 history lags ~5s post-close)
- _log_closed_pnl: include commission in P&L, extract entry/exit prices
  and direction from deal history; log entry -> exit price + lot size
- After order loop: send one Telegram message per filled signal with
  direction, regime, prob, lot×N, SL, TP levels and ticket numbers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 17:07:32 +03:00
Luke MosotiandClaude Sonnet 4.6 5f2b08a796 fix: pass prob/short_threshold_override into _run_loop_inner — resolves Pylance undefined variable warnings
The override params were added to run_live_loop() but not threaded
into _run_loop_inner() where the threshold resolution logic lives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:58:07 +03:00
Luke MosotiandClaude Sonnet 4.6 bb04b54760 feat: M5 scalping refinements — profit guard, tighter TPs, threshold tuning
optimizer.py:
- Narrow M5 prob_threshold search to 0.50-0.53 (was 0.50-0.55) for
  high-frequency sensitivity; H1/M15 unchanged at 0.50-0.58

mt5_trader.py:
- TF_PROB_THRESHOLD fallbacks: M5 0.70->0.52, M15/H1 0.65->0.54
- TF_SHORT_THRESHOLD fallbacks: M5 0.30->0.48, M15/H1 0.35->0.46
  (now symmetric with buy thresholds; Optuna / CLI overrides take priority)
- TF_TP_CONFIG: M5 runner 2.0->1.5 ATR (realistic scalp target); M5 chop
  0.6->0.5; M15 TP1 1.5->1.0, runner 3.0->2.0, chop 1.5->0.8; H1 chop 1.5->1.0
- Add _apply_profit_guard(): moves SL to entry+2*spread when price reaches
  70% of TP1 distance — fires before TP1 fills, applies to all TFs
- signal_tracker gains tp1_level and guard_hit fields
- run_live_loop() accepts prob_threshold_override / short_threshold_override

main.py:
- Add --prob_threshold and --short_threshold CLI args for live mode override
  e.g. --mode live --tf M5 --prob_threshold 0.52 --short_threshold 0.48

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:53:54 +03:00
Luke MosotiandClaude Sonnet 4.6 d1bf7af883 feat: narrow H1/M15 prob threshold search space to prevent over-conservative models
- prob_threshold: 0.52-0.65 -> 0.50-0.58 (ceiling cut stops optimizer settling
  at 0.64 where only 40 trades fire per OOS window)
- short_threshold: 0.35-0.48 -> 0.42-0.50 (raises floor for symmetric buy/sell
  sensitivity; was asymmetrically biased against shorts)
- README: update probability threshold table for M15 and H1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:14:59 +03:00
Luke MosotiandClaude Sonnet 4.6 79e21cd7d1 feat: raise MIN_OOS_TRADES to 200 for M15/H1; TF-aware validate warning
- optimizer: MIN_OOS_TRADES_BY_TF M15 100->200, H1 50->200; both datasets
  have ~4.1yr OOS (125K H1 / 493K M15 bars, 20% split), so 200 trades =
  ~49/year forces actively-trading models rather than ultra-conservative ones
- validator: replace flat MIN_TRADES_WARNING=30 with TF-aware dict
  (M5=30, M15=15, H1=10) so H1 doesn't warn on legitimate 10-trade quarters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:09:37 +03:00
Luke MosotiandClaude Sonnet 4.6 3ff132914b fix: M5 4-trade/day cap, TF-aware model loading, USDCHF README update
- risk_manager: store tf in AdaptiveRiskManager.__init__; get_trade_limits
  and can_trade use self.tf by default — M5 small accounts correctly get
  4 trades/day without threading tf= through every call site
- mt5_trader: pass tf=tf to both AdaptiveRiskManager instantiations so
  the live loop displays and enforces trades=0/4 for M5 (was 0/2)
- README: DXY -> USDCHF throughout; TF-specific model file names; M5/M15/H1
  workflow sections; consolidate mode in command reference; correct
  short_threshold table; M5 n_states restriction note; updated trade limit
  table showing M5 4/day cap; period 6m recommendation for H1/M15 validate
- models/m5_meta.json: updated with latest optimization result (score 4.49)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:44:45 +03:00
Luke Mosoti 69a54d2a64 feat: implement TF-specific model and ensemble path retrieval for HMM and XGB 2026-04-07 07:40:22 +03:00
Luke Mosoti 906a32c953 feat: add USDCHF data consolidation feature and update related processing logic 2026-04-06 21:33:14 +03:00
Luke Mosoti 9e7c426e1c feat: enhance trading logic with short_threshold parameter and update logging for P&L tracking 2026-04-06 16:13:56 +03:00
Luke MosotiandClaude Opus 4.6 39a22adc42 feat: Telegram Command Center — /start, renamed optimize button, richer BOT STATUS
remote_control.py:
- Rename button/handler: 'START OPTIMIZE (M5)' → 'OPTIMIZE M5 (0.50-0.55)'
  to match the current prob_threshold search space and make the range visible
  from the keyboard itself
- Add /start and /help handler: shows a welcome message with a description of
  each button; accessible to anyone (auth gate only applies to action commands)
- Enhance BOT STATUS: now shows process health block (Trading Loop ✅/❌,
  Optimizer 🔄/💤) above the P&L report; passes session_limit (2 for ≤$50
  accounts) so the auditor can show "1/2 trades used today"
- Default LIVE_TF env fallback changed from H1 → M5 to match active timeframe
- Optimize subprocess message updated to confirm range + trial target

auditor.py:
- get_daily_report() accepts optional session_limit param; when provided the
  trade count line renders as "1/2 used today" instead of a plain count,
  giving the user immediate capacity awareness from the Telegram status button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 10:57:26 +03:00
Luke MosotiandClaude Opus 4.6 15812267a3 fix: downsample M5 charts to remove straight-line weekend gaps and white fills
M5 regime overlay and equity curve were rendering 626K bars causing two
visual artefacts:
1. Straight horizontal lines — matplotlib connects Friday 23:55 directly to
   Sunday/Monday bar, drawing a line across the weekend gap for every week
   in 10 years of data.
2. White fill sections — fill_between() with alpha=0.15 on densely packed
   5-min bars produced near-invisible colour overlap that appeared white.

Fix: _downsample() reduces display to max 15K bars (step = n // 15000),
equivalent to ~H1 resolution on M5, before any chart is rendered.
Models and backtest metrics are completely unaffected — downsampling is
cosmetic only. Alpha raised 0.15 → 0.25 and scatter dot size raised for
better visibility at the lower data density.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 10:43:08 +03:00
Luke Mosoti 381ee3e090 fix: update M5 model metadata and remove unused Optuna study database 2026-04-04 10:46:47 +03:00
Luke MosotiandClaude Opus 4.6 51449753ba feat: implement DXY fallback mechanism in MT5 trader and update XGBoost ensemble loading
- optimizer: M5 prob_threshold range narrowed to 0.50-0.55 (live probs cluster
  below 0.56; wider range let Optuna miss the workable window entirely)
- optimizer: H1/M15 prob_threshold uses 0.52-0.65 (wider buffer appropriate
  for higher timeframes with more information per bar)
- optimizer: --trials N now means total study target, not additional trials;
  remaining = max(0, N - already_done) is passed to study.optimize so
  resuming with --trials 500 after 400 done runs exactly 100 more
- optimizer: progress bar shows [total_done/total_target] instead of
  [session_done/session_target] so resumed runs display true context
- optimizer: Telegram heartbeat pct now based on total_done/total_target
- optimizer: early-exit with clear message when target already reached

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 10:45:28 +03:00
Luke MosotiandClaude Opus 4.6 0bf01f3233 fix: pass prob_threshold in cmd_report; raise M5 OOS trade floor to 300
cmd_report was calling vectorized_backtest without prob_threshold, so it
fell back to the hardcoded default (0.65) instead of the Optuna-tuned value
(0.578).  This caused the report to show far fewer trades than the optimizer
actually found (38 IS / 9 OOS vs the 50+ OOS the study required).

MIN_OOS_TRADES is now TF-aware: M5=300, M15=100, H1=50.  With ~434 OOS
trading days and a 2/day cap, M5=50 allowed ultra-infrequent cherry-picked
wins (0.11 trades/day); 300 forces at least 0.69 trades/day so Optuna
cannot reward near-zero-trade setups with inflated Sharpe ratios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 01:18:30 +03:00
Luke Mosoti 17ee052009 feat: implement DXY fallback mechanism in MT5 trader and update XGBoost ensemble loading 2026-04-01 22:53:24 +03:00
Luke MosotiandClaude Opus 4.6 9af5cd38a5 docs+fix: volatility ensemble docs, DXY forward-fill, validator ensemble API
- README: add dedicated Volatility Ensemble section documenting three-model
  bucketing (low/med/high ATR), feature table, threshold explanation, and
  ONNX file list; update pipeline diagram, train/export descriptions, and
  prob_threshold range (0.505-0.60)
- optimizer.py: lower prob_threshold search space lower bound 0.52 → 0.505
  so Optuna can find thresholds matching the model's real output range
- processor.py: add map_dxy_to_bars() helper that forward-fills DXY beyond
  file coverage (handles sync data newer than last DXY export); fix
  load_dxy_data() date format to match YYYY-MM-DD saved format
- validator.py: use load_xgb_ensemble + get_predictions_ensemble; import
  and apply map_dxy_to_bars in _apply_features() so DXY is included in
  validation inference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 22:46:01 +03:00
Luke Mosoti dcb6da39bb Add workspace configuration for GoldRegime_X with Python environment settings 2026-04-01 15:08:58 +03:00
Luke MosotiandClaude Opus 4.6 97474652b6 refactor: consolidate DXY to single shared raw file for all timeframes
DXY is a daily index exposed by MT5 only at the day level — there is no
per-timeframe variant.  Remove the three separate dxy_raw_path entries
from TF_CONFIG and replace them with a single module-level DXY_RAW_PATH
constant (data/raw/DXY_data.csv) that all timeframes share.

process_pipeline() now references DXY_RAW_PATH directly; the pipeline
degrades gracefully (4-feature model) if the file is absent.

README Data Setup section updated with DXY export instructions and the
single expected filename.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 01:24:02 +03:00
Luke MosotiandClaude Sonnet 4.6 1a57dc3b7c feat: cross-asset regime-switching architecture with three-model ensemble
### DXY Integration (mt5_sync.py, processor.py)
- Added DXY_SYMBOL_ALIASES + _find_dxy_symbol() for broker-agnostic USD Index lookup
- Added fetch_cross_asset_bars() — fetches XAUUSD + DXY and inner-joins on timestamps
- Added dxy_raw_path to TF_CONFIG for all timeframes (H1/M15/M5)
- Added load_dxy_data() — loads DXY CSV and computes dxy_log_return
- process_pipeline() now optionally merges dxy_log_return when DXY CSV exists;
  falls back gracefully with a warning when no DXY file is present

### Dynamic Feature Detection (engine_xgb.py)
- FEATURE_COLS remains the 4-feature base; get_feature_cols(df) appends
  dxy_log_return when it is present and has >50% coverage
- prepare_features() now calls get_feature_cols() so feature count adapts
  automatically to data availability (4 or 5 features)
- train_xgb() now uses X.columns for feature_importance (was hardcoded FEATURE_COLS,
  which broke with 5-feature data)

### Three-Model Volatility Ensemble (engine_xgb.py)
- compute_vol_thresholds() / assign_vol_bucket() — ATR tertile partitioning
- train_xgb_ensemble() — trains Low/Med/High vol bucket models on IS data only
  (thresholds computed from IS to prevent look-ahead bias)
- get_predictions_ensemble() — routes each bar to its bucket model at inference
- save_xgb_ensemble() / load_xgb_ensemble() — persists all 3 models + thresholds
  + feature_cols in models/xgb_ensemble.pkl
- export_onnx_ensemble() — exports xgb_model_vol_{low,med,high}.onnx

### Pipeline wired end-to-end
- optimizer.py objective now trains and scores with train_xgb_ensemble +
  get_predictions_ensemble (same OOS-only scoring, same prob_threshold search)
- main.py _train_for_tf(), cmd_train, cmd_export all updated to ensemble
- mt5_trader.py loads xgb_ensemble.pkl; compute_live_features() returns a named
  DataFrame; DXY log return is fetched live if model was trained with it (falls
  back to 0.0 if broker has no DXY symbol)

### Not changed (already implemented)
- Break-even SL, session limits, cent normalisation — already in place

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:31:16 +03:00
Luke MosotiandGitHub dfab542b6b Update README to include M15 and M5 timeframes 2026-03-30 23:57:49 +03:00
Luke MosotiandClaude Sonnet 4.6 50409ac18e docs: comprehensive README with full setup, workflow, and architecture guide
Covers installation, data setup, Telegram config, full step-by-step workflow
for H1/M15/M5 timeframes, signal logic, risk management, MQL5 EA, and
troubleshooting. Replaces the auto-generated GitHub placeholder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 23:55:05 +03:00
Luke MosotiandClaude Sonnet 4.6 d26c704a93 security: replace real credentials in .env.example with placeholders
Bot token and chat IDs were accidentally committed with real values.
Replaced with placeholder strings. Revoke and regenerate the bot token
via @BotFather /revoke immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 23:49:00 +03:00