From a8a05c1af419ed283218e5c30a3ba521b874ee12 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 21 May 2026 09:56:43 +0800 Subject: [PATCH] Compress trader cockpit readout --- SESSION.md | 7 +- TASKS.md | 3 +- ...CT_主线纠偏与功能裁剪方案_2026-05-20_v1.md | 8 ++ scripts/run_readonly_live_analysis_smoke.py | 7 +- src/web/i18n.js | 30 +++++ src/web/index.html | 6 +- src/web/styles.css | 12 +- src/web/trader_mode.html | 6 +- src/web/trader_mode.js | 113 +++++++++++++++--- tests/unit/test_api_static_server.py | 19 +-- tests/unit/test_documentation_consistency.py | 1 + ...est_readonly_live_analysis_smoke_script.py | 14 ++- 12 files changed, 187 insertions(+), 39 deletions(-) diff --git a/SESSION.md b/SESSION.md index e7e623c..0a8dd54 100644 --- a/SESSION.md +++ b/SESSION.md @@ -18,7 +18,7 @@ Automation execution-layer PXX remains closed and its known scope stays frozen. ## Last Updated -2026-05-20 UTC +2026-05-21 UTC ## Automation Status @@ -140,6 +140,9 @@ Automation execution-layer PXX remains closed and its known scope stays frozen. - latest_strategy_backtest_status: implemented_deployed_remote_smoke_passed - latest_strategy_backtest_closure: Strategy Backtest now has `/trading/backtests`, a read-only workbench page with instrument/run controls, latest stored backtest, quality gate, sample/executed counts, total R, expectancy, profit factor, drawdown, loss streak, equity curve, top sessions, failure reasons, and recent run list. The page catches candle/backtest endpoint failures so one local DB permission issue does not blank the whole workbench. - latest_strategy_backtest_validation: node --check app/i18n, focused API/static tests, `npm run build`, `npm run lint` full unit discovery 791 tests, `git diff --check` with only LF/CRLF warnings, deploy smoke 11 endpoints, remote ops smoke, readonly live analysis smoke, remote `/trading/backtests` field smoke, and browser audit on `http://192.168.3.90:8000/#strategy-backtest` passed. Remote latest run `#489` is correctly blocked by quality gate (`sample_size_too_small`, executed sample, expectancy, profit factor, consecutive-loss reasons) and the Chinese UI renders those as trader-readable reasons. +- latest_trader_cockpit_recompression_slice: ict_six_point_readout_with_backtest_edge +- latest_trader_cockpit_recompression_status: implemented_deployed_remote_ops_passed_readonly_launch_blocked_by_external_proxy +- latest_trader_cockpit_recompression_closure: Trader Cockpit first screen now uses the ICT mainline six-point readout `Now / Reason / Wait / Risk / Historical Edge / Boundary`, fetches `/trading/backtests` for the active instrument, and summarizes the latest quality gate as historical edge evidence without promoting any setup into a buy/sell or order-submission instruction. Local build, full lint/unit, deploy smoke, remote ops smoke, remote `/trading/backtests` field smoke, and remote browser QA passed. `run_readonly_live_analysis_smoke.py` static/API checks passed but the final launch-readiness gate remains blocked by external market/news/broker freshness because the configured market proxy refuses OKX connections and direct OKX access times out. - latest_decision_assistant_workflow_queue_slice: assistant_loop_queue - latest_decision_assistant_workspace_loop_slice: workflow_section_navigation_loop_queue - latest_decision_assistant_learning_focus_slice: learning_focus_queue @@ -832,7 +835,7 @@ Automation execution-layer PXX remains closed and its known scope stays frozen. ## Exact Next Step -Next continue Step 4 of `docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md` under the hard mainline gate in `docs/AI_ICT_硬性主线约束_必须遵循ICT交易全书_2026-05-21_v1.md`: compress Trader Cockpit further so the first screen uses ICT book order plus the new backtest evidence to answer only `now / reason / wait / risk / historical edge / boundary`. Do not restart external-context/archive/digest long-tail work, do not create order-submission features, and do not fabricate R2 paper samples; R2 evidence collection remains live but secondary to the current trader-facing mainline correction. Keep `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, and operator confirmation protocol unchanged. +Next continue Step 5 of `docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md` only after Step 4 validation/deploy closes: perform a code-level deletion readiness audit for non-mainline trader-facing surfaces. Start with dependency scan, API usage scan, and test coverage confirmation; do not physically delete shared or diagnostic code until the scan proves it is unused or safely isolated under `System Ops`. Do not restart external-context/archive/digest long-tail work, do not create order-submission features, and do not fabricate R2 paper samples. Keep `execution_allowed`, `decision_support_ready`, `real_live_ready`, risk governor, trust bucket, and operator confirmation protocol unchanged. ## Validation Commands Used Recently diff --git a/TASKS.md b/TASKS.md index c5fe159..edf7227 100644 --- a/TASKS.md +++ b/TASKS.md @@ -931,7 +931,8 @@ - [x] Existing UI i18n/R2 gate polish follow-up: existing Trader Mode/readiness/shadow-paper labels now translate runtime/gate jargon such as `Auto refresh`, `All Trust`, `Incident Journal`, `Live Readiness`, `paper_ticket_sample_gate`, and `operator_feedback_count`; R2 evidence window now follows canonical `failed_criteria`, remote browser audit has no repeated first-screen Chinese phrases and only 13 active-view English tokens left; deploy smoke, remote ops smoke, read-only live smoke, focused tests, static checks, and full unit (`790`) passed - [x] Session Focus dynamic Chinese label follow-up: existing i18n now translates reported dynamic session-focus labels/values (`ASIA`, `NY_PM`, `status`, `window`, `candidates`, `executable`, `open executions`, `alerts`, `recommendation`, `action hint`, `incomplete`, `observe @ n/a`, `avoid_new_risk`, `review_alerts`); remote browser audit on `/trader-mode#session-focus` passed with no reported English leftovers and no console errors - [x] Trader mainline Step 3 Strategy Backtest productization: added read-only `/trading/backtests`, Strategy Backtest workbench controls, latest-run summary, quality gate explanation, R metrics, equity curve, top sessions, failure reasons, recent run list, Chinese labels for backtest gate reasons, and resilient candle/backtest failure fallback; full unit (`791`), deploy smoke, remote ops smoke, readonly live smoke, remote backtest endpoint smoke, and browser audit passed -- [ ] Trader mainline Step 4 cockpit recompression: under the hard ICT book mainline gate, use Strategy Backtest evidence on Trader Cockpit first screen and reduce it to now / reason / wait / risk / historical edge / boundary +- [x] Trader mainline Step 4 cockpit recompression implemented/deployed: under the hard ICT book mainline gate, Trader Cockpit first screen now reduces to `Now / Reason / Wait / Risk / Historical Edge / Boundary` and uses latest Strategy Backtest evidence without changing any execution/readiness gate; deploy smoke, remote ops smoke, remote backtest field smoke, and browser QA passed, while readonly launch smoke remains blocked by external market/news/broker freshness through the currently unreachable OKX/proxy path +- [ ] Trader mainline Step 5 deletion readiness audit: scan non-mainline trader-facing surfaces for dependency/API/test coverage before any code-level deletion; keep diagnostics under `System Ops` unless proven removable - [ ] R2 paper-ticket sample gate is waiting on a real executable candidate; do not fabricate paper tickets from blocked candidates - [ ] R2 operator feedback sample gate still needs 2 more real feedback samples (`operator_feedback_count=3/5`) - [ ] R2 weekly review visible gate still needs a real execution-derived journal/weekly review entry (`weekly_review_entry_count=0`) diff --git a/docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md b/docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md index a8b45a1..fff7063 100644 --- a/docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md +++ b/docs/AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md @@ -317,6 +317,14 @@ Trader Cockpit 不再展示复杂系统状态。 边界:只读,不下单 ``` +状态更新(2026-05-21): + +- [x] Trader Cockpit 首屏已重新压缩为 `Now / Reason / Wait / Risk / Historical Edge / Boundary` 六项速读。 +- [x] Trader Cockpit 刷新时读取 `/trading/backtests` 最新只读回测证据,并把质量门结果压缩成“历史优势是否足够”的一句话。 +- [x] 历史优势未通过或不可达时只提示继续观察 / 先看 Strategy Backtest,不生成买卖或下单指令。 +- [x] 保持 `execution_allowed`、`decision_support_ready`、`real_live_ready`、risk governor、trust bucket、operator confirmation protocol 不变。 +- [x] 已完成部署 smoke、remote ops smoke、remote backtest field smoke 与浏览器 QA;`run_readonly_live_analysis_smoke.py` 的最终 launch-readiness gate 仍被外部行情/新闻/只读账户 freshness 阻塞,原因是当前 OKX 代理连接被拒绝且直连超时。 + ### Step 5:代码级删除 只有在 Step 2-4 稳定后,才开始删除代码。 diff --git a/scripts/run_readonly_live_analysis_smoke.py b/scripts/run_readonly_live_analysis_smoke.py index bbd89e8..9bb9f05 100644 --- a/scripts/run_readonly_live_analysis_smoke.py +++ b/scripts/run_readonly_live_analysis_smoke.py @@ -389,7 +389,9 @@ def _run_payload_check(*, payload_check: str, payload) -> dict: item for item in [ "Trader Mode", - "Decision Now", + "Now", + "Wait", + "ICT Fast Read", "Market Last Updated", "Review Packet Updated", "Fast Queue", @@ -429,6 +431,9 @@ def _run_payload_check(*, payload_check: str, payload) -> dict: "/trading/maintenance-summary", "/trading/unattended-harness", "/candles", + "/trading/backtests", + "Historical Edge", + "buildHistoricalEdgeSummary", "post_market_review_draft", "chart_context_bridge", "ops_duty_panel", diff --git a/src/web/i18n.js b/src/web/i18n.js index a6c3f6b..2f6625f 100644 --- a/src/web/i18n.js +++ b/src/web/i18n.js @@ -133,6 +133,11 @@ 'current_focus_matches_profile': '当前焦点匹配模板', 'Status': '状态', 'Decision Now': '当前判断', + 'Now': '现在', + 'Wait': '等待什么', + 'Risk': '风险', + 'Historical Edge': '历史优势', + 'ICT Fast Read': 'ICT 六项速读', 'Next Action': '下一步', 'Loading': '加载中', 'Waiting for live brief.': '等待实时简报。', @@ -209,6 +214,9 @@ 'Focus Reason': '焦点原因', 'Data State': '数据状态', 'No Candidate': '无候选', + 'Historical edge unavailable: check Strategy Backtest before trusting this setup.': '历史优势不可用:信任该形态前先查看策略回测。', + 'Historical edge unavailable: Strategy Backtest data is not reachable.': '历史优势不可用:策略回测数据暂时不可达。', + 'No historical edge yet: run Strategy Backtest before trusting this setup.': '还没有历史优势:信任该形态前先运行策略回测。', 'Read-only analysis': '只读分析', 'No order submission': '不提交订单', 'Not a buy/sell instruction': '不是买卖指令', @@ -519,6 +527,14 @@ ['do not trust strategy yet', '暂不信任策略'], ['run backtest replay no lookahead', '运行无未来函数重放回测'], ['missing backtest', '缺少回测'], + ['Historical edge passed', '历史优势通过'], + ['No historical edge yet', '还没有历史优势'], + ['Historical edge unavailable', '历史优势不可用'], + ['Still read-only', '仍然只读'], + ['confirm current ICT context first', '先确认当前 ICT 上下文'], + ['check Strategy Backtest before trusting this setup', '信任该形态前先查看策略回测'], + ['run Strategy Backtest before trusting this setup', '信任该形态前先运行策略回测'], + ['Strategy Backtest data is not reachable', '策略回测数据暂时不可达'], ['incomplete', '未完成'], ['open executions', '未平仓执行'], ['action hint', '动作提示'], @@ -673,6 +689,9 @@ ['Observe Only', '仅观察'], ['Review Now', '立即复核'], ['Do Not Use', '不要使用'], + ['Read-only analysis', '只读分析'], + ['No order submission', '不提交订单'], + ['Not a buy/sell instruction', '不是买卖指令'], ['Read-only Live Analysis', '只读实盘分析'], ['Trader Mode / Live Brief', '交易员模式 / 实时简报'], ['ready_for_readonly_live_analysis', '只读实盘分析就绪'], @@ -696,9 +715,15 @@ ['FVG retrace', 'FVG 回撤'], ['trust gate', '信任门禁'], ['restore market feed first', '先恢复行情源'], + ['restore freshness/readiness before reading this market', '先恢复数据新鲜度/就绪状态,再阅读行情'], + ['wait market feed', '等待行情源恢复'], ['Refresh runtime/feed first', '先刷新运行状态/行情源'], ['restore runtime first', '先恢复运行状态'], ['until status leaves', '直到状态离开'], + ['until 状态 leaves', '直到状态离开'], + ['Frozen:', '已冻结:'], + ['market feed', '行情源'], + ['leaves', '离开'], ['ignore', '忽略'], ['setup output', '形态输出'], ['ignore setup output until status leaves Do Not Use', '状态离开“不要使用”前忽略形态输出'], @@ -747,6 +772,11 @@ ['fvg retrace confirmed', 'FVG 回撤确认'], ['drill down only if needed', '仅在需要时下钻'], ['read-only', '只读'], + ['sample size too small', '样本太少'], + ['executed sample too small', '执行样本太少'], + ['expectancy below minimum', '期望值低于下限'], + ['profit factor below minimum', '盈利因子低于下限'], + ['consecutive loss limit exceeded', '连续亏损超过上限'], ['review packet', '复核包'], ['operator feedback', '操作员反馈'], ['paper ticket', '纸面票据'], diff --git a/src/web/index.html b/src/web/index.html index e1e7e66..c684911 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -112,17 +112,17 @@
Loading
-
Decision Now
+
Now
Waiting for live brief.
-
Next Action
+
Wait
n/a
-

