Compress trader cockpit readout
This commit is contained in:
+5
-2
@@ -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
|
||||
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -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 稳定后,才开始删除代码。
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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', '纸面票据'],
|
||||
|
||||
+3
-3
@@ -112,17 +112,17 @@
|
||||
<div id="traderStatusLabel" class="trader-status-label">Loading</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="metric">Decision Now</div>
|
||||
<div class="metric">Now</div>
|
||||
<div id="traderConclusion" class="trader-conclusion">Waiting for live brief.</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="metric">Next Action</div>
|
||||
<div class="metric">Wait</div>
|
||||
<div id="traderNextAction" class="trader-next-action">n/a</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="trader-mode-band trader-readout-band">
|
||||
<h2>Live Readout</h2>
|
||||
<h2>ICT Fast Read</h2>
|
||||
<div id="traderReadoutPanel" class="trader-readout-grid"></div>
|
||||
</section>
|
||||
|
||||
|
||||
+11
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -34,17 +34,17 @@
|
||||
<div id="traderStatusLabel" class="trader-status-label">Loading</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="metric">Decision Now</div>
|
||||
<div class="metric">Now</div>
|
||||
<div id="traderConclusion" class="trader-conclusion">Waiting for live brief.</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="metric">Next Action</div>
|
||||
<div class="metric">Wait</div>
|
||||
<div id="traderNextAction" class="trader-next-action">n/a</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="trader-mode-band trader-readout-band">
|
||||
<h2>Live Readout</h2>
|
||||
<h2>ICT Fast Read</h2>
|
||||
<div id="traderReadoutPanel" class="trader-readout-grid"></div>
|
||||
</section>
|
||||
|
||||
|
||||
+99
-14
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
),
|
||||
}
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user