feat(live): B4前端三层展示+预算表单+账户实况端点(spec§B4)——①新建实盘表单:起始资金升级『实例预算』,默认值=剩余可分配(budget-info,用户改过不跟随),占用率进度条(已分配+本次 vs 现金),超限红条+禁提交,快照不可用警告条(与后端fail-closed双保险)②监控页三层重构:本策略买卖(live_trades归因,今日/全部)/本策略账本+持仓(实例视图,现金/市值/净值语义重命名)/账户实况(新卡:现金/市值/总资产+Σ实例市值+未归因市值=账户市值−Σ实例+实例分解表+QMT全账户持仓表)③列表页:每QMT账号一条占用率横幅,存量超限亮黄条⚠④后端补GET /live/account-snapshot(注册在{aid}前):全局快照+同账号实例最新账本分解+unattributed_mv,快照缺失fresh=False数值None;⑤live.ts补BudgetInfo/AccountSnapshotView类型+updateLive带initial_capital;+3端点测试(分解算术/无快照降级/跨账号过滤);api 164绿;npm run build绿 [vps]
CI/CD / test (push) Successful in 15s
CI/CD / nas-deploy (push) Successful in 1m24s
CI/CD / nas-verify (push) Successful in 15s

This commit is contained in:
2026-08-19 22:26:41 +08:00
parent 5a91be2efd
commit 537fd2d571
6 changed files with 431 additions and 18 deletions
+71
View File
@@ -149,7 +149,78 @@ export interface LiveUpdateReq {
interval?: string
}
export interface LiveUpdateReq {
name?: string
account?: string
vt_symbol?: string
strategy_name?: string
interval?: string
/** B3 预算(initial_capital 含义升级为资金额度) */
initial_capital?: number
}
export async function updateLive(aid: number, req: LiveUpdateReq): Promise<{ updated: boolean }> {
const { data } = await apiClient.put(`/live/${aid}`, req)
return data
}
// ===== B3/B4 预算制 + 账户实况 =====
/** B3 预算信息(GET /live/budget-info) */
export interface BudgetInfo {
account: string
/** 快照是否新鲜(10 分钟内);false 时 remaining=null(fail-closed) */
fresh: boolean
account_cash: number | null
allocated: number
remaining: number | null
snapshot_at?: string | null
}
export async function getBudgetInfo(account: string): Promise<BudgetInfo> {
const { data } = await apiClient.get<BudgetInfo>('/live/budget-info', {
params: { account },
})
return data
}
/** B4 账户实况持仓行(qmt_account_snapshot.positions JSON) */
export interface AccountPositionRow {
symbol: string
volume: number
can_use: number
avg_price: number
mv: number
}
/** B4 账户实况实例分解行 */
export interface SnapshotInstanceRow {
id: number
name: string
status: string
initial_capital: number
cash: number | null
market_value: number | null
equity: number | null
}
/** B4 账户实况(GET /live/account-snapshot) */
export interface AccountSnapshotView {
account: string
fresh: boolean
cash: number | null
market_value: number | null
total: number | null
positions: AccountPositionRow[]
updated_at?: string | null
instances: SnapshotInstanceRow[]
instance_mv_total: number
unattributed_mv: number | null
}
export async function getAccountSnapshot(account: string): Promise<AccountSnapshotView> {
const { data } = await apiClient.get<AccountSnapshotView>('/live/account-snapshot', {
params: { account },
})
return data
}