mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
* orderbook: change Base struct name to Snapshot * linter: fix * Update exchanges/exchange.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/depth.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_types.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Snapshot -> Book * Tranche(s) -> Level(s) * Tranche(s) -> Level(s) * rm tranche ref * linter: fix * linter: rides again * update tests * Update exchange/websocket/buffer/buffer.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update backtester/eventhandlers/exchange/slippage/slippage.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchange/websocket/buffer/buffer.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchange/websocket/buffer/buffer.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchanges/orderbook/orderbook_types.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update exchanges/orderbook/orderbook_types.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * fixup tests * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_types.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/orderbook/orderbook_types.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * gk: nits and rm stuff that is not needed * Update exchanges/orderbook/orderbook_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * gk: nits --------- Co-authored-by: shazbert <ryan.oharareid@thrasher.io> Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
312 lines
7.8 KiB
Go
312 lines
7.8 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thrasher-corp/gocryptotrader/config"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
|
)
|
|
|
|
func TestWebsocketRoutineManagerSetup(t *testing.T) {
|
|
_, err := setupWebsocketRoutineManager(nil, nil, nil, nil, false)
|
|
assert.ErrorIs(t, err, errNilExchangeManager)
|
|
|
|
_, err = setupWebsocketRoutineManager(NewExchangeManager(), (*OrderManager)(nil), nil, nil, false)
|
|
assert.ErrorIs(t, err, errNilCurrencyPairSyncer)
|
|
|
|
_, err = setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, nil, false)
|
|
assert.ErrorIs(t, err, errNilCurrencyConfig)
|
|
|
|
_, err = setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, ¤cy.Config{}, true)
|
|
assert.ErrorIs(t, err, errNilCurrencyPairFormat)
|
|
|
|
m, err := setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, ¤cy.Config{CurrencyPairFormat: ¤cy.PairFormat{}}, false)
|
|
assert.NoError(t, err)
|
|
|
|
if m == nil {
|
|
t.Error("expecting manager")
|
|
}
|
|
}
|
|
|
|
func TestWebsocketRoutineManagerStart(t *testing.T) {
|
|
var m *WebsocketRoutineManager
|
|
err := m.Start()
|
|
assert.ErrorIs(t, err, ErrNilSubsystem)
|
|
|
|
cfg := ¤cy.Config{CurrencyPairFormat: ¤cy.PairFormat{
|
|
Uppercase: false,
|
|
Delimiter: "-",
|
|
}}
|
|
m, err = setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, cfg, true)
|
|
assert.NoError(t, err)
|
|
|
|
err = m.Start()
|
|
assert.NoError(t, err)
|
|
|
|
err = m.Start()
|
|
assert.ErrorIs(t, err, ErrSubSystemAlreadyStarted)
|
|
}
|
|
|
|
func TestWebsocketRoutineManagerIsRunning(t *testing.T) {
|
|
var m *WebsocketRoutineManager
|
|
if m.IsRunning() {
|
|
t.Error("expected false")
|
|
}
|
|
|
|
m, err := setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, ¤cy.Config{CurrencyPairFormat: ¤cy.PairFormat{}}, false)
|
|
assert.NoError(t, err)
|
|
|
|
if m.IsRunning() {
|
|
t.Error("expected false")
|
|
}
|
|
|
|
err = m.Start()
|
|
assert.NoError(t, err)
|
|
|
|
for atomic.LoadInt32(&m.state) == startingState {
|
|
<-time.After(time.Second / 100)
|
|
}
|
|
if !m.IsRunning() {
|
|
t.Error("expected true")
|
|
}
|
|
}
|
|
|
|
func TestWebsocketRoutineManagerStop(t *testing.T) {
|
|
var m *WebsocketRoutineManager
|
|
err := m.Stop()
|
|
assert.ErrorIs(t, err, ErrNilSubsystem)
|
|
|
|
m, err = setupWebsocketRoutineManager(NewExchangeManager(), &OrderManager{}, &SyncManager{}, ¤cy.Config{CurrencyPairFormat: ¤cy.PairFormat{}}, false)
|
|
assert.NoError(t, err)
|
|
|
|
err = m.Stop()
|
|
assert.ErrorIs(t, err, ErrSubSystemNotStarted)
|
|
|
|
err = m.Start()
|
|
assert.NoError(t, err)
|
|
|
|
err = m.Stop()
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestWebsocketRoutineManagerHandleData(t *testing.T) {
|
|
exchName := "Bitstamp"
|
|
var wg sync.WaitGroup
|
|
em := NewExchangeManager()
|
|
exch, err := em.NewExchangeByName(exchName)
|
|
require.NoError(t, err)
|
|
|
|
exch.SetDefaults()
|
|
err = em.Add(exch)
|
|
require.NoError(t, err)
|
|
|
|
om, err := SetupOrderManager(em, &CommunicationManager{}, &wg, &config.OrderManager{})
|
|
assert.NoError(t, err)
|
|
|
|
err = om.Start()
|
|
assert.NoError(t, err)
|
|
|
|
cfg := ¤cy.Config{CurrencyPairFormat: ¤cy.PairFormat{
|
|
Uppercase: false,
|
|
Delimiter: "-",
|
|
}}
|
|
m, err := setupWebsocketRoutineManager(em, om, &SyncManager{}, cfg, true)
|
|
assert.NoError(t, err)
|
|
|
|
err = m.Start()
|
|
assert.NoError(t, err)
|
|
|
|
orderID := "1337"
|
|
err = m.websocketDataHandler(exchName, errors.New("error"))
|
|
if err == nil {
|
|
t.Error("Error not handled correctly")
|
|
}
|
|
err = m.websocketDataHandler(exchName, websocket.FundingData{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = m.websocketDataHandler(exchName, &ticker.Price{
|
|
ExchangeName: exchName,
|
|
Pair: currency.NewPair(currency.BTC, currency.USDC),
|
|
AssetType: asset.Spot,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
err = m.websocketDataHandler(exchName, websocket.KlineData{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
origOrder := &order.Detail{
|
|
Exchange: exchName,
|
|
OrderID: orderID,
|
|
Amount: 1337,
|
|
Price: 1337,
|
|
}
|
|
err = m.websocketDataHandler(exchName, origOrder)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
// Send it again since it exists now
|
|
err = m.websocketDataHandler(exchName, &order.Detail{
|
|
Exchange: exchName,
|
|
OrderID: orderID,
|
|
Amount: 1338,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
updated, err := m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.OrderID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if updated.Amount != 1338 {
|
|
t.Error("Bad pipeline")
|
|
}
|
|
|
|
err = m.websocketDataHandler(exchName, &order.Detail{
|
|
Exchange: "Bitstamp",
|
|
OrderID: orderID,
|
|
Status: order.Active,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
updated, err = m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.OrderID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if updated.Status != order.Active {
|
|
t.Error("Expected order to be modified to Active")
|
|
}
|
|
|
|
// Send some gibberish
|
|
err = m.websocketDataHandler(exchName, order.Stop)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = m.websocketDataHandler(exchName, websocket.UnhandledMessageWarning{
|
|
Message: "there's an issue here's a tissue",
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
classificationError := order.ClassificationError{
|
|
Exchange: "test",
|
|
OrderID: "one",
|
|
Err: errors.New("lol"),
|
|
}
|
|
err = m.websocketDataHandler(exchName, classificationError)
|
|
if err == nil {
|
|
t.Error("Expected error")
|
|
}
|
|
assert.ErrorIs(t, err, classificationError.Err)
|
|
|
|
err = m.websocketDataHandler(exchName, &orderbook.Book{
|
|
Exchange: "Bitstamp",
|
|
Pair: currency.NewBTCUSD(),
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = m.websocketDataHandler(exchName, "this is a test string")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestRegisterWebsocketDataHandlerWithFunctionality(t *testing.T) {
|
|
t.Parallel()
|
|
var m *WebsocketRoutineManager
|
|
err := m.registerWebsocketDataHandler(nil, false)
|
|
require.ErrorIs(t, err, ErrNilSubsystem)
|
|
|
|
m = new(WebsocketRoutineManager)
|
|
m.shutdown = make(chan struct{})
|
|
|
|
err = m.registerWebsocketDataHandler(nil, false)
|
|
require.ErrorIs(t, err, errNilWebsocketDataHandlerFunction)
|
|
|
|
// externally defined capture device
|
|
dataChan := make(chan any)
|
|
fn := func(_ string, data any) error {
|
|
switch data.(type) {
|
|
case string:
|
|
dataChan <- data
|
|
default:
|
|
}
|
|
return nil
|
|
}
|
|
|
|
err = m.registerWebsocketDataHandler(fn, true)
|
|
require.NoError(t, err)
|
|
|
|
if len(m.dataHandlers) != 1 {
|
|
t.Fatal("unexpected data handlers registered")
|
|
}
|
|
|
|
mock := websocket.NewManager()
|
|
mock.ToRoutine = make(chan any)
|
|
m.state = readyState
|
|
err = m.websocketDataReceiver(mock)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mock.ToRoutine <- nil
|
|
mock.ToRoutine <- 1336
|
|
mock.ToRoutine <- "intercepted"
|
|
|
|
if r := <-dataChan; r != "intercepted" {
|
|
t.Fatal("unexpected value received")
|
|
}
|
|
|
|
close(m.shutdown)
|
|
m.wg.Wait()
|
|
}
|
|
|
|
func TestSetWebsocketDataHandler(t *testing.T) {
|
|
t.Parallel()
|
|
var m *WebsocketRoutineManager
|
|
err := m.setWebsocketDataHandler(nil)
|
|
require.ErrorIs(t, err, ErrNilSubsystem)
|
|
|
|
m = new(WebsocketRoutineManager)
|
|
m.shutdown = make(chan struct{})
|
|
|
|
err = m.setWebsocketDataHandler(nil)
|
|
require.ErrorIs(t, err, errNilWebsocketDataHandlerFunction)
|
|
|
|
err = m.registerWebsocketDataHandler(m.websocketDataHandler, false)
|
|
require.NoError(t, err)
|
|
|
|
err = m.registerWebsocketDataHandler(m.websocketDataHandler, false)
|
|
require.NoError(t, err)
|
|
|
|
err = m.registerWebsocketDataHandler(m.websocketDataHandler, false)
|
|
require.NoError(t, err)
|
|
|
|
if len(m.dataHandlers) != 3 {
|
|
t.Fatal("unexpected data handler count")
|
|
}
|
|
|
|
err = m.setWebsocketDataHandler(m.websocketDataHandler)
|
|
require.NoError(t, err)
|
|
|
|
if len(m.dataHandlers) != 1 {
|
|
t.Fatal("unexpected data handler count")
|
|
}
|
|
}
|