mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
exchanges: add setTimeWindow boolean to GetKlineRequest param (#1160)
* exchanges: add setTimeWindow boolean to GetKlineRequest params to differentiate between a set time period return from endpoint. * glorious: nits * exchange: conjugation * Update exchanges/exchange.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits and an assortment of differences * exchanges: remove some comments * glorious: nits * cleanup * tests: fix * Update exchanges/hitbtc/hitbtc_wrapper.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/kline/kline.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * Update exchanges/kline/kline_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits * kline: fix test * rm unused variables * almost: nits * glorious: nits * linter: fix * rm unused variable * Refactored comment in the okex tests to ensure that it accurately reflects the variable name and the issue related to the time window, as requested by GloriousCode. The previous comment did not align with the identifier assigned to the property, which could cause confusion and misunderstanding among other programmers or stakeholders. The updated comment will improve the clarity and readability of the codebase and make it easier to understand the intended purpose of the associated variables. The change was made with the aim of improving the overall quality and maintainability of the code. --------- Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io> Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
@@ -815,12 +815,19 @@ func (bt *BackTest) loadData(cfg *config.Config, exch gctexchange.IBotExchange,
|
||||
if cfg.DataSettings.APIData.InclusiveEndDate {
|
||||
cfg.DataSettings.APIData.EndDate = cfg.DataSettings.APIData.EndDate.Add(cfg.DataSettings.Interval.Duration())
|
||||
}
|
||||
|
||||
var limit int64
|
||||
limit, err = b.Features.Enabled.Kline.GetIntervalResultLimit(cfg.DataSettings.Interval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err = loadAPIData(
|
||||
cfg,
|
||||
exch,
|
||||
fPair,
|
||||
a,
|
||||
b.Features.Enabled.Kline.ResultLimit,
|
||||
uint32(limit),
|
||||
dataType)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
|
||||
@@ -2530,7 +2530,7 @@ func TestGetTechnicalAnalysis(t *testing.T) {
|
||||
Enabled: currency.Pairs{cp},
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.OneDay)
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.IntervalCapacity{Interval: kline.OneDay})
|
||||
err = em.Add(fExchange{IBotExchange: exch})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
|
||||
@@ -167,23 +167,23 @@ func (b *Binance) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.EightHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.EightHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1686,7 +1686,7 @@ func (b *Binance) FormatExchangeKlineInterval(interval kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *Binance) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1701,7 +1701,7 @@ func (b *Binance) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
Symbol: req.Pair,
|
||||
StartTime: req.Start,
|
||||
EndTime: req.End,
|
||||
Limit: int(b.Features.Enabled.Kline.ResultLimit),
|
||||
Limit: int(req.RequestLimit),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1741,7 +1741,7 @@ func (b *Binance) GetHistoricCandlesExtended(ctx context.Context, pair currency.
|
||||
Symbol: req.Pair,
|
||||
StartTime: req.RangeHolder.Ranges[x].Start.Time,
|
||||
EndTime: req.RangeHolder.Ranges[x].End.Time,
|
||||
Limit: int(b.Features.Enabled.Kline.ResultLimit),
|
||||
Limit: int(req.RequestLimit),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -124,23 +124,23 @@ func (bi *Binanceus) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.EightHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.EightHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -869,7 +869,7 @@ func (bi *Binanceus) ValidateCredentials(ctx context.Context, assetType asset.It
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (bi *Binanceus) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := bi.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := bi.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -879,7 +879,7 @@ func (bi *Binanceus) GetHistoricCandles(ctx context.Context, pair currency.Pair,
|
||||
Symbol: req.Pair,
|
||||
StartTime: req.Start,
|
||||
EndTime: req.End,
|
||||
Limit: int64(bi.Features.Enabled.Kline.ResultLimit),
|
||||
Limit: req.RequestLimit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -914,7 +914,7 @@ func (bi *Binanceus) GetHistoricCandlesExtended(ctx context.Context, pair curren
|
||||
Symbol: req.Pair,
|
||||
StartTime: req.RangeHolder.Ranges[x].Start.Time,
|
||||
EndTime: req.RangeHolder.Ranges[x].End.Time,
|
||||
Limit: int64(bi.Features.Enabled.Kline.ResultLimit),
|
||||
Limit: req.RequestLimit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -147,20 +147,20 @@ func (b *Bitfinex) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.ThreeHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.TwoWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.TwoWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 10000,
|
||||
GlobalResultLimit: 10000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1084,7 +1084,7 @@ func (b *Bitfinex) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *Bitfinex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1099,7 +1099,8 @@ func (b *Bitfinex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
req.Start.UnixMilli(),
|
||||
req.End.UnixMilli(),
|
||||
b.Features.Enabled.Kline.ResultLimit, true)
|
||||
uint32(req.RequestLimit),
|
||||
true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1138,7 +1139,7 @@ func (b *Bitfinex) GetHistoricCandlesExtended(ctx context.Context, pair currency
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
req.RangeHolder.Ranges[x].Start.Ticks*1000,
|
||||
req.RangeHolder.Ranges[x].End.Ticks*1000,
|
||||
b.Features.Enabled.Kline.ResultLimit,
|
||||
uint32(req.RequestLimit),
|
||||
true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -53,7 +53,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
err = b.UpdateTradablePairs(context.Background(), false)
|
||||
if err != nil {
|
||||
log.Fatal("Bithumb Setup() init error")
|
||||
log.Fatal("Bithumb Setup() init error", err)
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
@@ -617,8 +617,8 @@ func TestGetHistoricCandles(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startTime := time.Now().AddDate(0, 0, -1)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneMin, startTime, time.Now())
|
||||
startTime := time.Now().AddDate(0, -2, 0)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, startTime, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -115,17 +115,22 @@ func (b *Bithumb) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.TenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.TenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
// NOTE: The supported time intervals below are returned
|
||||
// offset to the Asia/Seoul time zone. This may lead to
|
||||
// issues with candle quality and conversion as the
|
||||
// intervals may be broken up. Therefore the below intervals
|
||||
// are constructed from hourly candles.
|
||||
// kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
// kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
// kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
),
|
||||
ResultLimit: 1500,
|
||||
GlobalResultLimit: 1500,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -784,7 +789,7 @@ func (b *Bithumb) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *Bithumb) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -111,20 +111,20 @@ func (b *Bitstamp) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -855,7 +855,7 @@ func (b *Bitstamp) ValidateCredentials(ctx context.Context, assetType asset.Item
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *Bitstamp) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -865,7 +865,7 @@ func (b *Bitstamp) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
req.Start,
|
||||
req.End,
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(int64(b.Features.Enabled.Kline.ResultLimit), 10))
|
||||
strconv.FormatInt(req.RequestLimit, 10))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -903,7 +903,7 @@ func (b *Bitstamp) GetHistoricCandlesExtended(ctx context.Context, pair currency
|
||||
req.RangeHolder.Ranges[x].Start.Time,
|
||||
req.RangeHolder.Ranges[x].End.Time,
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(int64(b.Features.Enabled.Kline.ResultLimit), 10),
|
||||
strconv.FormatInt(req.RequestLimit, 10),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -697,20 +697,43 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Parallel()
|
||||
pair, err := currency.NewPairFromString("btc-usdt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
start := time.Unix(1546300800, 0)
|
||||
end := time.Unix(1577836799, 0)
|
||||
end := start.AddDate(0, 12, 0)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, start, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
end = time.Now()
|
||||
start = end.AddDate(0, -12, 0)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, start, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
end = time.Now()
|
||||
start = end.AddDate(0, 0, -30)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneHour, start, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
end = time.Now()
|
||||
start = end.AddDate(0, 0, -1).Add(time.Minute * 5)
|
||||
_, err = b.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.FiveMin, start, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
t.Parallel()
|
||||
pair, err := currency.NewPairFromString("btc-usdt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -28,6 +28,12 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
var (
|
||||
oneDay = time.Hour * 24
|
||||
oneMonth = oneDay * 31
|
||||
oneYear = oneDay * 366
|
||||
)
|
||||
|
||||
// GetDefaultConfig returns a default exchange config
|
||||
func (b *Bittrex) GetDefaultConfig(ctx context.Context) (*config.Exchange, error) {
|
||||
b.SetDefaults()
|
||||
@@ -111,12 +117,11 @@ func (b *Bittrex) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.OneHour,
|
||||
kline.OneDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin, Capacity: 1440}, // 1m interval: candles for 1 day (0:00 - 23:59)
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin, Capacity: 288}, // 5m interval: candles for 1 day (0:00 - 23:55)
|
||||
kline.IntervalCapacity{Interval: kline.OneHour, Capacity: 744}, // 1 hour interval: candles for 31 days (0:00 - 23:00)
|
||||
kline.IntervalCapacity{Interval: kline.OneDay, Capacity: 366}, // 1 day interval: candles for 366 days
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -954,39 +959,36 @@ func (b *Bittrex) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
// This implementation rounds returns candles up to the next interval or to the end
|
||||
// time (whichever comes first)
|
||||
func (b *Bittrex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
candleInterval := b.FormatExchangeKlineInterval(req.ExchangeInterval)
|
||||
if candleInterval == "notfound" {
|
||||
return nil, errors.New("invalid interval")
|
||||
return nil, fmt.Errorf("%w %v", kline.ErrInvalidInterval, interval)
|
||||
}
|
||||
|
||||
year, month, day := req.Start.Date()
|
||||
year, month, day := req.End.Date()
|
||||
curYear, curMonth, curDay := time.Now().Date()
|
||||
|
||||
getHistoric := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
|
||||
getRecent := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
|
||||
|
||||
var getHistoric, getRecent bool
|
||||
switch req.ExchangeInterval {
|
||||
case kline.OneMin, kline.FiveMin:
|
||||
if time.Since(req.Start) > 24*time.Hour {
|
||||
if time.Since(req.Start) > oneDay {
|
||||
getHistoric = true
|
||||
}
|
||||
if year >= curYear && month >= curMonth && day >= curDay {
|
||||
getRecent = true
|
||||
}
|
||||
case kline.OneHour:
|
||||
if time.Since(req.Start) > 31*24*time.Hour {
|
||||
if time.Since(req.Start) > oneMonth {
|
||||
getHistoric = true
|
||||
}
|
||||
if year >= curYear && month >= curMonth {
|
||||
getRecent = true
|
||||
}
|
||||
case kline.OneDay:
|
||||
if time.Since(req.Start) > 366*24*time.Hour {
|
||||
if time.Since(req.Start) > oneYear {
|
||||
getHistoric = true
|
||||
}
|
||||
if year >= curYear {
|
||||
@@ -994,46 +996,48 @@ func (b *Bittrex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
}
|
||||
}
|
||||
|
||||
var ohlcData []CandleData
|
||||
if !getHistoric && !getRecent {
|
||||
return nil, errors.New("start end time range cannot get historic or recent candles")
|
||||
}
|
||||
|
||||
var candleData []CandleData
|
||||
if getHistoric {
|
||||
var historicData []CandleData
|
||||
historicData, err = b.GetHistoricalCandles(ctx,
|
||||
historicData, err := b.GetHistoricalCandles(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
candleInterval,
|
||||
"TRADE",
|
||||
year,
|
||||
int(month),
|
||||
day)
|
||||
start.Year(),
|
||||
int(start.Month()),
|
||||
start.Day())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ohlcData = append(ohlcData, historicData...)
|
||||
candleData = append(candleData, historicData...)
|
||||
}
|
||||
|
||||
if getRecent {
|
||||
var recentData []CandleData
|
||||
recentData, err = b.GetRecentCandles(ctx,
|
||||
recentData, err := b.GetRecentCandles(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
b.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
candleInterval,
|
||||
"TRADE")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ohlcData = append(ohlcData, recentData...)
|
||||
candleData = append(candleData, recentData...)
|
||||
}
|
||||
|
||||
timeSeries := make([]kline.Candle, 0, len(ohlcData))
|
||||
for x := range ohlcData {
|
||||
if ohlcData[x].StartsAt.Before(req.Start) ||
|
||||
ohlcData[x].StartsAt.After(req.End) {
|
||||
timeSeries := make([]kline.Candle, 0, len(candleData))
|
||||
for x := range candleData {
|
||||
if candleData[x].StartsAt.Before(req.Start) || candleData[x].StartsAt.After(req.End) {
|
||||
continue
|
||||
}
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: ohlcData[x].StartsAt,
|
||||
Open: ohlcData[x].Open,
|
||||
High: ohlcData[x].High,
|
||||
Low: ohlcData[x].Low,
|
||||
Close: ohlcData[x].Close,
|
||||
Volume: ohlcData[x].Volume,
|
||||
Time: candleData[x].StartsAt,
|
||||
Open: candleData[x].Open,
|
||||
High: candleData[x].High,
|
||||
Low: candleData[x].Low,
|
||||
Close: candleData[x].Close,
|
||||
Volume: candleData[x].Volume,
|
||||
})
|
||||
}
|
||||
return req.ProcessResponse(timeSeries)
|
||||
|
||||
@@ -116,21 +116,21 @@ func (b *BTCMarkets) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.ThreeHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1016,7 +1016,7 @@ func (b *BTCMarkets) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *BTCMarkets) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -130,15 +130,15 @@ func (b *BTSE) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.SixHour,
|
||||
kline.OneDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
),
|
||||
ResultLimit: 300,
|
||||
GlobalResultLimit: 300,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -972,7 +972,7 @@ func (b *BTSE) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (b *BTSE) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := b.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -988,7 +988,7 @@ func (b *BTSE) GetHistoricCandles(ctx context.Context, pair currency.Pair, a ass
|
||||
req, err := b.OHLCV(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
req.Start,
|
||||
req.End,
|
||||
req.End.Add(-req.ExchangeInterval.Duration()), // End time is inclusive so we need to subtract the interval.
|
||||
intervalInt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -136,21 +136,21 @@ func (by *Bybit) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 200,
|
||||
GlobalResultLimit: 200,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1834,7 +1834,7 @@ func (by *Bybit) FormatExchangeKlineIntervalFutures(ctx context.Context, interva
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := by.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := by.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1846,7 +1846,7 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
|
||||
candles, err = by.GetKlines(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
by.FormatExchangeKlineInterval(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.Start,
|
||||
req.End)
|
||||
if err != nil {
|
||||
@@ -1869,7 +1869,7 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
|
||||
candles, err = by.GetFuturesKlineData(ctx,
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1891,7 +1891,7 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
|
||||
candles, err = by.GetUSDTFuturesKlineData(ctx,
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1914,7 +1914,7 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
req.Start,
|
||||
int64(by.Features.Enabled.Kline.ResultLimit))
|
||||
req.RequestLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1951,7 +1951,7 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
|
||||
candles, err = by.GetKlines(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
by.FormatExchangeKlineInterval(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.RangeHolder.Ranges[x].Start.Time,
|
||||
req.RangeHolder.Ranges[x].End.Time)
|
||||
if err != nil {
|
||||
@@ -1973,7 +1973,7 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
|
||||
candles, err = by.GetFuturesKlineData(ctx,
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.RangeHolder.Ranges[x].Start.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1994,7 +1994,7 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
|
||||
candles, err = by.GetUSDTFuturesKlineData(ctx,
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
int64(by.Features.Enabled.Kline.ResultLimit),
|
||||
req.RequestLimit,
|
||||
req.RangeHolder.Ranges[x].Start.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2016,7 +2016,7 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
|
||||
req.RequestFormatted,
|
||||
by.FormatExchangeKlineIntervalFutures(ctx, req.ExchangeInterval),
|
||||
req.RangeHolder.Ranges[x].Start.Time,
|
||||
int64(by.Features.Enabled.Kline.ResultLimit))
|
||||
req.RequestLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -118,14 +118,14 @@ func (c *CoinbasePro) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.OneHour,
|
||||
kline.SixHour,
|
||||
kline.OneDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
),
|
||||
ResultLimit: 300,
|
||||
GlobalResultLimit: 300,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -892,7 +892,7 @@ func (c *CoinbasePro) GetOrderHistory(ctx context.Context, req *order.GetOrdersR
|
||||
// GetHistoricCandles returns a set of candle between two time periods for a
|
||||
// designated time period
|
||||
func (c *CoinbasePro) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := c.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := c.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1500,7 +1500,7 @@ func (b *Base) IsPerpetualFutureCurrency(asset.Item, currency.Pair) (bool, error
|
||||
|
||||
// GetKlineRequest returns a helper for the fetching of candle/kline data for
|
||||
// a single request within a pre-determined time window.
|
||||
func (b *Base) GetKlineRequest(pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Request, error) {
|
||||
func (b *Base) GetKlineRequest(pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time, fixedAPICandleLength bool) (*kline.Request, error) {
|
||||
if pair.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
@@ -1516,17 +1516,6 @@ func (b *Base) GetKlineRequest(pair currency.Pair, a asset.Item, interval kline.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NOTE: This check is here to make sure a client is notified that using
|
||||
// this functionality will result in error if the total candles cannot be
|
||||
// theoretically retrieved.
|
||||
if count := kline.TotalCandlesPerInterval(start, end, exchangeInterval); count >
|
||||
int64(b.Features.Enabled.Kline.ResultLimit) {
|
||||
return nil, fmt.Errorf("candles count: %d, max limit: %d %w",
|
||||
count,
|
||||
b.Features.Enabled.Kline.ResultLimit,
|
||||
kline.ErrRequestExceedsExchangeLimits)
|
||||
}
|
||||
|
||||
err = b.ValidateKline(pair, a, exchangeInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1537,7 +1526,49 @@ func (b *Base) GetKlineRequest(pair currency.Pair, a asset.Item, interval kline.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kline.CreateKlineRequest(b.Name, pair, formatted, a, interval, exchangeInterval, start, end)
|
||||
limit, err := b.Features.Enabled.Kline.GetIntervalResultLimit(exchangeInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := kline.CreateKlineRequest(b.Name, pair, formatted, a, interval, exchangeInterval, start, end, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NOTE: The checks below makes sure a client is notified that using this
|
||||
// functionality will result in error if the total candles cannot be
|
||||
// theoretically retrieved.
|
||||
if fixedAPICandleLength {
|
||||
origCount := kline.TotalCandlesPerInterval(req.Start, req.End, interval)
|
||||
modifiedCount := kline.TotalCandlesPerInterval(req.Start, time.Now(), exchangeInterval)
|
||||
if modifiedCount > limit {
|
||||
errMsg := fmt.Sprintf("for %v %v candles between %v-%v. ",
|
||||
origCount,
|
||||
interval,
|
||||
start.Format(common.SimpleTimeFormatWithTimezone),
|
||||
end.Format(common.SimpleTimeFormatWithTimezone))
|
||||
if interval != exchangeInterval {
|
||||
errMsg += fmt.Sprintf("Request converts to %v %v candles. ",
|
||||
modifiedCount,
|
||||
exchangeInterval)
|
||||
}
|
||||
boundary := time.Now().Add(-exchangeInterval.Duration() * time.Duration(limit))
|
||||
return nil, fmt.Errorf("%w %v, exceeding the limit of %v %v candles up to %v. Please reduce timeframe or use GetHistoricCandlesExtended",
|
||||
kline.ErrRequestExceedsExchangeLimits,
|
||||
errMsg,
|
||||
limit,
|
||||
exchangeInterval,
|
||||
boundary.Format(common.SimpleTimeFormatWithTimezone))
|
||||
}
|
||||
} else if count := kline.TotalCandlesPerInterval(req.Start, req.End, exchangeInterval); count > limit {
|
||||
return nil, fmt.Errorf("candle count exceeded: %d. The endpoint has a set candle limit return of %d candles. Candle data will be incomplete: %w",
|
||||
count,
|
||||
limit,
|
||||
kline.ErrRequestExceedsExchangeLimits)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// GetKlineExtendedRequest returns a helper for the fetching of candle/kline
|
||||
@@ -1566,12 +1597,18 @@ func (b *Base) GetKlineExtendedRequest(pair currency.Pair, a asset.Item, interva
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := kline.CreateKlineRequest(b.Name, pair, formatted, a, interval, exchangeInterval, start, end)
|
||||
limit, err := b.Features.Enabled.Kline.GetIntervalResultLimit(exchangeInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := kline.CreateKlineRequest(b.Name, pair, formatted, a, interval, exchangeInterval, start, end, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.IsExtended = true
|
||||
dates, err := r.GetRanges(b.Features.Enabled.Kline.ResultLimit)
|
||||
|
||||
dates, err := r.GetRanges(uint32(limit))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1948,7 +1948,7 @@ func TestBase_ValidateKline(t *testing.T) {
|
||||
Features: Features{
|
||||
Enabled: FeaturesEnabled{
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(kline.OneMin),
|
||||
Intervals: kline.DeployExchangeIntervals(kline.IntervalCapacity{Interval: kline.OneMin}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2685,42 +2685,17 @@ func TestHasAssetTypeAccountSegregation(t *testing.T) {
|
||||
func TestGetKlineRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Base{Name: "klineTest"}
|
||||
_, err := b.GetKlineRequest(currency.EMPTYPAIR, asset.Empty, 0, time.Time{}, time.Time{})
|
||||
_, err := b.GetKlineRequest(currency.EMPTYPAIR, asset.Empty, 0, time.Time{}, time.Time{}, false)
|
||||
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrCurrencyPairEmpty)
|
||||
}
|
||||
|
||||
pair := currency.NewPair(currency.BTC, currency.USDT)
|
||||
_, err = b.GetKlineRequest(pair, asset.Empty, 0, time.Time{}, time.Time{})
|
||||
_, err = b.GetKlineRequest(pair, asset.Empty, 0, time.Time{}, time.Time{}, false)
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, 0, time.Time{}, time.Time{})
|
||||
if !errors.Is(err, kline.ErrInvalidInterval) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrInvalidInterval)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneMin, time.Time{}, time.Time{})
|
||||
if !errors.Is(err, kline.ErrCannotConstructInterval) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrCannotConstructInterval)
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.OneMin)
|
||||
b.Features.Enabled.Kline.ResultLimit = 1439
|
||||
start := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := start.AddDate(0, 0, 1)
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneMin, start, end)
|
||||
if !errors.Is(err, kline.ErrRequestExceedsExchangeLimits) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrRequestExceedsExchangeLimits)
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.OneHour)
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneHour, start, end)
|
||||
if !errors.Is(err, kline.ErrValidatingParams) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrValidatingParams)
|
||||
}
|
||||
|
||||
err = b.CurrencyPairs.Store(asset.Spot, ¤cy.PairStore{
|
||||
AssetEnabled: convert.BoolPtr(true),
|
||||
Enabled: []currency.Pair{pair},
|
||||
@@ -2730,7 +2705,19 @@ func TestGetKlineRequest(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneHour, start, end)
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, 0, time.Time{}, time.Time{}, false)
|
||||
if !errors.Is(err, kline.ErrInvalidInterval) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrInvalidInterval)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneMin, time.Time{}, time.Time{}, false)
|
||||
if !errors.Is(err, kline.ErrCannotConstructInterval) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrCannotConstructInterval)
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.IntervalCapacity{Interval: kline.OneMin})
|
||||
b.Features.Enabled.Kline.GlobalResultLimit = 1439
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneHour, time.Time{}, time.Time{}, false)
|
||||
if !errors.Is(err, errAssetRequestFormatIsNil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errAssetRequestFormatIsNil)
|
||||
}
|
||||
@@ -2745,7 +2732,65 @@ func TestGetKlineRequest(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
r, err := b.GetKlineRequest(pair, asset.Spot, kline.OneHour, start, end)
|
||||
start := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := start.AddDate(0, 0, 1)
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneMin, start, end, true)
|
||||
if !errors.Is(err, kline.ErrRequestExceedsExchangeLimits) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrRequestExceedsExchangeLimits)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Spot, kline.OneMin, start, end, false)
|
||||
if !errors.Is(err, kline.ErrRequestExceedsExchangeLimits) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrRequestExceedsExchangeLimits)
|
||||
}
|
||||
|
||||
_, err = b.GetKlineRequest(pair, asset.Futures, kline.OneHour, start, end, false)
|
||||
if !errors.Is(err, kline.ErrValidatingParams) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrValidatingParams)
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.IntervalCapacity{Interval: kline.OneHour})
|
||||
r, err := b.GetKlineRequest(pair, asset.Spot, kline.OneHour, start, end, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if r.Exchange != "klineTest" {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.Exchange, "klineTest")
|
||||
}
|
||||
|
||||
if !r.Pair.Equal(pair) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.Pair, pair)
|
||||
}
|
||||
|
||||
if r.Asset != asset.Spot {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.Asset, asset.Spot)
|
||||
}
|
||||
|
||||
if r.ExchangeInterval != kline.OneHour {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.ExchangeInterval, kline.OneHour)
|
||||
}
|
||||
|
||||
if r.ClientRequired != kline.OneHour {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.ClientRequired, kline.OneHour)
|
||||
}
|
||||
|
||||
if r.Start != start {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.Start, start)
|
||||
}
|
||||
|
||||
if r.End != end {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.End, end)
|
||||
}
|
||||
|
||||
if r.RequestFormatted.String() != "BTCUSDT" {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", r.RequestFormatted.String(), "BTCUSDT")
|
||||
}
|
||||
|
||||
end = time.Now().Truncate(kline.OneHour.Duration()).UTC()
|
||||
start = end.Add(-kline.OneHour.Duration() * 1439)
|
||||
|
||||
r, err = b.GetKlineRequest(pair, asset.Spot, kline.OneHour, start, end, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
@@ -2807,8 +2852,8 @@ func TestGetKlineExtendedRequest(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, kline.ErrCannotConstructInterval)
|
||||
}
|
||||
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.OneMin)
|
||||
b.Features.Enabled.Kline.ResultLimit = 100
|
||||
b.Features.Enabled.Kline.Intervals = kline.DeployExchangeIntervals(kline.IntervalCapacity{Interval: kline.OneMin})
|
||||
b.Features.Enabled.Kline.GlobalResultLimit = 100
|
||||
start := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := start.AddDate(0, 0, 1)
|
||||
|
||||
|
||||
@@ -115,19 +115,19 @@ func (g *Gateio) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
),
|
||||
ResultLimit: 1001,
|
||||
GlobalResultLimit: 1001,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -902,7 +902,7 @@ func (g *Gateio) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (g *Gateio) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := g.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := g.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func (h *HitBTC) GetCandles(ctx context.Context, currencyPair, limit, period str
|
||||
}
|
||||
|
||||
var resp []ChartData
|
||||
path := fmt.Sprintf("/%s/%s?%s", apiV2Candles, currencyPair, vals.Encode())
|
||||
path := "/" + apiV2Candles + "/" + currencyPair + "?" + vals.Encode()
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
}
|
||||
startTime := time.Unix(1546300800, 0)
|
||||
end := time.Unix(1577836799, 0)
|
||||
|
||||
_, err = h.GetHistoricCandlesExtended(context.Background(), pair, asset.Spot, kline.OneHour, startTime, end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -979,6 +978,7 @@ func TestWsTrades(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_FormatExchangeKlineInterval(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
interval kline.Interval
|
||||
@@ -1000,18 +1000,20 @@ func Test_FormatExchangeKlineInterval(t *testing.T) {
|
||||
"D7",
|
||||
},
|
||||
{
|
||||
"AllOther",
|
||||
"OneMonth",
|
||||
kline.OneMonth,
|
||||
"",
|
||||
"1M",
|
||||
},
|
||||
}
|
||||
|
||||
for x := range testCases {
|
||||
test := testCases[x]
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ret := h.FormatExchangeKlineInterval(test.interval)
|
||||
|
||||
t.Parallel()
|
||||
ret, err := h.FormatExchangeKlineInterval(test.interval)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ret != test.output {
|
||||
t.Fatalf("unexpected result return expected: %v received: %v", test.output, ret)
|
||||
}
|
||||
|
||||
@@ -116,18 +116,18 @@ func (h *HitBTC) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.FourHour,
|
||||
kline.OneDay,
|
||||
kline.SevenDay,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.SevenDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -850,30 +850,48 @@ func (h *HitBTC) ValidateCredentials(ctx context.Context, assetType asset.Item)
|
||||
}
|
||||
|
||||
// FormatExchangeKlineInterval returns Interval to exchange formatted string
|
||||
func (h *HitBTC) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
func (h *HitBTC) FormatExchangeKlineInterval(in kline.Interval) (string, error) {
|
||||
switch in {
|
||||
case kline.OneMin, kline.ThreeMin,
|
||||
kline.FiveMin, kline.FifteenMin, kline.ThirtyMin:
|
||||
return "M" + in.Short()[:len(in.Short())-1]
|
||||
case kline.OneMin:
|
||||
return "M1", nil
|
||||
case kline.ThreeMin:
|
||||
return "M3", nil
|
||||
case kline.FiveMin:
|
||||
return "M5", nil
|
||||
case kline.FifteenMin:
|
||||
return "M15", nil
|
||||
case kline.ThirtyMin:
|
||||
return "M30", nil
|
||||
case kline.OneHour:
|
||||
return "H1", nil
|
||||
case kline.FourHour:
|
||||
return "H4", nil
|
||||
case kline.OneDay:
|
||||
return "D1"
|
||||
case kline.SevenDay:
|
||||
return "D7"
|
||||
return "D1", nil
|
||||
case kline.OneWeek:
|
||||
return "D7", nil
|
||||
case kline.OneMonth:
|
||||
return "1M", nil
|
||||
}
|
||||
return ""
|
||||
return "", fmt.Errorf("%w %v", kline.ErrInvalidInterval, in)
|
||||
}
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (h *HitBTC) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := h.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := h.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
formattedInterval, err := h.FormatExchangeKlineInterval(req.ExchangeInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := h.GetCandles(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatInt(int64(h.Features.Enabled.Kline.ResultLimit), 10),
|
||||
h.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.RequestLimit, 10),
|
||||
formattedInterval,
|
||||
req.Start,
|
||||
req.End)
|
||||
if err != nil {
|
||||
@@ -901,13 +919,18 @@ func (h *HitBTC) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
|
||||
return nil, err
|
||||
}
|
||||
|
||||
formattedInterval, err := h.FormatExchangeKlineInterval(req.ExchangeInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeSeries := make([]kline.Candle, 0, req.Size())
|
||||
for y := range req.RangeHolder.Ranges {
|
||||
var data []ChartData
|
||||
data, err = h.GetCandles(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatInt(int64(h.Features.Enabled.Kline.ResultLimit), 10),
|
||||
h.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.RequestLimit, 10),
|
||||
formattedInterval,
|
||||
req.RangeHolder.Ranges[y].Start.Time,
|
||||
req.RangeHolder.Ranges[y].End.Time)
|
||||
if err != nil {
|
||||
|
||||
@@ -145,18 +145,23 @@ func (h *HUOBI) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.FourHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.OneYear,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneYear},
|
||||
// NOTE: The supported time intervals below are returned
|
||||
// offset to the Asia/Shanghai time zone. This may lead to
|
||||
// issues with candle quality and conversion as the
|
||||
// intervals may be broken up. Therefore the below intervals
|
||||
// are constructed from hourly candles.
|
||||
// kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
// kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
// kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 2000,
|
||||
GlobalResultLimit: 2000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1745,7 +1750,7 @@ func (h *HUOBI) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (h *HUOBI) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := h.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := h.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1758,6 +1763,7 @@ func (h *HUOBI) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
|
||||
candles, err := h.GetSpotKline(ctx, KlinesRequestParams{
|
||||
Period: h.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
Symbol: req.Pair,
|
||||
Size: int(req.RequestLimit),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -163,17 +163,21 @@ func (k *Item) addPadding(start, exclusiveEnd time.Time, purgeOnPartial bool) er
|
||||
return errCannotEstablishTimeWindow
|
||||
}
|
||||
|
||||
segments := int(window / k.Interval.Duration())
|
||||
if segments == len(k.Candles) {
|
||||
return nil
|
||||
}
|
||||
|
||||
padded := make([]Candle, segments)
|
||||
padded := make([]Candle, int(window/k.Interval.Duration()))
|
||||
var target int
|
||||
for x := range padded {
|
||||
if target >= len(k.Candles) || !k.Candles[target].Time.Equal(start) {
|
||||
switch {
|
||||
case target >= len(k.Candles):
|
||||
padded[x].Time = start
|
||||
} else {
|
||||
case !k.Candles[target].Time.Equal(start):
|
||||
if k.Candles[target].Time.Before(start) {
|
||||
return fmt.Errorf("%w when it should be %s truncated at a %s interval",
|
||||
errCandleOpenTimeIsNotUTCAligned,
|
||||
start.Add(k.Interval.Duration()),
|
||||
k.Interval)
|
||||
}
|
||||
padded[x].Time = start
|
||||
default:
|
||||
padded[x] = k.Candles[target]
|
||||
target++
|
||||
}
|
||||
@@ -183,8 +187,15 @@ func (k *Item) addPadding(start, exclusiveEnd time.Time, purgeOnPartial bool) er
|
||||
// NOTE: This checks if the end time exceeds time.Now() and we are capturing
|
||||
// a partially created candle. This will only delete an element if it is
|
||||
// empty.
|
||||
if purgeOnPartial && padded[len(padded)-1].Volume == 0 {
|
||||
padded = padded[:len(padded)-1]
|
||||
if purgeOnPartial {
|
||||
lastElement := padded[len(padded)-1]
|
||||
if lastElement.Volume == 0 &&
|
||||
lastElement.Open == 0 &&
|
||||
lastElement.High == 0 &&
|
||||
lastElement.Low == 0 &&
|
||||
lastElement.Close == 0 {
|
||||
padded = padded[:len(padded)-1]
|
||||
}
|
||||
}
|
||||
k.Candles = padded
|
||||
return nil
|
||||
@@ -349,29 +360,38 @@ func (k *Item) ConvertToNewInterval(newInterval Interval) (*Item, error) {
|
||||
if len(candles) == 0 {
|
||||
return nil, fmt.Errorf("%w to %v no candle data", ErrInsufficientCandleData, newInterval)
|
||||
}
|
||||
|
||||
var target int
|
||||
for x := range k.Candles {
|
||||
if candles[target].Time.IsZero() {
|
||||
candles[target].Time = k.Candles[x].Time
|
||||
}
|
||||
// If this check does not pass, this candle has zero values or is padding.
|
||||
// It has nothing to apply to the new interval candle as it will distort
|
||||
// candle data.
|
||||
if k.Candles[x].Open != 0 &&
|
||||
k.Candles[x].High != 0 &&
|
||||
k.Candles[x].Low != 0 &&
|
||||
k.Candles[x].Close != 0 &&
|
||||
k.Candles[x].Volume != 0 {
|
||||
if candles[target].Time.IsZero() {
|
||||
candles[target].Time = k.Candles[x].Time
|
||||
}
|
||||
|
||||
if candles[target].Open == 0 {
|
||||
candles[target].Open = k.Candles[x].Open
|
||||
}
|
||||
if candles[target].Open == 0 {
|
||||
candles[target].Open = k.Candles[x].Open
|
||||
}
|
||||
|
||||
if k.Candles[x].High > candles[target].High {
|
||||
candles[target].High = k.Candles[x].High
|
||||
}
|
||||
if k.Candles[x].High > candles[target].High {
|
||||
candles[target].High = k.Candles[x].High
|
||||
}
|
||||
|
||||
if candles[target].Low == 0 || k.Candles[x].Low < candles[target].Low {
|
||||
candles[target].Low = k.Candles[x].Low
|
||||
}
|
||||
if candles[target].Low == 0 || k.Candles[x].Low < candles[target].Low {
|
||||
candles[target].Low = k.Candles[x].Low
|
||||
}
|
||||
|
||||
candles[target].Volume += k.Candles[x].Volume
|
||||
candles[target].Volume += k.Candles[x].Volume
|
||||
candles[target].Close = k.Candles[x].Close
|
||||
}
|
||||
|
||||
if (x+1)%oldIntervalsPerNewCandle == 0 {
|
||||
candles[target].Close = k.Candles[x].Close
|
||||
target++
|
||||
// Note: Below checks the length of the proceeding slice so we can
|
||||
// break instantly if we cannot make an entire candle. e.g. 60 min
|
||||
// candles in an hour candle and we have 59 minute candles left.
|
||||
@@ -379,6 +399,7 @@ func (k *Item) ConvertToNewInterval(newInterval Interval) (*Item, error) {
|
||||
if len(k.Candles[x:])-1 < oldIntervalsPerNewCandle {
|
||||
break
|
||||
}
|
||||
target++
|
||||
}
|
||||
}
|
||||
return &Item{
|
||||
@@ -582,12 +603,12 @@ func (k *Item) EqualSource(i *Item) error {
|
||||
|
||||
// DeployExchangeIntervals aligns and stores supported intervals for an exchange
|
||||
// for future matching.
|
||||
func DeployExchangeIntervals(enabled ...Interval) ExchangeIntervals {
|
||||
sort.Slice(enabled, func(i, j int) bool { return enabled[i] < enabled[j] })
|
||||
func DeployExchangeIntervals(enabled ...IntervalCapacity) ExchangeIntervals {
|
||||
sort.Slice(enabled, func(i, j int) bool { return enabled[i].Interval < enabled[j].Interval })
|
||||
|
||||
supported := make(map[Interval]bool)
|
||||
supported := make(map[Interval]int64)
|
||||
for x := range enabled {
|
||||
supported[enabled[x]] = true
|
||||
supported[enabled[x].Interval] = enabled[x].Capacity
|
||||
}
|
||||
return ExchangeIntervals{supported: supported, aligned: enabled}
|
||||
}
|
||||
@@ -596,7 +617,8 @@ func DeployExchangeIntervals(enabled ...Interval) ExchangeIntervals {
|
||||
// future this might be able to be deprecated because we can construct custom
|
||||
// intervals from the supported list.
|
||||
func (e *ExchangeIntervals) ExchangeSupported(in Interval) bool {
|
||||
return e.supported[in]
|
||||
_, ok := e.supported[in]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Construct fetches supported interval that can construct the required interval
|
||||
@@ -606,17 +628,41 @@ func (e *ExchangeIntervals) Construct(required Interval) (Interval, error) {
|
||||
return 0, ErrInvalidInterval
|
||||
}
|
||||
|
||||
if e.supported[required] {
|
||||
if _, ok := e.supported[required]; ok {
|
||||
// Directly supported by exchange can return.
|
||||
return required, nil
|
||||
}
|
||||
|
||||
for x := len(e.aligned) - 1; x > -1; x-- {
|
||||
if e.aligned[x] < required && required%e.aligned[x] == 0 {
|
||||
if e.aligned[x].Interval < required && required%e.aligned[x].Interval == 0 {
|
||||
// Indirectly supported by exchange. Can generate required candle
|
||||
// from this lower time frame supported candle.
|
||||
return e.aligned[x], nil
|
||||
return e.aligned[x].Interval, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrCannotConstructInterval
|
||||
}
|
||||
|
||||
// GetIntervalResultLimit returns the maximum amount of candles that can be
|
||||
// returned for a specific interval. If the individual interval limit is not set,
|
||||
// it will be ignored and the global result limit will be returned.
|
||||
func (e *ExchangeCapabilitiesEnabled) GetIntervalResultLimit(interval Interval) (int64, error) {
|
||||
if e == nil {
|
||||
return 0, errExchangeCapabilitiesEnabledIsNil
|
||||
}
|
||||
|
||||
val, ok := e.Intervals.supported[interval]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("[%s] %w", interval, errIntervalNotSupported)
|
||||
}
|
||||
|
||||
if val > 0 {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
if e.GlobalResultLimit == 0 {
|
||||
return 0, fmt.Errorf("%w there is no global result limit set", errCannotFetchIntervalLimit)
|
||||
}
|
||||
|
||||
return int64(e.GlobalResultLimit), nil
|
||||
}
|
||||
|
||||
@@ -1033,6 +1033,18 @@ func TestConvertToNewInterval(t *testing.T) {
|
||||
Close: 5555,
|
||||
Volume: 2520,
|
||||
},
|
||||
{
|
||||
Time: tn.AddDate(0, 0, 6),
|
||||
// Empty end padding
|
||||
},
|
||||
{
|
||||
Time: tn.AddDate(0, 0, 7),
|
||||
// Empty end padding
|
||||
},
|
||||
{
|
||||
Time: tn.AddDate(0, 0, 8),
|
||||
// Empty end padding
|
||||
},
|
||||
}
|
||||
|
||||
_, err = old.ConvertToNewInterval(newInterval)
|
||||
@@ -1040,7 +1052,7 @@ func TestConvertToNewInterval(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errCandleDataNotPadded)
|
||||
}
|
||||
|
||||
err = old.addPadding(tn, tn.AddDate(0, 0, 6), false)
|
||||
err = old.addPadding(tn, tn.AddDate(0, 0, 9), false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
@@ -1050,8 +1062,8 @@ func TestConvertToNewInterval(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
if len(newCandle.Candles) != 2 {
|
||||
t.Errorf("received '%v' expected '%v'", len(newCandle.Candles), 2)
|
||||
if len(newCandle.Candles) != 3 {
|
||||
t.Errorf("received '%v' expected '%v'", len(newCandle.Candles), 3)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,6 +1118,37 @@ func TestAddPadding(t *testing.T) {
|
||||
t.Fatalf("received '%v' expected '%v'", err, errCannotEstablishTimeWindow)
|
||||
}
|
||||
|
||||
k.Candles = []Candle{
|
||||
{
|
||||
Time: tn.Add(time.Hour * 8),
|
||||
Open: 1337,
|
||||
High: 1339,
|
||||
Low: 1336,
|
||||
Close: 1338,
|
||||
Volume: 1337,
|
||||
},
|
||||
{
|
||||
Time: tn.AddDate(0, 0, 1).Add(time.Hour * 8),
|
||||
Open: 1338,
|
||||
High: 2000,
|
||||
Low: 1332,
|
||||
Close: 1696,
|
||||
Volume: 6420,
|
||||
},
|
||||
{
|
||||
Time: tn.AddDate(0, 0, 2).Add(time.Hour * 8),
|
||||
Open: 1696,
|
||||
High: 1998,
|
||||
Low: 1337,
|
||||
Close: 6969,
|
||||
Volume: 2520,
|
||||
}}
|
||||
|
||||
err = k.addPadding(tn, tn.AddDate(0, 0, 3), false)
|
||||
if !errors.Is(err, errCandleOpenTimeIsNotUTCAligned) {
|
||||
t.Fatalf("received '%v' expected '%v'", err, errCandleOpenTimeIsNotUTCAligned)
|
||||
}
|
||||
|
||||
k.Candles = []Candle{
|
||||
{
|
||||
Time: tn,
|
||||
@@ -1207,7 +1250,7 @@ func TestDeployExchangeIntervals(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", exchangeIntervals.ExchangeSupported(OneWeek), false)
|
||||
}
|
||||
|
||||
exchangeIntervals = DeployExchangeIntervals(OneWeek)
|
||||
exchangeIntervals = DeployExchangeIntervals(IntervalCapacity{Interval: OneWeek})
|
||||
if !exchangeIntervals.ExchangeSupported(OneWeek) {
|
||||
t.Errorf("received '%v' expected '%v'", exchangeIntervals.ExchangeSupported(OneWeek), true)
|
||||
}
|
||||
@@ -1231,7 +1274,7 @@ func TestDeployExchangeIntervals(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", request, OneWeek)
|
||||
}
|
||||
|
||||
exchangeIntervals = DeployExchangeIntervals(OneWeek, OneDay)
|
||||
exchangeIntervals = DeployExchangeIntervals(IntervalCapacity{Interval: OneWeek}, IntervalCapacity{Interval: OneDay})
|
||||
|
||||
request, err = exchangeIntervals.Construct(OneMonth)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -1286,3 +1329,51 @@ func TestSetHasDataFromCandles(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIntervalResultLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var e *ExchangeCapabilitiesEnabled
|
||||
_, err := e.GetIntervalResultLimit(OneMin)
|
||||
if !errors.Is(err, errExchangeCapabilitiesEnabledIsNil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errExchangeCapabilitiesEnabledIsNil)
|
||||
}
|
||||
|
||||
e = &ExchangeCapabilitiesEnabled{}
|
||||
e.Intervals = ExchangeIntervals{}
|
||||
_, err = e.GetIntervalResultLimit(OneDay)
|
||||
if !errors.Is(err, errIntervalNotSupported) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errIntervalNotSupported)
|
||||
}
|
||||
|
||||
e.Intervals = ExchangeIntervals{
|
||||
supported: map[Interval]int64{
|
||||
OneDay: 100000,
|
||||
OneMin: 0,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = e.GetIntervalResultLimit(OneMin)
|
||||
if !errors.Is(err, errCannotFetchIntervalLimit) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errCannotFetchIntervalLimit)
|
||||
}
|
||||
|
||||
limit, err := e.GetIntervalResultLimit(OneDay)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
if limit != 100000 {
|
||||
t.Errorf("received '%v' expected '%v'", limit, 100000)
|
||||
}
|
||||
|
||||
e.GlobalResultLimit = 1337
|
||||
limit, err = e.GetIntervalResultLimit(OneMin)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
if limit != 1337 {
|
||||
t.Errorf("received '%v' expected '%v'", limit, 1337)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +71,14 @@ var (
|
||||
// back further than what is allowed.
|
||||
ErrRequestExceedsMaxLookback = errors.New("the requested time window exceeds the maximum lookback period available in the historical data, please reduce window between start and end date of your request")
|
||||
|
||||
errInsufficientTradeData = errors.New("insufficient trade data")
|
||||
errCandleDataNotPadded = errors.New("candle data not padded")
|
||||
errCannotEstablishTimeWindow = errors.New("cannot establish time window")
|
||||
errNilKline = errors.New("kline item is nil")
|
||||
errInsufficientTradeData = errors.New("insufficient trade data")
|
||||
errCandleDataNotPadded = errors.New("candle data not padded")
|
||||
errCannotEstablishTimeWindow = errors.New("cannot establish time window")
|
||||
errNilKline = errors.New("kline item is nil")
|
||||
errExchangeCapabilitiesEnabledIsNil = errors.New("exchange capabilities enabled is nil")
|
||||
errCannotFetchIntervalLimit = errors.New("cannot fetch interval limit")
|
||||
errIntervalNotSupported = errors.New("interval not supported")
|
||||
errCandleOpenTimeIsNotUTCAligned = errors.New("candle open time is not UTC aligned")
|
||||
|
||||
oneYearDurationInNano = float64(OneYear.Duration().Nanoseconds())
|
||||
|
||||
@@ -138,15 +142,20 @@ type ExchangeCapabilitiesSupported struct {
|
||||
|
||||
// ExchangeCapabilitiesEnabled all kline related exchange enabled options
|
||||
type ExchangeCapabilitiesEnabled struct {
|
||||
Intervals ExchangeIntervals
|
||||
ResultLimit uint32
|
||||
// Intervals defines whether the exchange supports interval kline requests.
|
||||
Intervals ExchangeIntervals
|
||||
// GlobalResultLimit is the maximum amount of candles that can be returned
|
||||
// across all intervals. This is used to determine if a request will exceed
|
||||
// the exchange limits. Indivudal interval limits are stored in the
|
||||
// ExchangeIntervals struct. If this is set to 0, it will be ignored.
|
||||
GlobalResultLimit uint32
|
||||
}
|
||||
|
||||
// ExchangeIntervals stores the supported intervals in an optimized lookup table
|
||||
// with a supplementary aligned retrieval list
|
||||
type ExchangeIntervals struct {
|
||||
supported map[Interval]bool
|
||||
aligned []Interval
|
||||
supported map[Interval]int64
|
||||
aligned []IntervalCapacity
|
||||
}
|
||||
|
||||
// Interval type for kline Interval usage
|
||||
@@ -183,3 +192,9 @@ type IntervalTime struct {
|
||||
Time time.Time
|
||||
Ticks int64
|
||||
}
|
||||
|
||||
// IntervalCapacity is used to store the interval and capacity for a candle return
|
||||
type IntervalCapacity struct {
|
||||
Interval Interval
|
||||
Capacity int64
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
|
||||
var (
|
||||
// ErrUnsetName is an error for when the exchange name is not set
|
||||
ErrUnsetName = errors.New("unset exchange name")
|
||||
errNilRequest = errors.New("nil kline request")
|
||||
errNoTimeSeriesDataToConvert = errors.New("no time series data to convert")
|
||||
ErrUnsetName = errors.New("unset exchange name")
|
||||
errNilRequest = errors.New("nil kline request")
|
||||
errNoTimeSeriesDataToConvert = errors.New("no time series data to convert")
|
||||
errInvalidSpecificEndpointLimit = errors.New("specific endpoint limit must be greater than 0")
|
||||
|
||||
// PartialCandle is string flag for when the most recent candle is partially
|
||||
// formed.
|
||||
@@ -53,11 +54,14 @@ type Request struct {
|
||||
// ProcessedCandles stores the candles that have been processed, but not converted
|
||||
// to the ClientRequiredInterval
|
||||
ProcessedCandles []Candle
|
||||
// RequestLimit is the potential maximum amount of candles that can be
|
||||
// returned
|
||||
RequestLimit int64
|
||||
}
|
||||
|
||||
// CreateKlineRequest generates a `Request` type for interval conversions
|
||||
// supported by an exchange.
|
||||
func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item, clientRequired, exchangeInterval Interval, start, end time.Time) (*Request, error) {
|
||||
func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item, clientRequired, exchangeInterval Interval, start, end time.Time, specificEndpointLimit int64) (*Request, error) {
|
||||
if name == "" {
|
||||
return nil, ErrUnsetName
|
||||
}
|
||||
@@ -81,6 +85,10 @@ func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if specificEndpointLimit <= 0 {
|
||||
return nil, errInvalidSpecificEndpointLimit
|
||||
}
|
||||
|
||||
// Force UTC alignment
|
||||
start = start.UTC()
|
||||
end = end.UTC()
|
||||
@@ -116,6 +124,7 @@ func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item
|
||||
Start: start,
|
||||
End: end,
|
||||
PartialCandle: end.After(time.Now()),
|
||||
RequestLimit: specificEndpointLimit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -13,51 +13,56 @@ import (
|
||||
|
||||
func TestCreateKlineRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := CreateKlineRequest("", currency.EMPTYPAIR, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{})
|
||||
_, err := CreateKlineRequest("", currency.EMPTYPAIR, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, ErrUnsetName) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, ErrUnsetName)
|
||||
}
|
||||
|
||||
_, err = CreateKlineRequest("name", currency.EMPTYPAIR, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", currency.EMPTYPAIR, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, currency.ErrCurrencyPairEmpty)
|
||||
}
|
||||
|
||||
pair := currency.NewPair(currency.BTC, currency.USDT)
|
||||
_, err = CreateKlineRequest("name", pair, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, currency.EMPTYPAIR, 0, 0, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, currency.ErrCurrencyPairEmpty)
|
||||
}
|
||||
|
||||
pair2 := pair.Upper()
|
||||
_, err = CreateKlineRequest("name", pair, pair2, 0, 0, 0, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, pair2, 0, 0, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, 0, 0, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, 0, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, ErrInvalidInterval) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, ErrInvalidInterval)
|
||||
}
|
||||
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, 0, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, 0, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, ErrInvalidInterval) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, ErrInvalidInterval)
|
||||
}
|
||||
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, time.Time{}, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, time.Time{}, time.Time{}, 0)
|
||||
if !errors.Is(err, common.ErrDateUnset) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, common.ErrDateUnset)
|
||||
}
|
||||
|
||||
start := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, time.Time{})
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, time.Time{}, 0)
|
||||
if !errors.Is(err, common.ErrDateUnset) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, common.ErrDateUnset)
|
||||
}
|
||||
|
||||
end := start.AddDate(0, 0, 1)
|
||||
r, err := CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, end)
|
||||
_, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, end, 0)
|
||||
if !errors.Is(err, errInvalidSpecificEndpointLimit) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, errInvalidSpecificEndpointLimit)
|
||||
}
|
||||
|
||||
r, err := CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -98,7 +103,7 @@ func TestCreateKlineRequest(t *testing.T) {
|
||||
// aligned correctly.
|
||||
end = end.Round(0)
|
||||
end = end.Add(time.Second * 30)
|
||||
r, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair2, asset.Spot, OneHour, OneMin, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -121,7 +126,7 @@ func TestGetRanges(t *testing.T) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, errNilRequest)
|
||||
}
|
||||
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -207,8 +212,13 @@ func TestRequest_ProcessResponse(t *testing.T) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, errNoTimeSeriesDataToConvert)
|
||||
}
|
||||
|
||||
_, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneHour, start, end, 0)
|
||||
if !errors.Is(err, errInvalidSpecificEndpointLimit) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
// no conversion
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneHour, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneHour, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -223,7 +233,7 @@ func TestRequest_ProcessResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
// with conversion
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -240,7 +250,7 @@ func TestRequest_ProcessResponse(t *testing.T) {
|
||||
// Potential partial candle
|
||||
end = time.Now().UTC()
|
||||
start = end.AddDate(0, 0, -5).Truncate(time.Duration(OneDay))
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneDay, OneDay, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneDay, OneDay, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -285,7 +295,7 @@ func TestRequest_ProcessResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
// end date far into the dark depths of future reality
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneDay, OneDay, start, end.AddDate(1, 0, 0))
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneDay, OneDay, start, end.AddDate(1, 0, 0), 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -338,7 +348,7 @@ func TestExtendedRequest_ProcessResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
// no conversion
|
||||
r, err := CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneHour, start, end)
|
||||
r, err := CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneHour, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
@@ -361,7 +371,7 @@ func TestExtendedRequest_ProcessResponse(t *testing.T) {
|
||||
|
||||
// with conversion
|
||||
ohc = getOneMinute()
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end)
|
||||
r, err = CreateKlineRequest("name", pair, pair, asset.Spot, OneHour, OneMin, start, end, 1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v', but expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
@@ -158,17 +158,17 @@ func (k *Kraken) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.FourHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.FifteenDay,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenDay},
|
||||
),
|
||||
ResultLimit: 720,
|
||||
GlobalResultLimit: 720,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1472,7 +1472,7 @@ func (k *Kraken) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (k *Kraken) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := k.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := k.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -93,19 +93,25 @@ func (l *Lbank) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.FourHour,
|
||||
kline.EightHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
|
||||
// NOTE: The supported time intervals below are returned
|
||||
// offset to the Asia/HongKong time zone. This may lead to
|
||||
// issues with candle quality and conversion as the
|
||||
// intervals may be broken up. Therefore the below intervals
|
||||
// are constructed from hourly -> 4 hourly candles.
|
||||
// kline.IntervalCapacity{Interval: kline.EightHour}, // The docs suggest this is supported but it isn't.
|
||||
// kline.IntervalCapacity{Interval: kline.TwelveHour}, // The docs suggest this is supported but it isn't.
|
||||
// kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
// kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
// kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 2000,
|
||||
GlobalResultLimit: 2000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -889,14 +895,14 @@ func (l *Lbank) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (l *Lbank) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := l.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := l.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := l.GetKlines(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatInt(int64(l.Features.Enabled.Kline.ResultLimit), 10),
|
||||
strconv.FormatInt(req.RequestLimit, 10),
|
||||
l.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.Start.Unix(), 10))
|
||||
if err != nil {
|
||||
@@ -929,7 +935,7 @@ func (l *Lbank) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
|
||||
var data []KlineResponse
|
||||
data, err = l.GetKlines(ctx,
|
||||
req.RequestFormatted.String(),
|
||||
strconv.FormatInt(int64(l.Features.Enabled.Kline.ResultLimit), 10),
|
||||
strconv.FormatInt(req.RequestLimit, 10),
|
||||
l.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
strconv.FormatInt(req.RangeHolder.Ranges[x].Start.Ticks, 10))
|
||||
if err != nil {
|
||||
|
||||
@@ -419,26 +419,24 @@ func (o *OKCoin) GetMarketData(ctx context.Context, request *GetMarketDataReques
|
||||
if !ok {
|
||||
return nil, common.GetAssertError("string", t[0])
|
||||
}
|
||||
var tempCandle kline.Candle
|
||||
if tempCandle.Time, err = time.Parse(time.RFC3339, v); err != nil {
|
||||
if candles[x].Time, err = time.Parse(time.RFC3339, v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tempCandle.Open, err = convert.FloatFromString(t[1]); err != nil {
|
||||
if candles[x].Open, err = convert.FloatFromString(t[1]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tempCandle.High, err = convert.FloatFromString(t[2]); err != nil {
|
||||
if candles[x].High, err = convert.FloatFromString(t[2]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tempCandle.Low, err = convert.FloatFromString(t[3]); err != nil {
|
||||
if candles[x].Low, err = convert.FloatFromString(t[3]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tempCandle.Close, err = convert.FloatFromString(t[4]); err != nil {
|
||||
if candles[x].Close, err = convert.FloatFromString(t[4]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tempCandle.Volume, err = convert.FloatFromString(t[5]); err != nil {
|
||||
if candles[x].Volume, err = convert.FloatFromString(t[5]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
candles[x] = tempCandle
|
||||
}
|
||||
return candles, nil
|
||||
}
|
||||
|
||||
@@ -1277,8 +1277,8 @@ func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startTime := time.Unix(1588636800, 0)
|
||||
_, err = o.GetHistoricCandles(context.Background(),
|
||||
pair, asset.Spot, kline.OneDay, startTime, time.Now())
|
||||
endTime := startTime.Add(time.Hour * 24 * 7)
|
||||
_, err = o.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, startTime, endTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1292,8 +1292,7 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
}
|
||||
|
||||
startTime := time.Unix(1588636800, 0)
|
||||
_, err = o.GetHistoricCandlesExtended(context.Background(),
|
||||
pair, asset.Spot, kline.OneWeek, startTime, time.Now())
|
||||
_, err = o.GetHistoricCandlesExtended(context.Background(), pair, asset.Spot, kline.OneWeek, startTime, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -119,21 +119,26 @@ func (o *OKCoin) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.OneWeek,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
// NOTE: The supported time intervals below are returned
|
||||
// offset to the Asia/Shanghai time zone. This may lead to
|
||||
// issues with candle quality and conversion as the
|
||||
// intervals may be broken up. Therefore the below intervals
|
||||
// are constructed from hourly candles.
|
||||
// kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
// kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
// kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
// kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
// kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
),
|
||||
ResultLimit: 1440,
|
||||
GlobalResultLimit: 1440,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1021,7 +1026,7 @@ func (o *OKCoin) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.I
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (o *OKCoin) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := o.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := o.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2303,7 +2303,7 @@ func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Parallel()
|
||||
pair := currency.NewPair(currency.BTC, currency.USDT)
|
||||
startTime := time.Date(2021, 2, 1, 0, 0, 0, 0, time.UTC)
|
||||
endTime := time.Date(2021, 9, 15, 0, 0, 0, 0, time.UTC)
|
||||
endTime := startTime.AddDate(0, 0, 100)
|
||||
_, err := ok.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, startTime, endTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -131,27 +131,27 @@ func (ok *Okx) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.TwoDay,
|
||||
kline.ThreeDay,
|
||||
kline.FiveDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.ThreeMonth,
|
||||
kline.SixMonth,
|
||||
kline.OneYear,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.TwoDay},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
kline.IntervalCapacity{Interval: kline.FiveDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMonth},
|
||||
kline.IntervalCapacity{Interval: kline.SixMonth},
|
||||
kline.IntervalCapacity{Interval: kline.OneYear},
|
||||
),
|
||||
ResultLimit: 300,
|
||||
GlobalResultLimit: 100, // Reference: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -363,8 +363,7 @@ func (ok *Okx) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var baseVolume float64
|
||||
var quoteVolume float64
|
||||
var baseVolume, quoteVolume float64
|
||||
switch a {
|
||||
case asset.Spot, asset.Margin:
|
||||
baseVolume = mdata.Vol24H.Float64()
|
||||
@@ -1365,7 +1364,7 @@ func (ok *Okx) ValidateCredentials(ctx context.Context, assetType asset.Item) er
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (ok *Okx) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := ok.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := ok.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -123,22 +123,22 @@ func (p *Poloniex) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.FiveMin,
|
||||
kline.TenMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.OneWeek,
|
||||
kline.OneMonth,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.TenMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
kline.IntervalCapacity{Interval: kline.OneMonth},
|
||||
),
|
||||
ResultLimit: 500,
|
||||
GlobalResultLimit: 500,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -950,7 +950,7 @@ func (p *Poloniex) ValidateCredentials(ctx context.Context, assetType asset.Item
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (p *Poloniex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := p.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := p.GetKlineRequest(pair, a, interval, start, end, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -867,23 +867,32 @@ func TestWsCreateSubUserResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetSpotKline(t *testing.T) {
|
||||
t.Parallel()
|
||||
limit, err := z.Features.Enabled.Kline.GetIntervalResultLimit(kline.OneMin)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
arg := KlinesRequestParams{
|
||||
Symbol: testCurrency,
|
||||
Type: kline.OneMin.Short() + "in",
|
||||
Size: int64(z.Features.Enabled.Kline.ResultLimit),
|
||||
Size: limit,
|
||||
}
|
||||
if mockTests {
|
||||
startTime := time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC)
|
||||
arg.Since = startTime.UnixMilli()
|
||||
arg.Type = "1day"
|
||||
}
|
||||
_, err := z.GetSpotKline(context.Background(), arg)
|
||||
_, err = z.GetSpotKline(context.Background(), arg)
|
||||
if err != nil {
|
||||
t.Errorf("ZB GetSpotKline: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricCandles(t *testing.T) {
|
||||
t.Parallel()
|
||||
if mockTests {
|
||||
t.Skip("mock testing is not supported for this function")
|
||||
}
|
||||
currencyPair, err := currency.NewPairFromString(testCurrency)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -891,20 +900,14 @@ func TestGetHistoricCandles(t *testing.T) {
|
||||
|
||||
startTime := time.Now().Add(-time.Hour * 24)
|
||||
endTime := time.Now()
|
||||
if mockTests {
|
||||
startTime = time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC)
|
||||
endTime = time.Date(2020, 9, 2, 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
// Current endpoint is dead.
|
||||
_, err = z.GetHistoricCandles(context.Background(),
|
||||
currencyPair, asset.Spot, kline.OneDay, startTime, endTime)
|
||||
_, err = z.GetHistoricCandles(context.Background(), currencyPair, asset.Spot, kline.OneDay, startTime, endTime)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString(testCurrency)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -920,8 +923,7 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
startTime = time.Now().Add(-time.Hour * 24 * 365)
|
||||
endTime = time.Now()
|
||||
if mockTests {
|
||||
startTime = time.UnixMilli(1674489600000)
|
||||
endTime = startTime.Add(kline.OneDay.Duration())
|
||||
t.Skip("mock testing is not supported for this function")
|
||||
}
|
||||
_, err = z.GetHistoricCandlesExtended(context.Background(),
|
||||
currencyPair, asset.Spot, kline.OneDay, startTime, endTime)
|
||||
|
||||
@@ -111,21 +111,26 @@ func (z *ZB) SetDefaults() {
|
||||
AutoPairUpdates: true,
|
||||
Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
Intervals: kline.DeployExchangeIntervals(
|
||||
kline.OneMin,
|
||||
kline.ThreeMin,
|
||||
kline.FiveMin,
|
||||
kline.FifteenMin,
|
||||
kline.ThirtyMin,
|
||||
kline.OneHour,
|
||||
kline.TwoHour,
|
||||
kline.FourHour,
|
||||
kline.SixHour,
|
||||
kline.TwelveHour,
|
||||
kline.OneDay,
|
||||
kline.ThreeDay,
|
||||
kline.OneWeek,
|
||||
kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThreeMin},
|
||||
kline.IntervalCapacity{Interval: kline.FiveMin},
|
||||
kline.IntervalCapacity{Interval: kline.FifteenMin},
|
||||
kline.IntervalCapacity{Interval: kline.ThirtyMin},
|
||||
kline.IntervalCapacity{Interval: kline.OneHour},
|
||||
kline.IntervalCapacity{Interval: kline.TwoHour},
|
||||
kline.IntervalCapacity{Interval: kline.FourHour},
|
||||
// NOTE: The supported time intervals below are returned
|
||||
// offset to the Asia/Shanghai time zone. This may lead to
|
||||
// issues with candle quality and conversion as the
|
||||
// intervals may be broken up. Therefore the below intervals
|
||||
// are constructed from hourly candles.
|
||||
// kline.IntervalCapacity{Interval: kline.SixHour},
|
||||
// kline.IntervalCapacity{Interval: kline.TwelveHour},
|
||||
// kline.IntervalCapacity{Interval: kline.OneDay},
|
||||
// kline.IntervalCapacity{Interval: kline.ThreeDay},
|
||||
// kline.IntervalCapacity{Interval: kline.OneWeek},
|
||||
),
|
||||
ResultLimit: 1000,
|
||||
GlobalResultLimit: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -885,7 +890,7 @@ func (z *ZB) FormatExchangeKlineInterval(in kline.Interval) string {
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (z *ZB) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
req, err := z.GetKlineRequest(pair, a, interval, start, end)
|
||||
req, err := z.GetKlineRequest(pair, a, interval, start, end, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -894,7 +899,7 @@ func (z *ZB) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset
|
||||
Type: z.FormatExchangeKlineInterval(req.ExchangeInterval),
|
||||
Symbol: req.RequestFormatted.String(),
|
||||
Since: start.UnixMilli(),
|
||||
Size: int64(z.Features.Enabled.Kline.ResultLimit),
|
||||
Size: req.RequestLimit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user