Add demo trading executor and analysis scheduling (plan 3 C4)

- Executor reconciles each symbol to its desired orders: journaled ap{id}
  client ids, reduce-only quantity stop placed before entries, make-before-
  break stop moves, breakeven after TP1, orphan cancel, -2021 market close
- Plan lifecycle: proposed plans are adopted only if the position is
  unchanged; holding-mode plans may only tighten the stop
- Program rules: time stop, short-term invalidation close, long-term 4h
  review, reevaluate conditions, takeover of unmanaged positions
- Trigger and routine analysis scheduling with a 10 min gap, daily cap and
  bounded retries
- Plan endpoint and plan status, fills and countdowns on the trading page
This commit is contained in:
eezd committed 2026-10-15 11:07:00 +08:00
1 parent 78ca4422af
commit 1fcf41952c
12 files changed
+1192 -67

No files matched your search

+45 -3
View File
@@ -77,7 +77,10 @@ export interface TradingSymbol {
added_at: string
analysis_requested_at: string | null
analyzing: boolean
plan_status: "pending" | "open" | null
/** 执行器正在管理的计划 */
plan_id: number | null
plan_status: "pending" | "open" | "closing" | null
close_deadline: string | null
}
export interface SymbolOption {
@@ -183,6 +186,10 @@ export interface Sizing {
capped_by_leverage: boolean
reward_risk: string
reward_risk_first_only: string
/** 采纳前核对用:提交时的持仓数量 */
position_qty: string
/** 持仓中调整的计划:不加仓 */
managed: boolean
}
export interface Analysis {
@@ -201,13 +208,13 @@ export interface Analysis {
usage: { input_tokens: number, output_tokens: number } | null
started_at: string
finished_at: string | null
plan_status: "pending" | "open" | "closed" | "canceled" | "replaced" | null
plan_status: PlanStatus | null
valid_until: string | null
first_fill_at: string | null
close_deadline: string | null
closed_at: string | null
close_reason: string | null
result: Record<string, unknown> | null
result: { realized_pnl: string, commission: string, net: string } | null
}
/** 与协议无关的消息格式,同 Chat */
@@ -221,6 +228,41 @@ export interface AnalysisDetail extends Analysis {
transcript: TranscriptMessage[] | null
}
export type PlanStatus = "proposed" | "pending" | "open" | "closing" | "closed" | "canceled" | "replaced" | "stale" | "applied"
export const PLAN_STATUS_LABELS: Record<PlanStatus, string> = {
proposed: "待采纳",
pending: "挂单中",
open: "持仓中",
closing: "平仓中",
closed: "已结束",
canceled: "已撤销",
replaced: "已被替换",
stale: "已作废",
applied: "已执行"
}
/** 执行器的订单流水 */
export interface OrderRow {
id: number
purpose: "entry" | "stop" | "tp" | "close"
leg: number | null
side: "BUY" | "SELL"
type: string
price: string | null
trigger_price: string | null
quantity: string
status: string
filled_qty: string
avg_price: string | null
error: string | null
created_at: string
}
export function getSymbolPlan(symbol: string): Promise<{ plan: Analysis | null, orders: OrderRow[] }> {
return http.get(`/trading/symbols/${symbol}/plan`)
}
export function requestAnalysis(symbol: string): Promise<void> {
return http.post(`/trading/symbols/${symbol}/analyze`)
}