package logic import ( "context" "fmt" "strings" "time" "big-qmt/go-client/libs" "big-qmt/go-client/sdk" ) func Overview(cfg Config, assets *sdk.Assets, positions []sdk.Position) { fmt.Println("\n" + strings.Repeat("=", 80)) fmt.Printf("【时间】%s\n", time.Now().Format("2006-01-02 15:04:05")) fmt.Printf("【配置】account_id: %s host_key: %s open_money: %.0f\n", cfg.AccountID, cfg.HostKey, cfg.OpenMoney) if assets != nil { fmt.Printf("【资金】总资产:%.2f元,可用资金:%.2f元\n", assets.Total, assets.Available) } else { fmt.Println("【资金】查询失败") } fmt.Printf("【持仓】%d只\n", len(positions)) fmt.Println(strings.Repeat("=", 80)) for _, p := range positions { if p.Volume <= 0 { continue } code := normalizeCode(p.StockCode, "") fmt.Printf("【持仓】%s %s 持仓=%d 可用=%d 冻结=%d 在途=%d 昨仓=%d 成本=%.3f 现价=%.3f 市值=%.2f 浮盈=%.2f 盈亏比例=%.2f%%\n", code, p.StockName, p.Volume, p.CanUseVolume, p.FrozenVolume, p.OnRoadVolume, p.YesterdayVolume, p.OpenPrice, p.LastPrice, p.MarketValue, p.FloatProfit, p.ProfitRate*100) } } func RunOnce(ctx context.Context, client *sdk.Client, books *OrderBook, cfg Config) { if !tradingTime(time.Now()) { return } roundCtx, cancel := context.WithTimeout(ctx, cfg.HTTPTimeout*4) defer cancel() assets, err := client.Assets(roundCtx) if err != nil { logf("ERROR", "获取资产失败: %v", err) return } positions, err := client.Positions(roundCtx) if err != nil { logf("ERROR", "获取持仓失败: %v", err) return } signals := fetchSignal(cfg, "dcm_signal") seen := map[string]struct{}{} stockList := make([]string, 0, len(signals)+len(positions)) addCode := func(code string) { n := normalizeCode(code, "") if n == "" { n = strings.ToUpper(strings.TrimSpace(code)) } if n == "" { return } if _, ok := seen[n]; ok { return } seen[n] = struct{}{} stockList = append(stockList, n) } for code := range signals { addCode(code) } for _, p := range positions { addCode(p.StockCode) } ticks := map[string]sdk.Tick{} if len(stockList) > 0 { raw, err := client.FullTick(roundCtx, stockList) if err != nil { logf("ERROR", "获取行情失败: %v", err) return } for code, tick := range raw { ticks[normalizeCode(code, "")] = tick ticks[code] = tick } } runRound(roundCtx, client, books, cfg, assets, ticks, positions, signals) } func runRound(ctx context.Context, client *sdk.Client, books *OrderBook, cfg Config, assets *sdk.Assets, ticks map[string]sdk.Tick, positions []sdk.Position, signals map[string]map[string]any) { books.cancelExpired(ctx, client, cfg) hold := positionCodes(positions) openSignals := map[string]map[string]any{} for code, signal := range signals { norm := normalizeCode(code, "") if norm == "" { norm = code } if _, held := hold[norm]; held { continue } openSignals[norm] = signal } if len(openSignals) > 0 { if books.refresh(ctx, client, cfg) { buys, _, ok := books.activeSets(ctx, client, cfg) if ok { filtered := map[string]map[string]any{} for code, signal := range openSignals { if _, buying := buys[code]; buying { continue } filtered[code] = signal } openSignals = filtered } } } marketOK := libs.AllowOpen(cfg.APIHost, cfg.HTTPTimeout) if len(openSignals) > 0 { openSignal(ctx, client, books, cfg, assets, ticks, openSignals, marketOK) } managePositions(ctx, client, books, cfg, ticks, positions, marketOK) }