accounts: Move to instance methods, fix races and isolate tests (#1923)

* Bybit: Fix race in TestUpdateAccountInfo and  TestWSHandleData

* DriveBy rename TestWSHandleData
* This doesn't address running with -race=2+ due to the singleton

* Accounts: Add account.GetService()

* exchange: Assertify TestSetupDefaults

* Exchanges: Add account.Service override for testing

* Exchanges: Remove duplicate IsWebsocketEnabled test from TestSetupDefaults

* Dispatch: Replace nil checks with NilGuard

* Engine: Remove deprecated printAccountHoldingsChangeSummary

* Dispatcher: Add EnsureRunning method

* Accounts: Move singleton accounts service to exchange Accounts

* Move singleton accounts service to exchange Accounts

This maintains the concept of a global store, whilst allowing exchanges
to override it when needed, particularly for testing.

APIServer:

* Remove getAllActiveAccounts from apiserver

Deprecated apiserver only thing using this, so remove it instead of
updating it

* Update comment for UpdateAccountBalances everywhere

* Docs: Add punctuation to function comments

* Bybit: Coverage for wsProcessWalletPushData Save
This commit is contained in:
Gareth Kirwan
2025-10-28 09:52:45 +07:00
committed by GitHub
parent bda9bbec66
commit 73e200e4e7
140 changed files with 3515 additions and 4025 deletions

View File

@@ -223,35 +223,32 @@ func (e *Exchange) GetLoanOrders(ctx context.Context, ccy string) (LoanOrders, e
}
// GetBalances returns balances for your account.
func (e *Exchange) GetBalances(ctx context.Context) (Balance, error) {
func (e *Exchange) GetBalances(ctx context.Context) (map[currency.Code]float64, error) {
var result any
if err := e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, poloniexBalances, url.Values{}, &result); err != nil {
return Balance{}, err
return nil, err
}
data, ok := result.(map[string]any)
if !ok {
return Balance{}, common.GetTypeAssertError("map[string]any", result, "balance result")
return nil, common.GetTypeAssertError("map[string]any", result, "balance result")
}
balance := Balance{
Currency: make(map[string]float64),
}
bals := make(map[currency.Code]float64, len(data))
for x, y := range data {
bal, ok := y.(string)
if !ok {
return Balance{}, common.GetTypeAssertError("string", y, "balance amount")
return nil, common.GetTypeAssertError("string", y, "balance amount")
}
var err error
balance.Currency[x], err = strconv.ParseFloat(bal, 64)
if err != nil {
return Balance{}, err
if bals[currency.NewCode(x)], err = strconv.ParseFloat(bal, 64); err != nil {
return nil, err
}
}
return balance, nil
return bals, nil
}
// GetCompleteBalances returns complete balances from your account.

View File

@@ -12,6 +12,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
@@ -550,7 +551,7 @@ func TestWsAuth(t *testing.T) {
if err != nil {
t.Fatal(err)
}
go e.wsReadData()
go e.wsReadData(t.Context())
creds, err := e.GetCredentials(t.Context())
if err != nil {
t.Fatal(err)
@@ -570,7 +571,7 @@ func TestWsAuth(t *testing.T) {
func TestWsSubAck(t *testing.T) {
pressXToJSON := []byte(`[1002, 1]`)
err := e.wsHandleData(pressXToJSON)
err := e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
@@ -582,7 +583,7 @@ func TestWsTicker(t *testing.T) {
t.Error(err)
}
pressXToJSON := []byte(`[1002, null, [ 50, "382.98901522", "381.99755898", "379.41296309", "-0.04312950", "14969820.94951828", "38859.58435407", 0, "412.25844455", "364.56122072" ] ]`)
err = e.wsHandleData(pressXToJSON)
err = e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
@@ -594,7 +595,7 @@ func TestWsExchangeVolume(t *testing.T) {
t.Error(err)
}
pressXToJSON := []byte(`[1003,null,["2018-11-07 16:26",5804,{"BTC":"3418.409","ETH":"2645.921","USDT":"10832502.689","USDC":"1578020.908"}]]`)
err = e.wsHandleData(pressXToJSON)
err = e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
@@ -607,7 +608,7 @@ func TestWsTrades(t *testing.T) {
t.Error(err)
}
pressXToJSON := []byte(`[14, 8768, [["t", "42706057", 1, "0.05567134", "0.00181421", 1522877119]]]`)
err = e.wsHandleData(pressXToJSON)
err = e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
@@ -619,13 +620,13 @@ func TestWsPriceAggregateOrderbook(t *testing.T) {
t.Error(err)
}
pressXToJSON := []byte(`[50,141160924,[["i",{"currencyPair":"BTC_LTC","orderBook":[{"0.002784":"17.55","0.002786":"1.47","0.002792":"13.25","0.0028":"0.21","0.002804":"0.02","0.00281":"1.5","0.002811":"258.82","0.002812":"3.81","0.002817":"0.06","0.002824":"3","0.002825":"0.02","0.002836":"18.01","0.002837":"0.03","0.00284":"0.03","0.002842":"12.7","0.00285":"0.02","0.002852":"0.02","0.002855":"1.3","0.002857":"15.64","0.002864":"0.01"},{"0.002782":"45.93","0.002781":"1.46","0.002774":"13.34","0.002773":"0.04","0.002771":"0.05","0.002765":"6.21","0.002764":"3","0.00276":"10.77","0.002758":"3.11","0.002754":"0.02","0.002751":"288.94","0.00275":"24.06","0.002745":"187.27","0.002743":"0.04","0.002742":"0.96","0.002731":"0.06","0.00273":"12.13","0.002727":"0.02","0.002725":"0.03","0.002719":"1.09"}]}, "1692080077892"]]]`)
err = e.wsHandleData(pressXToJSON)
err = e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
pressXToJSON = []byte(`[50,141160925,[["o",1,"0.002742","0", "1692080078806"],["o",1,"0.002718","0.02", "1692080078806"]]]`)
err = e.wsHandleData(pressXToJSON)
err = e.wsHandleData(t.Context(), pressXToJSON)
if err != nil {
t.Error(err)
}
@@ -675,23 +676,23 @@ func TestProcessAccountMarginPosition(t *testing.T) {
}
margin := []byte(`[1000,"",[["m", 23432933, 28, "-0.06000000"]]]`)
err = e.wsHandleData(margin)
err = e.wsHandleData(t.Context(), margin)
require.ErrorIs(t, err, errNotEnoughData)
margin = []byte(`[1000,"",[["m", "23432933", 28, "-0.06000000", null]]]`)
err = e.wsHandleData(margin)
err = e.wsHandleData(t.Context(), margin)
require.ErrorIs(t, err, errTypeAssertionFailure)
margin = []byte(`[1000,"",[["m", 23432933, "28", "-0.06000000", null]]]`)
err = e.wsHandleData(margin)
err = e.wsHandleData(t.Context(), margin)
require.ErrorIs(t, err, errTypeAssertionFailure)
margin = []byte(`[1000,"",[["m", 23432933, 28, -0.06000000, null]]]`)
err = e.wsHandleData(margin)
err = e.wsHandleData(t.Context(), margin)
require.ErrorIs(t, err, errTypeAssertionFailure)
margin = []byte(`[1000,"",[["m", 23432933, 28, "-0.06000000", null]]]`)
err = e.wsHandleData(margin)
err = e.wsHandleData(t.Context(), margin)
if err != nil {
t.Fatal(err)
}
@@ -704,38 +705,38 @@ func TestProcessAccountPendingOrder(t *testing.T) {
}
pending := []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000","0"]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errNotEnoughData)
pending = []byte(`[1000,"",[["p","431682155857",127,"1000.00000000","1.00000000","0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errTypeAssertionFailure)
pending = []byte(`[1000,"",[["p",431682155857,"127","1000.00000000","1.00000000","0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errTypeAssertionFailure)
pending = []byte(`[1000,"",[["p",431682155857,127,1000.00000000,"1.00000000","0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errTypeAssertionFailure)
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000",1.00000000,"0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errTypeAssertionFailure)
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000",0,null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
require.ErrorIs(t, err, errTypeAssertionFailure)
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000","0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
if err != nil {
t.Fatal(err)
}
// Unmatched pair in system
pending = []byte(`[1000,"",[["p",431682155857,666,"1000.00000000","1.00000000","0",null]]]`)
err = e.wsHandleData(pending)
err = e.wsHandleData(t.Context(), pending)
if err != nil {
t.Fatal(err)
}
@@ -743,45 +744,45 @@ func TestProcessAccountPendingOrder(t *testing.T) {
func TestProcessAccountOrderUpdate(t *testing.T) {
orderUpdate := []byte(`[1000,"",[["o",431682155857,"0.00000000","f"]]]`)
err := e.wsHandleData(orderUpdate)
err := e.wsHandleData(t.Context(), orderUpdate)
require.ErrorIs(t, err, errNotEnoughData)
orderUpdate = []byte(`[1000,"",[["o","431682155857","0.00000000","f",null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
require.ErrorIs(t, err, errTypeAssertionFailure)
orderUpdate = []byte(`[1000,"",[["o",431682155857,0.00000000,"f",null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
require.ErrorIs(t, err, errTypeAssertionFailure)
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000",123,null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
require.ErrorIs(t, err, errTypeAssertionFailure)
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","c",null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
require.ErrorIs(t, err, errNotEnoughData)
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.50000000","c",null,"0.50000000"]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","c",null,"1.00000000"]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.50000000","f",null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","s",null]]]`)
err = e.wsHandleData(orderUpdate)
err = e.wsHandleData(t.Context(), orderUpdate)
if err != nil {
t.Fatal(err)
}
@@ -794,39 +795,39 @@ func TestProcessAccountOrderLimit(t *testing.T) {
}
accountTrade := []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000"]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errNotEnoughData)
accountTrade = []byte(`[1000,"",[["n","127",431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,"431682155857","0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,0,"1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0",1000.00000000,"1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000",1.00000000,"2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000",1234,"1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56",1.00000000,null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = e.wsHandleData(accountTrade)
err = e.wsHandleData(t.Context(), accountTrade)
if err != nil {
t.Fatal(err)
}
@@ -839,59 +840,58 @@ func TestProcessAccountBalanceUpdate(t *testing.T) {
}
balance := []byte(`[1000,"",[["b",243,"e"]]]`)
err = e.wsHandleData(balance)
err = e.wsHandleData(t.Context(), balance)
require.ErrorIs(t, err, errNotEnoughData)
balance = []byte(`[1000,"",[["b","243","e","-1.00000000"]]]`)
err = e.wsHandleData(balance)
err = e.wsHandleData(t.Context(), balance)
require.ErrorIs(t, err, errTypeAssertionFailure)
balance = []byte(`[1000,"",[["b",243,1234,"-1.00000000"]]]`)
err = e.wsHandleData(balance)
err = e.wsHandleData(t.Context(), balance)
require.ErrorIs(t, err, errTypeAssertionFailure)
balance = []byte(`[1000,"",[["b",243,"e",-1.00000000]]]`)
err = e.wsHandleData(balance)
err = e.wsHandleData(t.Context(), balance)
require.ErrorIs(t, err, errTypeAssertionFailure)
ctx := accounts.DeployCredentialsToContext(t.Context(), &accounts.Credentials{Key: "test", Secret: "test"})
balance = []byte(`[1000,"",[["b",243,"e","-1.00000000"]]]`)
err = e.wsHandleData(balance)
if err != nil {
t.Fatal(err)
}
err = e.wsHandleData(ctx, balance)
require.NoError(t, err, "wsHandleData must not error")
}
func TestProcessAccountTrades(t *testing.T) {
accountTrades := []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345"]]]`)
err := e.wsHandleData(accountTrades)
err := e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errNotEnoughData)
accountTrades = []byte(`[1000,"",[["t", "12345", "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, 0.03000000, "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", 0.50000000, "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, 0.00000375, "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, 0.0000037, "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", 12345, "12345", 0.015]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
require.ErrorIs(t, err, errTypeAssertionFailure)
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = e.wsHandleData(accountTrades)
err = e.wsHandleData(t.Context(), accountTrades)
if err != nil {
t.Fatal(err)
}
@@ -899,15 +899,15 @@ func TestProcessAccountTrades(t *testing.T) {
func TestProcessAccountKilledOrder(t *testing.T) {
kill := []byte(`[1000,"",[["k", 1337]]]`)
err := e.wsHandleData(kill)
err := e.wsHandleData(t.Context(), kill)
require.ErrorIs(t, err, errNotEnoughData)
kill = []byte(`[1000,"",[["k", "1337", null]]]`)
err = e.wsHandleData(kill)
err = e.wsHandleData(t.Context(), kill)
require.ErrorIs(t, err, errTypeAssertionFailure)
kill = []byte(`[1000,"",[["k", 1337, null]]]`)
err = e.wsHandleData(kill)
err = e.wsHandleData(t.Context(), kill)
if err != nil {
t.Fatal(err)
}

View File

@@ -144,11 +144,6 @@ type LoanOrders struct {
Demands []LoanOrder `json:"demands"`
}
// Balance holds data for a range of currencies
type Balance struct {
Currency map[string]float64
}
// CompleteBalance contains the complete balance with a btcvalue
type CompleteBalance struct {
Available float64 `json:"available,string"`

View File

@@ -15,8 +15,8 @@ import (
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
@@ -72,7 +72,7 @@ func (e *Exchange) WsConnect() error {
}
e.Websocket.Wg.Add(1)
go e.wsReadData()
go e.wsReadData(ctx)
return nil
}
@@ -103,21 +103,21 @@ func (e *Exchange) loadCurrencyDetails(ctx context.Context) error {
}
// wsReadData handles data from the websocket connection
func (e *Exchange) wsReadData() {
func (e *Exchange) wsReadData(ctx context.Context) {
defer e.Websocket.Wg.Done()
for {
resp := e.Websocket.Conn.ReadMessage()
if resp.Raw == nil {
return
}
err := e.wsHandleData(resp.Raw)
err := e.wsHandleData(ctx, resp.Raw)
if err != nil {
e.Websocket.DataHandler <- fmt.Errorf("%s: %w", e.Name, err)
}
}
}
func (e *Exchange) wsHandleData(respRaw []byte) error {
func (e *Exchange) wsHandleData(ctx context.Context, respRaw []byte) error {
var result any
err := json.Unmarshal(respRaw, &result)
if err != nil {
@@ -185,7 +185,7 @@ func (e *Exchange) wsHandleData(respRaw []byte) error {
return fmt.Errorf("account notification limit order creation: %w", err)
}
case accountNotificationBalanceUpdate:
err = e.processAccountBalanceUpdate(notification)
err = e.processAccountBalanceUpdate(ctx, notification)
if err != nil {
return fmt.Errorf("account notification balance update: %w", err)
}
@@ -585,7 +585,7 @@ func (e *Exchange) Unsubscribe(subs subscription.List) error {
}
func (e *Exchange) manageSubs(ctx context.Context, subs subscription.List, op wsOp) error {
var creds *account.Credentials
var creds *accounts.Credentials
if e.IsWebsocketAuthenticationSupported() {
var err error
creds, err = e.GetCredentials(ctx)
@@ -918,7 +918,7 @@ func (e *Exchange) processAccountOrderLimit(notification []any) error {
return nil
}
func (e *Exchange) processAccountBalanceUpdate(notification []any) error {
func (e *Exchange) processAccountBalanceUpdate(ctx context.Context, notification []any) error {
if len(notification) < 4 {
return errNotEnoughData
}
@@ -927,7 +927,7 @@ func (e *Exchange) processAccountBalanceUpdate(notification []any) error {
if !ok {
return fmt.Errorf("%w currency ID not float64", errTypeAssertionFailure)
}
code, err := e.details.GetCode(currencyID)
curr, err := e.details.GetCode(currencyID)
if err != nil {
return err
}
@@ -946,18 +946,20 @@ func (e *Exchange) processAccountBalanceUpdate(notification []any) error {
return err
}
// TODO: Integrate with exchange account system
// NOTES: This will affect free amount, a rest call might be needed to get
// locked and total amounts periodically.
e.Websocket.DataHandler <- account.Change{
Account: deriveWalletType(walletType),
AssetType: asset.Spot,
Balance: &account.Balance{
Currency: code,
Total: amount,
Free: amount,
},
bal := accounts.Balance{
Currency: curr,
Total: amount,
Free: amount,
}
id := deriveWalletType(walletType)
subAccts := accounts.SubAccounts{accounts.NewSubAccount(asset.Spot, id)}
subAccts[0].Balances.Set(curr, bal)
if err := e.Accounts.Save(ctx, subAccts, true); err != nil {
return err
}
e.Websocket.DataHandler <- subAccts
return nil
}

View File

@@ -13,10 +13,10 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket/buffer"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
@@ -339,43 +339,20 @@ func (e *Exchange) UpdateOrderbook(ctx context.Context, pair currency.Pair, asse
return orderbook.Get(e.Name, pair, assetType)
}
// UpdateAccountInfo retrieves balances for all enabled currencies for the
// Poloniex exchange
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
var response account.Holdings
response.Exchange = e.Name
accountBalance, err := e.GetBalances(ctx)
// UpdateAccountBalances retrieves currency balances
func (e *Exchange) UpdateAccountBalances(ctx context.Context, assetType asset.Item) (accounts.SubAccounts, error) {
resp, err := e.GetBalances(ctx)
if err != nil {
return response, err
return nil, err
}
currencies := make([]account.Balance, 0, len(accountBalance.Currency))
for x, y := range accountBalance.Currency {
currencies = append(currencies, account.Balance{
Currency: currency.NewCode(x),
Total: y,
})
subAccts := accounts.SubAccounts{accounts.NewSubAccount(assetType, "")}
for curr, bal := range resp {
subAccts[0].Balances.Set(curr, accounts.Balance{Total: bal})
}
response.Accounts = append(response.Accounts, account.SubAccount{
AssetType: assetType,
Currencies: currencies,
})
creds, err := e.GetCredentials(ctx)
if err != nil {
return account.Holdings{}, err
}
err = account.Process(&response, creds)
if err != nil {
return account.Holdings{}, err
}
return response, nil
return subAccts, e.Accounts.Save(ctx, subAccts, true)
}
// GetAccountFundingHistory returns funding history, deposits and
// withdrawals
// GetAccountFundingHistory returns funding history, deposits and withdrawals
func (e *Exchange) GetAccountFundingHistory(ctx context.Context) ([]exchange.FundingHistory, error) {
end := time.Now()
walletActivity, err := e.WalletActivity(ctx, end.Add(-time.Hour*24*365), end, "")
@@ -932,10 +909,9 @@ func (e *Exchange) GetOrderHistory(ctx context.Context, req *order.MultiOrderReq
return req.Filter(e.Name, orders), nil
}
// ValidateAPICredentials validates current credentials used for wrapper
// functionality
// ValidateAPICredentials validates current credentials used for wrapper functionality
func (e *Exchange) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
_, err := e.UpdateAccountInfo(ctx, assetType)
_, err := e.UpdateAccountBalances(ctx, assetType)
return e.CheckTransientError(err)
}