Live Readout

+

ICT Fast Read

diff --git a/src/web/styles.css b/src/web/styles.css index c15be18..0768511 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -569,7 +569,7 @@ th { color: #9db0d3; } } .trader-readout-grid { display: grid; - grid-template-columns: 1.25fr 1.25fr 1fr 1fr 1fr; + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; min-width: 0; } @@ -592,6 +592,16 @@ th { color: #9db0d3; } .trader-readout-blocked { border-color: #ef4444; } +.trader-readout-risk { + border-color: #f59e0b; +} +.trader-readout-edge { + border-color: #22c55e; +} +.trader-readout-boundary, +.trader-readout-neutral { + border-color: #64748b; +} .trader-readout-muted { opacity: 0.86; } diff --git a/src/web/trader_mode.html b/src/web/trader_mode.html index f4e9937..a8b9b53 100644 --- a/src/web/trader_mode.html +++ b/src/web/trader_mode.html @@ -34,17 +34,17 @@
Loading
-
Decision Now
+
Now
Waiting for live brief.
-
Next Action
+
Wait
n/a
-

Live Readout

+

ICT Fast Read

diff --git a/src/web/trader_mode.js b/src/web/trader_mode.js index bf70625..d8f92d0 100644 --- a/src/web/trader_mode.js +++ b/src/web/trader_mode.js @@ -163,6 +163,18 @@ function formatDurationSeconds(value) { return `${(seconds / 3600).toFixed(1)}h`; } +function formatCompactNumber(value, digits = 2) { + const number = Number(value); + if (!Number.isFinite(number)) return 'n/a'; + return number.toFixed(digits); +} + +function formatCompactR(value) { + const number = Number(value); + if (!Number.isFinite(number)) return 'n/a'; + return `${number.toFixed(2)}R`; +} + function normalizeTone(value) { return String(value || 'observe').toLowerCase().replace(/[^a-z0-9]+/g, '-'); } @@ -404,25 +416,96 @@ function buildClientReadout(trader, focus, overrides = {}) { || trader.no_candidate_state || trader.trader_readout?.no_candidate_state || (focus?.candidate_id ? 'Candidate present; drill down only if needed.' : 'No matching candidate. Stay observe-only.'); - const headline = overrides.headline || trader.trader_readout?.headline || `${trader.status_label || 'Observe Only'}: ${watchNext}`; + const historicalEdge = overrides.historical_edge + || trader.trader_readout?.historical_edge + || 'Historical edge unavailable: check Strategy Backtest before trusting this setup.'; + const boundary = overrides.boundary + || trader.trader_readout?.boundary + || 'Read-only analysis; no order submission; not a buy/sell instruction.'; + const now = overrides.now || overrides.headline || trader.trader_readout?.now || trader.trader_readout?.headline || `${trader.status_label || 'Observe Only'}: ${watchNext}`; + const reason = overrides.reason || focusReason; + const wait = overrides.wait || watchNext; + const risk = overrides.risk || `${whyNoTrade} ${dataState}`.trim(); + const headline = now; return { mode: 'trader_one_screen_readout', headline, + now, + reason, + wait, + risk, + historical_edge: historicalEdge, + boundary, why_no_trade: whyNoTrade, - watch_next: watchNext, - focus_reason: focusReason, + watch_next: wait, + focus_reason: reason, data_state: dataState, no_candidate_state: noCandidateState, one_screen_cards: [ - { label: 'Why No Trade', value: whyNoTrade, tone: 'caution' }, - { label: 'Watch Next', value: watchNext, tone: 'focus' }, - { label: 'Focus Reason', value: focusReason, tone: focus?.candidate_id ? 'focus' : 'muted' }, - { label: 'Data State', value: dataState, tone: freshness.is_stale ? 'blocked' : 'neutral' }, - { label: 'No Candidate', value: noCandidateState, tone: focus?.candidate_id ? 'muted' : 'caution' }, + { label: 'Now', value: now, tone: freshness.is_stale ? 'blocked' : 'focus' }, + { label: 'Reason', value: reason, tone: focus?.candidate_id ? 'focus' : 'muted' }, + { label: 'Wait', value: wait, tone: 'caution' }, + { label: 'Risk', value: risk, tone: freshness.is_stale ? 'blocked' : 'risk' }, + { label: 'Historical Edge', value: historicalEdge, tone: overrides.historical_edge_tone || 'edge' }, + { label: 'Boundary', value: boundary, tone: 'boundary' }, ], }; } +function backtestLatestRun(backtests) { + return backtests?.latest || (Array.isArray(backtests?.items) ? backtests.items[0] : null); +} + +function buildHistoricalEdgeSummary(backtests) { + if (backtests?.unavailable) { + return { + value: 'Historical edge unavailable: Strategy Backtest data is not reachable.', + tone: 'blocked', + }; + } + const latest = backtestLatestRun(backtests); + if (!latest) { + return { + value: 'No historical edge yet: run Strategy Backtest before trusting this setup.', + tone: 'caution', + }; + } + const summary = latest.summary || {}; + const qualityGate = backtests?.quality_gate || summary.quality_gate || {}; + const passed = Boolean(qualityGate.passed); + const reasons = Array.isArray(qualityGate.reasons) ? qualityGate.reasons : []; + const sampleCount = summary.executed_signals ?? summary.total_signals ?? summary.candidate_count ?? 0; + const metricLine = [ + `expectancy ${formatCompactR(summary.expectancy_r)}`, + `PF ${formatCompactNumber(summary.profit_factor_r)}`, + `DD ${formatCompactR(summary.max_drawdown_r)}`, + `${sampleCount} samples`, + ].join(', '); + if (passed) { + return { + value: `Historical edge passed: ${metricLine}. Still read-only; confirm current ICT context first.`, + tone: 'edge', + }; + } + const reasonText = reasons.length ? reasons.slice(0, 2).map(humanizeToken).join('; ') : 'quality gate blocked'; + return { + value: `No historical edge yet: ${reasonText}. ${metricLine}.`, + tone: 'caution', + }; +} + +function buildDisplayReadout(trader, focus, backtests) { + const historicalEdge = buildHistoricalEdgeSummary(backtests); + const boundary = (trader.boundary_badges || ['Read-only analysis', 'No order submission', 'Not a buy/sell instruction']) + .slice(0, 3) + .join('; '); + return buildClientReadout(trader, focus, { + historical_edge: historicalEdge.value, + historical_edge_tone: historicalEdge.tone, + boundary, + }); +} + function applyTraderProfile(payload, profile) { const trader = { ...(payload.trader || {}) }; const freshness = trader.freshness_summary || {}; @@ -656,14 +739,14 @@ function renderTraderQueuePanel(queueItems) { }); } -function renderTraderReadoutPanel(trader) { +function renderTraderReadoutPanel(trader, backtests) { clearNode(traderReadoutPanel); const focus = trader.primary_opportunity || {}; - const readout = trader.trader_readout || buildClientReadout(trader, focus); + const readout = buildDisplayReadout(trader, focus, backtests); const cards = Array.isArray(readout.one_screen_cards) && readout.one_screen_cards.length ? readout.one_screen_cards : buildClientReadout(trader, focus).one_screen_cards; - cards.slice(0, 5).forEach((card) => { + cards.slice(0, 6).forEach((card) => { const item = createElement('div', `trader-readout-card trader-readout-${normalizeTone(card.tone || card.label)}`); item.appendChild(createElement('div', 'metric', card.label || 'Readout')); item.appendChild(createElement('div', 'trader-readout-value', card.value || 'n/a')); @@ -720,13 +803,13 @@ function renderTraderMode(payload) { const evidence = trader.r2_evidence_window || profiledPayload.shadowPaper || {}; const tone = freshness.is_stale ? 'do-not-use' : normalizeTone(trader.status_tone || trader.status_color || trader.status); const safeStatusLabel = SAFE_STATUS_LABELS.includes(trader.status_label) ? trader.status_label : 'Observe Only'; - const readout = trader.trader_readout || buildClientReadout(trader, focus); + const readout = buildDisplayReadout(trader, focus, profiledPayload.backtests); traderStatusPanel.className = `trader-status-panel trader-status-${tone}`; setText(traderStatusLabel, freshness.is_stale ? 'Do Not Use' : safeStatusLabel); setText(traderConclusion, readout.headline || trader.primary_conclusion || 'No live brief is available.'); setText(traderNextAction, readout.watch_next || humanizeNextAction(trader.next_action || 'continue_observation_and_record_reason')); setText(traderHealth, profiledPayload.health?.app ? `API online / ${profiledPayload.health.app}` : 'API online'); - renderTraderReadoutPanel(trader); + renderTraderReadoutPanel({ ...trader, trader_readout: readout }, profiledPayload.backtests); renderTraderQueuePanel(profiledPayload.queue); clearNode(traderFreshnessGrid); traderFreshnessGrid.appendChild(createMetric('Market Last Updated', formatTimestamp(freshness.market_last_updated_ts))); @@ -836,7 +919,7 @@ async function savePostMarketDraftNote() { async function refreshTraderMode() { const profile = profileFromControls(); try { - const [health, runtimeStatus, launchReadiness, reviewPacket, shadowPaper, weeklyReview, maintenanceSummary, unattendedHarness, candles, queue] = await Promise.all([ + const [health, runtimeStatus, launchReadiness, reviewPacket, shadowPaper, weeklyReview, maintenanceSummary, unattendedHarness, candles, backtests, queue] = await Promise.all([ fetchJson('/health'), fetchJson('/trading/runtime-status').catch(() => ({ scheduler_state: 'unavailable', current_blockers: ['runtime_status_unavailable'] })), fetchJson(`/trading/launch-readiness?${queryString({ instrument_id: profile.instrumentId, timeframe: profile.timeframe })}`), @@ -846,6 +929,7 @@ async function refreshTraderMode() { fetchJson(`/trading/maintenance-summary?${queryString({ instrument_id: profile.instrumentId, alert_limit: 20, visual_limit: 20, incident_limit: 20 })}`).catch(() => ({ status: 'unavailable', blockers: ['maintenance_summary_unavailable'], warnings: [] })), fetchJson(`/trading/unattended-harness?${queryString({ instrument_id: profile.instrumentId })}`).catch(() => ({ status: 'not_checked', blockers: ['unattended_harness_unavailable'] })), fetchJson(`/candles?${queryString({ instrument_id: profile.instrumentId, timeframe: profile.timeframe, limit: 3 })}`).catch(() => ({ items: [] })), + fetchJson(`/trading/backtests?${queryString({ instrument_id: profile.instrumentId, limit: 1 })}`).catch(() => ({ unavailable: true, items: [], latest: null })), fetchTraderQueue(profile), ]); const trader = reviewPacket?.decision_assistant_summary?.trader_mode_summary || {}; @@ -859,6 +943,7 @@ async function refreshTraderMode() { maintenanceSummary, unattendedHarness, candles, + backtests, queue, trader, }); diff --git a/tests/unit/test_api_static_server.py b/tests/unit/test_api_static_server.py index 3180081..0f75a8d 100644 --- a/tests/unit/test_api_static_server.py +++ b/tests/unit/test_api_static_server.py @@ -584,9 +584,9 @@ class ApiStaticServerTests(unittest.TestCase): for expected in ( "Trader Mode", "Status", - "Decision Now", - "Next Action", - "Live Readout", + "Now", + "Wait", + "ICT Fast Read", "Market Last Updated", "Review Packet Updated", "Runtime Online", @@ -617,6 +617,7 @@ class ApiStaticServerTests(unittest.TestCase): "/trading/maintenance-summary", "/trading/unattended-harness", "/candles", + "/trading/backtests", "/trading/shadow-paper/observe", "/trading/operator-notes", "Do Not Use", @@ -636,11 +637,13 @@ class ApiStaticServerTests(unittest.TestCase): "pause_or_resume_auto_refresh", "profile_filter_status", "trader_readout", - "Why No Trade", - "Watch Next", - "Focus Reason", - "Data State", - "No Candidate", + "Now", + "Reason", + "Wait", + "Risk", + "Historical Edge", + "Boundary", + "buildHistoricalEdgeSummary", ): self.assertIn(expected, js_text) diff --git a/tests/unit/test_documentation_consistency.py b/tests/unit/test_documentation_consistency.py index b88ba6a..45cc675 100644 --- a/tests/unit/test_documentation_consistency.py +++ b/tests/unit/test_documentation_consistency.py @@ -18,6 +18,7 @@ OLD_TRAINING_DOC = ROOT / "docs" / "training_case_engine_m1_m6_product_readme.md NONEXISTENT_VISUAL_PLAN_NAME = "AI_ICT_" + "视觉盯盘与主动告警增强方案_v1.md" ACTIVE_TOP_LEVEL_DOCS = { + "AI_ICT_硬性主线约束_必须遵循ICT交易全书_2026-05-21_v1.md", "AI_ICT_主线纠偏与功能裁剪方案_2026-05-20_v1.md", "AI_ICT_实盘辅助分析决策助手上线必做清单_2026-05-18_v1.md", "AI_ICT_实盘辅助分析决策助手使用说明_2026-05-18_v1.md", diff --git a/tests/unit/test_readonly_live_analysis_smoke_script.py b/tests/unit/test_readonly_live_analysis_smoke_script.py index 262fd63..24ececf 100644 --- a/tests/unit/test_readonly_live_analysis_smoke_script.py +++ b/tests/unit/test_readonly_live_analysis_smoke_script.py @@ -64,22 +64,23 @@ class ReadonlyLiveAnalysisSmokeScriptTests(unittest.TestCase): }, "/trading/unattended-harness?instrument_id=1": {"status": "passed"}, "/candles?instrument_id=1&timeframe=1m&limit=3": {"items": []}, + "/trading/backtests?instrument_id=1&limit=1": {"items": [], "latest": None}, "/trading/candidates?instrument_id=1&limit=5": {"items": []}, "/static/app.js": ( "Read-only Live Analysis No order submission Not a buy/sell instruction " "Execution remains disabled ready_for_readonly_live_analysis must_not_trade" ), "/trader-mode": ( - "Trader Mode Decision Now Market Last Updated Review Packet Updated " + "Trader Mode Now Wait ICT Fast Read Market Last Updated Review Packet Updated " "Fast Queue Chart Bridge Duty Panel Profile Sessions Setups Recovery No Trade " "Need More Evidence After-Close Draft R2 Evidence Window" ), "/static/trader_mode.js": ( "/trading/review-packet /trading/shadow-paper/observe /trading/operator-notes " - "/trading/research/weekly-review /trading/maintenance-summary /trading/unattended-harness /candles " + "/trading/research/weekly-review /trading/maintenance-summary /trading/unattended-harness /candles /trading/backtests " "Do Not Use Review Now Observe Only TRADER_SIGNATURE_KEY TRADER_PROFILE_STORE_KEY ETH London SOL " "DEFAULT_QUEUE_INSTRUMENTS post_market_review_draft chart_context_bridge ops_duty_panel " - "aria-keyshortcuts pause_or_resume_auto_refresh" + "aria-keyshortcuts pause_or_resume_auto_refresh Historical Edge buildHistoricalEdgeSummary" ), } ) @@ -166,22 +167,23 @@ class ReadonlyLiveAnalysisSmokeScriptTests(unittest.TestCase): }, "/trading/unattended-harness?instrument_id=1": {"status": "passed"}, "/candles?instrument_id=1&timeframe=1m&limit=3": {"items": []}, + "/trading/backtests?instrument_id=1&limit=1": {"items": [], "latest": None}, "/trading/candidates?instrument_id=1&limit=5": {"items": []}, "/static/app.js": ( "Read-only Live Analysis No order submission Not a buy/sell instruction " "Execution remains disabled ready_for_readonly_live_analysis must_not_trade" ), "/trader-mode": ( - "Trader Mode Decision Now Market Last Updated Review Packet Updated " + "Trader Mode Now Wait ICT Fast Read Market Last Updated Review Packet Updated " "Fast Queue Chart Bridge Duty Panel Profile Sessions Setups Recovery No Trade " "Need More Evidence After-Close Draft R2 Evidence Window" ), "/static/trader_mode.js": ( "/trading/review-packet /trading/shadow-paper/observe /trading/operator-notes " - "/trading/research/weekly-review /trading/maintenance-summary /trading/unattended-harness /candles " + "/trading/research/weekly-review /trading/maintenance-summary /trading/unattended-harness /candles /trading/backtests " "Do Not Use Review Now Observe Only TRADER_SIGNATURE_KEY TRADER_PROFILE_STORE_KEY ETH London SOL " "DEFAULT_QUEUE_INSTRUMENTS post_market_review_draft chart_context_bridge ops_duty_panel " - "aria-keyshortcuts pause_or_resume_auto_refresh" + "aria-keyshortcuts pause_or_resume_auto_refresh Historical Edge buildHistoricalEdgeSummary" ), } ),