refactor: remove all futures-related capabilities
Delete USDT-M futures support since the user's Binance API key does not support futures trading. This simplifies the CLI to spot-only: - Remove futures client wrapper (um_futures_client.py) - Remove futures trade commands and close position logic - Simplify account service to spot-only (no market_type field) - Remove futures references from opportunity service - Update README and tests to reflect spot-only architecture - Bump version to 2.0.7 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,14 +41,6 @@ class FakeSpotClient:
|
||||
return {"symbols": [{"symbol": "BTCUSDT", "status": "TRADING"}, {"symbol": "ETHUSDT", "status": "TRADING"}, {"symbol": "DOGEUSDT", "status": "BREAK"}]}
|
||||
|
||||
|
||||
class FakeFuturesClient:
|
||||
def balance(self):
|
||||
return [{"asset": "USDT", "balance": "250.0", "availableBalance": "200.0"}]
|
||||
|
||||
def position_risk(self, symbol=None):
|
||||
return [{"symbol": "BTCUSDT", "positionAmt": "0.02", "notional": "1200", "entryPrice": "59000", "markPrice": "60000", "unRealizedProfit": "20"}]
|
||||
|
||||
|
||||
class AccountMarketServicesTestCase(unittest.TestCase):
|
||||
def test_account_overview_and_dust_filter(self):
|
||||
config = {
|
||||
@@ -57,13 +49,9 @@ class AccountMarketServicesTestCase(unittest.TestCase):
|
||||
}
|
||||
payload = account_service.get_overview(
|
||||
config,
|
||||
include_spot=True,
|
||||
include_futures=True,
|
||||
spot_client=FakeSpotClient(),
|
||||
futures_client=FakeFuturesClient(),
|
||||
)
|
||||
self.assertEqual(payload["overview"]["spot_equity_usdt"], 720.1)
|
||||
self.assertEqual(payload["overview"]["futures_equity_usdt"], 250.0)
|
||||
self.assertEqual(payload["overview"]["total_equity_usdt"], 720.1)
|
||||
symbols = {item["symbol"] for item in payload["positions"]}
|
||||
self.assertNotIn("DOGEUSDT", symbols)
|
||||
self.assertIn("BTCUSDT", symbols)
|
||||
|
||||
@@ -17,18 +17,6 @@ class FakeSpotClient:
|
||||
return {"symbol": kwargs["symbol"], "status": "FILLED", "orderId": 1}
|
||||
|
||||
|
||||
class FakeFuturesClient:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def new_order(self, **kwargs):
|
||||
self.calls.append(kwargs)
|
||||
return {"symbol": kwargs["symbol"], "status": "FILLED", "orderId": 2}
|
||||
|
||||
def position_risk(self, symbol=None):
|
||||
return [{"symbol": "BTCUSDT", "positionAmt": "-0.02", "notional": "-1200"}]
|
||||
|
||||
|
||||
class TradeServiceTestCase(unittest.TestCase):
|
||||
def test_spot_market_buy_dry_run_does_not_call_client(self):
|
||||
events = []
|
||||
@@ -66,18 +54,6 @@ class TradeServiceTestCase(unittest.TestCase):
|
||||
self.assertEqual(payload["trade"]["status"], "FILLED")
|
||||
self.assertEqual(client.calls[0]["timeInForce"], "GTC")
|
||||
|
||||
def test_futures_close_uses_opposite_side(self):
|
||||
with patch.object(trade_service, "audit_event", return_value=None):
|
||||
client = FakeFuturesClient()
|
||||
payload = trade_service.close_futures_position(
|
||||
{"trading": {"dry_run_default": False}},
|
||||
symbol="BTCUSDT",
|
||||
dry_run=False,
|
||||
futures_client=client,
|
||||
)
|
||||
self.assertEqual(payload["trade"]["side"], "BUY")
|
||||
self.assertEqual(client.calls[0]["reduceOnly"], "true")
|
||||
|
||||
def test_spot_market_buy_requires_quote(self):
|
||||
with patch.object(trade_service, "audit_event", return_value=None):
|
||||
with self.assertRaisesRegex(RuntimeError, "requires --quote"):
|
||||
|
||||
Reference in New Issue
Block a user