dev 5
This commit is contained in:
154
go-client/apps/trend/logic/order.go
Normal file
154
go-client/apps/trend/logic/order.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"big-qmt/go-client/sdk"
|
||||
)
|
||||
|
||||
var (
|
||||
STOCK_DIRECTION = 48
|
||||
STOCK_SIDE_BUY = 48
|
||||
STOCK_SIDE_SELL = 49
|
||||
OffsetFlag = map[string]string{"23": "BUY", "24": "SELL", "48": "BUY", "49": "SELL"}
|
||||
OrderTimeout = 5 * time.Minute
|
||||
|
||||
OrderBook *Books
|
||||
)
|
||||
|
||||
type OrderItem struct {
|
||||
ID string
|
||||
Code string
|
||||
Side string
|
||||
Remark string
|
||||
Status string
|
||||
CreatedAt time.Time
|
||||
Volume int
|
||||
}
|
||||
|
||||
type Books struct {
|
||||
mu sync.Mutex
|
||||
Data map[string]*OrderItem
|
||||
Index []string
|
||||
}
|
||||
|
||||
func NewOrderBook() {
|
||||
OrderBook = &Books{Data: make(map[string]*OrderItem), Index: make([]string, 0)}
|
||||
}
|
||||
|
||||
func NewOrderID(leg string) string {
|
||||
var random [6]byte
|
||||
_, _ = rand.Read(random[:])
|
||||
tag := fmt.Sprintf("zt-%s-%s", leg, hex.EncodeToString(random[:]))
|
||||
if len(tag) > 24 {
|
||||
return tag[:24]
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func (o *Books) IsLock(side, code string) bool {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
|
||||
keyStr := fmt.Sprintf("%s-%s", side, code)
|
||||
return slices.Contains(o.Index, keyStr)
|
||||
}
|
||||
|
||||
func (o *Books) Refresh(client *sdk.Client) error {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
raw, err := client.TradeDetailData(context.Background(), "order")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var idx []string
|
||||
orders := make(map[string]*OrderItem)
|
||||
for _, row := range raw {
|
||||
keyStr, item := parseOrder(row)
|
||||
orders[keyStr] = item
|
||||
idx = append(idx, keyStr)
|
||||
}
|
||||
o.Data = orders
|
||||
o.Index = idx
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Books) CancelExpired(client *sdk.Client) error {
|
||||
ctx := context.Background()
|
||||
err := o.Refresh(client)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[委托] 查询失败: %v", err)
|
||||
}
|
||||
for _, order := range o.Data {
|
||||
if order.CreatedAt.IsZero() || time.Since(order.CreatedAt) <= OrderTimeout {
|
||||
continue
|
||||
}
|
||||
if order.ID != "" {
|
||||
rs, err := client.CanCancelOrder(ctx, order.ID)
|
||||
if err != nil {
|
||||
logf("ERROR", "[委托] 撤销失败:%v", err)
|
||||
continue
|
||||
} else {
|
||||
logf("INFO", "[委托] 撤销成功:%v", rs)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Books) Place(client *sdk.Client, op int, code string, volume int, sn string) bool {
|
||||
if _, err := client.PassorderLatestTagged(context.Background(), op, code, volume, sn); err != nil {
|
||||
logf("ERROR", "[委托] %s 下单失败: %v", code, err)
|
||||
return false
|
||||
}
|
||||
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
|
||||
keyStr := fmt.Sprintf("%s-%s", OffsetFlag[strconv.Itoa(op)], code)
|
||||
o.Index = append(o.Index, keyStr)
|
||||
|
||||
logf("INFO", "[委托] 下单已提交 %d %s %d股", op, code, volume)
|
||||
return true
|
||||
}
|
||||
|
||||
func parseOrder(row map[string]string) (string, *OrderItem) {
|
||||
left, _ := strconv.Atoi(row["m_nVolumeTotal"])
|
||||
traded, _ := strconv.Atoi(row["m_nVolumeTraded"])
|
||||
volume := left + traded
|
||||
|
||||
item := &OrderItem{
|
||||
ID: row["m_strOrderSysID"],
|
||||
Code: row["m_strInstrumentID"],
|
||||
Side: OffsetFlag[row["m_nOffsetFlag"]],
|
||||
Remark: row["m_strRemark"],
|
||||
Status: row["m_nOrderStatus"],
|
||||
Volume: volume,
|
||||
CreatedAt: time.Unix(parseTimestamp(row), 0),
|
||||
}
|
||||
keyStr := fmt.Sprintf("%s-%s", item.Side, item.Code)
|
||||
return keyStr, item
|
||||
}
|
||||
|
||||
func parseTimestamp(row map[string]string) int64 {
|
||||
ts, _ := strconv.ParseInt(row["m_nOrderTime"], 10, 64)
|
||||
if ts > 1e11 {
|
||||
return ts / 1000
|
||||
}
|
||||
if ts > 0 {
|
||||
return ts
|
||||
}
|
||||
date := row["m_strInsertDate"]
|
||||
clock := strings.ReplaceAll(row["m_strInsertTime"], ":", "")
|
||||
clock = strings.Repeat("0", max(0, 6-len(clock))) + clock
|
||||
t, _ := time.ParseInLocation("20060102150405", date+clock, time.Local)
|
||||
return t.Unix()
|
||||
}
|
||||
Reference in New Issue
Block a user