You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

128 lines
3.3 KiB

package trading
import (
"fmt"
"sig-pub/api/pb"
"sig-pub/pkg/data"
"sig-pub/pkg/types"
"sig-pub/pkg/types/series"
"sig-pub/pkg/zlog"
"sync"
"sync/atomic"
)
const (
MaxSeriesKlines = 1000 // 有效k线数量
MaxCapSeriesKlines = 1280 // 最大k线数量, slice扩容12次后cap=1280
)
// TradeInstanceKlineSeries 单个交易产品所有周期k线
type TradeInstanceKlineSeries struct {
IntervalKlines *types.IntervalState[*KlineSeries]
Status atomic.Int32 // 交易产品状态
}
func NewTradeInstanceKlineSeries(exchange pb.ExchangeType, instId string) *TradeInstanceKlineSeries {
si := new(TradeInstanceKlineSeries)
si.Status.Store(int32(data.StatusNone))
si.IntervalKlines = types.NewIntervalState[*KlineSeries]()
for interval := range types.SupportedIntervals {
si.IntervalKlines.Set(interval, NewKlineSeries(exchange, instId, interval))
}
return si
}
type KlineSeries struct {
sync.RWMutex
Exchange pb.ExchangeType
InstId string
Interval types.Interval
IntervalAdder types.IntervalAdder
lastTs int64
klines []*types.Kline
}
func NewKlineSeries(exchange pb.ExchangeType, instId string, interval types.Interval) *KlineSeries {
intervalAdder, ok := types.SupportedIntervals[interval]
if !ok {
panic(fmt.Errorf("unsupport interval: %s", interval))
}
return &KlineSeries{
Exchange: exchange,
InstId: instId,
Interval: interval,
IntervalAdder: intervalAdder,
klines: make([]*types.Kline, 0, MaxSeriesKlines/10),
}
}
// Get [0]当前k线
func (s *KlineSeries) Get(start int16) types.Kline {
index := len(s.klines) - 1 - int(start)
if index >= 0 && index < len(s.klines)-1 {
return *(s.klines[index])
}
// todo query store
ts := s.Interval.MustAddMul(s.lastTs, int64(-start))
for _, k := range s.klines {
if k.Ts == ts {
return *k
}
}
panic("kline not exists")
}
// Series [start...end]
func (s *KlineSeries) Series(start, end int16) (klines series.Klines) {
s.RLock()
defer s.RUnlock()
endTs := s.Interval.MustAddMul(s.lastTs, int64(-start))
startTs := s.Interval.MustAddMul(s.lastTs, int64(-end))
_ = endTs
_ = startTs
// return a.klineStore.GetRange(startTs, endTs)
// todo
return
}
// 检查k线序列完整
func (s *KlineSeries) Update(kline *types.Kline) (lastTs int64, serial bool) {
s.Lock()
defer s.Unlock()
serial = true
lastTs = s.lastTs
if kline.Ts <= s.lastTs {
return
}
// 检查k线是否连续
if len(s.klines) > 0 {
expectTs := s.Interval.MustAddMul(s.lastTs, 1)
if kline.Ts != expectTs {
serial = false
zlog.Warningf("k线不连续: instId=%s(%s), interval=%s, lastTs=%d, expected=%d, got=%d", s.InstId, s.Exchange, s.Interval, s.lastTs, expectTs, kline.Ts)
return
}
}
if len(s.klines) < MaxCapSeriesKlines {
s.klines = append(s.klines, kline)
// 容量超过0.65, 直接扩容到最大
if capacity := cap(s.klines); capacity < MaxCapSeriesKlines && capacity > MaxCapSeriesKlines*0.65 {
klines := make([]*types.Kline, len(s.klines), MaxCapSeriesKlines)
copy(klines, s.klines)
s.klines = klines
}
} else {
// 循环复用切片空间,避免扩容
length := len(s.klines)
copy(s.klines, s.klines[length-MaxSeriesKlines+1:])
s.klines[MaxSeriesKlines-1] = kline
s.klines = s.klines[:MaxSeriesKlines]
}
s.lastTs = kline.Ts
return
}