fix: extract triggerPrice from priceTriggerOptions for stoploss orders
CCXT's krakenfutures parse_order misses triggerPrice when the /orders/status endpoint nests it inside priceTriggerOptions. Override _order_contracts_to_amount to populate triggerPrice and stopPrice from info.order.priceTriggerOptions.triggerPrice.
This commit is contained in:
@@ -132,6 +132,25 @@ class Krakenfutures(Exchange):
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _order_contracts_to_amount(self, order: CcxtOrder) -> CcxtOrder:
|
||||||
|
"""Normalize order and fix missing trigger price from CCXT parsing.
|
||||||
|
|
||||||
|
CCXT's krakenfutures parse_order reads triggerPrice from the top level of
|
||||||
|
the order details, but the /orders/status endpoint nests it inside
|
||||||
|
priceTriggerOptions.triggerPrice. This extracts it so stopPrice/triggerPrice
|
||||||
|
are populated correctly for stoploss order handling.
|
||||||
|
"""
|
||||||
|
order = super()._order_contracts_to_amount(order)
|
||||||
|
if order.get("triggerPrice") is None and order.get("stopPrice") is None:
|
||||||
|
info = order.get("info", {})
|
||||||
|
inner = info.get("order", {}) if isinstance(info, dict) else {}
|
||||||
|
opts = inner.get("priceTriggerOptions", {}) if isinstance(inner, dict) else {}
|
||||||
|
trigger = self._safe_float(opts.get("triggerPrice")) if isinstance(opts, dict) else None
|
||||||
|
if trigger is not None:
|
||||||
|
order["triggerPrice"] = trigger
|
||||||
|
order["stopPrice"] = trigger
|
||||||
|
return order
|
||||||
|
|
||||||
@retrier(retries=API_FETCH_ORDER_RETRY_COUNT)
|
@retrier(retries=API_FETCH_ORDER_RETRY_COUNT)
|
||||||
def fetch_order(
|
def fetch_order(
|
||||||
self, order_id: str, pair: str, params: dict[str, Any] | None = None
|
self, order_id: str, pair: str, params: dict[str, Any] | None = None
|
||||||
|
|||||||
@@ -55,6 +55,75 @@ def test_krakenfutures_ohlcv_candle_limit_funding_rate(mocker, default_conf):
|
|||||||
assert ex.ohlcv_candle_limit("1h", candle_type=CandleType.FUNDING_RATE) == 700
|
assert ex.ohlcv_candle_limit("1h", candle_type=CandleType.FUNDING_RATE) == 700
|
||||||
|
|
||||||
|
|
||||||
|
# --- _order_contracts_to_amount trigger price fix tests ---
|
||||||
|
|
||||||
|
|
||||||
|
def test_krakenfutures_order_contracts_fixes_missing_trigger_price(mocker, default_conf):
|
||||||
|
"""Extract triggerPrice from info.order.priceTriggerOptions when CCXT misses it."""
|
||||||
|
ex = get_patched_exchange(mocker, default_conf, exchange="krakenfutures")
|
||||||
|
order = {
|
||||||
|
"id": "abc",
|
||||||
|
"symbol": "BTC/USD:USD",
|
||||||
|
"triggerPrice": None,
|
||||||
|
"stopPrice": None,
|
||||||
|
"info": {
|
||||||
|
"order": {
|
||||||
|
"type": "TRIGGER_ORDER",
|
||||||
|
"priceTriggerOptions": {
|
||||||
|
"triggerPrice": 71641,
|
||||||
|
"triggerSignal": "LAST_PRICE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"status": "TRIGGER_PLACED",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result = ex._order_contracts_to_amount(order)
|
||||||
|
assert result["triggerPrice"] == 71641.0
|
||||||
|
assert result["stopPrice"] == 71641.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_krakenfutures_order_contracts_preserves_existing_trigger_price(mocker, default_conf):
|
||||||
|
"""Don't overwrite triggerPrice when CCXT already parsed it correctly."""
|
||||||
|
ex = get_patched_exchange(mocker, default_conf, exchange="krakenfutures")
|
||||||
|
order = {
|
||||||
|
"id": "abc",
|
||||||
|
"symbol": "BTC/USD:USD",
|
||||||
|
"triggerPrice": 70000.0,
|
||||||
|
"stopPrice": 70000.0,
|
||||||
|
"info": {
|
||||||
|
"order": {
|
||||||
|
"priceTriggerOptions": {
|
||||||
|
"triggerPrice": 71641,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result = ex._order_contracts_to_amount(order)
|
||||||
|
assert result["triggerPrice"] == 70000.0
|
||||||
|
assert result["stopPrice"] == 70000.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_krakenfutures_order_contracts_no_trigger_options(mocker, default_conf):
|
||||||
|
"""Regular (non-trigger) orders should pass through unchanged."""
|
||||||
|
ex = get_patched_exchange(mocker, default_conf, exchange="krakenfutures")
|
||||||
|
order = {
|
||||||
|
"id": "abc",
|
||||||
|
"symbol": "BTC/USD:USD",
|
||||||
|
"triggerPrice": None,
|
||||||
|
"stopPrice": None,
|
||||||
|
"info": {
|
||||||
|
"order": {
|
||||||
|
"type": "lmt",
|
||||||
|
"orderId": "abc",
|
||||||
|
},
|
||||||
|
"status": "placed",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result = ex._order_contracts_to_amount(order)
|
||||||
|
assert result["triggerPrice"] is None
|
||||||
|
assert result["stopPrice"] is None
|
||||||
|
|
||||||
|
|
||||||
# --- fetch_order fallback tests ---
|
# --- fetch_order fallback tests ---
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user