13 changed files with 339 additions and 88 deletions
@ -0,0 +1,92 @@
|
||||
package okx |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"net/url" |
||||
"sig-pub/pkg/types" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/go-resty/resty/v2" |
||||
"golang.org/x/time/rate" |
||||
) |
||||
|
||||
const ( |
||||
HttpBaseUrl = "https://www.okx.com" |
||||
KlineBefore0 int64 = 1672502400000 // k线开始数据 2023-01-01 00:00:00 GMT+8
|
||||
) |
||||
|
||||
type OkxFetcher struct { |
||||
client *resty.Client |
||||
httpProxy string |
||||
historyKlineLimiter *rate.Limiter |
||||
} |
||||
|
||||
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, |
||||
historyKlineLimiter: rate.NewLimiter(rate.Every(100*time.Millisecond), 20), // rate: 20次/2s
|
||||
} |
||||
return |
||||
} |
||||
|
||||
// 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 = f.historyKlineLimiter.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 |
||||
} |
||||
|
||||
fmt.Println(string(resp.Body())) |
||||
return |
||||
} |
||||
@ -0,0 +1,44 @@
|
||||
package okx |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"sig-pub/pkg/types" |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
func TestFetchHistoryKlines(t *testing.T) { |
||||
okxFetcher := NewOkxFetcher("http://192.168.1.5:7890") |
||||
|
||||
// get inst+interval before, if=0 -> global before
|
||||
|
||||
// for interval, adder := range types.SupportedIntervals {
|
||||
// _, _ = interval, adder
|
||||
// }
|
||||
interval := types.Interval5m |
||||
intervalAdder := types.SupportedIntervals[interval] |
||||
before := intervalAdder(KlineBefore0, -1) |
||||
for range 10 { |
||||
after := intervalAdder(before, 10) |
||||
klines, err := okxFetcher.FetchHistoryKlines(context.Background(), "BTC-USDT", interval, after, before) |
||||
if err != nil { |
||||
t.Error(err) |
||||
return |
||||
} |
||||
lastTs := intervalAdder(after, -1) // todo ts(last kline)-1
|
||||
before = lastTs |
||||
for _, kline := range klines { |
||||
fmt.Println(kline) |
||||
} |
||||
fmt.Println("-----------------------------------------------------") |
||||
} |
||||
} |
||||
|
||||
func TestA(t *testing.T) { |
||||
begin := time.UnixMilli(KlineBefore0) |
||||
before := begin.AddDate(0, -1, 0) |
||||
after := begin.AddDate(0, 3, 0) |
||||
fmt.Println("before:", before.UnixMilli()) |
||||
fmt.Println("after:", after.UnixMilli()) |
||||
} |
||||
Loading…
Reference in new issue