96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"log"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
"time"
|
||
|
||
"big-qmt/go-client/apps/zt/logic"
|
||
"big-qmt/go-client/config"
|
||
"big-qmt/go-client/libs"
|
||
"big-qmt/go-client/sdk"
|
||
|
||
"github.com/robfig/cron/v3"
|
||
)
|
||
|
||
var (
|
||
StrategyName = "zt"
|
||
)
|
||
|
||
func main() {
|
||
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
|
||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||
defer stop()
|
||
|
||
// 第一步:只从 YAML 文件加载系统配置和本机账户配置。
|
||
err := config.Load("etc")
|
||
if err != nil {
|
||
log.Fatalf("[ERROR] 加载配置失败: %v", err)
|
||
}
|
||
client := sdk.New(config.Global.QMTBaseURL, config.Global.QMTToken, config.HttpTimeOut)
|
||
|
||
// 第二步:QMT 未就绪时持续重试,退出信号仍可立即终止等待。
|
||
assets, positions, ok := waitForQMT(ctx, client)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
// 初始化
|
||
logic.InitWatch()
|
||
if err := logic.InitState(StrategyName); err != nil {
|
||
log.Panicln("ERROR", err.Error())
|
||
}
|
||
if err := logic.SyncPositions(positions); err != nil {
|
||
log.Panicln("ERROR", err.Error())
|
||
}
|
||
|
||
// 第三步:连接成功后接管首次持仓并打印账户概览。
|
||
logic.Overview(assets, positions)
|
||
signals, err := libs.FetchSignal(libs.Dcm_Signal, config.Account.HostKey)
|
||
if err != nil {
|
||
log.Printf("[ERROR] [ZT] 获取开仓信号失败: %v", err)
|
||
signals = &libs.SignalResult{Data: map[string]libs.SignalItem{}}
|
||
}
|
||
log.Printf("[INFO] [ZT] 已加载 %d 个开仓信号", len(signals.Data))
|
||
|
||
// 第四步:工作日每 30 秒触发,交易时段由 RunOnce 统一判断。
|
||
books := logic.NewOrderBook()
|
||
scheduler := cron.New(
|
||
cron.WithSeconds(),
|
||
cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)),
|
||
)
|
||
if _, err := scheduler.AddFunc("0,30 * 9-15 * * 1-5", func() {
|
||
logic.RunOnce(ctx, client, books, signals)
|
||
}); err != nil {
|
||
log.Fatalf("[ERROR] 创建计划任务失败: %v", err)
|
||
}
|
||
scheduler.Start()
|
||
log.Printf("[INFO] [ZT] 计划任务已启动")
|
||
|
||
<-ctx.Done()
|
||
<-scheduler.Stop().Done()
|
||
log.Printf("[INFO] [ZT] 停止")
|
||
}
|
||
|
||
func waitForQMT(ctx context.Context, client *sdk.Client) (*sdk.Assets, []sdk.Position, bool) {
|
||
for {
|
||
attempt, cancel := context.WithTimeout(ctx, config.HttpTimeOut)
|
||
assets, assetsErr := client.Assets(attempt)
|
||
_, positions, positionsErr := client.Positions(attempt)
|
||
cancel()
|
||
if assetsErr == nil && positionsErr == nil {
|
||
log.Printf("[INFO] [ZT] QMT连接成功: %s", config.Global.QMTBaseURL)
|
||
return assets, positions, true
|
||
}
|
||
log.Printf("[WARNING] [ZT] QMT未就绪,5秒后重试: assets=%v positions=%v", assetsErr, positionsErr)
|
||
select {
|
||
case <-ctx.Done():
|
||
return nil, nil, false
|
||
case <-time.After(5 * time.Second):
|
||
}
|
||
}
|
||
}
|