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:
Ryan O'Hara-Reid
2023-04-27 10:10:19 +10:00
committed by GitHub
parent 668d083749
commit 42475bf2b8
36 changed files with 809 additions and 471 deletions

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}