krakenfutures: run order adjustments via _order_contracts_to_amount
This commit is contained in:
@@ -134,14 +134,29 @@ class Krakenfutures(Exchange):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _order_contracts_to_amount(self, order: CcxtOrder) -> CcxtOrder:
|
def _order_contracts_to_amount(self, order: CcxtOrder) -> CcxtOrder:
|
||||||
"""Normalize order and fix missing trigger price from CCXT parsing.
|
"""Normalize order and apply Kraken Futures-specific fixes.
|
||||||
|
|
||||||
CCXT's krakenfutures parse_order reads triggerPrice from the top level of
|
This override applies all CCXT workarounds by calling _adjust_krakenfutures_order
|
||||||
the order details, but the /orders/status endpoint nests it inside
|
after the base class normalization. This ensures all orders (including those
|
||||||
priceTriggerOptions.triggerPrice. This extracts it so stopPrice/triggerPrice
|
from create_order that fill immediately) get correct prices and fees.
|
||||||
are populated correctly for stoploss order handling.
|
|
||||||
"""
|
"""
|
||||||
order = super()._order_contracts_to_amount(order)
|
order = super()._order_contracts_to_amount(order)
|
||||||
|
return self._adjust_krakenfutures_order(order)
|
||||||
|
|
||||||
|
def _adjust_krakenfutures_order(self, order: CcxtOrder) -> CcxtOrder:
|
||||||
|
"""Apply Kraken Futures-specific order corrections.
|
||||||
|
|
||||||
|
Fixes CCXT parsing issues:
|
||||||
|
1. triggerPrice nested in info.order.priceTriggerOptions (not extracted)
|
||||||
|
2. average set to limitPrice instead of actual fill price
|
||||||
|
|
||||||
|
For filled terminal orders, we ALWAYS fetch trades and compute VWAP because
|
||||||
|
CCXT's average is unreliable. We also aggregate fees to avoid a
|
||||||
|
redundant get_trades_for_order call from fee_detection_from_trades.
|
||||||
|
|
||||||
|
See: https://github.com/ccxt/ccxt/issues/27979
|
||||||
|
"""
|
||||||
|
# Fix 1: Extract nested triggerPrice for stoploss orders
|
||||||
if order.get("triggerPrice") is None and order.get("stopPrice") is None:
|
if order.get("triggerPrice") is None and order.get("stopPrice") is None:
|
||||||
trigger = safe_value_nested(order, "info.order.priceTriggerOptions.triggerPrice")
|
trigger = safe_value_nested(order, "info.order.priceTriggerOptions.triggerPrice")
|
||||||
if trigger is not None:
|
if trigger is not None:
|
||||||
@@ -149,23 +164,10 @@ class Krakenfutures(Exchange):
|
|||||||
if trigger_float is not None:
|
if trigger_float is not None:
|
||||||
order["triggerPrice"] = trigger_float
|
order["triggerPrice"] = trigger_float
|
||||||
order["stopPrice"] = trigger_float
|
order["stopPrice"] = trigger_float
|
||||||
return order
|
|
||||||
|
|
||||||
def _adjust_krakenfutures_order(self, order: CcxtOrder) -> CcxtOrder:
|
|
||||||
"""Fix missing average price and aggregate fees for filled orders.
|
|
||||||
|
|
||||||
Kraken Futures' /orders/status endpoint does not include execution data,
|
|
||||||
so CCXT sets price/average to the limitPrice (the order's limit, not the
|
|
||||||
actual fill price). For closed/filled orders we ALWAYS fetch trades and
|
|
||||||
compute VWAP because CCXT's average field is unreliable.
|
|
||||||
|
|
||||||
We also aggregate fees here to avoid a redundant get_trades_for_order call
|
|
||||||
from fee_detection_from_trades.
|
|
||||||
|
|
||||||
See: https://github.com/ccxt/ccxt/issues/27979
|
|
||||||
"""
|
|
||||||
filled = self._safe_float(order.get("filled")) or 0.0
|
filled = self._safe_float(order.get("filled")) or 0.0
|
||||||
if order.get("status") in ("canceled", "closed") and filled > 0:
|
if order.get("status") in ("canceled", "closed") and filled > 0:
|
||||||
|
# Fix 2: Compute VWAP and aggregate fees for filled orders
|
||||||
trades = self.get_trades_for_order(
|
trades = self.get_trades_for_order(
|
||||||
order["id"], order["symbol"], since=dt_from_ts(order["timestamp"])
|
order["id"], order["symbol"], since=dt_from_ts(order["timestamp"])
|
||||||
)
|
)
|
||||||
@@ -229,8 +231,7 @@ class Krakenfutures(Exchange):
|
|||||||
try:
|
try:
|
||||||
order = self._api.fetch_order(order_id, pair, params=status_params)
|
order = self._api.fetch_order(order_id, pair, params=status_params)
|
||||||
self._log_exchange_response("fetch_order", order)
|
self._log_exchange_response("fetch_order", order)
|
||||||
order = self._order_contracts_to_amount(order)
|
return self._order_contracts_to_amount(order)
|
||||||
return self._adjust_krakenfutures_order(order)
|
|
||||||
except ccxt.OrderNotFound:
|
except ccxt.OrderNotFound:
|
||||||
# Expected for older Kraken Futures orders not visible in orders/status.
|
# Expected for older Kraken Futures orders not visible in orders/status.
|
||||||
pass
|
pass
|
||||||
@@ -247,7 +248,7 @@ class Krakenfutures(Exchange):
|
|||||||
|
|
||||||
order = self._fetch_order_fallback(order_id, pair, params)
|
order = self._fetch_order_fallback(order_id, pair, params)
|
||||||
if order is not None:
|
if order is not None:
|
||||||
return self._adjust_krakenfutures_order(order)
|
return order
|
||||||
|
|
||||||
# Order not in status, open, closed, or canceled endpoints - genuinely gone.
|
# Order not in status, open, closed, or canceled endpoints - genuinely gone.
|
||||||
# Raise non-retrying InvalidOrderException (Kraken has limited history retention).
|
# Raise non-retrying InvalidOrderException (Kraken has limited history retention).
|
||||||
|
|||||||
Reference in New Issue
Block a user