Files
big-qmt/go-client/apps/zt/logic/boot.go
2026-08-25 22:35:44 +08:00

125 lines
3.5 KiB
Go

package logic
import (
"context"
"fmt"
"log"
"strings"
"time"
"big-qmt/go-client/config"
"big-qmt/go-client/libs"
"big-qmt/go-client/sdk"
)
func logf(level, format string, args ...any) {
log.Printf("[%s] %s", level, fmt.Sprintf(format, args...))
}
func Overview(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 buy_value: %.0f\n", config.Account.AccountID, config.Account.HostKey, config.Account.BuyValue)
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 := 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, signals *libs.SignalResult) {
if !libs.TradingTime(time.Now()) {
return
}
// 每轮先消费 QMT 回写,终态订单会立即释放本地委托锁。
books.readReceipts()
roundCtx, cancel := context.WithTimeout(ctx, config.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
}
seen := map[string]struct{}{}
stockList := make([]string, 0, len(signals.Data)+len(positions))
addCode := func(code string) {
if code == "" {
return
}
if _, ok := seen[code]; ok {
return
}
seen[code] = struct{}{}
stockList = append(stockList, code)
}
for code := range signals.Data {
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[code] = tick
}
}
runRound(roundCtx, client, books, assets, ticks, positions, signals.Data)
}
func runRound(ctx context.Context, client *sdk.Client, books *OrderBook, assets *sdk.Assets, ticks map[string]sdk.Tick, positions []sdk.Position, signals map[string]libs.SignalItem) {
if !books.cancelExpired(ctx, client) {
logf("ERROR", "[ZT] 委托查询失败,本轮跳过")
return
}
buys, sells, ok := books.activeSets(ctx, client)
if !ok {
return
}
hold := positionCodes(positions)
openSignals := map[string]libs.SignalItem{}
for code, signal := range signals {
if _, held := hold[code]; held {
continue
}
openSignals[code] = signal
}
for code := range buys {
delete(openSignals, code)
}
marketOK := libs.AllowOpen()
buyBudget := 0.0
if assets != nil {
buyBudget = assets.Available - assets.Total*config.Account.MinCashRatio
}
if len(openSignals) > 0 {
openSignal(ctx, client, books, ticks, openSignals, marketOK, &buyBudget)
}
managePositions(ctx, client, books, ticks, positions, buys, sells, marketOK, &buyBudget)
}