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:
@@ -148,116 +148,3 @@ def execute_spot_trade(
|
||||
)
|
||||
audit_event("trade_filled", {**_trade_log_payload(intent, payload, status=result["status"]), "response_payload": response})
|
||||
return {"trade": result}
|
||||
|
||||
|
||||
def execute_futures_trade(
|
||||
config: dict[str, Any],
|
||||
*,
|
||||
side: str,
|
||||
symbol: str,
|
||||
qty: float,
|
||||
order_type: str,
|
||||
price: float | None,
|
||||
reduce_only: bool,
|
||||
dry_run: bool | None,
|
||||
futures_client: Any,
|
||||
) -> dict[str, Any]:
|
||||
normalized_symbol = normalize_symbol(symbol)
|
||||
order_type = order_type.upper()
|
||||
side = side.upper()
|
||||
is_dry_run = _default_dry_run(config, dry_run)
|
||||
if qty <= 0:
|
||||
raise RuntimeError("Futures orders require a positive --qty")
|
||||
if order_type == "LIMIT" and price is None:
|
||||
raise RuntimeError("Futures limit orders require --price")
|
||||
|
||||
payload: dict[str, Any] = {
|
||||
"symbol": normalized_symbol,
|
||||
"side": side,
|
||||
"type": order_type,
|
||||
"quantity": qty,
|
||||
"reduceOnly": "true" if reduce_only else "false",
|
||||
}
|
||||
if price is not None:
|
||||
payload["price"] = price
|
||||
payload["timeInForce"] = "GTC"
|
||||
|
||||
intent = TradeIntent(
|
||||
market_type="futures",
|
||||
symbol=normalized_symbol,
|
||||
side=side,
|
||||
order_type=order_type,
|
||||
qty=qty,
|
||||
quote_amount=None,
|
||||
price=price,
|
||||
reduce_only=reduce_only,
|
||||
dry_run=is_dry_run,
|
||||
)
|
||||
|
||||
audit_event("trade_submitted", _trade_log_payload(intent, payload, status="submitted"))
|
||||
if is_dry_run:
|
||||
response = {"dry_run": True, "status": "DRY_RUN", "request": payload}
|
||||
result = asdict(
|
||||
TradeResult(
|
||||
market_type="futures",
|
||||
symbol=normalized_symbol,
|
||||
side=side,
|
||||
order_type=order_type,
|
||||
status="DRY_RUN",
|
||||
dry_run=True,
|
||||
request_payload=payload,
|
||||
response_payload=response,
|
||||
)
|
||||
)
|
||||
audit_event("trade_filled", {**_trade_log_payload(intent, payload, status="DRY_RUN"), "response_payload": response})
|
||||
return {"trade": result}
|
||||
|
||||
try:
|
||||
response = futures_client.new_order(**payload)
|
||||
except Exception as exc:
|
||||
audit_event("trade_failed", _trade_log_payload(intent, payload, status="failed", error=str(exc)))
|
||||
raise RuntimeError(f"Futures order failed: {exc}") from exc
|
||||
|
||||
result = asdict(
|
||||
TradeResult(
|
||||
market_type="futures",
|
||||
symbol=normalized_symbol,
|
||||
side=side,
|
||||
order_type=order_type,
|
||||
status=str(response.get("status", "UNKNOWN")),
|
||||
dry_run=False,
|
||||
request_payload=payload,
|
||||
response_payload=response,
|
||||
)
|
||||
)
|
||||
audit_event("trade_filled", {**_trade_log_payload(intent, payload, status=result["status"]), "response_payload": response})
|
||||
return {"trade": result}
|
||||
|
||||
|
||||
def close_futures_position(
|
||||
config: dict[str, Any],
|
||||
*,
|
||||
symbol: str,
|
||||
dry_run: bool | None,
|
||||
futures_client: Any,
|
||||
) -> dict[str, Any]:
|
||||
normalized_symbol = normalize_symbol(symbol)
|
||||
positions = futures_client.position_risk(normalized_symbol)
|
||||
target = next((item for item in positions if normalize_symbol(item["symbol"]) == normalized_symbol), None)
|
||||
if target is None:
|
||||
raise RuntimeError(f"No futures position found for {normalized_symbol}")
|
||||
position_amt = float(target.get("positionAmt", 0.0))
|
||||
if position_amt == 0:
|
||||
raise RuntimeError(f"No open futures position for {normalized_symbol}")
|
||||
side = "SELL" if position_amt > 0 else "BUY"
|
||||
return execute_futures_trade(
|
||||
config,
|
||||
side=side,
|
||||
symbol=normalized_symbol,
|
||||
qty=abs(position_amt),
|
||||
order_type="MARKET",
|
||||
price=None,
|
||||
reduce_only=True,
|
||||
dry_run=dry_run,
|
||||
futures_client=futures_client,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user