mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 00:07:01 +08:00
refactor: standardize code comments
This commit is contained in:
@@ -89,7 +89,7 @@ func (acc *BacktestAccount) Open(symbol, side string, quantity float64, leverage
|
||||
pos.LiquidationPrice = computeLiquidation(execPrice, leverage, side)
|
||||
} else {
|
||||
if leverage != pos.Leverage {
|
||||
// 采用权重平均杠杆(近似)
|
||||
// Use weighted average leverage (approximate)
|
||||
weightedMargin := pos.Margin + margin
|
||||
pos.Leverage = int(math.Round((pos.Notional + notional) / weightedMargin))
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func (acc *BacktestAccount) RealizedPnL() float64 {
|
||||
return acc.realizedPnL
|
||||
}
|
||||
|
||||
// RestoreFromSnapshots 用于从检查点恢复账户状态。
|
||||
// RestoreFromSnapshots restores account state from checkpoint.
|
||||
func (acc *BacktestAccount) RestoreFromSnapshots(cash float64, realized float64, snaps []PositionSnapshot) {
|
||||
acc.cash = cash
|
||||
acc.realizedPnL = realized
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"nofx/mcp"
|
||||
)
|
||||
|
||||
// configureMCPClient 根据配置创建/克隆 MCP 客户端(返回 mcp.AIClient 接口)。
|
||||
// 说明:mcp.New() 返回接口类型,这里统一转为具体实现再做拷贝,避免并发共享状态。
|
||||
// configureMCPClient creates/clones an MCP client based on configuration (returns mcp.AIClient interface).
|
||||
// Note: mcp.New() returns an interface type; here we convert to concrete implementation before copying to avoid concurrent shared state.
|
||||
func configureMCPClient(cfg BacktestConfig, base mcp.AIClient) (mcp.AIClient, error) {
|
||||
provider := strings.ToLower(strings.TrimSpace(cfg.AICfg.Provider))
|
||||
|
||||
@@ -48,9 +48,9 @@ func configureMCPClient(cfg BacktestConfig, base mcp.AIClient) (mcp.AIClient, er
|
||||
}
|
||||
}
|
||||
|
||||
// cloneBaseClient 复制基础客户端以避免共享可变状态。
|
||||
// cloneBaseClient copies the base client to avoid shared mutable state.
|
||||
func cloneBaseClient(base mcp.AIClient) *mcp.Client {
|
||||
// 优先尝试复用传入的基础客户端(深拷贝)
|
||||
// Prefer to reuse the passed-in base client (deep copy)
|
||||
switch c := base.(type) {
|
||||
case *mcp.Client:
|
||||
cp := *c
|
||||
@@ -66,6 +66,6 @@ func cloneBaseClient(base mcp.AIClient) *mcp.Client {
|
||||
return &cp
|
||||
}
|
||||
}
|
||||
// 回退到新的默认客户端
|
||||
// Fall back to a new default client
|
||||
return mcp.NewClient().(*mcp.Client)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type cachedDecision struct {
|
||||
Decision *decision.FullDecision `json:"decision"`
|
||||
}
|
||||
|
||||
// AICache 持久化 AI 决策,便于重复回测或重放。
|
||||
// AICache persists AI decisions for repeated backtesting or replay.
|
||||
type AICache struct {
|
||||
mu sync.RWMutex
|
||||
path string
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"nofx/market"
|
||||
)
|
||||
|
||||
// AIConfig 定义回测中使用的 AI 客户端配置。
|
||||
// AIConfig defines the AI client configuration used in backtesting.
|
||||
type AIConfig struct {
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
@@ -23,7 +23,7 @@ type LeverageConfig struct {
|
||||
AltcoinLeverage int `json:"altcoin_leverage"`
|
||||
}
|
||||
|
||||
// BacktestConfig 描述一次回测运行的输入配置。
|
||||
// BacktestConfig describes the input configuration for a backtest run.
|
||||
type BacktestConfig struct {
|
||||
RunID string `json:"run_id"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
@@ -54,7 +54,7 @@ type BacktestConfig struct {
|
||||
ReplayDecisionDir string `json:"replay_decision_dir,omitempty"`
|
||||
}
|
||||
|
||||
// Validate 对配置进行合法性检查并填充默认值。
|
||||
// Validate performs validity checks on the configuration and fills in default values.
|
||||
func (cfg *BacktestConfig) Validate() error {
|
||||
if cfg == nil {
|
||||
return fmt.Errorf("config is nil")
|
||||
@@ -151,7 +151,7 @@ func (cfg *BacktestConfig) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Duration 返回回测区间时长。
|
||||
// Duration returns the backtest interval duration.
|
||||
func (cfg *BacktestConfig) Duration() time.Duration {
|
||||
if cfg == nil {
|
||||
return 0
|
||||
@@ -160,11 +160,11 @@ func (cfg *BacktestConfig) Duration() time.Duration {
|
||||
}
|
||||
|
||||
const (
|
||||
// FillPolicyNextOpen 使用下一根 K 线的开盘价成交。
|
||||
// FillPolicyNextOpen uses the open price of the next bar for execution.
|
||||
FillPolicyNextOpen = "next_open"
|
||||
// FillPolicyBarVWAP 采用当前 K 线的近似 VWAP 成交。
|
||||
// FillPolicyBarVWAP uses the approximate VWAP of the current bar for execution.
|
||||
FillPolicyBarVWAP = "bar_vwap"
|
||||
// FillPolicyMidPrice 采用 (high+low)/2 的中间价成交。
|
||||
// FillPolicyMidPrice uses the mid-price (high+low)/2 for execution.
|
||||
FillPolicyMidPrice = "mid"
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ type symbolSeries struct {
|
||||
byTF map[string]*timeframeSeries
|
||||
}
|
||||
|
||||
// DataFeed 管理历史K线数据,为回测提供按时间推进的快照。
|
||||
// DataFeed manages historical kline data and provides time-progressive snapshots for backtesting.
|
||||
type DataFeed struct {
|
||||
cfg BacktestConfig
|
||||
symbols []string
|
||||
@@ -49,7 +49,7 @@ func (df *DataFeed) loadAll() error {
|
||||
start := time.Unix(df.cfg.StartTS, 0)
|
||||
end := time.Unix(df.cfg.EndTS, 0)
|
||||
|
||||
// longest timeframe用于辅助指标
|
||||
// longest timeframe used for auxiliary indicators
|
||||
var longestDur time.Duration
|
||||
for _, tf := range df.timeframes {
|
||||
dur, err := market.TFDuration(tf)
|
||||
@@ -93,7 +93,7 @@ func (df *DataFeed) loadAll() error {
|
||||
df.symbolSeries[symbol] = ss
|
||||
}
|
||||
|
||||
// 以第一个符号的主周期生成回测进度时间轴
|
||||
// Generate backtest progress timeline using the primary timeframe of the first symbol
|
||||
firstSymbol := df.symbols[0]
|
||||
primarySeries := df.symbolSeries[firstSymbol].byTF[df.primaryTF]
|
||||
startMs := start.UnixMilli()
|
||||
@@ -106,7 +106,7 @@ func (df *DataFeed) loadAll() error {
|
||||
break
|
||||
}
|
||||
df.decisionTimes = append(df.decisionTimes, ts)
|
||||
// 对齐其他符号,如果缺数据则提前报错
|
||||
// Align other symbols; report error early if data is missing
|
||||
for _, symbol := range df.symbols[1:] {
|
||||
if _, ok := df.symbolSeries[symbol].byTF[df.primaryTF]; !ok {
|
||||
return fmt.Errorf("symbol %s missing timeframe %s", symbol, df.primaryTF)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"nofx/market"
|
||||
)
|
||||
|
||||
// ResampleEquity 根据时间周期重采样资金曲线。
|
||||
// ResampleEquity resamples equity curve based on timeframe.
|
||||
func ResampleEquity(points []EquityPoint, timeframe string) ([]EquityPoint, error) {
|
||||
if timeframe == "" {
|
||||
return points, nil
|
||||
@@ -49,7 +49,7 @@ func ResampleEquity(points []EquityPoint, timeframe string) ([]EquityPoint, erro
|
||||
return resampled, nil
|
||||
}
|
||||
|
||||
// LimitEquityPoints 将数据点数量限制在给定范围内(均匀抽样)。
|
||||
// LimitEquityPoints limits the number of data points within a given range (uniform sampling).
|
||||
func LimitEquityPoints(points []EquityPoint, limit int) []EquityPoint {
|
||||
if limit <= 0 || len(points) <= limit {
|
||||
return points
|
||||
@@ -68,7 +68,7 @@ func LimitEquityPoints(points []EquityPoint, limit int) []EquityPoint {
|
||||
return result
|
||||
}
|
||||
|
||||
// LimitTradeEvents 同样对交易事件按均匀抽样。
|
||||
// LimitTradeEvents applies uniform sampling to trade events.
|
||||
func LimitTradeEvents(events []TradeEvent, limit int) []TradeEvent {
|
||||
if limit <= 0 || len(events) <= limit {
|
||||
return events
|
||||
@@ -86,7 +86,7 @@ func LimitTradeEvents(events []TradeEvent, limit int) []TradeEvent {
|
||||
return result
|
||||
}
|
||||
|
||||
// AlignEquityTimestamps 确保时间戳按升序排列。
|
||||
// AlignEquityTimestamps ensures timestamps are sorted in ascending order.
|
||||
func AlignEquityTimestamps(points []EquityPoint) []EquityPoint {
|
||||
sort.Slice(points, func(i, j int) bool {
|
||||
return points[i].Timestamp < points[j].Timestamp
|
||||
|
||||
@@ -15,7 +15,7 @@ const (
|
||||
lockStaleAfter = 10 * time.Second
|
||||
)
|
||||
|
||||
// RunLockInfo 表示回测运行的锁文件结构。
|
||||
// RunLockInfo represents the lock file structure for a backtest run.
|
||||
type RunLockInfo struct {
|
||||
RunID string `json:"run_id"`
|
||||
PID int `json:"pid"`
|
||||
|
||||
@@ -438,7 +438,7 @@ func (m *Manager) resolveAIConfig(cfg *BacktestConfig) error {
|
||||
m.mu.RUnlock()
|
||||
if resolver == nil {
|
||||
if apiKey == "" {
|
||||
return fmt.Errorf("AI配置缺少密钥且未配置解析器")
|
||||
return fmt.Errorf("AI configuration missing key and no resolver configured")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -453,7 +453,7 @@ func (m *Manager) ExportRun(runID string) (string, error) {
|
||||
return CreateRunExport(runID)
|
||||
}
|
||||
|
||||
// RestoreRunsFromDisk 扫描 backtests 目录并恢复现有 run 的元数据(服务重启场景)。
|
||||
// RestoreRuns scans the backtests directory and restores metadata for existing runs (service restart scenario).
|
||||
func (m *Manager) RestoreRuns() error {
|
||||
runIDs, err := LoadRunIDs()
|
||||
if err != nil {
|
||||
@@ -487,7 +487,7 @@ func (m *Manager) RestoreRuns() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreRunsFromDisk 保留旧方法名,兼容历史调用。
|
||||
// RestoreRunsFromDisk retains the old method name for backward compatibility.
|
||||
func (m *Manager) RestoreRunsFromDisk() error {
|
||||
return m.RestoreRuns()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CalculateMetrics 读取已有日志并计算汇总指标。state 可选,用于补充尚未落盘的信息。
|
||||
// CalculateMetrics reads existing logs and calculates summary metrics. state is optional, used to supplement information not yet persisted.
|
||||
func CalculateMetrics(runID string, cfg *BacktestConfig, state *BacktestState) (*Metrics, error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("config is nil")
|
||||
|
||||
@@ -29,7 +29,7 @@ const (
|
||||
aiDecisionMaxRetries = 3
|
||||
)
|
||||
|
||||
// Runner 封装单次回测运行的生命周期。
|
||||
// Runner encapsulates the lifecycle of a single backtest run.
|
||||
type Runner struct {
|
||||
cfg BacktestConfig
|
||||
feed *DataFeed
|
||||
@@ -63,7 +63,7 @@ type Runner struct {
|
||||
lockStop chan struct{}
|
||||
}
|
||||
|
||||
// NewRunner 构建回测运行器。
|
||||
// NewRunner constructs a backtest runner.
|
||||
func NewRunner(cfg BacktestConfig, mcpClient mcp.AIClient) (*Runner, error) {
|
||||
if err := ensureRunDir(cfg.RunID); err != nil {
|
||||
return nil, err
|
||||
@@ -179,7 +179,7 @@ func (r *Runner) releaseLock() {
|
||||
r.lockInfo = nil
|
||||
}
|
||||
|
||||
// Start 启动回测循环。
|
||||
// Start launches the backtest loop.
|
||||
func (r *Runner) Start(ctx context.Context) error {
|
||||
r.statusMu.Lock()
|
||||
if r.status != RunStateCreated && r.status != RunStatePaused {
|
||||
@@ -193,7 +193,7 @@ func (r *Runner) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PersistMetadata 将当前快照写入 run.json。
|
||||
// PersistMetadata writes the current snapshot to run.json.
|
||||
func (r *Runner) PersistMetadata() {
|
||||
r.persistMetadata()
|
||||
}
|
||||
@@ -214,7 +214,7 @@ func (r *Runner) lastErrorString() string {
|
||||
return r.lastError
|
||||
}
|
||||
|
||||
// CurrentMetadata 返回当前内存状态对应的元数据。
|
||||
// CurrentMetadata returns the metadata corresponding to the current in-memory state.
|
||||
func (r *Runner) CurrentMetadata() *RunMetadata {
|
||||
state := r.snapshotState()
|
||||
meta := r.buildMetadata(state, r.Status())
|
||||
@@ -292,7 +292,7 @@ func (r *Runner) stepOnce() error {
|
||||
ctx, rec, err := r.buildDecisionContext(ts, marketData, multiTF, priceMap, callCount)
|
||||
if err != nil {
|
||||
rec.Success = false
|
||||
rec.ErrorMessage = fmt.Sprintf("构建交易上下文失败: %v", err)
|
||||
rec.ErrorMessage = fmt.Sprintf("failed to build trading context: %v", err)
|
||||
_ = r.logDecision(rec)
|
||||
return err
|
||||
}
|
||||
@@ -312,7 +312,7 @@ func (r *Runner) stepOnce() error {
|
||||
} else if r.cfg.ReplayOnly {
|
||||
decisionErr := fmt.Errorf("replay_only enabled but cache miss at %d", ts)
|
||||
record.Success = false
|
||||
record.ErrorMessage = fmt.Sprintf("没有找到 ts=%d 的缓存决策", ts)
|
||||
record.ErrorMessage = fmt.Sprintf("cached decision not found for ts=%d", ts)
|
||||
_ = r.logDecision(record)
|
||||
return decisionErr
|
||||
}
|
||||
@@ -327,8 +327,8 @@ func (r *Runner) stepOnce() error {
|
||||
decisionAttempted = true
|
||||
hadError = true
|
||||
record.Success = false
|
||||
record.ErrorMessage = fmt.Sprintf("AI决策失败: %v", err)
|
||||
execLog = append(execLog, fmt.Sprintf("⚠️ AI决策失败: %v", err))
|
||||
record.ErrorMessage = fmt.Sprintf("AI decision failed: %v", err)
|
||||
execLog = append(execLog, fmt.Sprintf("⚠️ AI decision failed: %v", err))
|
||||
r.setLastError(err)
|
||||
} else {
|
||||
fullDecision = fd
|
||||
@@ -392,7 +392,7 @@ func (r *Runner) stepOnce() error {
|
||||
hadError = true
|
||||
tradeEvents = append(tradeEvents, liquidationEvents...)
|
||||
if record != nil {
|
||||
execLog = append(execLog, fmt.Sprintf("⚠️ 强制平仓: %s", liquidationNote))
|
||||
execLog = append(execLog, fmt.Sprintf("⚠️ Forced liquidation: %s", liquidationNote))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +690,7 @@ func (r *Runner) executeDecision(dec decision.Decision, priceMap map[string]floa
|
||||
return actionRecord, []TradeEvent{trade}, "", nil
|
||||
|
||||
case "hold", "wait":
|
||||
return actionRecord, nil, fmt.Sprintf("保持仓位: %s", dec.Action), nil
|
||||
return actionRecord, nil, fmt.Sprintf("hold position: %s", dec.Action), nil
|
||||
default:
|
||||
return actionRecord, nil, "", fmt.Errorf("unsupported action %s", dec.Action)
|
||||
}
|
||||
@@ -1078,14 +1078,14 @@ func (r *Runner) Wait() error {
|
||||
return r.err
|
||||
}
|
||||
|
||||
// Status 返回当前运行状态。
|
||||
// Status returns the current run state.
|
||||
func (r *Runner) Status() RunState {
|
||||
r.statusMu.RLock()
|
||||
defer r.statusMu.RUnlock()
|
||||
return r.status
|
||||
}
|
||||
|
||||
// StatusPayload 构建用于 API 的状态响应。
|
||||
// StatusPayload builds the status response for the API.
|
||||
func (r *Runner) StatusPayload() StatusPayload {
|
||||
snapshot := r.snapshotState()
|
||||
progress := progressPercent(snapshot, r.cfg)
|
||||
|
||||
@@ -132,7 +132,7 @@ func appendJSONLine(path string, payload any) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
// SaveCheckpoint 将检查点写入磁盘。
|
||||
// SaveCheckpoint writes the checkpoint to disk.
|
||||
func SaveCheckpoint(runID string, ckpt *Checkpoint) error {
|
||||
if ckpt == nil {
|
||||
return fmt.Errorf("checkpoint is nil")
|
||||
@@ -143,7 +143,7 @@ func SaveCheckpoint(runID string, ckpt *Checkpoint) error {
|
||||
return writeJSONAtomic(checkpointPath(runID), ckpt)
|
||||
}
|
||||
|
||||
// LoadCheckpoint 读取最近一次检查点。
|
||||
// LoadCheckpoint reads the most recent checkpoint.
|
||||
func LoadCheckpoint(runID string) (*Checkpoint, error) {
|
||||
if usingDB() {
|
||||
return loadCheckpointDB(runID)
|
||||
@@ -160,7 +160,7 @@ func LoadCheckpoint(runID string) (*Checkpoint, error) {
|
||||
return &ckpt, nil
|
||||
}
|
||||
|
||||
// SaveRunMetadata 写入 run.json。
|
||||
// SaveRunMetadata writes to run.json.
|
||||
func SaveRunMetadata(meta *RunMetadata) error {
|
||||
if meta == nil {
|
||||
return fmt.Errorf("run metadata is nil")
|
||||
@@ -178,7 +178,7 @@ func SaveRunMetadata(meta *RunMetadata) error {
|
||||
return writeJSONAtomic(runMetadataPath(meta.RunID), meta)
|
||||
}
|
||||
|
||||
// LoadRunMetadata 读取 run.json。
|
||||
// LoadRunMetadata reads run.json.
|
||||
func LoadRunMetadata(runID string) (*RunMetadata, error) {
|
||||
if usingDB() {
|
||||
return loadRunMetadataDB(runID)
|
||||
|
||||
@@ -2,7 +2,7 @@ package backtest
|
||||
|
||||
import "time"
|
||||
|
||||
// RunState 表示回测运行当前状态。
|
||||
// RunState represents the current state of a backtest run.
|
||||
type RunState string
|
||||
|
||||
const (
|
||||
@@ -15,7 +15,7 @@ const (
|
||||
RunStateLiquidated RunState = "liquidated"
|
||||
)
|
||||
|
||||
// PositionSnapshot 表示当前持仓的核心数据,用于回测状态与持久化。
|
||||
// PositionSnapshot represents core position data for backtest state and persistence.
|
||||
type PositionSnapshot struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
@@ -27,7 +27,7 @@ type PositionSnapshot struct {
|
||||
OpenTime int64 `json:"open_time"`
|
||||
}
|
||||
|
||||
// BacktestState 表示执行过程中的实时状态(内存态)。
|
||||
// BacktestState represents the real-time state during execution (in-memory state).
|
||||
type BacktestState struct {
|
||||
BarIndex int
|
||||
BarTimestamp int64
|
||||
@@ -46,7 +46,7 @@ type BacktestState struct {
|
||||
LiquidationNote string
|
||||
}
|
||||
|
||||
// EquityPoint 表示资金曲线中的单个节点。
|
||||
// EquityPoint represents a single point on the equity curve.
|
||||
type EquityPoint struct {
|
||||
Timestamp int64 `json:"ts"`
|
||||
Equity float64 `json:"equity"`
|
||||
@@ -57,7 +57,7 @@ type EquityPoint struct {
|
||||
Cycle int `json:"cycle"`
|
||||
}
|
||||
|
||||
// TradeEvent 记录一次交易执行结果或特殊事件(如爆仓)。
|
||||
// TradeEvent records a trade execution result or special event (such as liquidation).
|
||||
type TradeEvent struct {
|
||||
Timestamp int64 `json:"ts"`
|
||||
Symbol string `json:"symbol"`
|
||||
@@ -76,7 +76,7 @@ type TradeEvent struct {
|
||||
Note string `json:"note,omitempty"`
|
||||
}
|
||||
|
||||
// Metrics 汇总回测表现指标。
|
||||
// Metrics summarizes backtest performance metrics.
|
||||
type Metrics struct {
|
||||
TotalReturnPct float64 `json:"total_return_pct"`
|
||||
MaxDrawdownPct float64 `json:"max_drawdown_pct"`
|
||||
@@ -92,7 +92,7 @@ type Metrics struct {
|
||||
Liquidated bool `json:"liquidated"`
|
||||
}
|
||||
|
||||
// SymbolMetrics 记录单个标的的表现。
|
||||
// SymbolMetrics records performance for a single symbol.
|
||||
type SymbolMetrics struct {
|
||||
TotalTrades int `json:"total_trades"`
|
||||
WinningTrades int `json:"winning_trades"`
|
||||
@@ -102,7 +102,7 @@ type SymbolMetrics struct {
|
||||
WinRate float64 `json:"win_rate"`
|
||||
}
|
||||
|
||||
// Checkpoint 表示磁盘保存的检查点信息,用于暂停、恢复与崩溃恢复。
|
||||
// Checkpoint represents checkpoint information saved to disk for pause, resume, and crash recovery.
|
||||
type Checkpoint struct {
|
||||
BarIndex int `json:"bar_index"`
|
||||
BarTimestamp int64 `json:"bar_ts"`
|
||||
@@ -122,7 +122,7 @@ type Checkpoint struct {
|
||||
LiquidationNote string `json:"liquidation_note,omitempty"`
|
||||
}
|
||||
|
||||
// RunMetadata 记录 run.json 所需摘要。
|
||||
// RunMetadata records the summary required for run.json.
|
||||
type RunMetadata struct {
|
||||
RunID string `json:"run_id"`
|
||||
Label string `json:"label,omitempty"`
|
||||
@@ -135,7 +135,7 @@ type RunMetadata struct {
|
||||
Summary RunSummary `json:"summary"`
|
||||
}
|
||||
|
||||
// RunSummary 为 run.json 中的 summary 字段。
|
||||
// RunSummary represents the summary field in run.json.
|
||||
type RunSummary struct {
|
||||
SymbolCount int `json:"symbol_count"`
|
||||
DecisionTF string `json:"decision_tf"`
|
||||
@@ -147,7 +147,7 @@ type RunSummary struct {
|
||||
LiquidationNote string `json:"liquidation_note,omitempty"`
|
||||
}
|
||||
|
||||
// StatusPayload 用于 /status API 的响应。
|
||||
// StatusPayload is used for /status API responses.
|
||||
type StatusPayload struct {
|
||||
RunID string `json:"run_id"`
|
||||
State RunState `json:"state"`
|
||||
|
||||
Reference in New Issue
Block a user