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

@@ -16,33 +16,33 @@ import (
)
const (
orderbookFunc = "orderbook"
tickerFunc = "ticker"
exchangesFunc = "exchanges"
pairsFunc = "pairs"
accountInfoFunc = "accountinfo"
depositAddressFunc = "depositaddress"
orderQueryFunc = "orderquery"
orderCancelFunc = "ordercancel"
orderSubmitFunc = "ordersubmit"
withdrawCryptoFunc = "withdrawcrypto"
withdrawFiatFunc = "withdrawfiat"
ohlcvFunc = "ohlcv"
orderbookFunc = "orderbook"
tickerFunc = "ticker"
exchangesFunc = "exchanges"
pairsFunc = "pairs"
accountBalancesFunc = "accountbalances"
depositAddressFunc = "depositaddress"
orderQueryFunc = "orderquery"
orderCancelFunc = "ordercancel"
orderSubmitFunc = "ordersubmit"
withdrawCryptoFunc = "withdrawcrypto"
withdrawFiatFunc = "withdrawfiat"
ohlcvFunc = "ohlcv"
)
var exchangeModule = map[string]objects.Object{
orderbookFunc: &objects.UserFunction{Name: orderbookFunc, Value: ExchangeOrderbook},
tickerFunc: &objects.UserFunction{Name: tickerFunc, Value: ExchangeTicker},
exchangesFunc: &objects.UserFunction{Name: exchangesFunc, Value: ExchangeExchanges},
pairsFunc: &objects.UserFunction{Name: pairsFunc, Value: ExchangePairs},
accountInfoFunc: &objects.UserFunction{Name: accountInfoFunc, Value: ExchangeAccountInfo},
depositAddressFunc: &objects.UserFunction{Name: depositAddressFunc, Value: ExchangeDepositAddress},
orderQueryFunc: &objects.UserFunction{Name: orderQueryFunc, Value: ExchangeOrderQuery},
orderCancelFunc: &objects.UserFunction{Name: orderCancelFunc, Value: ExchangeOrderCancel},
orderSubmitFunc: &objects.UserFunction{Name: orderSubmitFunc, Value: ExchangeOrderSubmit},
withdrawCryptoFunc: &objects.UserFunction{Name: withdrawCryptoFunc, Value: ExchangeWithdrawCrypto},
withdrawFiatFunc: &objects.UserFunction{Name: withdrawFiatFunc, Value: ExchangeWithdrawFiat},
ohlcvFunc: &objects.UserFunction{Name: ohlcvFunc, Value: exchangeOHLCV},
orderbookFunc: &objects.UserFunction{Name: orderbookFunc, Value: ExchangeOrderbook},
tickerFunc: &objects.UserFunction{Name: tickerFunc, Value: ExchangeTicker},
exchangesFunc: &objects.UserFunction{Name: exchangesFunc, Value: ExchangeExchanges},
pairsFunc: &objects.UserFunction{Name: pairsFunc, Value: ExchangePairs},
accountBalancesFunc: &objects.UserFunction{Name: accountBalancesFunc, Value: ExchangeAccountBalances},
depositAddressFunc: &objects.UserFunction{Name: depositAddressFunc, Value: ExchangeDepositAddress},
orderQueryFunc: &objects.UserFunction{Name: orderQueryFunc, Value: ExchangeOrderQuery},
orderCancelFunc: &objects.UserFunction{Name: orderCancelFunc, Value: ExchangeOrderCancel},
orderSubmitFunc: &objects.UserFunction{Name: orderSubmitFunc, Value: ExchangeOrderSubmit},
withdrawCryptoFunc: &objects.UserFunction{Name: withdrawCryptoFunc, Value: ExchangeWithdrawCrypto},
withdrawFiatFunc: &objects.UserFunction{Name: withdrawFiatFunc, Value: ExchangeWithdrawFiat},
ohlcvFunc: &objects.UserFunction{Name: ohlcvFunc, Value: exchangeOHLCV},
}
// ExchangeOrderbook returns orderbook for requested exchange & currencypair
@@ -239,23 +239,23 @@ func ExchangePairs(args ...objects.Object) (objects.Object, error) {
return &r, nil
}
// ExchangeAccountInfo returns account information for requested exchange
func ExchangeAccountInfo(args ...objects.Object) (objects.Object, error) {
// ExchangeAccountBalances returns account balances for requested exchange
func ExchangeAccountBalances(args ...objects.Object) (objects.Object, error) {
if len(args) != 3 {
return nil, objects.ErrWrongNumArguments
}
scriptCtx, ok := objects.ToInterface(args[0]).(*Context)
if !ok {
return nil, constructRuntimeError(1, accountInfoFunc, "*gct.Context", args[0])
return nil, constructRuntimeError(1, accountBalancesFunc, "*gct.Context", args[0])
}
exchangeName, ok := objects.ToString(args[1])
if !ok {
return nil, constructRuntimeError(2, accountInfoFunc, "string", args[1])
return nil, constructRuntimeError(2, accountBalancesFunc, "string", args[1])
}
assetString, ok := objects.ToString(args[2])
if !ok {
return nil, constructRuntimeError(3, accountInfoFunc, "string", args[2])
return nil, constructRuntimeError(3, accountBalancesFunc, "string", args[2])
}
assetType, err := asset.New(assetString)
if err != nil {
@@ -263,25 +263,24 @@ func ExchangeAccountInfo(args ...objects.Object) (objects.Object, error) {
}
ctx := processScriptContext(scriptCtx)
rtnValue, err := wrappers.GetWrapper().
AccountInformation(ctx, exchangeName, assetType)
rtnValue, err := wrappers.GetWrapper().AccountBalances(ctx, exchangeName, assetType)
if err != nil {
return errorResponsef(standardFormatting, err)
}
var funds objects.Array
for x := range rtnValue.Accounts {
for y := range rtnValue.Accounts[x].Currencies {
temp := make(map[string]objects.Object, 3)
temp["name"] = &objects.String{Value: rtnValue.Accounts[x].Currencies[y].Currency.String()}
temp["total"] = &objects.Float{Value: rtnValue.Accounts[x].Currencies[y].Total}
temp["hold"] = &objects.Float{Value: rtnValue.Accounts[x].Currencies[y].Hold}
funds.Value = append(funds.Value, &objects.Map{Value: temp})
for i := range rtnValue {
for curr, bal := range rtnValue[i].Balances {
funds.Value = append(funds.Value, &objects.Map{Value: map[string]objects.Object{
"name": &objects.String{Value: curr.String()},
"total": &objects.Float{Value: bal.Total},
"hold": &objects.Float{Value: bal.Hold},
}})
}
}
data := make(map[string]objects.Object, 2)
data["exchange"] = &objects.String{Value: rtnValue.Exchange}
data["exchange"] = &objects.String{Value: exchangeName}
data["currencies"] = &funds
return &objects.Map{Value: data}, nil
}

View File

@@ -4,7 +4,7 @@ import (
"context"
objects "github.com/d5/tengo/v2"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
)
@@ -189,7 +189,7 @@ func processScriptContext(scriptCtx *Context) context.Context {
otp, _ = objects.ToString(object)
}
ctx = account.DeployCredentialsToContext(ctx, &account.Credentials{
ctx = accounts.DeployCredentialsToContext(ctx, &accounts.Credentials{
Key: key,
Secret: secret,
SubAccount: subAccount,
@@ -199,7 +199,7 @@ func processScriptContext(scriptCtx *Context) context.Context {
})
} else if object = scriptCtx.Value["subaccount"]; object != nil {
subAccount, _ := objects.ToString(object)
ctx = account.DeploySubAccountOverrideToContext(ctx, subAccount)
ctx = accounts.DeploySubAccountOverrideToContext(ctx, subAccount)
}
return ctx
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/gctscript/modules"
@@ -103,16 +103,16 @@ func TestExchangePairs(t *testing.T) {
assert.ErrorIs(t, err, objects.ErrWrongNumArguments)
}
func TestAccountInfo(t *testing.T) {
func TestAccountBalances(t *testing.T) {
t.Parallel()
_, err := ExchangeAccountInfo()
_, err := ExchangeAccountBalances()
assert.ErrorIs(t, err, objects.ErrWrongNumArguments)
_, err = ExchangeAccountInfo(ctx, exch, assetType)
_, err = ExchangeAccountBalances(ctx, exch, assetType)
assert.NoError(t, err)
_, err = ExchangeAccountInfo(ctx, exchError, assetType)
_, err = ExchangeAccountBalances(ctx, exchError, assetType)
assert.NoError(t, err)
}
@@ -391,7 +391,7 @@ func TestSetSubAccount(t *testing.T) {
t.Fatal("should not be nil")
}
subaccount, ok := ctx.Value(account.ContextSubAccountFlag).(string)
subaccount, ok := ctx.Value(accounts.ContextSubAccountFlag).(string)
if !ok {
t.Fatal("wrong type")
}

View File

@@ -5,7 +5,7 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
@@ -35,7 +35,7 @@ type GCTExchange interface {
QueryOrder(ctx context.Context, exch, orderid string, pair currency.Pair, assetType asset.Item) (*order.Detail, error)
SubmitOrder(ctx context.Context, submit *order.Submit) (*order.SubmitResponse, error)
CancelOrder(ctx context.Context, exch, orderid string, pair currency.Pair, item asset.Item) (bool, error)
AccountInformation(ctx context.Context, exch string, assetType asset.Item) (account.Holdings, error)
AccountBalances(ctx context.Context, exch string, assetType asset.Item) (accounts.SubAccounts, error)
DepositAddress(exch, chain string, currencyCode currency.Code) (*deposit.Address, error)
WithdrawalFiatFunds(ctx context.Context, bankAccountID string, request *withdraw.Request) (out string, err error)
WithdrawalCryptoFunds(ctx context.Context, request *withdraw.Request) (out string, err error)