feat(mcp-deribit,mcp-bybit): add place_combo_order

Deribit: private/create_combo + place_order sul combo instrument → una
sola crociata di spread invece di N (slippage atteso ridotto su
strutture liquide). ACL core + leverage cap su tutti i leg.

Bybit: place_batch_order su category=option (atomic multi-leg, 1
round-trip API). Reject su category != option (perp/linear non
supportano batch nativo). orderLinkId auto-generato per leg.

Tutti i test: deribit 48/48, bybit 123/123.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
AdrianoDev
2026-04-27 23:12:09 +02:00
parent bacd5aab33
commit c2fd8330ca
9 changed files with 358 additions and 1 deletions
@@ -47,6 +47,7 @@ def mock_client():
c.set_leverage = AsyncMock(return_value={"status": "leverage_set"})
c.switch_position_mode = AsyncMock(return_value={"status": "mode_switched"})
c.transfer_asset = AsyncMock(return_value={"transfer_id": "tx"})
c.place_combo_order = AsyncMock(return_value={"orders": [{"order_id": "ord-1"}, {"order_id": "ord-2"}]})
return c
@@ -88,9 +89,28 @@ WRITE_ENDPOINTS = [
("/tools/set_leverage", {"category": "linear", "symbol": "BTCUSDT", "leverage": 5}),
("/tools/switch_position_mode", {"category": "linear", "symbol": "BTCUSDT", "mode": "hedge"}),
("/tools/transfer_asset", {"coin": "USDT", "amount": 10.0, "from_type": "UNIFIED", "to_type": "FUND"}),
("/tools/place_combo_order", {
"category": "option",
"legs": [
{"symbol": "BTC-30APR26-75000-C-USDT", "side": "Buy", "qty": 0.01, "order_type": "Limit", "price": 5.0},
{"symbol": "BTC-30APR26-80000-C-USDT", "side": "Sell", "qty": 0.01, "order_type": "Limit", "price": 3.0},
],
}),
]
def test_place_combo_order_min_legs(http):
r = http.post(
"/tools/place_combo_order",
json={
"category": "option",
"legs": [{"symbol": "X", "side": "Buy", "qty": 1, "order_type": "Limit", "price": 1.0}],
},
headers=CORE,
)
assert r.status_code == 422
@pytest.mark.parametrize("path,payload", READ_ENDPOINTS)
def test_read_core_ok(http, path, payload):
r = http.post(path, json=payload, headers=CORE)