From ecf5e1ce6b4aa2f2fc0e145af31565780302a501 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Nov 2024 07:23:25 +0100 Subject: [PATCH] chore: first step to improved ccxtOrder Typing --- freqtrade/exchange/bybit.py | 8 ++++--- freqtrade/exchange/exchange.py | 33 ++++++++++++++++------------ freqtrade/exchange/exchange_types.py | 4 +++- freqtrade/exchange/gate.py | 6 +++-- freqtrade/exchange/okx.py | 12 +++++----- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/freqtrade/exchange/bybit.py b/freqtrade/exchange/bybit.py index 4face01c9..7d2351cf6 100644 --- a/freqtrade/exchange/bybit.py +++ b/freqtrade/exchange/bybit.py @@ -11,7 +11,7 @@ from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode from freqtrade.exceptions import DDosProtection, ExchangeError, OperationalException, TemporaryError from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier -from freqtrade.exchange.exchange_types import FtHas +from freqtrade.exchange.exchange_types import CcxtOrder, FtHas from freqtrade.util.datetime_helpers import dt_now, dt_ts @@ -229,7 +229,9 @@ class Bybit(Exchange): logger.warning(f"Could not update funding fees for {pair}.") return 0.0 - def fetch_orders(self, pair: str, since: datetime, params: Optional[dict] = None) -> list[dict]: + def fetch_orders( + self, pair: str, since: datetime, params: Optional[dict] = None + ) -> list[CcxtOrder]: """ Fetch all orders for a pair "since" :param pair: Pair for the query @@ -246,7 +248,7 @@ class Bybit(Exchange): return orders - def fetch_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> dict: + def fetch_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> CcxtOrder: if self.exchange_has("fetchOrder"): # Set acknowledged to True to avoid ccxt exception params = {"acknowledged": True} diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 48bb84369..ae9385a5d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -70,6 +70,7 @@ from freqtrade.exchange.common import ( ) from freqtrade.exchange.exchange_types import ( CcxtBalances, + CcxtOrder, CcxtPosition, FtHas, OHLCVResponse, @@ -1003,14 +1004,14 @@ class Exchange: leverage: float, params: Optional[dict] = None, stop_loss: bool = False, - ) -> dict[str, Any]: + ) -> CcxtOrder: now = dt_now() order_id = f"dry_run_{side}_{pair}_{now.timestamp()}" # Rounding here must respect to contract sizes _amount = self._contracts_to_amount( pair, self.amount_to_precision(pair, self._amount_to_contracts(pair, amount)) ) - dry_order: dict[str, Any] = { + dry_order: CcxtOrder = { "id": order_id, "symbol": pair, "price": rate, @@ -1072,9 +1073,9 @@ class Exchange: def add_dry_order_fee( self, pair: str, - dry_order: dict[str, Any], + dry_order: CcxtOrder, taker_or_maker: MakerTaker, - ) -> dict[str, Any]: + ) -> CcxtOrder: fee = self.get_fee(pair, taker_or_maker=taker_or_maker) dry_order.update( { @@ -1158,8 +1159,8 @@ class Exchange: return False def check_dry_limit_order_filled( - self, order: dict[str, Any], immediate: bool = False, orderbook: Optional[OrderBook] = None - ) -> dict[str, Any]: + self, order: CcxtOrder, immediate: bool = False, orderbook: Optional[OrderBook] = None + ) -> CcxtOrder: """ Check dry-run limit order fill and update fee (if it filled). """ @@ -1186,7 +1187,7 @@ class Exchange: return order - def fetch_dry_run_order(self, order_id) -> dict[str, Any]: + def fetch_dry_run_order(self, order_id) -> CcxtOrder: """ Return dry-run order Only call if running in dry-run mode. @@ -1460,7 +1461,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def fetch_order_emulated(self, order_id: str, pair: str, params: dict) -> dict: + def fetch_order_emulated(self, order_id: str, pair: str, params: dict) -> CcxtOrder: """ Emulated fetch_order if the exchange doesn't support fetch_order, but requires separate calls for open and closed orders. @@ -1494,7 +1495,7 @@ class Exchange: raise OperationalException(e) from e @retrier(retries=API_FETCH_ORDER_RETRY_COUNT) - def fetch_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> dict: + def fetch_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> CcxtOrder: if self._config["dry_run"]: return self.fetch_dry_run_order(order_id) if params is None: @@ -1523,12 +1524,14 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def fetch_stoploss_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> dict: + def fetch_stoploss_order( + self, order_id: str, pair: str, params: Optional[dict] = None + ) -> CcxtOrder: return self.fetch_order(order_id, pair, params) def fetch_order_or_stoploss_order( self, order_id: str, pair: str, stoploss_order: bool = False - ) -> dict: + ) -> CcxtOrder: """ Simple wrapper calling either fetch_order or fetch_stoploss_order depending on the stoploss_order parameter @@ -1589,7 +1592,7 @@ class Exchange: required = ("fee", "status", "amount") return all(corder.get(k, None) is not None for k in required) - def cancel_order_with_result(self, order_id: str, pair: str, amount: float) -> dict: + def cancel_order_with_result(self, order_id: str, pair: str, amount: float) -> CcxtOrder: """ Cancel order returning a result. Creates a fake result if cancel order returns a non-usable result @@ -1686,7 +1689,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def _fetch_orders_emulate(self, pair: str, since_ms: int) -> list[dict]: + def _fetch_orders_emulate(self, pair: str, since_ms: int) -> list[CcxtOrder]: orders = [] if self.exchange_has("fetchClosedOrders"): orders = self._api.fetch_closed_orders(pair, since=since_ms) @@ -1696,7 +1699,9 @@ class Exchange: return orders @retrier(retries=0) - def fetch_orders(self, pair: str, since: datetime, params: Optional[dict] = None) -> list[dict]: + def fetch_orders( + self, pair: str, since: datetime, params: Optional[dict] = None + ) -> list[CcxtOrder]: """ Fetch all orders for a pair "since" :param pair: Pair for the query diff --git a/freqtrade/exchange/exchange_types.py b/freqtrade/exchange/exchange_types.py index e9c58ec38..8ff373d35 100644 --- a/freqtrade/exchange/exchange_types.py +++ b/freqtrade/exchange/exchange_types.py @@ -1,4 +1,4 @@ -from typing import Optional, TypedDict +from typing import Any, Optional, TypedDict from freqtrade.enums import CandleType @@ -94,5 +94,7 @@ class CcxtPosition(TypedDict): liquidationPrice: Optional[float] +CcxtOrder = dict[str, Any] + # pair, timeframe, candleType, OHLCV, drop last?, OHLCVResponse = tuple[str, str, CandleType, list, bool] diff --git a/freqtrade/exchange/gate.py b/freqtrade/exchange/gate.py index 70f877210..e804e3716 100644 --- a/freqtrade/exchange/gate.py +++ b/freqtrade/exchange/gate.py @@ -7,7 +7,7 @@ from typing import Any, Optional from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, PriceType, TradingMode from freqtrade.exchange import Exchange -from freqtrade.exchange.exchange_types import FtHas +from freqtrade.exchange.exchange_types import CcxtOrder, FtHas from freqtrade.misc import safe_value_fallback2 @@ -102,7 +102,9 @@ class Gate(Exchange): def get_order_id_conditional(self, order: dict[str, Any]) -> str: return safe_value_fallback2(order, order, "id_stop", "id") - def fetch_stoploss_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> dict: + def fetch_stoploss_order( + self, order_id: str, pair: str, params: Optional[dict] = None + ) -> CcxtOrder: order = self.fetch_order(order_id=order_id, pair=pair, params={"stop": True}) if order.get("status", "open") == "closed": # Places a real order - which we need to fetch explicitly. diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index fbbf21757..804ef1995 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -14,7 +14,7 @@ from freqtrade.exceptions import ( ) from freqtrade.exchange import Exchange, date_minus_candles from freqtrade.exchange.common import API_RETRY_COUNT, retrier -from freqtrade.exchange.exchange_types import FtHas +from freqtrade.exchange.exchange_types import CcxtOrder, FtHas from freqtrade.misc import safe_value_fallback2 from freqtrade.util import dt_now, dt_ts @@ -209,7 +209,9 @@ class Okx(Exchange): return order @retrier(retries=API_RETRY_COUNT) - def fetch_stoploss_order(self, order_id: str, pair: str, params: Optional[dict] = None) -> dict: + def fetch_stoploss_order( + self, order_id: str, pair: str, params: Optional[dict] = None + ) -> CcxtOrder: if self._config["dry_run"]: return self.fetch_dry_run_order(order_id) @@ -231,7 +233,7 @@ class Okx(Exchange): return self._fetch_stop_order_fallback(order_id, pair) - def _fetch_stop_order_fallback(self, order_id: str, pair: str) -> dict: + def _fetch_stop_order_fallback(self, order_id: str, pair: str) -> CcxtOrder: params2 = {"stop": True, "ordType": "conditional"} for method in ( self._api.fetch_open_orders, @@ -263,7 +265,7 @@ class Okx(Exchange): def cancel_stoploss_order( self, order_id: str, pair: str, params: Optional[dict] = None - ) -> dict: + ) -> CcxtOrder: params1 = {"stop": True} # 'ordType': 'conditional' # @@ -273,7 +275,7 @@ class Okx(Exchange): params=params1, ) - def _fetch_orders_emulate(self, pair: str, since_ms: int) -> list[dict]: + def _fetch_orders_emulate(self, pair: str, since_ms: int) -> list[CcxtOrder]: orders = [] orders = self._api.fetch_closed_orders(pair, since=since_ms)