mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 08:45:16 +00:00
ftx: query kline using rest api
This commit is contained in:
parent
82abd5489b
commit
28c9ac95ac
|
@ -129,3 +129,19 @@ func toGlobalTrade(f fill) (types.Trade, error) {
|
||||||
IsIsolated: false,
|
IsIsolated: false,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toGlobalKLine(symbol string, interval types.Interval, h Candle) (types.KLine, error) {
|
||||||
|
return types.KLine{
|
||||||
|
Exchange: types.ExchangeFTX.String(),
|
||||||
|
Symbol: symbol,
|
||||||
|
StartTime: h.StartTime.Time,
|
||||||
|
EndTime: h.StartTime.Add(interval.Duration()),
|
||||||
|
Interval: interval,
|
||||||
|
Open: h.Open,
|
||||||
|
Close: h.Close,
|
||||||
|
High: h.High,
|
||||||
|
Low: h.Low,
|
||||||
|
Volume: h.Volume,
|
||||||
|
Closed: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -142,7 +142,51 @@ func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {
|
func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {
|
||||||
panic("implement me")
|
var since, until time.Time
|
||||||
|
if options.StartTime != nil {
|
||||||
|
since = *options.StartTime
|
||||||
|
}
|
||||||
|
if options.EndTime != nil {
|
||||||
|
until = *options.EndTime
|
||||||
|
} else {
|
||||||
|
until = time.Now()
|
||||||
|
}
|
||||||
|
if since.After(until) {
|
||||||
|
return nil, fmt.Errorf("invalid query klines time range, since: %+v, until: %+v", since, until)
|
||||||
|
}
|
||||||
|
if !isIntervalSupportedInKLine(interval) {
|
||||||
|
return nil, fmt.Errorf("interval %s is not supported", interval.String())
|
||||||
|
}
|
||||||
|
resp, err := e.newRest().HistoricalPrices(ctx, symbol, interval, int64(options.Limit), since, until)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !resp.Success {
|
||||||
|
return nil, fmt.Errorf("ftx returns failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
var kline []types.KLine
|
||||||
|
for _, r := range resp.Result {
|
||||||
|
globalKline, err := toGlobalKLine(symbol, interval, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kline = append(kline, globalKline)
|
||||||
|
}
|
||||||
|
return kline, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIntervalSupportedInKLine(interval types.Interval) bool {
|
||||||
|
_, ok := map[int]struct{}{
|
||||||
|
15: {},
|
||||||
|
60: {},
|
||||||
|
300: {},
|
||||||
|
900: {},
|
||||||
|
3600: {},
|
||||||
|
14400: {},
|
||||||
|
86400: {},
|
||||||
|
}[interval.Minutes()*60]
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) ([]types.Trade, error) {
|
func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) ([]types.Trade, error) {
|
||||||
|
@ -247,10 +291,6 @@ func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) {
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (types.OrderSlice, error) {
|
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (types.OrderSlice, error) {
|
||||||
var createdOrders types.OrderSlice
|
var createdOrders types.OrderSlice
|
||||||
// TODO: currently only support limit and market order
|
// TODO: currently only support limit and market order
|
||||||
|
|
|
@ -620,3 +620,19 @@ func TestExchange_QueryTrades(t *testing.T) {
|
||||||
}, trades[0])
|
}, trades[0])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_isIntervalSupportedInKLine(t *testing.T) {
|
||||||
|
supportedIntervals := []types.Interval{
|
||||||
|
types.Interval1m,
|
||||||
|
types.Interval5m,
|
||||||
|
types.Interval15m,
|
||||||
|
types.Interval1h,
|
||||||
|
types.Interval4h,
|
||||||
|
types.Interval1d,
|
||||||
|
}
|
||||||
|
for _, i := range supportedIntervals {
|
||||||
|
assert.True(t, isIntervalSupportedInKLine(i))
|
||||||
|
}
|
||||||
|
assert.False(t, isIntervalSupportedInKLine(types.Interval30m))
|
||||||
|
assert.False(t, isIntervalSupportedInKLine(types.Interval3d))
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type marketRequest struct {
|
type marketRequest struct {
|
||||||
|
@ -27,3 +31,41 @@ func (r *marketRequest) Markets(ctx context.Context) (marketsResponse, error) {
|
||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
supported resolutions: window length in seconds. options: 15, 60, 300, 900, 3600, 14400, 86400
|
||||||
|
doc: https://docs.ftx.com/?javascript#get-historical-prices
|
||||||
|
*/
|
||||||
|
func (r *marketRequest) HistoricalPrices(ctx context.Context, market string, interval types.Interval, limit int64, start, end time.Time) (HistoricalPricesResponse, error) {
|
||||||
|
q := map[string]string{
|
||||||
|
"resolution": strconv.FormatInt(int64(interval.Minutes())*60, 10),
|
||||||
|
}
|
||||||
|
|
||||||
|
if limit > 0 {
|
||||||
|
q["limit"] = strconv.FormatInt(limit, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if start != (time.Time{}) {
|
||||||
|
q["start_time"] = strconv.FormatInt(start.Unix(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if end != (time.Time{}) {
|
||||||
|
q["end_time"] = strconv.FormatInt(end.Unix(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := r.
|
||||||
|
Method("GET").
|
||||||
|
Query(q).
|
||||||
|
ReferenceURL(fmt.Sprintf("api/markets/%s/candles", market)).
|
||||||
|
DoAuthenticatedRequest(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return HistoricalPricesResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var h HistoricalPricesResponse
|
||||||
|
if err := json.Unmarshal(resp.Body, &h); err != nil {
|
||||||
|
return HistoricalPricesResponse{}, fmt.Errorf("failed to unmarshal historical prices response body to json: %w", err)
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
|
@ -198,6 +198,35 @@ type market struct {
|
||||||
VolumeUsd24h float64 `json:"volumeUsd24h"`
|
VolumeUsd24h float64 `json:"volumeUsd24h"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": [
|
||||||
|
{
|
||||||
|
"close": 11055.25,
|
||||||
|
"high": 11089.0,
|
||||||
|
"low": 11043.5,
|
||||||
|
"open": 11059.25,
|
||||||
|
"startTime": "2019-06-24T17:15:00+00:00",
|
||||||
|
"volume": 464193.95725
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
type HistoricalPricesResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Result []Candle `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Candle struct {
|
||||||
|
Close float64 `json:"close"`
|
||||||
|
High float64 `json:"high"`
|
||||||
|
Low float64 `json:"low"`
|
||||||
|
Open float64 `json:"open"`
|
||||||
|
StartTime datetime `json:"startTime"`
|
||||||
|
Volume float64 `json:"volume"`
|
||||||
|
}
|
||||||
|
|
||||||
type ordersHistoryResponse struct {
|
type ordersHistoryResponse struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Result []order `json:"result"`
|
Result []order `json:"result"`
|
||||||
|
|
Loading…
Reference in New Issue
Block a user