fix: Macro panel manage-only (not auto-open), Trump-only auto-trade copy, store docs

SystemControl was rendered as two per-system panels (Trump / Macro) that both
flipped the SAME global auto_trade, and its copy claimed a "qualifying Macro
Vibes signal auto-opens a trade". Both are wrong: bot_engine.process_post
early-returns for System 2, so the auto_trade gate only ever fires for Trump
(System 1). Macro Vibes is manage-only — it never auto-opens.

- Macro (`system="btc"`) panel: replaced the misleading Auto-Trade ON/OFF
  toggle with a manage-only explainer (open on HL → /adopt via Telegram → bot
  manages exits) and a note that the Trump-page switch has no effect here.
- Trump (`system="trump"`) panel: relabeled the switch "TRUMP (System 1)" and
  rewrote all copy/status lines to say Trump-only auto-open (was "GLOBAL
  (Trump + BTC)" / "both Trump & BTC").
- CLAUDE.md: corrected "No global store (no Redux/Zustand)" — the app DOES use
  a small Zustand store (store/dashboard.ts / useDashboardStore); documented
  what it holds and the guidance to keep it small.

Note (not a bug): dashboard adopt/release is intentionally Telegram-only —
there are no positions/adopt|hl|release client calls and the UI correctly
points to the Telegram /adopt command. No dashboard wiring is "broken".

tsc + next build clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
k
2026-05-29 15:04:36 +08:00
parent 3a113aaa8f
commit b2b96bb9c0
2 changed files with 61 additions and 12 deletions
+5 -1
View File
@@ -138,7 +138,11 @@ mutate the subscription.
## State management ## State management
- **No global store** (no Redux/Zustand). Tree-local state + props. - **One small global store** — `store/dashboard.ts` (Zustand, `useDashboardStore`).
Holds cross-page UI/session state: selected post, chart asset/timeframe,
wallet address, subscription + bot-readiness flags, masked HL key hint, and
the live-price map. Everything else stays tree-local (state + props) — don't
grow this store into a catch-all; page-specific data belongs in the page.
- **SWR-style cache** in `lib/cache.ts` for the API-heavy pages. - **SWR-style cache** in `lib/cache.ts` for the API-heavy pages.
- **WebSocket** singleton via `WsProvider` — used by `SignalMonitor` and - **WebSocket** singleton via `WsProvider` — used by `SignalMonitor` and
live price tickers. live price tickers.
+56 -11
View File
@@ -134,6 +134,49 @@ export default function SystemControl({ system }: { system: 'trump' | 'btc' }) {
const settingsHref = `/${locale}/settings#bot-config` const settingsHref = `/${locale}/settings#bot-config`
const settingsLabel = system === 'trump' ? 'Trump Signal' : 'Macro Vibes' const settingsLabel = system === 'trump' ? 'Trump Signal' : 'Macro Vibes'
// Macro Vibes (System 2) is MANAGE-ONLY by design — it NEVER auto-opens a
// trade. bot_engine.process_post early-returns for sys2 sources, so the
// master Auto-Trade switch only governs Trump (System 1). Presenting an
// ON/OFF auto-trade toggle here would (a) falsely imply Macro signals
// auto-open and (b) be a confusing second copy of the SAME global switch
// shown on the Trump page. Show the adopt-only flow instead.
if (system === 'btc') {
const linkStyle: React.CSSProperties = {
display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 12px',
borderRadius: 999, border: '1px solid var(--line)', background: 'var(--surface)',
fontSize: 12, color: 'var(--ink)', textDecoration: 'none', fontWeight: 700,
boxShadow: 'var(--shadow-1)',
}
return (
<div className="card" style={{ padding: 0, marginBottom: 16, overflow: 'hidden' }}>
<div style={{ padding: '14px 16px', background: s.soft,
borderLeft: `4px solid ${s.accent}` }}>
<div style={{ fontSize: 14, fontWeight: 700, color: s.accent }}>
{s.idx} {s.name} manage-only
</div>
</div>
<div style={{ padding: '16px', fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.6 }}>
<p style={{ margin: '0 0 10px' }}>
<strong>Macro Vibes does not auto-open trades.</strong> When a bottom-reversal
signal fires you get a Telegram alert. You open the position yourself on
Hyperliquid, then hand it to the bot with <code>/adopt</code> the bot then
manages the exit (staged stop ladder, de-risk, pyramid, peak-trail).
</p>
<p style={{ margin: '0 0 12px', color: 'var(--ink-4)', fontSize: 12 }}>
The Auto-Trade switch on the Trump page controls Trump (System&nbsp;1)
auto-opens only it has no effect on Macro Vibes.
</p>
<Link href={settingsHref} style={linkStyle}>
<span style={{ fontSize: 10, letterSpacing: '0.08em', textTransform: 'uppercase',
color: 'var(--ink-4)' }}>Settings</span>
<span>{settingsLabel}</span>
<span aria-hidden="true"></span>
</Link>
</div>
</div>
)
}
// Wallet not connected: a previous version showed a giant full-width // Wallet not connected: a previous version showed a giant full-width
// "Connect a wallet..." card here, which was redundant with the navbar's // "Connect a wallet..." card here, which was redundant with the navbar's
// Connect button. The opposite extreme — rendering null — silently hid // Connect button. The opposite extreme — rendering null — silently hid
@@ -203,13 +246,13 @@ export default function SystemControl({ system }: { system: 'trump' | 'btc' }) {
: `Circuit breaker tripped (${pub?.circuit_breaker_reason || 'risk limit'}). Turn Auto-Trade ON to acknowledge & resume.` : `Circuit breaker tripped (${pub?.circuit_breaker_reason || 'risk limit'}). Turn Auto-Trade ON to acknowledge & resume.`
} else if (!autoOn) { } else if (!autoOn) {
netMsg = isZh netMsg = isZh
? 'Auto-Trade 当前为关闭(全局): Trump 和 BTC 信号仍会显示,但不会自动开仓。' ? 'Auto-Trade 当前为关闭: Trump 信号仍会显示,但不会自动开仓。'
: 'Auto-Trade is OFF (global) — Trump AND Macro Vibes signals are shown in the feed but NOT traded.' : 'Auto-Trade is OFF — Trump signals are shown in the feed but NOT traded.'
} else { } else {
netOk = true netOk = true
netMsg = isZh netMsg = isZh
? `Auto-Trade 已开启(全局,覆盖 Trump 和 BTC: 下一条合格信号会自动开出${paper ? '模拟' : '真实'}仓位。` ? `Auto-Trade 已开启(Trump 系统①: 下一条合格 Trump 信号会自动开出${paper ? '模拟' : '真实'}仓位。`
: `Auto-Trade ON (global, both Trump & BTC) — will open a ${paper ? 'PAPER' : 'LIVE'} trade on the next qualifying signal.` : `Auto-Trade ON (Trump / System 1) — will open a ${paper ? 'PAPER' : 'LIVE'} trade on the next qualifying Trump signal.`
} }
const Pill = ({ active, onClick, children, tone }: { const Pill = ({ active, onClick, children, tone }: {
@@ -245,21 +288,23 @@ export default function SystemControl({ system }: { system: 'trump' | 'btc' }) {
<div> <div>
<div style={{ fontSize: 14, fontWeight: 700 }}> <div style={{ fontSize: 14, fontWeight: 700 }}>
Auto-Trade <span style={{ fontSize: 10, fontWeight: 600, Auto-Trade <span style={{ fontSize: 10, fontWeight: 600,
color: 'var(--ink-4)', marginLeft: 6 }}>{isZh ? 全局(Trump + BTC' : GLOBAL (Trump + BTC)'}</span> color: 'var(--ink-4)', marginLeft: 6 }}>{isZh ? '· Trump 系统①' : TRUMP (System 1)'}</span>
</div> </div>
<div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 3, maxWidth: 480, lineHeight: 1.5 }}> <div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 3, maxWidth: 480, lineHeight: 1.5 }}>
{isZh ? ( {isZh ? (
<> <>
<strong></strong> <strong> Trump </strong>
Trump BTC Trump
Macro Vibes Macro manage-only
</> </>
) : ( ) : (
<> <>
<strong>One switch for both systems.</strong> OFF: signals scanned <strong>Controls Trump (System 1) auto-opens.</strong> OFF: signals
&amp; shown in the feed, nothing traded. ON: a qualifying Trump OR scanned &amp; shown in the feed, nothing traded. ON: a qualifying
Macro Vibes signal auto-opens a trade. Stop-loss / staged de-risk Trump signal auto-opens a trade. Stop-loss / staged de-risk always
always protect open positions either way. protect open positions either way. (Macro Vibes is manage-only and
never auto-opens see its page.)
</> </>
)} )}
</div> </div>