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 }