dev 4
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -42,83 +43,53 @@ func RunOnce(ctx context.Context, client *sdk.Client, books *OrderBook, signals
|
||||
if !libs.TradingTime(time.Now()) {
|
||||
return
|
||||
}
|
||||
// 每轮先消费 QMT 回写,终态订单会立即释放本地委托锁。
|
||||
books.readReceipts()
|
||||
roundCtx, cancel := context.WithTimeout(ctx, config.HttpTimeOut*4)
|
||||
defer cancel()
|
||||
|
||||
assets, err := client.Assets(roundCtx)
|
||||
// 1 取消过期订单
|
||||
books.CancelExpired(ctx, client)
|
||||
|
||||
// 2 验证可用资金
|
||||
assets, err := client.Assets(ctx)
|
||||
if err != nil {
|
||||
logf("ERROR", "获取资产失败: %v", err)
|
||||
return
|
||||
}
|
||||
positions, err := client.Positions(roundCtx)
|
||||
if assets.Available < assets.Total*config.Account.MinCashRatio {
|
||||
logf("INFO", "资金总闸:可用金额太少,禁止开新仓")
|
||||
return
|
||||
}
|
||||
|
||||
// 3 获取大盘状态
|
||||
IsAllow := libs.MarketAllowOpen()
|
||||
|
||||
// 4 获取持仓
|
||||
var allCodes []string
|
||||
pos_codes, positions, err := client.Positions(ctx)
|
||||
if err != nil {
|
||||
logf("ERROR", "获取持仓失败: %v", err)
|
||||
return
|
||||
}
|
||||
allCodes = append(allCodes, pos_codes...)
|
||||
|
||||
seen := map[string]struct{}{}
|
||||
stockList := make([]string, 0, len(signals.Data)+len(positions))
|
||||
addCode := func(code string) {
|
||||
if code == "" {
|
||||
return
|
||||
// 5 验证有效开仓信号
|
||||
allowOpen := make([]libs.SignalItem, 0)
|
||||
for code, item := range signals.Data {
|
||||
if !slices.Contains(pos_codes, code) {
|
||||
allowOpen = append(allowOpen, item)
|
||||
}
|
||||
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 {
|
||||
// 6 获取行情tick
|
||||
ticks, err := client.FullTick(ctx, allCodes)
|
||||
if err != nil {
|
||||
logf("ERROR", "获取行情失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
hold := positionCodes(positions)
|
||||
openSignals := map[string]libs.SignalItem{}
|
||||
for code, signal := range signals {
|
||||
if _, held := hold[code]; held {
|
||||
continue
|
||||
}
|
||||
openSignals[code] = signal
|
||||
// 7 执行开仓:有开仓信号 && 大盘指数允许开仓
|
||||
if len(allowOpen) > 0 && IsAllow {
|
||||
openSignal(client, books, ticks, allowOpen)
|
||||
}
|
||||
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)
|
||||
|
||||
// 8 持仓计算
|
||||
managePositions(client, books, ticks, positions, IsAllow)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user