exchanges/wrappers: Refactor fetch orderbook/ticker/account info funcs (#1440)

* acrost: Pull thread, examine

* fix tests

* linter

* fix_linter

* revert rm ctx param to limit breakages when merging usptream

* linter fix

* Add in priority update grouping so that tests pass

* Update cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious nits

* fixed spelling

* whoopsie

* aanother whoops

* glorious: NITTERS!

* glorious: further nitters

* srry linter gods

* glorious: nits continued

* sub test p ara lel

* drop main t.Parallel

* fix whoops

* wrappertests: use context with cancel (test)

* linter: fix

* ensure primary execution

* kucoin test fix

* revert standards test changes and bypass non critical errors

* rm single override

* wrap exported error for accounts

* thrasher: nits ch name

* gk: nits

* gk: nits FetchTickerCached -> GetCachedTicker

* gk: nits rn FetchOrderbookCached -> GetCachedOrderbook

* gk: nits rn FetchAccountInfoCached -> GetCachedAccountInfo

* linter: fix

* gk: nits

* thrasher: nitters 1

* thrasher: nitters tmpls

* gk: nitter

---------

Co-authored-by: shazbert <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
Ryan O'Hara-Reid
2025-02-19 10:47:10 +11:00
committed by GitHub
parent 2fc7e8e3e3
commit 08e015a125
122 changed files with 545 additions and 1962 deletions

View File

@@ -34,7 +34,7 @@ exchange interface system set by exchange wrapper orderbook functions in
Examples below:
```go
ob, err := yobitExchange.FetchOrderbook()
ob, err := yobitExchange.UpdateOrderbook(...)
if err != nil {
// Handle error
}

View File

@@ -36,8 +36,7 @@ func SubscribeToExchangeOrderbooks(exchange string) (dispatch.Pipe, error) {
defer service.mu.Unlock()
exch, ok := service.books[strings.ToLower(exchange)]
if !ok {
return dispatch.Pipe{}, fmt.Errorf("%w for %s exchange",
errCannotFindOrderbook, exchange)
return dispatch.Pipe{}, fmt.Errorf("%w for %s exchange", ErrOrderbookNotFound, exchange)
}
return service.Mux.Subscribe(exch.ID)
}
@@ -129,8 +128,7 @@ func (s *Service) GetDepth(exchange string, p currency.Pair, a asset.Item) (*Dep
defer s.mu.Unlock()
m1, ok := s.books[strings.ToLower(exchange)]
if !ok {
return nil, fmt.Errorf("%w for %s exchange",
errCannotFindOrderbook, exchange)
return nil, fmt.Errorf("%w for %s exchange", ErrOrderbookNotFound, exchange)
}
book, ok := m1.m[key.PairAsset{
@@ -139,7 +137,7 @@ func (s *Service) GetDepth(exchange string, p currency.Pair, a asset.Item) (*Dep
Asset: a,
}]
if !ok {
return nil, fmt.Errorf("%w associated with base currency %s", errCannotFindOrderbook, p.Quote)
return nil, fmt.Errorf("%w associated with base currency %s", ErrOrderbookNotFound, p.Quote)
}
return book, nil
}
@@ -158,7 +156,7 @@ func (s *Service) Retrieve(exchange string, p currency.Pair, a asset.Item) (*Bas
defer s.mu.Unlock()
m1, ok := s.books[strings.ToLower(exchange)]
if !ok {
return nil, fmt.Errorf("%w for %s exchange", errCannotFindOrderbook, exchange)
return nil, fmt.Errorf("%w for %s exchange", ErrOrderbookNotFound, exchange)
}
book, ok := m1.m[key.PairAsset{
Base: p.Base.Item,
@@ -166,7 +164,7 @@ func (s *Service) Retrieve(exchange string, p currency.Pair, a asset.Item) (*Bas
Asset: a,
}]
if !ok {
return nil, fmt.Errorf("%w associated with base currency %s", errCannotFindOrderbook, p.Quote)
return nil, fmt.Errorf("%w associated with currency %s %s", ErrOrderbookNotFound, p, a)
}
return book.Retrieve()
}

View File

@@ -10,6 +10,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/dispatch"
@@ -25,10 +26,9 @@ func TestMain(m *testing.M) {
}
func TestSubscribeToExchangeOrderbooks(t *testing.T) {
t.Parallel()
_, err := SubscribeToExchangeOrderbooks("")
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("expected: %v but received: %v", errCannotFindOrderbook, err)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
p := currency.NewPair(currency.BTC, currency.USD)
@@ -39,15 +39,10 @@ func TestSubscribeToExchangeOrderbooks(t *testing.T) {
Bids: []Tranche{{Price: 100, Amount: 1}, {Price: 99, Amount: 1}},
}
err = b.Process()
if err != nil {
t.Error(err)
}
require.NoError(t, b.Process(), "process must not error")
_, err = SubscribeToExchangeOrderbooks("SubscribeToExchangeOrderbooks")
if err != nil {
t.Error(err)
}
assert.NoError(t, err, "SubscribeToExchangeOrderbooks should not error")
}
func TestVerify(t *testing.T) {
@@ -175,10 +170,11 @@ func TestCalculateTotalAsks(t *testing.T) {
}
func TestGetOrderbook(t *testing.T) {
t.Parallel()
c, err := currency.NewPairFromStrings("BTC", "USD")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err, "NewPairFromStrings must not error")
base := &Base{
Pair: c,
Asks: []Tranche{{Price: 100, Amount: 10}},
@@ -187,57 +183,39 @@ func TestGetOrderbook(t *testing.T) {
Asset: asset.Spot,
}
err = base.Process()
if err != nil {
t.Fatal(err)
}
require.NoError(t, base.Process(), "Process must not error")
result, err := Get("Exchange", c, asset.Spot)
if err != nil {
t.Fatalf("TestGetOrderbook failed to get orderbook. Error %s",
err)
}
if !result.Pair.Equal(c) {
t.Fatal("TestGetOrderbook failed. Mismatched pairs")
}
require.NoError(t, err, "Get must not error")
assert.True(t, result.Pair.Equal(c))
_, err = Get("nonexistent", c, asset.Spot)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("received '%v', expected '%v'", err, errCannotFindOrderbook)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
c.Base = currency.NewCode("blah")
_, err = Get("Exchange", c, asset.Spot)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("received '%v', expected '%v', using invalid first currency", err, errCannotFindOrderbook)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
newCurrency, err := currency.NewPairFromStrings("BTC", "AUD")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err, "NewPairFromStrings must not error")
_, err = Get("Exchange", newCurrency, asset.Spot)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("received '%v', expected '%v', using invalid second currency", err, errCannotFindOrderbook)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
base.Pair = newCurrency
err = base.Process()
if err != nil {
t.Error(err)
}
require.NoError(t, base.Process(), "Process must not error")
_, err = Get("Exchange", newCurrency, asset.Empty)
if err == nil {
t.Error("error cannot be nil")
}
got, err := Get("Exchange", newCurrency, asset.Spot)
require.NoError(t, err, "Get must not error")
assert.True(t, got.Pair.Equal(newCurrency))
}
func TestGetDepth(t *testing.T) {
t.Parallel()
c, err := currency.NewPairFromStrings("BTC", "USD")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err, "NewPairFromStrings must not error")
base := &Base{
Pair: c,
Asks: []Tranche{{Price: 100, Amount: 10}},
@@ -246,57 +224,38 @@ func TestGetDepth(t *testing.T) {
Asset: asset.Spot,
}
err = base.Process()
if err != nil {
t.Fatal(err)
}
require.NoError(t, base.Process(), "Process must not error")
result, err := GetDepth("Exchange", c, asset.Spot)
if err != nil {
t.Fatalf("TestGetOrderbook failed to get orderbook. Error %s",
err)
}
if !result.pair.Equal(c) {
t.Fatal("TestGetOrderbook failed. Mismatched pairs")
}
require.NoError(t, err, "GetDepth must not error")
assert.True(t, result.pair.Equal(c))
_, err = GetDepth("nonexistent", c, asset.Spot)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("expecting %s error but received %v", errCannotFindOrderbook, err)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
c.Base = currency.NewCode("blah")
_, err = GetDepth("Exchange", c, asset.Spot)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("expecting %s error but received %v", errCannotFindOrderbook, err)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
newCurrency, err := currency.NewPairFromStrings("BTC", "DOGE")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err, "NewPairFromStrings must not error")
_, err = GetDepth("Exchange", newCurrency, asset.Futures)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("expecting %s error but received %v", errCannotFindOrderbook, err)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
base.Pair = newCurrency
err = base.Process()
if err != nil {
t.Error(err)
}
require.NoError(t, base.Process(), "Process must not error")
_, err = GetDepth("Exchange", newCurrency, asset.Empty)
if !errors.Is(err, errCannotFindOrderbook) {
t.Fatalf("expecting %s error but received %v", errCannotFindOrderbook, err)
}
assert.ErrorIs(t, err, ErrOrderbookNotFound)
}
func TestBaseGetDepth(t *testing.T) {
t.Parallel()
c, err := currency.NewPairFromStrings("BTC", "UST")
if err != nil {
t.Error(err)
}
require.NoError(t, err, "NewPairFromStrings must not error")
base := &Base{
Pair: c,
Asks: []Tranche{{Price: 100, Amount: 10}},
@@ -305,19 +264,14 @@ func TestBaseGetDepth(t *testing.T) {
Asset: asset.Spot,
}
if _, err = base.GetDepth(); !errors.Is(err, errCannotFindOrderbook) {
t.Errorf("expecting %s error but received %v", errCannotFindOrderbook, err)
}
_, err = base.GetDepth()
assert.ErrorIs(t, err, ErrOrderbookNotFound)
if err = base.Process(); err != nil {
t.Error(err)
}
require.NoError(t, base.Process(), "Process must not error")
if result, err := base.GetDepth(); err != nil {
t.Errorf("failed to get orderbook. Error %s", err)
} else if !result.pair.Equal(c) {
t.Errorf("Mismatched pairs: %v %v", result.pair, c)
}
result, err := base.GetDepth()
require.NoError(t, err, "GetDepth must not error")
assert.True(t, result.pair.Equal(c))
}
func TestDeployDepth(t *testing.T) {

View File

@@ -12,19 +12,21 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
)
// const values for orderbook package
const (
bidLoadBookFailure = "cannot load book for exchange %s pair %s asset %s for Bids: %w"
askLoadBookFailure = "cannot load book for exchange %s pair %s asset %s for Asks: %w"
bookLengthIssue = "Potential book issue for exchange %s pair %s asset %s length Bids %d length Asks %d"
)
// Vars for the orderbook package
// Public errors
var (
ErrOrderbookNotFound = errors.New("cannot find orderbook(s)")
)
var (
errExchangeNameUnset = errors.New("orderbook exchange name not set")
errPairNotSet = errors.New("orderbook currency pair not set")
errAssetTypeNotSet = errors.New("orderbook asset type not set")
errCannotFindOrderbook = errors.New("cannot find orderbook(s)")
errPriceNotSet = errors.New("price cannot be zero")
errAmountInvalid = errors.New("amount cannot be less or equal to zero")
errPriceOutOfOrder = errors.New("pricing out of order")

View File

@@ -25,7 +25,7 @@ func TestSimulate(t *testing.T) {
},
},
}
o, err := b.FetchOrderbook(context.Background(),
o, err := b.UpdateOrderbook(context.Background(),
currency.NewPair(currency.BTC, currency.USD), asset.Spot)
if err != nil {
t.Fatal(err)