exchanges/websocket: Implement subscription configuration (#1394)

* Websockets: Move Subscription to its own package

This allows the small type to be imported from both `config` and from
`stream` without an import cycle, so we don't have to repeat ourselves

* Subs: Renamed Currency to Pair

This was being mis-used through much of the code, and since we're
already touching everything, we might as well fix it

* Websockets: Add Subscription configuration

* Binance: Add subscription configuration

* Kucoin: Subscription configuration

* Simplify GenerateDefaultSubs
* Improve TestGenSubs coverage
* Test Candle Sub generation
* Support Candle intervals
* Full responsibility for formatting Channel name on GenerateDefaultSubs
  OR consumer of Subscribe
* Simplify generatePayloads as a result
* Fix test coverage of asset types in processMarketSnapshot

* Exchanges: Abstract ParallelChanOp

* Tests: Generic ws mock instances

* Kucoin: Fix intermittent conflict in test currs

Use isolated test instance for `TestGetOpenInterest`.

`TestGetOpenInterest` would occassionally change pairs before
GenerateDefault Subs.
This commit is contained in:
Gareth Kirwan
2024-01-24 05:54:07 +01:00
committed by GitHub
parent 301551ac20
commit e007f69f7c
67 changed files with 3705 additions and 3167 deletions

View File

@@ -1,9 +1,11 @@
package kline
import (
"bytes"
"errors"
"fmt"
"sort"
"strconv"
"strings"
"time"
@@ -143,6 +145,31 @@ func (i Interval) Short() string {
return s
}
// UnmarshalJSON implements the json.Unmarshaler interface for Intervals
// It does not validate the duration is aligned, only that it is a parsable duration
func (i *Interval) UnmarshalJSON(text []byte) error {
text = bytes.Trim(text, `"`)
if len(bytes.TrimLeft(text, `0123456789`)) > 0 { // contains non-numerics, ParseDuration can handle errors
d, err := time.ParseDuration(string(text))
if err != nil {
return err
}
*i = Interval(d)
} else {
n, err := strconv.ParseInt(string(text), 10, 64)
if err != nil {
return err
}
*i = Interval(n)
}
return nil
}
// MarshalText implements the TextMarshaler interface for Intervals
func (i Interval) MarshalText() ([]byte, error) {
return []byte(i.Short()), nil
}
// addPadding inserts padding time aligned when exchanges do not supply all data
// when there is no activity in a certain time interval.
// Start defines the request start and due to potential no activity from this

View File

@@ -10,6 +10,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/database"
@@ -1396,3 +1397,18 @@ func TestGetIntervalResultLimit(t *testing.T) {
t.Errorf("received '%v' expected '%v'", limit, 1337)
}
}
func TestUnmarshalJSON(t *testing.T) {
i := new(Interval)
err := i.UnmarshalJSON([]byte(`"3m"`))
assert.NoError(t, err, "UnmarshalJSON should not error")
assert.Equal(t, time.Minute*3, i.Duration(), "Interval should have correct value")
err = i.UnmarshalJSON([]byte(`"15s"`))
assert.NoError(t, err, "UnmarshalJSON should not error")
assert.Equal(t, time.Second*15, i.Duration(), "Interval should have correct value")
err = i.UnmarshalJSON([]byte(`720000000000`))
assert.NoError(t, err, "UnmarshalJSON should not error")
assert.Equal(t, time.Minute*12, i.Duration(), "Interval should have correct value")
err = i.UnmarshalJSON([]byte(`"6hedgehogs"`))
assert.ErrorContains(t, err, "unknown unit", "UnmarshalJSON should error")
}