BTC Markets: Fix sending trades to the websocket DataHandler (#1847)

* Fix websocket trade streaming

* Fix lint

* Rename trade.Data var

* Update wsTrade side type

* Add test for the invalid side

* Test the side
This commit is contained in:
Bea
2025-03-25 12:20:54 +07:00
committed by GitHub
parent e5a238aa9d
commit 9a6e230e40
5 changed files with 82 additions and 24 deletions

View File

@@ -20,6 +20,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
)
@@ -542,18 +543,53 @@ func TestWsTicker(t *testing.T) {
}
}
func TestWsTrade(t *testing.T) {
pressXToJSON := []byte(` { "marketId": "BTC-AUD",
"timestamp": "2019-04-08T20:54:27.632Z",
"tradeId": 3153171493,
"price": "7370.11",
"volume": "0.10901605",
"side": "Ask",
"messageType": "trade"
}`)
err := b.wsHandleData(pressXToJSON)
if err != nil {
t.Error(err)
func TestWSTrade(t *testing.T) {
t.Parallel()
b := new(BTCMarkets) //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
require.NoError(t, testexch.Setup(b), "Test instance Setup must not error")
fErrs := testexch.FixtureToDataHandlerWithErrors(t, "testdata/wsAllTrades.json", b.wsHandleData)
require.Equal(t, 2, len(fErrs), "Must get correct number of errors from wsHandleData")
assert.ErrorIs(t, fErrs[0].Err, order.ErrSideIsInvalid, "Side.UnmarshalJSON errors should propagate correctly")
assert.ErrorContains(t, fErrs[0].Err, "WRONG", "Side.UnmarshalJSON errors should propagate correctly")
assert.ErrorIs(t, fErrs[1].Err, order.ErrSideIsInvalid, "wsHandleData errors should propagate correctly")
assert.ErrorContains(t, fErrs[1].Err, "ANY", "wsHandleData errors should propagate correctly")
close(b.Websocket.DataHandler)
exp := []trade.Data{
{
Exchange: b.Name,
CurrencyPair: currency.NewPairWithDelimiter("BTC", "AUD", currency.DashDelimiter),
Timestamp: time.Date(2025, 3, 13, 8, 27, 55, 691000000, time.UTC),
Price: 131200.34,
Amount: 0.00151228,
Side: order.Buy,
TID: "7006384466",
AssetType: asset.Spot,
},
{
Exchange: b.Name,
CurrencyPair: currency.NewPairWithDelimiter("BTC", "AUD", currency.DashDelimiter),
Timestamp: time.Date(2025, 3, 13, 8, 28, 2, 273000000, time.UTC),
Price: 131065.01,
Amount: 0.05,
Side: order.Sell,
TID: "7006384467",
AssetType: asset.Spot,
},
}
require.Len(t, b.Websocket.DataHandler, 2, "Must see correct number of trades")
for resp := range b.Websocket.DataHandler {
switch v := resp.(type) {
case trade.Data:
i := 1 - len(b.Websocket.DataHandler)
require.Equalf(t, exp[i], v, "Trade[%d] must be correct", i)
case error:
t.Error(v)
default:
t.Errorf("Unexpected type in DataHandler: %T(%s)", v, v)
}
}
}

View File

@@ -4,6 +4,7 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
)
@@ -373,13 +374,13 @@ type WsTick struct {
// WsTrade message received for trade data
type WsTrade struct {
Currency string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
TradeID int64 `json:"tradeId"`
Price float64 `json:"price,string"`
Volume float64 `json:"volume,string"`
Side string `json:"side"`
MessageType string `json:"messageType"`
Currency string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
TradeID int64 `json:"tradeId"`
Price float64 `json:"price,string"`
Volume float64 `json:"volume,string"`
Side order.Side `json:"side"`
MessageType string `json:"messageType"`
}
// WsOrderbook message received for orderbook data

View File

@@ -185,9 +185,12 @@ func (b *BTCMarkets) wsHandleData(respRaw []byte) error {
}
return nil
case tradeEndPoint:
if !b.IsSaveTradeDataEnabled() {
tradeFeed := b.IsTradeFeedEnabled()
saveTradeData := b.IsSaveTradeDataEnabled()
if !saveTradeData && !tradeFeed {
return nil
}
var t WsTrade
err := json.Unmarshal(respRaw, &t)
if err != nil {
@@ -200,11 +203,16 @@ func (b *BTCMarkets) wsHandleData(respRaw []byte) error {
}
side := order.Buy
if t.Side == "Ask" {
switch {
case t.Side.IsLong():
// Nothing to do
case t.Side.IsShort():
side = order.Sell
default:
return fmt.Errorf("%w: `%s`", order.ErrSideIsInvalid, t.Side)
}
return trade.AddTradesToBuffer(trade.Data{
td := trade.Data{
Timestamp: t.Timestamp,
CurrencyPair: p,
AssetType: asset.Spot,
@@ -213,7 +221,14 @@ func (b *BTCMarkets) wsHandleData(respRaw []byte) error {
Amount: t.Volume,
Side: side,
TID: strconv.FormatInt(t.TradeID, 10),
})
}
if tradeFeed {
b.Websocket.DataHandler <- td
}
if saveTradeData {
return trade.AddTradesToBuffer(td)
}
case tick:
var tick WsTick
err := json.Unmarshal(respRaw, &tick)

View File

@@ -0,0 +1,4 @@
{"marketId":"BTC-AUD","timestamp":"2025-03-13T08:27:55.691Z","tradeId":7006384466,"price":"131200.34","volume":"0.00151228","messageType":"trade","side":"Bid"}
{"marketId":"BTC-AUD","timestamp":"2025-03-13T08:28:02.273Z","tradeId":7006384467,"price":"131065.01","volume":"0.05","messageType":"trade","side":"Ask"}
{"marketId":"BTC-AUD","timestamp":"2025-03-13T08:28:02.274Z","tradeId":7006384468,"price":"131065.02","volume":"0.06","messageType":"trade","side":"Wrong"}
{"marketId":"BTC-AUD","timestamp":"2025-03-13T08:28:02.274Z","tradeId":7006384469,"price":"131065.02","volume":"0.06","messageType":"trade","side":"Any"}

View File

@@ -297,7 +297,9 @@
},
"enabled": {
"autoPairUpdates": true,
"websocketAPI": false
"websocketAPI": false,
"saveTradeData": false,
"tradeFeed": true
}
},
"bankAccounts": [