diff --git a/tests/exchange_online/conftest.py b/tests/exchange_online/conftest.py index 7abd6b4b8..9a39b2090 100644 --- a/tests/exchange_online/conftest.py +++ b/tests/exchange_online/conftest.py @@ -572,6 +572,50 @@ EXCHANGES: dict[str, TestExchangeOnlineSetup] = { "futures_pair": "BTC/USD:USD", "hasQuoteVolumeFutures": False, "leverage_tiers_public": True, + "sample_order_futures": [ + { + # Trigger order + "exchange_response": { + "order": { + "type": "TRIGGER_ORDER", + "orderId": "a11a8ff3-17f3-5112-8caa-9cbbacfa1c8e", + "cliOrdId": None, + "symbol": "PF_XBTUSD", + "side": "buy", + "quantity": 0.0004, + "limitPrice": 71712, + "reduceOnly": True, + "timestamp": "2026-02-17T16:26:02.918Z", + "lastUpdateTimestamp": "2026-02-17T16:26:02.918Z", + "priceTriggerOptions": { + "triggerPrice": 71641, + "triggerSignal": "LAST_PRICE", + "triggerSide": "TRIGGER_ABOVE", + "limitPriceOffsetValue": None, + "limitPriceOffsetUnit": None, + }, + }, + "status": "TRIGGER_PLACED", + "updateReason": None, + "error": None, + }, + "pair": "BTC/USD:USD", + "expected": { + "symbol": "BTC/USD:USD", + "id": "a11a8ff3-17f3-5112-8caa-9cbbacfa1c8e", + "timestamp": 1771345562918, + "datetime": "2026-02-17T16:26:02.918Z", + "price": 71712.0, + "status": "open", + "amount": 0.0004, + "side": "buy", + # TODO: this should work if stoploss is supposed to work. + # "triggerPrice": 71641.0, + # "stopPrice": 71641.0, + # "stopLossPrice": 71641.0, + }, + }, + ], }, } diff --git a/tests/exchange_online/test_ccxt_compat.py b/tests/exchange_online/test_ccxt_compat.py index f33818d3d..e2988cc61 100644 --- a/tests/exchange_online/test_ccxt_compat.py +++ b/tests/exchange_online/test_ccxt_compat.py @@ -101,6 +101,30 @@ class TestCCXTExchange: else: pytest.skip(f"No sample order available for exchange {exchangename}") + def test_ccxt_order_parse_futures(self, exchange_futures: EXCHANGE_FIXTURE_TYPE): + exch, exchangename, exchange_params = exchange_futures + if orders := exchange_params.get("sample_order_futures"): + for order in orders: + pair = order["pair"] + exchange_response: dict = order["exchange_response"] + + market = exch._api.markets[pair] + po = exch._api.parse_order(exchange_response, market) + expected = order["expected"] + assert isinstance(po["id"], str) + assert po["id"] is not None + + # Generic comparison which works for all fields + for key, value in expected.items(): + assert key in po, f"Expected key {key} not found in parsed order" + assert isinstance(po[key], type(value)), ( + f"Expected {key} to be of type {type(value)}, got {type(po[key])}" + ) + assert po[key] == value, f"Expected {key} to be {value}, got {po[key]}" + + else: + pytest.skip(f"No sample order available for exchange {exchangename}") + def test_ccxt_my_trades_parse(self, exchange: EXCHANGE_FIXTURE_TYPE): exch, exchangename, exchange_params = exchange if trades := exchange_params.get("sample_my_trades"):