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.
 
 

125 lines
2.8 KiB

package okx
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"sig-pub/pkg/types"
"strconv"
"strings"
"time"
"github.com/bytedance/sonic"
"github.com/go-resty/resty/v2"
"github.com/govalues/decimal"
)
const (
HttpBaseUrl = "https://www.okx.com"
)
type OkxFetcher struct {
client *resty.Client
httpProxy string
}
func NewOkxFetcher(httpProxy string) (f *OkxFetcher) {
client := resty.New()
client.SetTimeout(30 * time.Second)
client.SetTransport(&http.Transport{
MaxIdleConns: 100,
MaxConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
})
if httpProxy != "" {
client.SetProxy(httpProxy)
}
f = &OkxFetcher{
client: client,
httpProxy: httpProxy,
}
return
}
func (okx *OkxFetcher) ExhcangeType() types.Exchange {
return types.ExchangeOKX
}
// FetchHistoryKlines 获取交易产品历史K线数据
// https://my.okx.com/docs-v5/zh/#order-book-trading-market-data-get-candlesticks-history
// 周期区间 after > before, (after, before)
func (f *OkxFetcher) FetchHistoryKlines(ctx context.Context, okxInstId string, interval types.Interval, after, before int64) (klines []*types.Kline, err error) {
if okxInstId == "" {
err = errors.New("instid is empty")
return
}
if after <= 0 && before <= 0 {
err = errors.New("time range zero")
return
}
if err = fetchHistoryKlineLimiter.Wait(ctx); err != nil {
return
}
var params []string
params = append(params, fmt.Sprintf("instId=%s", url.QueryEscape(okxInstId)))
params = append(params, "limit=100") // 最大为100
if v, ok := subscribeCandles[interval]; ok {
params = append(params, "bar="+v)
}
if after > 0 {
params = append(params, fmt.Sprintf("after=%d", after))
}
if before > 0 {
params = append(params, fmt.Sprintf("before=%d", before))
}
url := fmt.Sprintf("%s/api/v5/market/history-candles?%s", HttpBaseUrl, strings.Join(params, "&"))
resp, err := f.client.R().Get(url)
if err != nil {
return
}
status := resp.StatusCode()
if status != 200 {
err = fmt.Errorf("request history klines status error: %s, %s", url, resp.Status())
return
}
r := new(RespHistoryKline)
if err = sonic.Unmarshal(resp.Body(), r); err != nil {
return
}
if r.Code != "0" {
err = fmt.Errorf("code: %s, msg: %s", r.Code, r.Msg)
return
}
for _, data := range r.Data {
ts, e := strconv.ParseInt(data[0], 10, 64)
if e != nil {
err = e
return
}
kline := &types.Kline{
Interval: interval,
Ts: ts,
Confirm: data[8] == "1",
}
var kinds = []*decimal.Decimal{&kline.Open, &kline.High, &kline.Low, &kline.Close, &kline.Vol, nil, &kline.VolQuote}
for i := 1; i <= 7; i++ {
if kinds[i-1] == nil {
continue
}
*kinds[i-1], err = decimal.Parse(data[i])
if err != nil {
return
}
}
klines = append(klines, kline)
}
return
}