This commit is contained in:
2026-08-26 23:27:42 +08:00
parent c30c1541d2
commit cdbd03fe53
13 changed files with 256 additions and 355 deletions

View File

@@ -0,0 +1,152 @@
package logic
import (
"encoding/json"
"fmt"
"os"
"path"
"slices"
"sync"
"big-qmt/go-client/config"
"big-qmt/go-client/sdk"
)
var (
StatusNone = ""
StatusIng = "ING" // 处理中
StatusOk = "OK" // 成功
QuantState *State
)
type State struct {
AbsPath string
mu sync.Mutex
Items map[string]*StateItem
Codes []string
}
type StateItem struct {
Code string `json:"code"`
BaseOrderId string `json:"base_order_id"`
BaseQty int `json:"base_qty"`
BaseCost float64 `json:"base_cost"`
BaseStatus string `json:"base_status,omitempty"`
AddedOrderId string `json:"added_order_id"`
AddedNum int `json:"add_num"`
AddedQty int `json:"add_qty"`
AddedCost float64 `json:"add_cost"`
AddedStatus string `json:"added_status,omitempty"`
}
func InitState(sn string) error {
absPath := path.Join(config.Global.QMTDataDir, fmt.Sprintf("%s_%s_state.json", sn, config.Account.AccountID))
items, err := loadStateFile(absPath)
if err != nil {
return err
}
var codes []string
for code, _ := range items {
codes = append(codes, code)
}
QuantState = &State{
AbsPath: absPath,
Items: items,
Codes: codes,
}
return nil
}
func loadStateFile(fp string) (map[string]*StateItem, error) {
raw, err := os.ReadFile(fp)
if err != nil {
return nil, fmt.Errorf("[状态] 读取失败: %v", err)
}
var items map[string]*StateItem
if err := json.Unmarshal(raw, &items); err != nil {
return nil, fmt.Errorf("[状态] 解析失败:%s", err)
}
return items, nil
}
func SyncPositions(positions []sdk.Position) error {
for _, pos := range positions {
code := pos.StockCode
if code == "" || pos.Volume <= 0 || pos.OpenPrice <= 0 {
continue
}
if !slices.Contains(QuantState.Codes, code) {
item := &StateItem{
Code: code,
BaseQty: pos.Volume,
BaseCost: pos.OpenPrice,
BaseStatus: StatusOk,
}
QuantState.Append(item)
logf("WARNING", "[状态] %s 首次接管为底仓 数量=%d 成本=%.2f", code, pos.Volume, pos.OpenPrice)
}
}
return QuantState.Save()
}
func (s *State) Append(i *StateItem) {
s.mu.Lock()
defer s.mu.Unlock()
s.Items[i.Code] = i
s.Codes = append(s.Codes, i.Code)
}
func (s *State) Get(code string) (*StateItem, error) {
s.mu.Lock()
defer s.mu.Unlock()
if i, ok := s.Items[code]; ok {
return i, nil
} else {
return nil, fmt.Errorf("%s not found.", code)
}
}
func (s *State) Set(i *StateItem) {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.Items[i.Code]; !ok {
s.Codes = append(s.Codes, i.Code)
}
s.Items[i.Code] = i
}
func (s *State) Delete(code string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.Items, code)
if index := slices.Index(s.Codes, code); index >= 0 {
s.Codes = slices.Delete(s.Codes, index, index+1)
}
}
func (s *State) Save() error {
s.mu.Lock()
defer s.mu.Unlock()
// 写入AbsPath文件
f, err := os.OpenFile(s.AbsPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil {
return fmt.Errorf("[状态] 打开文件失败: %v", err)
}
defer f.Close()
encoder := json.NewEncoder(f)
encoder.SetIndent("", " ")
if err := encoder.Encode(s.Items); err != nil {
return fmt.Errorf("[状态] 写入失败: %v", err)
}
return nil
}