mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-13 07:46:54 +08:00
fix(trader): harden API calls with timeouts, strict balance parsing, error context
- binance/bybit/gate: SDK default http.DefaultClient has no timeout; use a dedicated 30s-timeout client so a hung connection cannot stall the loop - bybit: stop mutating http.DefaultClient.Transport, which leaked the referer header into every other HTTP request in the process - add types.ParseFloatField: empty exchange fields stay zero, but malformed numeric values now surface as errors instead of silently becoming zero balances (applied to GetBalance across 8 exchanges) - wrap order/market-data errors in auto_trader_orders and okx cancel paths with symbol context; log per-order cancel failures in okx CancelAllOrders
This commit is contained in:
@@ -45,16 +45,22 @@ func NewBybitTrader(apiKey, secretKey string) *BybitTrader {
|
||||
|
||||
client := bybit.NewBybitHttpClient(apiKey, secretKey, bybit.WithBaseURL(bybit.MAINNET))
|
||||
|
||||
// Set HTTP transport
|
||||
if client != nil && client.HTTPClient != nil {
|
||||
defaultTransport := client.HTTPClient.Transport
|
||||
if defaultTransport == nil {
|
||||
defaultTransport = http.DefaultTransport
|
||||
// Set HTTP transport. Use a dedicated client instead of mutating the
|
||||
// SDK default (http.DefaultClient): mutating it would leak the referer
|
||||
// header to every other request in the process, and the default client
|
||||
// has no timeout, so a hung connection would stall the trading loop.
|
||||
if client != nil {
|
||||
defaultTransport := http.DefaultTransport
|
||||
if client.HTTPClient != nil && client.HTTPClient != http.DefaultClient && client.HTTPClient.Transport != nil {
|
||||
defaultTransport = client.HTTPClient.Transport
|
||||
}
|
||||
|
||||
client.HTTPClient.Transport = &headerRoundTripper{
|
||||
base: defaultTransport,
|
||||
refererID: src,
|
||||
client.HTTPClient = &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: &headerRoundTripper{
|
||||
base: defaultTransport,
|
||||
refererID: src,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,19 +51,28 @@ func (t *BybitTrader) GetBalance() (map[string]interface{}, error) {
|
||||
|
||||
if len(list) > 0 {
|
||||
account, _ := list[0].(map[string]interface{})
|
||||
var parseErr error
|
||||
if equityStr, ok := account["totalEquity"].(string); ok {
|
||||
totalEquity, _ = strconv.ParseFloat(equityStr, 64)
|
||||
if totalEquity, parseErr = types.ParseFloatField("totalEquity", equityStr); parseErr != nil {
|
||||
return nil, parseErr
|
||||
}
|
||||
}
|
||||
if availStr, ok := account["totalAvailableBalance"].(string); ok {
|
||||
availableBalance, _ = strconv.ParseFloat(availStr, 64)
|
||||
if availableBalance, parseErr = types.ParseFloatField("totalAvailableBalance", availStr); parseErr != nil {
|
||||
return nil, parseErr
|
||||
}
|
||||
}
|
||||
// Bybit UNIFIED account wallet balance field
|
||||
if walletStr, ok := account["totalWalletBalance"].(string); ok {
|
||||
totalWalletBalance, _ = strconv.ParseFloat(walletStr, 64)
|
||||
if totalWalletBalance, parseErr = types.ParseFloatField("totalWalletBalance", walletStr); parseErr != nil {
|
||||
return nil, parseErr
|
||||
}
|
||||
}
|
||||
// Bybit perpetual contract unrealized PnL
|
||||
if uplStr, ok := account["totalPerpUPL"].(string); ok {
|
||||
totalPerpUPL, _ = strconv.ParseFloat(uplStr, 64)
|
||||
if totalPerpUPL, parseErr = types.ParseFloatField("totalPerpUPL", uplStr); parseErr != nil {
|
||||
return nil, parseErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user