diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go
index 854d7a46761..73132ce356f 100644
--- a/exchanges/bitfinex/bitfinex_test.go
+++ b/exchanges/bitfinex/bitfinex_test.go
@@ -25,6 +25,7 @@ import (
 	"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
 	"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
 	"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
+	"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"
 	"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
@@ -1107,8 +1108,8 @@ func TestGetDepositAddress(t *testing.T) {
 	}
 }
 
-// TestWsAuth dials websocket, sends login request.
-func TestWsAuth(t *testing.T) {
+// TestWSAuth dials websocket, sends login request.
+func TestWSAuth(t *testing.T) {
 	if !b.Websocket.IsEnabled() {
 		t.Skip(stream.ErrWebsocketNotEnabled.Error())
 	}
@@ -1172,9 +1173,9 @@ func TestGenerateSubscriptions(t *testing.T) {
 	testsubs.EqualLists(t, exp, subs)
 }
 
-// TestWsSubscribe tests Subscribe and Unsubscribe functionality
+// TestWSSubscribe tests Subscribe and Unsubscribe functionality
 // See also TestSubscribeReq which covers key and symbol conversion
-func TestWsSubscribe(t *testing.T) {
+func TestWSSubscribe(t *testing.T) {
 	b := new(Bitfinex) //nolint:govet // Intentional shadow of b to avoid future copy/paste mistakes
 	require.NoError(t, testexch.Setup(b), "TestInstance must not error")
 	testexch.SetupWs(t, b)
@@ -1258,8 +1259,8 @@ func TestSubToMap(t *testing.T) {
 	assert.Equal(t, "tBTCLTC", r["symbol"], "symbol should not use colon delimiter if both currencies < 3 chars")
 }
 
-// TestWsPlaceOrder dials websocket, sends order request.
-func TestWsPlaceOrder(t *testing.T) {
+// TestWSPlaceOrder dials websocket, sends order request.
+func TestWSPlaceOrder(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 
@@ -1275,8 +1276,8 @@ func TestWsPlaceOrder(t *testing.T) {
 	}
 }
 
-// TestWsCancelOrder dials websocket, sends cancel request.
-func TestWsCancelOrder(t *testing.T) {
+// TestWSCancelOrder dials websocket, sends cancel request.
+func TestWSCancelOrder(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	if err := b.WsCancelOrder(1234); err != nil {
@@ -1284,8 +1285,8 @@ func TestWsCancelOrder(t *testing.T) {
 	}
 }
 
-// TestWsCancelOrder dials websocket, sends modify request.
-func TestWsUpdateOrder(t *testing.T) {
+// TestWSCancelOrder dials websocket, sends modify request.
+func TestWSUpdateOrder(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	err := b.WsModifyOrder(&WsUpdateOrderRequest{
@@ -1298,8 +1299,8 @@ func TestWsUpdateOrder(t *testing.T) {
 	}
 }
 
-// TestWsCancelAllOrders dials websocket, sends cancel all request.
-func TestWsCancelAllOrders(t *testing.T) {
+// TestWSCancelAllOrders dials websocket, sends cancel all request.
+func TestWSCancelAllOrders(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	if err := b.WsCancelAllOrders(); err != nil {
@@ -1307,8 +1308,8 @@ func TestWsCancelAllOrders(t *testing.T) {
 	}
 }
 
-// TestWsCancelAllOrders dials websocket, sends cancel all request.
-func TestWsCancelMultiOrders(t *testing.T) {
+// TestWSCancelAllOrders dials websocket, sends cancel all request.
+func TestWSCancelMultiOrders(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	err := b.WsCancelMultiOrders([]int64{1, 2, 3, 4})
@@ -1317,8 +1318,8 @@ func TestWsCancelMultiOrders(t *testing.T) {
 	}
 }
 
-// TestWsNewOffer dials websocket, sends new offer request.
-func TestWsNewOffer(t *testing.T) {
+// TestWSNewOffer dials websocket, sends new offer request.
+func TestWSNewOffer(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	err := b.WsNewOffer(&WsNewOfferRequest{
@@ -1333,8 +1334,8 @@ func TestWsNewOffer(t *testing.T) {
 	}
 }
 
-// TestWsCancelOffer dials websocket, sends cancel offer request.
-func TestWsCancelOffer(t *testing.T) {
+// TestWSCancelOffer dials websocket, sends cancel offer request.
+func TestWSCancelOffer(t *testing.T) {
 	sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
 	testexch.SetupWs(t, b)
 	if err := b.WsCancelOffer(1234); err != nil {
@@ -1342,7 +1343,7 @@ func TestWsCancelOffer(t *testing.T) {
 	}
 }
 
-func TestWsSubscribedResponse(t *testing.T) {
+func TestWSSubscribedResponse(t *testing.T) {
 	ch, err := b.Websocket.Match.Set("subscribe:waiter1", 1)
 	assert.NoError(t, err, "Setting a matcher should not error")
 	err = b.wsHandleData([]byte(`{"event":"subscribed","channel":"ticker","chanId":224555,"subId":"waiter1","symbol":"tBTCUSD","pair":"BTCUSD"}`))
@@ -1364,7 +1365,7 @@ func TestWsSubscribedResponse(t *testing.T) {
 	}
 }
 
-func TestWsOrderBook(t *testing.T) {
+func TestWSOrderBook(t *testing.T) {
 	err := b.Websocket.AddSubscriptions(b.Websocket.Conn, &subscription.Subscription{Key: 23405, Asset: asset.Spot, Pairs: currency.Pairs{btcusdPair}, Channel: subscription.OrderbookChannel})
 	require.NoError(t, err, "AddSubscriptions must not error")
 	pressXToJSON := `[23405,[[38334303613,9348.8,0.53],[38334308111,9348.8,5.98979404],[38331335157,9344.1,1.28965787],[38334302803,9343.8,0.08230094],[38334279092,9343,0.8],[38334307036,9342.938663676,0.8],[38332749107,9342.9,0.2],[38332277330,9342.8,0.85],[38329406786,9342,0.1432012],[38332841570,9341.947288638,0.3],[38332163238,9341.7,0.3],[38334303384,9341.6,0.324],[38332464840,9341.4,0.5],[38331935870,9341.2,0.5],[38334312082,9340.9,0.02126899],[38334261292,9340.8,0.26763],[38334138680,9340.625455254,0.12],[38333896802,9339.8,0.85],[38331627527,9338.9,1.57863959],[38334186713,9338.9,0.26769],[38334305819,9338.8,2.999],[38334211180,9338.75285796,3.999],[38334310699,9337.8,0.10679883],[38334307414,9337.5,1],[38334179822,9337.1,0.26773],[38334306600,9336.659955102,1.79],[38334299667,9336.6,1.1],[38334306452,9336.6,0.13979771],[38325672859,9336.3,1.25],[38334311646,9336.2,1],[38334258509,9336.1,0.37],[38334310592,9336,1.79],[38334310378,9335.6,1.43],[38334132444,9335.2,0.26777],[38331367325,9335,0.07],[38334310703,9335,0.10680562],[38334298209,9334.7,0.08757301],[38334304857,9334.456899462,0.291],[38334309940,9334.088390727,0.0725],[38334310377,9333.7,1.2868],[38334297615,9333.607784,0.1108],[38334095188,9333.3,0.26785],[38334228913,9332.7,0.40861186],[38334300526,9332.363996604,0.3884],[38334310701,9332.2,0.10680562],[38334303548,9332.005382871,0.07],[38334311798,9331.8,0.41285228],[38334301012,9331.7,1.7952],[38334089877,9331.4,0.2679],[38321942150,9331.2,0.2],[38334310670,9330,1.069],[38334063096,9329.6,0.26796],[38334310700,9329.4,0.10680562],[38334310404,9329.3,1],[38334281630,9329.1,6.57150597],[38334036864,9327.7,0.26801],[38334310702,9326.6,0.10680562],[38334311799,9326.1,0.50220625],[38334164163,9326,0.219638],[38334309722,9326,1.5],[38333051682,9325.8,0.26807],[38334302027,9325.7,0.75],[38334203435,9325.366592,0.32397696],[38321967613,9325,0.05],[38334298787,9324.9,0.3],[38334301719,9324.8,3.6227592],[38331316716,9324.763454646,0.71442],[38334310698,9323.8,0.10680562],[38334035499,9323.7,0.23431017],[38334223472,9322.670551788,0.42150603],[38334163459,9322.560399006,0.143967],[38321825171,9320.8,2],[38334075805,9320.467496148,0.30772633],[38334075800,9319.916732238,0.61457592],[38333682302,9319.7,0.0011],[38331323088,9319.116771762,0.12913],[38333677480,9319,0.0199],[38334277797,9318.6,0.89],[38325235155,9318.041088,1.20249],[38334310910,9317.82382938,1.79],[38334311811,9317.2,0.61079138],[38334311812,9317.2,0.71937652],[38333298214,9317.1,50],[38334306359,9317,1.79],[38325531545,9316.382823951,0.21263],[38333727253,9316.3,0.02316372],[38333298213,9316.1,45],[38333836479,9316,2.135],[38324520465,9315.9,2.7681],[38334307411,9315.5,1],[38330313617,9315.3,0.84455],[38334077770,9315.294024,0.01248397],[38334286663,9315.294024,1],[38325533762,9315.290315394,2.40498],[38334310018,9315.2,3],[38333682617,9314.6,0.0011],[38334304794,9314.6,0.76364676],[38334304798,9314.3,0.69242113],[38332915733,9313.8,0.0199],[38334084411,9312.8,1],[38334311893,9350.1,-1.015],[38334302734,9350.3,-0.26737],[38334300732,9350.8,-5.2],[38333957619,9351,-0.90677089],[38334300521,9351,-1.6457],[38334301600,9351.012829557,-0.0523],[38334308878,9351.7,-2.5],[38334299570,9351.921544,-0.1015],[38334279367,9352.1,-0.26732],[38334299569,9352.411802928,-0.4036],[38334202773,9353.4,-0.02139404],[38333918472,9353.7,-1.96412776],[38334278782,9354,-0.26731],[38334278606,9355,-1.2785],[38334302105,9355.439221251,-0.79191542],[38313897370,9355.569409242,-0.43363],[38334292995,9355.584296,-0.0979],[38334216989,9355.8,-0.03686414],[38333894025,9355.9,-0.26721],[38334293798,9355.936691952,-0.4311],[38331159479,9356,-0.4204022],[38333918888,9356.1,-1.10885563],[38334298205,9356.4,-0.20124428],[38328427481,9356.5,-0.1],[38333343289,9356.6,-0.41034213],[38334297205,9356.6,-0.08835018],[38334277927,9356.741101161,-0.0737],[38334311645,9356.8,-0.5],[38334309002,9356.9,-5],[38334309736,9357,-0.10680107],[38334306448,9357.4,-0.18645275],[38333693302,9357.7,-0.2672],[38332815159,9357.8,-0.0011],[38331239824,9358.2,-0.02],[38334271608,9358.3,-2.999],[38334311971,9358.4,-0.55],[38333919260,9358.5,-1.9972841],[38334265365,9358.5,-1.7841],[38334277960,9359,-3],[38334274601,9359.020969848,-3],[38326848839,9359.1,-0.84],[38334291080,9359.247048,-0.16199869],[38326848844,9359.4,-1.84],[38333680200,9359.6,-0.26713],[38331326606,9359.8,-0.84454],[38334309738,9359.8,-0.10680107],[38331314707,9359.9,-0.2],[38333919803,9360.9,-1.41177599],[38323651149,9361.33417827,-0.71442],[38333656906,9361.5,-0.26705],[38334035500,9361.5,-0.40861586],[38334091886,9362.4,-6.85940815],[38334269617,9362.5,-4],[38323629409,9362.545858872,-2.40497],[38334309737,9362.7,-0.10680107],[38334312380,9362.7,-3],[38325280830,9362.8,-1.75123],[38326622800,9362.8,-1.05145],[38333175230,9363,-0.0011],[38326848745,9363.2,-0.79],[38334308960,9363.206775564,-0.12],[38333920234,9363.3,-1.25318113],[38326848843,9363.4,-1.29],[38331239823,9363.4,-0.02],[38333209613,9363.4,-0.26719],[38334299964,9364,-0.05583123],[38323470224,9364.161816648,-0.12912],[38334284711,9365,-0.21346019],[38334299594,9365,-2.6757062],[38323211816,9365.073132585,-0.21262],[38334312456,9365.1,-0.11167861],[38333209612,9365.2,-0.26719],[38327770474,9365.3,-0.0073],[38334298788,9365.3,-0.3],[38334075803,9365.409831204,-0.30772637],[38334309740,9365.5,-0.10680107],[38326608767,9365.7,-2.76809],[38333920657,9365.7,-1.25848083],[38329594226,9366.6,-0.02587],[38334311813,9366.7,-4.72290945],[38316386301,9367.39258128,-2.37581],[38334302026,9367.4,-4.5],[38334228915,9367.9,-0.81725458],[38333921381,9368.1,-1.72213641],[38333175678,9368.2,-0.0011],[38334301150,9368.2,-2.654604],[38334297208,9368.3,-0.78036466],[38334309739,9368.3,-0.10680107],[38331227515,9368.7,-0.02],[38331184470,9369,-0.003975],[38334203436,9369.319616,-0.32397695],[38334269964,9369.7,-0.5],[38328386732,9370,-4.11759935],[38332719555,9370,-0.025],[38333921935,9370.5,-1.2224398],[38334258511,9370.5,-0.35],[38326848842,9370.8,-0.34],[38333985038,9370.9,-0.8551502],[38334283018,9370.9,-1],[38326848744,9371,-1.34]],5]`
@@ -1382,17 +1383,74 @@ func TestWsOrderBook(t *testing.T) {
 	assert.ErrorIs(t, err, errNoSeqNo, "handleWSBookUpdate should send correct error")
 }
 
-func TestWsTradeResponse(t *testing.T) {
+func TestWSTrades(t *testing.T) {
+	t.Parallel()
+
+	b := new(Bitfinex) //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
+	require.NoError(t, testexch.Setup(b), "Test instance Setup must not error")
 	err := b.Websocket.AddSubscriptions(b.Websocket.Conn, &subscription.Subscription{Asset: asset.Spot, Pairs: currency.Pairs{btcusdPair}, Channel: subscription.AllTradesChannel, Key: 18788})
 	require.NoError(t, err, "AddSubscriptions must not error")
-	pressXToJSON := `[18788,[[412685577,1580268444802,11.1998,176.3],[412685575,1580268444802,5,176.29952759],[412685574,1580268374717,1.99069999,176.41],[412685573,1580268374717,1.00930001,176.41],[412685572,1580268358760,0.9907,176.47],[412685571,1580268324362,0.5505,176.44],[412685570,1580268297270,-0.39040819,176.39],[412685568,1580268297270,-0.39780162,176.46475676],[412685567,1580268283470,-0.09,176.41],[412685566,1580268256536,-2.31310783,176.48],[412685565,1580268256536,-0.59669217,176.49],[412685564,1580268256536,-0.9902,176.49],[412685562,1580268194474,0.9902,176.55],[412685561,1580268186215,0.1,176.6],[412685560,1580268185964,-2.17096773,176.5],[412685559,1580268185964,-1.82903227,176.51],[412685558,1580268181215,2.098914,176.53],[412685557,1580268169844,16.7302,176.55],[412685556,1580268169844,3.25,176.54],[412685555,1580268155725,0.23576115,176.45],[412685553,1580268155725,3,176.44596249],[412685552,1580268155725,3.25,176.44],[412685551,1580268155725,5,176.44],[412685550,1580268155725,0.65830078,176.41],[412685549,1580268155725,0.45063807,176.41],[412685548,1580268153825,-0.67604704,176.39],[412685547,1580268145713,2.5883,176.41],[412685543,1580268087513,12.92927,176.33],[412685542,1580268087513,0.40083,176.33],[412685533,1580268005756,-0.17096773,176.32]]]`
-	err = b.wsHandleData([]byte(pressXToJSON))
-	if err != nil {
-		t.Error(err)
+	testexch.FixtureToDataHandler(t, "testdata/wsAllTrades.json", b.wsHandleData)
+	close(b.Websocket.DataHandler)
+	exp := []trade.Data{{
+		TID:          "412685577",
+		Exchange:     b.Name,
+		CurrencyPair: btcusdPair,
+		AssetType:    asset.Spot,
+		Side:         order.Buy,
+		Timestamp:    time.UnixMicro(1580268444802000).UTC(),
+		Amount:       11.11998,
+		Price:        176.3,
+	}}
+	require.Len(t, b.Websocket.DataHandler, len(exp), "Must see correct number of trades")
+	for resp := range b.Websocket.DataHandler {
+		switch v := resp.(type) {
+		case *trade.Data:
+			i := 7 - len(b.Websocket.DataHandler)
+			require.Equalf(t, exp[i], v, "Trade [%d] should be correct", i)
+			/*
+				case 0:
+					assert.Equal(t, asset.Spot, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+					assert.Equal(t, "412685577", v.TID, "TID should be correct for a trade update")
+					assert.Equal(t, ), v.Timestamp, "Timestamp should be correct for a trade update")
+					assert.Equal(t, 11.1998, v.Amount, "Amount should be correct")
+					assert.Equal(t, 176.3, v.Price, "Price should be correct")
+				case 3:
+					assert.Equal(t, asset.MarginFunding, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+					assert.Equal(t, "412685534", v.TID, "TID should be correct for a funding trade update")
+					assert.Equal(t, time.UnixMicro(1580268005757000).UTC(), v.Timestamp, "Timestamp should be correct for a funding trade update")
+					assert.Equal(t, 4.2, v.Amount, "Amount should be correct for a funding trade update")
+					assert.Equal(t, 0.1244, v.Price, "Price should be correct for a funding trade update")
+				case 4:
+					assert.Equal(t, asset.Spot, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+					assert.Equal(t, "1690221201", v.TID, "TID should be correct for a funding trade update")
+					assert.Equal(t, time.UnixMicro(1734237017719).UTC(), v.Timestamp, "Timestamp should be correct for a funding trade update")
+					assert.Equal(t, 4.2, v.Amount, "Amount should be correct for a funding trade update")
+					assert.Equal(t, 0.1244, v.Price, "Price should be correct for a funding trade update")
+				case 5:
+					assert.Equal(t, asset.Spot, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+					assert.Equal(t, 0.1244, v.Price, "Price should be correct for a funding trade update")
+				case 6:
+					assert.Equal(t, asset.MarginFunding, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+					assert.Equal(t, 0.1244, v.Price, "Price should be correct for a funding trade update")
+				case 7:
+					assert.Equal(t, asset.MarginFunding, v.AssetType, "AssetType should be correct")
+					assert.Equal(t, btcusdPair, v.CurrencyPair, "Pair should be correct")
+			*/
+		case error:
+			t.Error(v)
+		default:
+			t.Errorf("Unexpected type in DataHandler: %T (%s)", v, v)
+		}
 	}
 }
 
-func TestWsTickerResponse(t *testing.T) {
+func TestWSTickerResponse(t *testing.T) {
 	err := b.Websocket.AddSubscriptions(b.Websocket.Conn, &subscription.Subscription{Asset: asset.Spot, Pairs: currency.Pairs{btcusdPair}, Channel: subscription.TickerChannel, Key: 11534})
 	require.NoError(t, err, "AddSubscriptions must not error")
 	pressXToJSON := `[11534,[61.304,2228.36155358,61.305,1323.2442970500003,0.395,0.0065,61.371,50973.3020771,62.5,57.421]]`
@@ -1435,7 +1493,7 @@ func TestWsTickerResponse(t *testing.T) {
 	}
 }
 
-func TestWsCandleResponse(t *testing.T) {
+func TestWSCandleResponse(t *testing.T) {
 	err := b.Websocket.AddSubscriptions(b.Websocket.Conn, &subscription.Subscription{Asset: asset.Spot, Pairs: currency.Pairs{btcusdPair}, Channel: subscription.CandlesChannel, Key: 343351})
 	require.NoError(t, err, "AddSubscriptions must not error")
 	pressXToJSON := `[343351,[[1574698260000,7379.785503,7383.8,7388.3,7379.785503,1.68829482]]]`
@@ -1450,7 +1508,7 @@ func TestWsCandleResponse(t *testing.T) {
 	}
 }
 
-func TestWsOrderSnapshot(t *testing.T) {
+func TestWSOrderSnapshot(t *testing.T) {
 	pressXToJSON := `[0,"os",[[34930659963,null,1574955083558,"tETHUSD",1574955083558,1574955083573,0.201104,0.201104,"EXCHANGE LIMIT",null,null,null,0,"ACTIVE",null,null,120,0,0,0,null,null,null,0,0,null,null,null,"BFX",null,null,null]]]`
 	err := b.wsHandleData([]byte(pressXToJSON))
 	if err != nil {
@@ -1463,7 +1521,7 @@ func TestWsOrderSnapshot(t *testing.T) {
 	}
 }
 
-func TestWsNotifications(t *testing.T) {
+func TestWSNotifications(t *testing.T) {
 	pressXToJSON := `[0,"n",[1575282446099,"fon-req",null,null,[41238905,null,null,null,-1000,null,null,null,null,null,null,null,null,null,0.002,2,null,null,null,null,null],null,"SUCCESS","Submitting funding bid of 1000.0 USD at 0.2000 for 2 days."]]`
 	err := b.wsHandleData([]byte(pressXToJSON))
 	if err != nil {
@@ -1477,7 +1535,7 @@ func TestWsNotifications(t *testing.T) {
 	}
 }
 
-func TestWsFundingOfferSnapshotAndUpdate(t *testing.T) {
+func TestWSFundingOfferSnapshotAndUpdate(t *testing.T) {
 	pressXToJSON := `[0,"fos",[[41237920,"fETH",1573912039000,1573912039000,0.5,0.5,"LIMIT",null,null,0,"ACTIVE",null,null,null,0.0024,2,0,0,null,0,null]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
@@ -1489,7 +1547,7 @@ func TestWsFundingOfferSnapshotAndUpdate(t *testing.T) {
 	}
 }
 
-func TestWsFundingCreditSnapshotAndUpdate(t *testing.T) {
+func TestWSFundingCreditSnapshotAndUpdate(t *testing.T) {
 	pressXToJSON := `[0,"fcs",[[26223578,"fUST",1,1575052261000,1575296187000,350,0,"ACTIVE",null,null,null,0,30,1575052261000,1575293487000,0,0,null,0,null,0,"tBTCUST"],[26223711,"fUSD",-1,1575291961000,1575296187000,180,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295587000,0,0,null,0,null,0,"tETHUSD"]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
@@ -1501,7 +1559,7 @@ func TestWsFundingCreditSnapshotAndUpdate(t *testing.T) {
 	}
 }
 
-func TestWsFundingLoanSnapshotAndUpdate(t *testing.T) {
+func TestWSFundingLoanSnapshotAndUpdate(t *testing.T) {
 	pressXToJSON := `[0,"fls",[[2995442,"fUSD",-1,1575291961000,1575295850000,820,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295850000,0,0,null,0,null,0]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
@@ -1513,35 +1571,35 @@ func TestWsFundingLoanSnapshotAndUpdate(t *testing.T) {
 	}
 }
 
-func TestWsWalletSnapshot(t *testing.T) {
+func TestWSWalletSnapshot(t *testing.T) {
 	pressXToJSON := `[0,"ws",[["exchange","SAN",19.76,0,null,null,null]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
 	}
 }
 
-func TestWsBalanceUpdate(t *testing.T) {
+func TestWSBalanceUpdate(t *testing.T) {
 	const pressXToJSON = `[0,"bu",[4131.85,4131.85]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
 	}
 }
 
-func TestWsMarginInfoUpdate(t *testing.T) {
+func TestWSMarginInfoUpdate(t *testing.T) {
 	const pressXToJSON = `[0,"miu",["base",[-13.014640000000007,0,49331.70267297,49318.68803297,27]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
 	}
 }
 
-func TestWsFundingInfoUpdate(t *testing.T) {
+func TestWSFundingInfoUpdate(t *testing.T) {
 	const pressXToJSON = `[0,"fiu",["sym","tETHUSD",[149361.09689202666,149639.26293509,830.0182168075556,895.0658432466332]]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
 	}
 }
 
-func TestWsFundingTrade(t *testing.T) {
+func TestWSFundingTrade(t *testing.T) {
 	pressXToJSON := `[0,"fte",[636854,"fUSD",1575282446000,41238905,-1000,0.002,7,null]]`
 	if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
 		t.Error(err)
diff --git a/exchanges/bitfinex/bitfinex_types.go b/exchanges/bitfinex/bitfinex_types.go
index 69c506ea977..43f74d19b65 100644
--- a/exchanges/bitfinex/bitfinex_types.go
+++ b/exchanges/bitfinex/bitfinex_types.go
@@ -8,13 +8,13 @@ import (
 	"github.com/thrasher-corp/gocryptotrader/common"
 	"github.com/thrasher-corp/gocryptotrader/currency"
 	"github.com/thrasher-corp/gocryptotrader/exchanges/order"
+	"github.com/thrasher-corp/gocryptotrader/types"
 )
 
 var (
 	errSetCannotBeEmpty        = errors.New("set cannot be empty")
 	errNoSeqNo                 = errors.New("no sequence number")
 	errParamNotAllowed         = errors.New("param not allowed")
-	errParsingWSField          = errors.New("error parsing WS field")
 	errTickerInvalidSymbol     = errors.New("invalid ticker symbol")
 	errTickerInvalidResp       = errors.New("invalid ticker response format")
 	errTickerInvalidFieldCount = errors.New("invalid ticker response field count")
@@ -488,16 +488,13 @@ type WebsocketBook struct {
 	Period int64
 }
 
-// WebsocketTrade holds trade information
-type WebsocketTrade struct {
+// WsTrade holds trade information
+type WsTrade struct {
 	ID        int64
-	Timestamp int64
-	Price     float64
+	Timestamp types.Time
 	Amount    float64
-	// Funding rate of the trade
-	Rate float64
-	// Funding offer period in days
-	Period int64
+	Price     float64
+	Period    int64 // Funding offer period in days
 }
 
 // Candle holds OHLC data
@@ -625,7 +622,7 @@ const (
 	wsPositionClose                        = "pc"
 	wsWalletSnapshot                       = "ws"
 	wsWalletUpdate                         = "wu"
-	wsTradeExecutionUpdate                 = "tu"
+	wsTradeUpdated                         = "tu"
 	wsTradeExecuted                        = "te"
 	wsFundingCreditSnapshot                = "fcs"
 	wsFundingCreditNew                     = "fcn"
@@ -636,7 +633,7 @@ const (
 	wsFundingLoanUpdate                    = "flu"
 	wsFundingLoanCancel                    = "flc"
 	wsFundingTradeExecuted                 = "fte"
-	wsFundingTradeUpdate                   = "ftu"
+	wsFundingTradeUpdated                  = "ftu"
 	wsFundingInfoUpdate                    = "fiu"
 	wsBalanceUpdate                        = "bu"
 	wsMarginInfoUpdate                     = "miu"
diff --git a/exchanges/bitfinex/bitfinex_websocket.go b/exchanges/bitfinex/bitfinex_websocket.go
index 74c04afc2d3..933615b12da 100644
--- a/exchanges/bitfinex/bitfinex_websocket.go
+++ b/exchanges/bitfinex/bitfinex_websocket.go
@@ -33,6 +33,11 @@ import (
 	"github.com/thrasher-corp/gocryptotrader/log"
 )
 
+var (
+	errParsingWSField      = errors.New("error parsing WS field")
+	errInvalidWSFieldCount = errors.New("invalid WS field count")
+)
+
 var defaultSubscriptions = subscription.List{
 	{Enabled: true, Channel: subscription.TickerChannel, Asset: asset.All},
 	{Enabled: true, Channel: subscription.AllTradesChannel, Asset: asset.All},
@@ -162,8 +167,8 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
 		eventType, hasEventType := d[1].(string)
 
 		if chanID != 0 {
-			if c := b.Websocket.GetSubscription(chanID); c != nil {
-				return b.handleWSChannelUpdate(c, eventType, d)
+			if s := b.Websocket.GetSubscription(chanID); s != nil {
+				return b.handleWSChannelUpdate(s, respRaw, eventType, d)
 			}
 			if b.Verbose {
 				log.Warnf(log.ExchangeSys, "%s %s; dropped WS message: %s", b.Name, subscription.ErrNotFound, respRaw)
@@ -201,8 +206,8 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
 			return b.handleWSPositionSnapshot(d)
 		case wsPositionNew, wsPositionUpdate, wsPositionClose:
 			return b.handleWSPositionUpdate(d)
-		case wsTradeExecuted, wsTradeExecutionUpdate:
-			return b.handleWSTradeUpdate(d, eventType)
+		case wsTradeExecuted, wsTradeUpdated:
+			return b.handleWSMyTradeUpdate(d, eventType)
 		case wsFundingOfferSnapshot:
 			if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
 				if _, ok := snapBundle[0].([]interface{}); ok {
@@ -398,7 +403,7 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
 					b.Websocket.DataHandler <- fundingInfo
 				}
 			}
-		case wsFundingTradeExecuted, wsFundingTradeUpdate:
+		case wsFundingTradeExecuted, wsFundingTradeUpdated:
 			if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
 				var wsFundingTrade WsFundingTrade
 				tradeID, ok := data[0].(float64)
@@ -544,16 +549,15 @@ func (b *Bitfinex) handleWSSubscribed(respRaw []byte) error {
 	return nil
 }
 
-func (b *Bitfinex) handleWSChannelUpdate(s *subscription.Subscription, eventType string, d []interface{}) error {
+func (b *Bitfinex) handleWSChannelUpdate(s *subscription.Subscription, respRaw []byte, eventType string, d []interface{}) error {
 	if s == nil {
 		return fmt.Errorf("%w: Subscription param", common.ErrNilPointer)
 	}
 
-	if eventType == wsChecksum {
+	switch eventType {
+	case wsChecksum:
 		return b.handleWSChecksum(s, d)
-	}
-
-	if eventType == wsHeartbeat {
+	case wsHeartbeat:
 		return nil
 	}
 
@@ -569,7 +573,7 @@ func (b *Bitfinex) handleWSChannelUpdate(s *subscription.Subscription, eventType
 	case subscription.TickerChannel:
 		return b.handleWSTickerUpdate(s, d)
 	case subscription.AllTradesChannel:
-		return b.handleWSTradesUpdate(s, eventType, d)
+		return b.handleWSTrades(s, respRaw)
 	}
 
 	return fmt.Errorf("%s unhandled channel update: %s", b.Name, s.Channel)
@@ -869,139 +873,102 @@ func (b *Bitfinex) handleWSTickerUpdate(c *subscription.Subscription, d []interf
 	return nil
 }
 
-func (b *Bitfinex) handleWSTradesUpdate(c *subscription.Subscription, eventType string, d []interface{}) error {
-	if c == nil {
+func (b *Bitfinex) handleWSTrades(s *subscription.Subscription, respRaw []byte) error {
+	feedEnabled := b.IsTradeFeedEnabled()
+	if !feedEnabled && !b.IsSaveTradeDataEnabled() {
+		return nil
+	}
+	if s == nil {
 		return fmt.Errorf("%w: Subscription param", common.ErrNilPointer)
 	}
-	if len(c.Pairs) != 1 {
+	if len(s.Pairs) != 1 {
 		return subscription.ErrNotSinglePair
 	}
-	if !b.IsSaveTradeDataEnabled() {
+	if s.Asset == asset.MarginFunding {
 		return nil
 	}
-	if c.Asset == asset.MarginFunding {
-		return nil
+	_, valueType, _, err := jsonparser.Get(respRaw, "[1]")
+	if err != nil {
+		return fmt.Errorf("%w `tradesUpdate[1]`: %w", errParsingWSField, err)
 	}
-	var tradeHolder []WebsocketTrade
-	switch len(d) {
-	case 2:
-		snapshot, ok := d[1].([]interface{})
-		if !ok {
-			return errors.New("unable to type assert trade snapshot data")
-		}
-		for i := range snapshot {
-			elem, ok := snapshot[i].([]interface{})
-			if !ok {
-				return errors.New("unable to type assert trade snapshot element data")
-			}
-			tradeID, ok := elem[0].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade ID")
-			}
-			timestamp, ok := elem[1].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade timestamp")
-			}
-			amount, ok := elem[2].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade amount")
-			}
-			wsTrade := WebsocketTrade{
-				ID:        int64(tradeID),
-				Timestamp: int64(timestamp),
-				Amount:    amount,
-			}
-			if len(elem) == 5 {
-				rate, ok := elem[3].(float64)
-				if !ok {
-					return errors.New("unable to type assert trade rate")
-				}
-				wsTrade.Rate = rate
-				period, ok := elem[4].(float64)
-				if !ok {
-					return errors.New("unable to type assert trade period")
-				}
-				wsTrade.Period = int64(period)
-			} else {
-				price, ok := elem[3].(float64)
-				if !ok {
-					return errors.New("unable to type assert trade price")
-				}
-				wsTrade.Rate = price
-			}
-			tradeHolder = append(tradeHolder, wsTrade)
-		}
-	case 3:
-		if eventType != wsFundingTradeUpdate && eventType != wsTradeExecutionUpdate {
-			return fmt.Errorf("unhandled WS trade update event: %s", eventType)
+	var wsTrades []*WsTrade
+	switch valueType {
+	case jsonparser.String:
+		if t, err := b.handleWSPublicTradeUpdate(respRaw); err != nil {
+			return err
+		} else {
+			wsTrades = []*WsTrade{t}
 		}
-		data, ok := d[2].([]interface{})
-		if !ok {
-			return errors.New("trade data type assertion error")
+	case jsonparser.Array:
+		if wsTrades, err = b.handleWSPublicTradesSnapshot(respRaw); err != nil {
+			return err
 		}
-
-		tradeID, ok := data[0].(float64)
-		if !ok {
-			return errors.New("unable to type assert trade ID")
+	default:
+		return fmt.Errorf("%w `tradesUpdate[1]`: %w `%s`", errParsingWSField, jsonparser.UnknownValueTypeError, valueType)
+	}
+	trades := make([]trade.Data, len(wsTrades))
+	for i, w := range wsTrades {
+		t := trade.Data{
+			Exchange:     b.Name,
+			AssetType:    s.Asset,
+			CurrencyPair: s.Pairs[0],
+			TID:          strconv.FormatInt(w.ID, 10),
+			Timestamp:    w.Timestamp.Time().UTC(),
+			Side:         order.Buy,
+			Amount:       w.Amount,
+			Price:        w.Price,
 		}
-		timestamp, ok := data[1].(float64)
-		if !ok {
-			return errors.New("unable to type assert trade timestamp")
+		if w.Period != 0 {
+			t.AssetType = asset.MarginFunding
 		}
-		amount, ok := data[2].(float64)
-		if !ok {
-			return errors.New("unable to type assert trade amount")
+		if t.Amount < 0 {
+			t.Side = order.Sell
+			t.Amount *= -1
 		}
-		wsTrade := WebsocketTrade{
-			ID:        int64(tradeID),
-			Timestamp: int64(timestamp),
-			Amount:    amount,
+		if feedEnabled {
+			b.Websocket.DataHandler <- &t
 		}
-		if len(data) == 5 {
-			rate, ok := data[3].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade rate")
-			}
-			period, ok := data[4].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade period")
-			}
-			wsTrade.Rate = rate
-			wsTrade.Period = int64(period)
+		trades[i] = t
+	}
+	if b.IsSaveTradeDataEnabled() {
+		err = trade.AddTradesToBuffer(b.GetName(), trades...)
+	}
+	return err
+}
+
+func (b *Bitfinex) handleWSPublicTradesSnapshot(respRaw []byte) (trades []*WsTrade, errs error) {
+	handleTrade := func(v []byte, valueType jsonparser.ValueType, _ int, _ error) {
+		if valueType != jsonparser.Array {
+			errs = common.AppendError(errs, fmt.Errorf("%w `tradesSnapshot[1][*]`: %w `%s`", errParsingWSField, jsonparser.UnknownValueTypeError, valueType))
 		} else {
-			price, ok := data[3].(float64)
-			if !ok {
-				return errors.New("unable to type assert trade price")
+			t := &WsTrade{}
+			if err := json.Unmarshal(v, &[]any{&t.ID, &t.Timestamp, &t.Amount, &t.Price, &t.Period}); err != nil {
+				errs = common.AppendError(errs, fmt.Errorf("%w `tradesSnapshot[1][*]`: %w", errParsingWSField, err))
+			} else {
+				trades = append(trades, t)
 			}
-			wsTrade.Price = price
-		}
-		tradeHolder = append(tradeHolder, wsTrade)
-	}
-	trades := make([]trade.Data, len(tradeHolder))
-	for i := range tradeHolder {
-		side := order.Buy
-		newAmount := tradeHolder[i].Amount
-		if newAmount < 0 {
-			side = order.Sell
-			newAmount *= -1
-		}
-		price := tradeHolder[i].Price
-		if price == 0 && tradeHolder[i].Rate > 0 {
-			price = tradeHolder[i].Rate
-		}
-		trades[i] = trade.Data{
-			TID:          strconv.FormatInt(tradeHolder[i].ID, 10),
-			CurrencyPair: c.Pairs[0],
-			Timestamp:    time.UnixMilli(tradeHolder[i].Timestamp),
-			Price:        price,
-			Amount:       newAmount,
-			Exchange:     b.Name,
-			AssetType:    c.Asset,
-			Side:         side,
 		}
 	}
 
-	return b.AddTradesToBuffer(trades...)
+	if _, err := jsonparser.ArrayEach(respRaw, handleTrade, "[1]"); err != nil {
+		common.AppendError(errs, err)
+	}
+	return
+}
+
+func (b *Bitfinex) handleWSPublicTradeUpdate(respRaw []byte) (*WsTrade, error) {
+	v, valueType, _, err := jsonparser.Get(respRaw, "[2]")
+	if err != nil {
+		return nil, fmt.Errorf("%w `tradesUpdate[2]`: %w", errParsingWSField, err)
+	}
+	if valueType != jsonparser.Array {
+		return nil, fmt.Errorf("%w `tradesUpdate[2]`: %w `%s`", errParsingWSField, jsonparser.UnknownValueTypeError, valueType)
+	}
+	t := &WsTrade{}
+	if err := json.Unmarshal(v, &[]any{&t.ID, &t.Timestamp, &t.Amount, &t.Price, &t.Period}); err != nil {
+		return nil, fmt.Errorf("%w `tradeUpdate[2]`: %w", errParsingWSField, err)
+	}
+	return t, nil
 }
 
 func (b *Bitfinex) handleWSNotification(d []interface{}, respRaw []byte) error {
@@ -1173,7 +1140,7 @@ func (b *Bitfinex) handleWSPositionUpdate(d []interface{}) error {
 	return nil
 }
 
-func (b *Bitfinex) handleWSTradeUpdate(d []interface{}, eventType string) error {
+func (b *Bitfinex) handleWSMyTradeUpdate(d []interface{}, eventType string) error {
 	tradeData, ok := d[2].([]interface{})
 	if !ok {
 		return common.GetTypeAssertError("[]interface{}", d[2], "tradeUpdate")
diff --git a/exchanges/bitfinex/testdata/wsAllTrades.json b/exchanges/bitfinex/testdata/wsAllTrades.json
new file mode 100644
index 00000000000..614a12b5180
--- /dev/null
+++ b/exchanges/bitfinex/testdata/wsAllTrades.json
@@ -0,0 +1,5 @@
+[18788,[[412685577,1580268444802,11.1998,176.3],[412685575,1580268444802,-5,176.29952759],[412685534,1580268005757,4.2,0.1244,12]],1]
+[18788,"te",[1690221201,1734237017719,0.00991467,102550],2]
+[18788,"tu",[1690221198,1734237017704,-0.01925285,102550],3]
+[18788,"fte",[1690221401,1734237018019,0.00991467,102550,30],4]
+[18788,"ftu",[1690221598,1734237018094,-0.01925285,10255030],5]
diff --git a/testdata/configtest.json b/testdata/configtest.json
index 04f87dc7cc6..689de937dc4 100644
--- a/testdata/configtest.json
+++ b/testdata/configtest.json
@@ -647,7 +647,8 @@
     },
     "enabled": {
      "autoPairUpdates": true,
-     "websocketAPI": true
+     "websocketAPI": true,
+     "tradeFeed": true
     }
    },
    "bankAccounts": [