mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-22 23:16:48 +00:00
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:
@@ -18,17 +18,7 @@ import (
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
e = new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatalf("Bybit Setup error: %s", err)
|
||||
}
|
||||
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.API.AuthenticatedWebsocketSupport = true
|
||||
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
}
|
||||
e = testInstance()
|
||||
|
||||
if e.API.AuthenticatedSupport {
|
||||
if _, err := e.FetchAccountType(context.Background()); err != nil {
|
||||
@@ -41,6 +31,21 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func testInstance() *Bybit {
|
||||
e := new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatalf("Bybit Setup error: %s", err)
|
||||
}
|
||||
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.API.AuthenticatedWebsocketSupport = true
|
||||
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func instantiateTradablePairs() {
|
||||
handleError := func(msg string, err error) {
|
||||
if err != nil {
|
||||
|
||||
@@ -18,16 +18,7 @@ import (
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
e = new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatalf("Bybit Setup error: %s", err)
|
||||
}
|
||||
|
||||
e.SetCredentials("mock", "tester", "", "", "", "") // Hack for UpdateAccountInfo test
|
||||
|
||||
if err := testexch.MockHTTPInstance(e); err != nil {
|
||||
log.Fatalf("Bybit MockHTTPInstance error: %s", err)
|
||||
}
|
||||
e = testInstance()
|
||||
|
||||
if err := e.UpdateTradablePairs(context.Background()); err != nil {
|
||||
log.Fatalf("Bybit unable to UpdateTradablePairs: %s", err)
|
||||
@@ -57,3 +48,18 @@ func TestMain(m *testing.M) {
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func testInstance() *Exchange {
|
||||
b := new(Exchange)
|
||||
if err := testexch.Setup(b); err != nil {
|
||||
log.Fatalf("Bybit Setup error: %s", err)
|
||||
}
|
||||
|
||||
b.SetCredentials("mock", "tester", "", "", "", "") // Hack for UpdateAccountBalances test
|
||||
|
||||
if err := testexch.MockHTTPInstance(b); err != nil {
|
||||
log.Fatalf("Bybit MockHTTPInstance error: %s", err)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"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/order/limits"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
||||
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/fill"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
|
||||
@@ -2778,44 +2778,49 @@ func TestGetBrokerEarning(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAccountInfo(t *testing.T) {
|
||||
func TestUpdateAccountBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !mockTests {
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
}
|
||||
|
||||
r, err := e.UpdateAccountInfo(t.Context(), asset.Spot)
|
||||
require.NoError(t, err, "UpdateAccountInfo must not error")
|
||||
require.NotEmpty(t, r, "UpdateAccountInfo must return account info")
|
||||
e := testInstance() //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
|
||||
|
||||
subAccts, err := e.UpdateAccountBalances(t.Context(), asset.Spot)
|
||||
require.NoError(t, err, "UpdateAccountBalances must not error")
|
||||
require.NotEmpty(t, subAccts, "UpdateAccountBalances must return account info")
|
||||
|
||||
if mockTests {
|
||||
require.Len(t, r.Accounts, 1, "Accounts must have 1 item")
|
||||
require.Len(t, r.Accounts[0].Currencies, 3, "Accounts currencies must have 3 currency items")
|
||||
require.Len(t, subAccts, 1, "Accounts must have 1 item")
|
||||
require.Len(t, subAccts[0].Balances, 3, "Accounts currencies must have 3 currency items")
|
||||
|
||||
for x := range r.Accounts[0].Currencies {
|
||||
switch x {
|
||||
case 0:
|
||||
assert.Equal(t, currency.USDC, r.Accounts[0].Currencies[x].Currency, "Currency should be USDC")
|
||||
assert.Equal(t, -30723.63021638, r.Accounts[0].Currencies[x].Total, "Total amount should be correct")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Hold, "Hold amount should be zero")
|
||||
assert.Equal(t, 30723.630216383711792744, r.Accounts[0].Currencies[x].Borrowed, "Borrowed amount should be correct")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Free, "Free amount should be zero")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be zero")
|
||||
case 1:
|
||||
assert.Equal(t, currency.AVAX, r.Accounts[0].Currencies[x].Currency, "Currency should be AVAX")
|
||||
assert.Equal(t, 2473.9, r.Accounts[0].Currencies[x].Total, "Total amount should be correct")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Hold, "Hold amount should be zero")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Borrowed, "Borrowed amount should be zero")
|
||||
assert.Equal(t, 2473.9, r.Accounts[0].Currencies[x].Free, "Free amount should be correct")
|
||||
assert.Equal(t, 1005.79191187, r.Accounts[0].Currencies[x].AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be correct")
|
||||
case 2:
|
||||
assert.Equal(t, currency.USDT, r.Accounts[0].Currencies[x].Currency, "Currency should be USDT")
|
||||
assert.Equal(t, 935.1415, r.Accounts[0].Currencies[x].Total, "Total amount should be correct")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Borrowed, "Borrowed amount should be zero")
|
||||
assert.Zero(t, r.Accounts[0].Currencies[x].Hold, "Hold amount should be zero")
|
||||
assert.Equal(t, 935.1415, r.Accounts[0].Currencies[x].Free, "Free amount should be correct")
|
||||
assert.Equal(t, 935.1415, r.Accounts[0].Currencies[x].AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be correct")
|
||||
}
|
||||
for _, curr := range []currency.Code{currency.USDC, currency.AVAX, currency.USDT} {
|
||||
t.Run(curr.String(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Contains(t, subAccts[0].Balances, curr, "Balances must contain currency")
|
||||
bal := subAccts[0].Balances[curr]
|
||||
assert.Equal(t, curr, bal.Currency, "Balance Currency should be set")
|
||||
switch curr {
|
||||
case currency.USDC:
|
||||
assert.Equal(t, -30723.63021638, bal.Total, "Total amount should be correct")
|
||||
assert.Zero(t, bal.Hold, "Hold amount should be zero")
|
||||
assert.Equal(t, 30723.630216383711792744, bal.Borrowed, "Borrowed amount should be correct")
|
||||
assert.Zero(t, bal.Free, "Free amount should be zero")
|
||||
assert.Zero(t, bal.AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be zero")
|
||||
case currency.AVAX:
|
||||
assert.Equal(t, 2473.9, bal.Total, "Total amount should be correct")
|
||||
assert.Zero(t, bal.Hold, "Hold amount should be zero")
|
||||
assert.Zero(t, bal.Borrowed, "Borrowed amount should be zero")
|
||||
assert.Equal(t, 2473.9, bal.Free, "Free amount should be correct")
|
||||
assert.Equal(t, 1005.79191187, bal.AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be correct")
|
||||
case currency.USDT:
|
||||
assert.Equal(t, 935.1415, bal.Total, "Total amount should be correct")
|
||||
assert.Zero(t, bal.Borrowed, "Borrowed amount should be zero")
|
||||
assert.Zero(t, bal.Hold, "Hold amount should be zero")
|
||||
assert.Equal(t, 935.1415, bal.Free, "Free amount should be correct")
|
||||
assert.Equal(t, 935.1415, bal.AvailableWithoutBorrow, "AvailableWithoutBorrow amount should be correct")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2980,9 +2985,11 @@ var pushDataMap = map[string]string{
|
||||
"unhandled": `{"topic": "unhandled"}`,
|
||||
}
|
||||
|
||||
func TestPushDataPublic(t *testing.T) {
|
||||
func TestWSHandleData(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
e := testInstance() //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
|
||||
|
||||
keys := slices.Collect(maps.Keys(pushDataMap))
|
||||
slices.Sort(keys)
|
||||
for x := range keys {
|
||||
@@ -3009,14 +3016,21 @@ func TestWSHandleAuthenticatedData(t *testing.T) {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.API.AuthenticatedWebsocketSupport = true
|
||||
e.SetCredentials("test", "test", "", "", "", "")
|
||||
testexch.FixtureToDataHandler(t, "testdata/wsAuth.json", func(ctx context.Context, r []byte) error {
|
||||
fErrs := testexch.FixtureToDataHandlerWithErrors(t, "testdata/wsAuth.json", func(ctx context.Context, r []byte) error {
|
||||
if bytes.Contains(r, []byte("%s")) {
|
||||
r = fmt.Appendf(nil, string(r), optionsTradablePair.String())
|
||||
}
|
||||
if bytes.Contains(r, []byte("FANGLE-ACCOUNTS")) {
|
||||
hold := e.Accounts
|
||||
e.Accounts = nil
|
||||
defer func() { e.Accounts = hold }()
|
||||
}
|
||||
return e.wsHandleAuthenticatedData(ctx, &FixtureConnection{match: websocket.NewMatch()}, r)
|
||||
})
|
||||
close(e.Websocket.DataHandler)
|
||||
require.Len(t, e.Websocket.DataHandler, 6, "Should see correct number of messages")
|
||||
require.Len(t, fErrs, 1, "Must get exactly one error message")
|
||||
assert.ErrorContains(t, fErrs[0].Err, "cannot save holdings: nil pointer: *accounts.Accounts")
|
||||
|
||||
i := 0
|
||||
for data := range e.Websocket.DataHandler {
|
||||
@@ -3081,63 +3095,39 @@ func TestWSHandleAuthenticatedData(t *testing.T) {
|
||||
assert.Equal(t, 0.358635, v[0].Fee, "fee should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262444), v[0].Date, "Created time should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262457), v[0].LastUpdated, "Updated time should be correct")
|
||||
case []account.Change:
|
||||
require.Len(t, v, 6, "must see 6 items")
|
||||
for i, change := range v {
|
||||
assert.Empty(t, change.Account, "Account type should be empty")
|
||||
assert.Equal(t, asset.Spot, change.AssetType, "Asset type should be Spot")
|
||||
require.NotNil(t, change.Balance, "balance must not be nil")
|
||||
switch i {
|
||||
case 0:
|
||||
assert.True(t, currency.USDC.Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should zero")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Equal(t, 201.34882644, change.Balance.Free, "Free should be correct")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Equal(t, 201.34882644, change.Balance.Total, "Total should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
case 1:
|
||||
assert.True(t, currency.BTC.Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Equal(t, 0.06488393, change.Balance.Free, "Free should be correct")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should zero")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Equal(t, 0.06488393, change.Balance.Total, "Total should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
case 2:
|
||||
assert.True(t, currency.ETH.Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Zero(t, change.Balance.Free, "Free should be 0")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should zero")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Zero(t, change.Balance.Total, "Total should be 0")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
case 3:
|
||||
assert.True(t, currency.USDT.Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Equal(t, 11728.54414904, change.Balance.Free, "Free should be correct")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should be 0")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Equal(t, 11728.54414904, change.Balance.Total, "Total should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
case 4:
|
||||
assert.True(t, currency.NewCode("EOS3L").Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Equal(t, 215.0570412, change.Balance.Free, "Free should be correct")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should be 0")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Equal(t, 215.0570412, change.Balance.Total, "Total should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
case 5:
|
||||
assert.True(t, currency.BIT.Equal(change.Balance.Currency), "currency should match")
|
||||
assert.Equal(t, 1.82, change.Balance.Free, "Free should be correct")
|
||||
assert.Zero(t, change.Balance.AvailableWithoutBorrow, "AvailableWithoutBorrow should be 0")
|
||||
assert.Zero(t, change.Balance.Borrowed, "Borrowed should be 0")
|
||||
assert.Zero(t, change.Balance.Hold, "Hold should be 0")
|
||||
assert.Equal(t, 1.82, change.Balance.Total, "Total should be correct")
|
||||
assert.Equal(t, time.UnixMilli(1672364262482), change.Balance.UpdatedAt, "Last updated should be correct")
|
||||
}
|
||||
}
|
||||
case accounts.SubAccounts:
|
||||
require.Len(t, v, 1, "Must have correct number of SubAccounts")
|
||||
assert.Equal(t, asset.Spot, v[0].AssetType, "Asset type should be correct")
|
||||
exp := accounts.CurrencyBalances{}
|
||||
exp.Set(currency.ETH, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
})
|
||||
exp.Set(currency.USDT, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
Total: 11728.54414904,
|
||||
Free: 11728.54414904,
|
||||
})
|
||||
exp.Set(currency.EOS3L, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
Total: 215.0570412,
|
||||
Free: 215.0570412,
|
||||
})
|
||||
exp.Set(currency.BIT, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
Total: 1.82,
|
||||
Free: 1.82,
|
||||
})
|
||||
exp.Set(currency.USDC, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
Total: 201.34882644,
|
||||
Free: 201.34882644,
|
||||
})
|
||||
exp.Set(currency.BTC, accounts.Balance{
|
||||
UpdatedAt: time.UnixMilli(1672364262482),
|
||||
Total: 0.06488393,
|
||||
Free: 0.06488393,
|
||||
})
|
||||
assert.Equal(t, exp, v[0].Balances, "Balances should be correct")
|
||||
case *GreeksResponse:
|
||||
assert.Equal(t, "592324fa945a30-2603-49a5-b865-21668c29f2a6", v.ID, "ID should be correct")
|
||||
assert.Equal(t, "greeks", v.Topic, "Topic should be correct")
|
||||
@@ -3162,7 +3152,7 @@ func TestWSHandleAuthenticatedData(t *testing.T) {
|
||||
assert.Equal(t, 0.3374, v[0].Price, "price should be correct")
|
||||
assert.Equal(t, 25.0, v[0].Amount, "amount should be correct")
|
||||
default:
|
||||
t.Errorf("Unexpected data received: %v", v)
|
||||
t.Errorf("Unexpected data received: %T %v", v, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3170,11 +3160,11 @@ func TestWSHandleAuthenticatedData(t *testing.T) {
|
||||
func TestWsTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
e := new(Exchange) //nolint:govet // Intentional shadow
|
||||
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
||||
assetRouting := []asset.Item{
|
||||
asset.Spot, asset.Options, asset.USDTMarginedFutures, asset.USDTMarginedFutures,
|
||||
asset.USDCMarginedFutures, asset.USDCMarginedFutures, asset.CoinMarginedFutures, asset.CoinMarginedFutures,
|
||||
}
|
||||
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
||||
testexch.FixtureToDataHandler(t, "testdata/wsTicker.json", func(_ context.Context, r []byte) error {
|
||||
defer slices.Delete(assetRouting, 0, 1)
|
||||
return e.wsHandleData(nil, assetRouting[0], r)
|
||||
@@ -3730,7 +3720,7 @@ func TestWebsocketAuthenticatePrivateConnection(t *testing.T) {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.API.AuthenticatedWebsocketSupport = true
|
||||
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
ctx := account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "dummy", Secret: "dummy"})
|
||||
ctx := accounts.DeployCredentialsToContext(t.Context(), &accounts.Credentials{Key: "dummy", Secret: "dummy"})
|
||||
err = e.WebsocketAuthenticatePrivateConnection(ctx, &FixtureConnection{})
|
||||
require.NoError(t, err)
|
||||
err = e.WebsocketAuthenticatePrivateConnection(ctx, &FixtureConnection{sendMessageReturnResponseOverride: []byte(`{"success":false,"ret_msg":"failed auth","conn_id":"5758770c-8152-4545-a84f-dae089e56499","req_id":"1","op":"subscribe"}`)})
|
||||
@@ -3749,7 +3739,7 @@ func TestWebsocketAuthenticateTradeConnection(t *testing.T) {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.API.AuthenticatedWebsocketSupport = true
|
||||
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
ctx := account.DeployCredentialsToContext(t.Context(), &account.Credentials{Key: "dummy", Secret: "dummy"})
|
||||
ctx := accounts.DeployCredentialsToContext(t.Context(), &accounts.Credentials{Key: "dummy", Secret: "dummy"})
|
||||
err = e.WebsocketAuthenticateTradeConnection(ctx, &FixtureConnection{sendMessageReturnResponseOverride: []byte(`{"retCode":0,"retMsg":"OK","op":"auth","connId":"d2a641kgcg7ab33b7mdg-4x6a"}`)})
|
||||
require.NoError(t, err)
|
||||
err = e.WebsocketAuthenticateTradeConnection(ctx, &FixtureConnection{sendMessageReturnResponseOverride: []byte(`{"retCode":10004,"retMsg":"Invalid sign","op":"auth","connId":"d2a63t6p49kk82nefh90-4ye8"}`)})
|
||||
|
||||
@@ -17,8 +17,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/fill"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
@@ -315,26 +315,21 @@ func (e *Exchange) wsProcessWalletPushData(ctx context.Context, resp []byte) err
|
||||
if err := json.Unmarshal(resp, &result); err != nil {
|
||||
return err
|
||||
}
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var changes []account.Change
|
||||
subAccts := accounts.SubAccounts{accounts.NewSubAccount(asset.Spot, "")}
|
||||
for x := range result.Data {
|
||||
for y := range result.Data[x].Coin {
|
||||
changes = append(changes, account.Change{
|
||||
AssetType: asset.Spot,
|
||||
Balance: &account.Balance{
|
||||
Currency: result.Data[x].Coin[y].Coin,
|
||||
Total: result.Data[x].Coin[y].WalletBalance.Float64(),
|
||||
Free: result.Data[x].Coin[y].WalletBalance.Float64(),
|
||||
UpdatedAt: result.CreationTime.Time(),
|
||||
},
|
||||
subAccts[0].Balances.Set(result.Data[x].Coin[y].Coin, accounts.Balance{
|
||||
Total: result.Data[x].Coin[y].WalletBalance.Float64(),
|
||||
Free: result.Data[x].Coin[y].WalletBalance.Float64(),
|
||||
UpdatedAt: result.CreationTime.Time(),
|
||||
})
|
||||
}
|
||||
}
|
||||
e.Websocket.DataHandler <- changes
|
||||
return account.ProcessChange(e.Name, changes, creds)
|
||||
if err := e.Accounts.Save(ctx, subAccts, false); err != nil {
|
||||
return err
|
||||
}
|
||||
e.Websocket.DataHandler <- subAccts
|
||||
return nil
|
||||
}
|
||||
|
||||
// wsProcessOrder the order stream to see changes to your orders in real-time.
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"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/order/limits"
|
||||
"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"
|
||||
@@ -653,16 +653,13 @@ func (e *Exchange) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy
|
||||
return orderbook.Get(e.Name, p, assetType)
|
||||
}
|
||||
|
||||
// UpdateAccountInfo retrieves balances for all enabled currencies
|
||||
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
var info account.Holdings
|
||||
var acc account.SubAccount
|
||||
var accountType string
|
||||
info.Exchange = e.Name
|
||||
// UpdateAccountBalances retrieves currency balances
|
||||
func (e *Exchange) UpdateAccountBalances(ctx context.Context, assetType asset.Item) (accounts.SubAccounts, error) {
|
||||
at, err := e.FetchAccountType(ctx)
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
var accountType string
|
||||
switch assetType {
|
||||
case asset.Spot, asset.Options, asset.USDCMarginedFutures, asset.USDTMarginedFutures:
|
||||
switch at {
|
||||
@@ -678,15 +675,15 @@ func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item)
|
||||
case asset.CoinMarginedFutures:
|
||||
accountType = "CONTRACT"
|
||||
default:
|
||||
return info, fmt.Errorf("%s %w", assetType, asset.ErrNotSupported)
|
||||
return nil, fmt.Errorf("%s %w", assetType, asset.ErrNotSupported)
|
||||
}
|
||||
balances, err := e.GetWalletBalance(ctx, accountType, "")
|
||||
resp, err := e.GetWalletBalance(ctx, accountType, "")
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
currencyBalance := []account.Balance{}
|
||||
for i := range balances.List {
|
||||
for _, c := range balances.List[i].Coin {
|
||||
subAccts := accounts.SubAccounts{accounts.NewSubAccount(assetType, "")}
|
||||
for i := range resp.List {
|
||||
for _, c := range resp.List[i].Coin {
|
||||
// borrow amounts get truncated to 8 dec places when total and equity are calculated on the exchange
|
||||
truncBorrow := c.BorrowAmount.Decimal().Truncate(8).InexactFloat64()
|
||||
|
||||
@@ -699,8 +696,7 @@ func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item)
|
||||
freeBalance = c.AvailableBalanceForSpot.Float64()
|
||||
}
|
||||
|
||||
currencyBalance = append(currencyBalance, account.Balance{
|
||||
Currency: c.Coin,
|
||||
subAccts[0].Balances.Set(c.Coin, accounts.Balance{
|
||||
Total: c.WalletBalance.Float64(),
|
||||
Free: freeBalance,
|
||||
Borrowed: c.BorrowAmount.Float64(),
|
||||
@@ -709,18 +705,7 @@ func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item)
|
||||
})
|
||||
}
|
||||
}
|
||||
acc.Currencies = currencyBalance
|
||||
acc.AssetType = assetType
|
||||
info.Accounts = append(info.Accounts, acc)
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return account.Holdings{}, err
|
||||
}
|
||||
err = account.Process(&info, creds)
|
||||
if err != nil {
|
||||
return account.Holdings{}, err
|
||||
}
|
||||
return info, nil
|
||||
return subAccts, e.Accounts.Save(ctx, subAccts, true)
|
||||
}
|
||||
|
||||
// GetAccountFundingHistory returns funding history, deposits and
|
||||
@@ -1474,7 +1459,7 @@ func (e *Exchange) getCategoryFromPair(pair currency.Pair) []asset.Item {
|
||||
|
||||
// ValidateAPICredentials validates current credentials used for wrapper
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
3
exchanges/bybit/testdata/wsAuth.json
vendored
3
exchanges/bybit/testdata/wsAuth.json
vendored
@@ -3,4 +3,5 @@
|
||||
{ "id": "5923242c464be9-25ca-483d-a743-c60101fc656f", "topic": "wallet", "creationTime": 1672364262482, "data": [ { "accountIMRate": "0.016", "accountMMRate": "0.003", "totalEquity": "12837.78330098", "totalWalletBalance": "12840.4045924", "totalMarginBalance": "12837.78330188", "totalAvailableBalance": "12632.05767702", "totalPerpUPL": "-2.62129051", "totalInitialMargin": "205.72562486", "totalMaintenanceMargin": "39.42876721", "coin": [ { "coin": "USDC", "equity": "200.62572554", "usdValue": "200.62572554", "walletBalance": "201.34882644", "availableToWithdraw": "0", "availableToBorrow": "1500000", "borrowAmount": "0", "accruedInterest": "0", "totalOrderIM": "0", "totalPositionIM": "202.99874213", "totalPositionMM": "39.14289747", "unrealisedPnl": "74.2768991", "cumRealisedPnl": "-209.1544627", "bonus": "0" }, { "coin": "BTC", "equity": "0.06488393", "usdValue": "1023.08402268", "walletBalance": "0.06488393", "availableToWithdraw": "0.06488393", "availableToBorrow": "2.5", "borrowAmount": "0", "accruedInterest": "0", "totalOrderIM": "0", "totalPositionIM": "0", "totalPositionMM": "0", "unrealisedPnl": "0", "cumRealisedPnl": "0", "bonus": "0" }, { "coin": "ETH", "equity": "0", "usdValue": "0", "walletBalance": "0", "availableToWithdraw": "0", "availableToBorrow": "26", "borrowAmount": "0", "accruedInterest": "0", "totalOrderIM": "0", "totalPositionIM": "0", "totalPositionMM": "0", "unrealisedPnl": "0", "cumRealisedPnl": "0", "bonus": "0" }, { "coin": "USDT", "equity": "11726.64664904", "usdValue": "11613.58597018", "walletBalance": "11728.54414904", "availableToWithdraw": "11723.92075829", "availableToBorrow": "2500000", "borrowAmount": "0", "accruedInterest": "0", "totalOrderIM": "0", "totalPositionIM": "2.72589075", "totalPositionMM": "0.28576575", "unrealisedPnl": "-1.8975", "cumRealisedPnl": "0.64782276", "bonus": "0" }, { "coin": "EOS3L", "equity": "215.0570412", "usdValue": "0", "walletBalance": "215.0570412", "availableToWithdraw": "215.0570412", "availableToBorrow": "0", "borrowAmount": "0", "accruedInterest": "", "totalOrderIM": "0", "totalPositionIM": "0", "totalPositionMM": "0", "unrealisedPnl": "0", "cumRealisedPnl": "0", "bonus": "0" }, { "coin": "BIT", "equity": "1.82", "usdValue": "0.48758257", "walletBalance": "1.82", "availableToWithdraw": "1.82", "availableToBorrow": "0", "borrowAmount": "0", "accruedInterest": "", "totalOrderIM": "0", "totalPositionIM": "0", "totalPositionMM": "0", "unrealisedPnl": "0", "cumRealisedPnl": "0", "bonus": "0" } ], "accountType": "UNIFIED", "accountLTV": "0.017" } ] }
|
||||
{ "id": "592324fa945a30-2603-49a5-b865-21668c29f2a6", "topic": "greeks", "creationTime": 1672364262482, "data": [ { "baseCoin": "ETH", "totalDelta": "0.06999986", "totalGamma": "-0.00000001", "totalVega": "-0.00000024", "totalTheta": "0.00001314" } ] }
|
||||
{"id": "592324803b2785-26fa-4214-9963-bdd4727f07be", "topic": "execution", "creationTime": 1672364174455, "data": [ { "category": "linear", "symbol": "XRPUSDT", "execFee": "0.005061", "execId": "7e2ae69c-4edf-5800-a352-893d52b446aa", "execPrice": "0.3374", "execQty": "25", "execType": "Trade", "execValue": "8.435", "isMaker": false, "feeRate": "0.0006", "tradeIv": "", "markIv": "", "blockTradeId": "", "markPrice": "0.3391", "indexPrice": "", "underlyingPrice": "", "leavesQty": "0", "orderId": "f6e324ff-99c2-4e89-9739-3086e47f9381", "orderLinkId": "", "orderPrice": "0.3207", "orderQty":"25","orderType":"Market","stopOrderType":"UNKNOWN","side":"Sell","execTime":"1672364174443","isLeverage": "0","closedSize": "","seq":4688002127}]}
|
||||
{ "id": "someID", "topic": "order", "creationTime": 1672364262474, "data": [{"category":"linear","symbol":"BTCUSDT","orderId":"c1956690-b731-4191-97c0-94b00422231b","orderLinkId":"","blockTradeId":"","side":"Sell","positionIdx":0,"orderStatus":"Filled","cancelType":"UNKNOWN","rejectReason":"EC_NoError","timeInForce":"IOC","isLeverage":"","price":"4.033","qty":"1.7","avgPrice":"4.24","leavesQty":"0","leavesValue":"0","cumExecQty":"1.7","cumExecValue":"7.2086","cumExecFee":"0.00288344","orderType":"Market","stopOrderType":"","orderIv":"","triggerPrice":"","takeProfit":"","stopLoss":"","triggerBy":"","tpTriggerBy":"","slTriggerBy":"","triggerDirection":0,"placeType":"","lastPriceOnCreated":"4.245","closeOnTrigger":false,"reduceOnly":false,"smpGroup":0,"smpType":"None","smpOrderId":"","slLimitPrice":"0","tpLimitPrice":"0","tpslMode":"UNKNOWN","createType":"CreateByUser","marketUnit":"","createdTime":"1733778525913","updatedTime":"1733778525917","feeCurrency":"","closedPnl":"0"}]}
|
||||
{ "id": "someID", "topic": "order", "creationTime": 1672364262474, "data": [{"category":"linear","symbol":"BTCUSDT","orderId":"c1956690-b731-4191-97c0-94b00422231b","orderLinkId":"","blockTradeId":"","side":"Sell","positionIdx":0,"orderStatus":"Filled","cancelType":"UNKNOWN","rejectReason":"EC_NoError","timeInForce":"IOC","isLeverage":"","price":"4.033","qty":"1.7","avgPrice":"4.24","leavesQty":"0","leavesValue":"0","cumExecQty":"1.7","cumExecValue":"7.2086","cumExecFee":"0.00288344","orderType":"Market","stopOrderType":"","orderIv":"","triggerPrice":"","takeProfit":"","stopLoss":"","triggerBy":"","tpTriggerBy":"","slTriggerBy":"","triggerDirection":0,"placeType":"","lastPriceOnCreated":"4.245","closeOnTrigger":false,"reduceOnly":false,"smpGroup":0,"smpType":"None","smpOrderId":"","slLimitPrice":"0","tpLimitPrice":"0","tpslMode":"UNKNOWN","createType":"CreateByUser","marketUnit":"","createdTime":"1733778525913","updatedTime":"1733778525917","feeCurrency":"","closedPnl":"0"}]}
|
||||
{ "id": "FANGLE-ACCOUNTS", "topic": "wallet", "creationTime": 1672364262483, "data": [ { "coin": [ { "coin": "BREAK", "walletBalance": "201.34882644"}]}]}
|
||||
|
||||
Reference in New Issue
Block a user