diff --git a/trader/okx/trader_account.go b/trader/okx/trader_account.go index 53fa0550..416a109d 100644 --- a/trader/okx/trader_account.go +++ b/trader/okx/trader_account.go @@ -82,31 +82,14 @@ func (t *OKXTrader) GetBalance() (map[string]interface{}, error) { // SetMarginMode sets margin mode func (t *OKXTrader) SetMarginMode(symbol string, isCrossMargin bool) error { - instId := t.convertSymbol(symbol) t.isCrossMargin = isCrossMargin mgnMode := t.marginMode() - body := map[string]interface{}{ - "instId": instId, - "mgnMode": mgnMode, - } - - _, err := t.doRequest("POST", "/api/v5/account/set-isolated-mode", body) - if err != nil { - // Ignore error if already in target mode - if strings.Contains(err.Error(), "already") { - logger.Infof(" ✓ %s margin mode is already %s", symbol, mgnMode) - return nil - } - // Cannot change when there are positions - if strings.Contains(err.Error(), "position") { - logger.Infof(" ⚠️ %s has positions, cannot change margin mode", symbol) - return nil - } - return err - } - - logger.Infof(" ✓ %s margin mode set to %s", symbol, mgnMode) + // OKX V5 unified account applies cross/isolated per order via tdMode, + // while leverage uses mgnMode on /account/set-leverage. + // Persist the configured mode locally so subsequent leverage/order calls use it, + // instead of calling the legacy isolated-mode endpoint that returns 51000 errors. + logger.Infof(" ✓ %s margin mode configured as %s (applied via tdMode/mgnMode on subsequent requests)", symbol, mgnMode) return nil } diff --git a/trader/okx/trader_margin_mode_test.go b/trader/okx/trader_margin_mode_test.go index b0a78305..b633a364 100644 --- a/trader/okx/trader_margin_mode_test.go +++ b/trader/okx/trader_margin_mode_test.go @@ -98,6 +98,34 @@ func TestOKXSetLeverageUsesConfiguredMarginMode(t *testing.T) { } } +func TestOKXSetMarginModeUpdatesFutureRequestsWithoutAPIError(t *testing.T) { + rt := &recordingTransport{} + trader := newTestOKXTrader(rt, true) + + if err := trader.SetMarginMode("BTCUSDT", false); err != nil { + t.Fatalf("SetMarginMode failed: %v", err) + } + + if len(rt.requestsForPath("/api/v5/account/set-isolated-mode")) != 0 { + t.Fatal("expected SetMarginMode not to call legacy isolated-mode endpoint") + } + + if err := trader.SetLeverage("BTCUSDT", 5); err != nil { + t.Fatalf("SetLeverage failed: %v", err) + } + + leverageRequests := rt.requestsForPath(okxLeveragePath) + if len(leverageRequests) != 2 { + t.Fatalf("expected 2 leverage requests, got %d", len(leverageRequests)) + } + + for _, req := range leverageRequests { + if req.Body["mgnMode"] != "isolated" { + t.Fatalf("expected isolated leverage mode after SetMarginMode(false), got %#v", req.Body["mgnMode"]) + } + } +} + func TestOKXOpenLongUsesConfiguredMarginMode(t *testing.T) { rt := &recordingTransport{} trader := newTestOKXTrader(rt, false)