The run_bot.bat console path froze for minutes after two log lines with 0 CPU:
asyncio.run() -> ProactorEventLoop.__init__ -> socket.socketpair() -> Python
3.12 _fallback_socketpair() blocks forever in accept() on the loopback TCP
handshake (security software filters 127.0.0.1 in this interactive console +
xau-trader.exe session). Git-bash redirect runs worked 4/4, proving it is
environment, not interpreter.
Windows 10 17063+ supports AF_UNIX sockets, which need no loopback TCP at all.
Monkey-patch socket.socketpair on win32 to self-pair over AF_UNIX via ctypes
(ws2_32; python.org builds don't expose the AF_UNIX constant), falling back to
the stock socketpair if AF_UNIX is unavailable. socket.socket(fileno=N) treats
N as a raw SOCKET handle on Windows, so the raw handles wrap cleanly.
Verified: smoke test raw pair family=1 + full asyncio.run Proactor loop; the
exe boot went from hang to 'Main loop started' in ~10s.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Phase-3 execution-layer fixes, config values are the phase-2 gate winners
(conf=55/breakeven 0.7/atr_trail 1.5/trigger 1.2 - scalping 5-month sweep PF
2.11 at conf=55, baseline PF 1.50):
- trailing_stop: trail now arms only after trail_trigger_atr x ATR unrealized
gain and never trails past TP (tick-capped). Old logic trailed on H1-ATR
(~6) while SL/TP were M5-ATR-calibrated (~-6) - breakeven at +1.85 was
unreachable, every scalp exited at SL
- bot.py: entry cooldown per (strategy, direction) from the cooldown: YAML
block (scalping 1800s/day_trading 3600s/swing 7200s) - signals were re-firing
every 30s cycle and piling same-direction positions; Step 4 AI prediction on
df_m15 (model trains on M15); Step 8 trails on M5 ATR; removed duplicate
on_trade_closed hook in Step 9 (each external close was learned twice,
strat_scalping multiplier decayed 0.527->0.41 on garbage inputs);
performance_snapshots now trigger on wall clock (boot + every >=30min) so
restarts can't reset the cycle counter to 0
- trade_executor: execute_signal threads ai_score/regime_score into signal
records; close_trade + sync_positions share _learner_context built from the
DB Trade row (was: hardcoded regime=RANGING/confluence=75/sentiment=0)
- trading_params.yaml: moderate scalping 50->55, breakeven 0.7, trail 1.5,
trail_trigger_atr 1.2, cooldown + backtest sections
- tests: scalping moderate confluence assertion 50.0 -> 55.0
Co-Authored-By: Claude Code <noreply@anthropic.com>
Replace the Google Gemini lock-in with a unified chat client usable with any
OpenAI-compatible /v1 endpoint (OpenAI, OpenRouter, DeepSeek, Moonshot, Qwen,
Ollama, Gemini-via-compat...). Switch provider purely via AI_BASE_URL/AI_MODEL.
- ai/llm_client.py (new): lazy openai SDK, per-candidate 429/503/timeout
failover across AI_MODEL_FAILOVER, robust JSON extraction, reasoning-budget
retry, image analysis via base64 data URI, singleton get_llm_client()
- settings.py: GeminiSettings -> LLMSettings (api_key/base_url/model/failover/
vision_model), keeps GEMINI_API_KEY fallback so existing .env keeps working
- news_analyzer.py: analyze_with_gemini -> analyze_with_llm (same output keys);
FinBERT now loads in a daemon warm-up thread with lexicon fallback - the
transformers first import was blocking the asyncio main loop 15-45s
(importlib.metadata full package scan); HF_ENDPOINT hf-mirror setdefault
- telegram_bot.py: news digest + AI-vision chart analysis via the LLM client
- requirements: google-genai -> openai>=1.0; docs/.env.example/README updated
for the new provider-agnostic setup; dashboard meta updated
Co-Authored-By: Claude Code <noreply@anthropic.com>
The prove-before-live gate tooling. Both runners fetch real MT5 history
(M5/H1 for simulation, M15 for AI, H4 for regime), build zero-lookahead
time-aligned lookups, run the live-parity engine, append config->metrics rows
to grid_results.csv and print the gate verdict:
expectancy > 0 AND profit_factor >= 1.2 AND max_drawdown_pct <= 15 AND total_trades >= 60
- run_real_backtest.py: scalping gate mirroring live moderate params
- backtest_day_trading_gate.py: H1-frame gate for the day_trading family
(isolation loop disables scalping/swing), compares conf=live(55) vs
conf=raw(70); 5-month run: conf=55 PASS (72 trades, WR 70.8%, PF 3.45,
exp +47.91, maxDD 2.25%), conf=70 FAIL (0 trades - threshold unbeatable)
- grid_results.csv: full scan history incl. the 5-month all-configs sweep
whose baseline (50/0/2.0: 2214 trades, PF 1.50) proved live losses were
the execution layer, not the entry spec
Co-Authored-By: Claude Code <noreply@anthropic.com>
Phase 1 of the prove-before-live alignment. The backtest engine now mirrors
the live signal path instead of hardcoding HOLD/NEUTRAL:
- predict_batch (signal_classifier): vectorized per-bar AI signals reusing the
exact live predict() pipeline (class-index mapping, conf<0.5 -> HOLD)
- backtester: per-bar time-aligned AI lookup (M15 close = signal-available
time, searchsorted, no lookahead), exogenous H4 regime plan with dynamic
confluence-key deltas, AttentionMarketScorer alignment, per-strategy entry
cooldown, max-hold timeout exit, breakeven + trailing capped at TP, running-
equity pnl_pct (was: static initial balance)
- fix: store direction.value on entry (Enum vs str compare silently disabled
every exit - no trade ever closed)
- fix: _check_mode_sync only clears override on genuine mode transition (grid
threshold injection was wiped on first read)
- SignalAggregator(use_adaptive_weights=True): backtest uses pure config
weights so garbage live adaptive weights can't contaminate gate scores
Co-Authored-By: Claude Code <noreply@anthropic.com>
The guard previously hardcoded the scalping base for every strategy, so
day_trading and swing_trading signals were screened against scalping's
numbers. New _strategy_base_confluence() resolves each strategy to its own
settings section (day_trading_params / swing_trading_params), mirroring
BaseStrategy.min_confluence_score routing; unknown names fall back to
scalping (legacy). Moderate-mode parity verified by smoke test: penalty
override 55+6=61, memory veto 55+8=63 for both day_trading and scalping.
Full suite: 39 tests pass.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The guard vetoed UNCONDITIONALLY whenever a strategy multiplier fell below
0.65x, never comparing the confluence the '+6' message claimed. A stale 0.408x
SCALPING multiplier (garbage-era lessons incl. one double-learned duplicate)
then locked the bot out permanently: no trades → no lessons → no recovery.
Now the veto is conditional on confluence >= base + 6 (penalty still applied
to effective_score downstream), and multipliers time-decay back toward 1.0
(~24h constant, persisted without touching win/loss counts).
Co-Authored-By: Claude Code <noreply@anthropic.com>
- Implemented scripts/train_ai.py for institutional XGBoost training on MT5 historical candles
- Integrated 46 multi-indicator features, TimeSeriesSplit validation, and feature importance drivers
- Added --train-only and improved --train in main.py
- Enabled MT5 AutoTrading configuration ([Experts] AllowLiveTrading=1)
- Added send_pending_order and cancel_order to MT5Connector (BUY_LIMIT, SELL_LIMIT, BUY_STOP, SELL_STOP)
- Added automatic 12-hour periodic model retraining job in BotScheduler and TradingBot
- Updated Telegram Command Center with MT5 standalone fallback and pending order telemetry
- Placed live test BUY market trade and scheduled BUY_LIMIT order on XAUUSD
- Implemented TradeLearner with post-mortem mistake diagnostics and defensive rule formulation
- Added Mistake Memory Guard to screen prospective signals against past loss patterns and traps
- Dynamic Multi-Armed Bandit strategy multipliers (Scalping, Day, Swing) and adaptive confluence weighting
- Integrated with TradeExecutor, Bot position synchronization, and SignalAggregator
- Real-time Self-Learning HUD in modern glassmorphic web dashboard (/api/learning)
- Added /learning command and interactive callback button to Telegram Command Center
- Added TradeLesson and AdaptiveWeight persistence models in SQLite WAL database
- Updated documentation and README