112 lines
2.3 KiB
Go
112 lines
2.3 KiB
Go
|
package exchange
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sort"
|
||
|
"time"
|
||
|
|
||
|
. "git.qtrade.icu/coin-quant/trademodel"
|
||
|
"github.com/sirupsen/logrus"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
WatchTypeCandle = "candle"
|
||
|
WatchTypeDepth = "depth"
|
||
|
WatchTypeTradeMarket = "trade_market"
|
||
|
WatchTypeTrade = "trade"
|
||
|
WatchTypePosition = "position"
|
||
|
WatchTypeBalance = "balance"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrRetry = errors.New("need retry")
|
||
|
)
|
||
|
|
||
|
type WatchParam struct {
|
||
|
Type string
|
||
|
Param map[string]string
|
||
|
}
|
||
|
|
||
|
func WatchCandle(symbol, binSize string) WatchParam {
|
||
|
return WatchParam{
|
||
|
Type: WatchTypeCandle,
|
||
|
Param: map[string]string{"symbol": symbol, "bin": binSize},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type WatchFn func(interface{})
|
||
|
|
||
|
type FetchLimit struct {
|
||
|
Duration string
|
||
|
Limit int
|
||
|
}
|
||
|
|
||
|
// ExchangeInfo exchange info
|
||
|
type ExchangeInfo struct {
|
||
|
Name string
|
||
|
Value string
|
||
|
Desc string
|
||
|
KLineLimit FetchLimit
|
||
|
OrderLimit FetchLimit
|
||
|
}
|
||
|
|
||
|
type Exchange interface {
|
||
|
Info() ExchangeInfo
|
||
|
Symbols() ([]Symbol, error)
|
||
|
|
||
|
Start() error
|
||
|
Stop() error
|
||
|
|
||
|
// Watch exchange event, call multiple times for different event
|
||
|
Watch(WatchParam, WatchFn) error
|
||
|
|
||
|
// Kline get klines
|
||
|
GetKline(symbol, bSize string, start, end time.Time) (data []*Candle, err error)
|
||
|
|
||
|
// for trade
|
||
|
ProcessOrder(act TradeAction) (ret *Order, err error)
|
||
|
CancelAllOrders() (orders []*Order, err error)
|
||
|
CancelOrder(old *Order) (orders *Order, err error)
|
||
|
}
|
||
|
|
||
|
func KlineChan(e Exchange, symbol, bSize string, start, end time.Time) (dataCh chan *Candle, errCh chan error) {
|
||
|
dataCh = make(chan *Candle, 1024*10)
|
||
|
errCh = make(chan error, 1)
|
||
|
go func() {
|
||
|
defer func() {
|
||
|
close(dataCh)
|
||
|
close(errCh)
|
||
|
}()
|
||
|
tStart := start
|
||
|
tEnd := end
|
||
|
var nPrevStart int64
|
||
|
for {
|
||
|
klines, err := e.GetKline(symbol, bSize, tStart, tEnd)
|
||
|
if err != nil {
|
||
|
if errors.Is(err, ErrRetry) {
|
||
|
time.Sleep(time.Second * 5)
|
||
|
continue
|
||
|
}
|
||
|
errCh <- err
|
||
|
return
|
||
|
}
|
||
|
sort.Slice(klines, func(i, j int) bool {
|
||
|
return klines[i].Start < klines[j].Start
|
||
|
})
|
||
|
for _, v := range klines {
|
||
|
if v.Start <= nPrevStart {
|
||
|
continue
|
||
|
}
|
||
|
dataCh <- v
|
||
|
tStart = v.Time()
|
||
|
}
|
||
|
if tStart.Sub(tEnd) >= 0 || tStart.Unix() <= nPrevStart || len(klines) == 0 {
|
||
|
logrus.Info("KlineChan finished: [%s]-[%s], last datatime: %s", start, end, tStart)
|
||
|
break
|
||
|
}
|
||
|
nPrevStart = tStart.Unix()
|
||
|
}
|
||
|
}()
|
||
|
return
|
||
|
}
|