chore: bump ruff target-version to 3.10

This commit is contained in:
Meng Xiangzhuo
2024-11-08 04:37:33 +08:00
parent 44ff6d50ec
commit 41b725714f
122 changed files with 920 additions and 995 deletions

View File

@@ -12,7 +12,7 @@ from copy import deepcopy
from datetime import datetime, timedelta, timezone
from math import floor, isnan
from threading import Lock
from typing import Any, Literal, Optional, TypeGuard, Union
from typing import Any, Literal, TypeGuard
import ccxt
import ccxt.pro as ccxt_pro
@@ -170,7 +170,7 @@ class Exchange:
self,
config: Config,
*,
exchange_config: Optional[ExchangeConfig] = None,
exchange_config: ExchangeConfig | None = None,
validate: bool = True,
load_leverage_tiers: bool = False,
) -> None:
@@ -182,7 +182,7 @@ class Exchange:
self._api: ccxt.Exchange
self._api_async: ccxt_pro.Exchange
self._ws_async: ccxt_pro.Exchange = None
self._exchange_ws: Optional[ExchangeWS] = None
self._exchange_ws: ExchangeWS | None = None
self._markets: dict = {}
self._trading_fees: dict[str, Any] = {}
self._leverage_tiers: dict[str, list[dict]] = {}
@@ -453,7 +453,7 @@ class Exchange:
logger.info(f"API {endpoint}: {add_info_str}{response}")
def ohlcv_candle_limit(
self, timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None
self, timeframe: str, candle_type: CandleType, since_ms: int | None = None
) -> int:
"""
Exchange ohlcv candle limit
@@ -473,8 +473,8 @@ class Exchange:
def get_markets(
self,
base_currencies: Optional[list[str]] = None,
quote_currencies: Optional[list[str]] = None,
base_currencies: list[str] | None = None,
quote_currencies: list[str] | None = None,
spot_only: bool = False,
margin_only: bool = False,
futures_only: bool = False,
@@ -567,7 +567,7 @@ class Exchange:
else:
return DataFrame(columns=DEFAULT_TRADES_COLUMNS)
def get_contract_size(self, pair: str) -> Optional[float]:
def get_contract_size(self, pair: str) -> float | None:
if self.trading_mode == TradingMode.FUTURES:
market = self.markets.get(pair, {})
contract_size: float = 1.0
@@ -710,7 +710,7 @@ class Exchange:
return pair
raise ValueError(f"Could not combine {curr_1} and {curr_2} to get a valid pair.")
def validate_timeframes(self, timeframe: Optional[str]) -> None:
def validate_timeframes(self, timeframe: str | None) -> None:
"""
Check if timeframe from config is a supported timeframe on the exchange
"""
@@ -840,7 +840,7 @@ class Exchange:
def validate_trading_mode_and_margin_mode(
self,
trading_mode: TradingMode,
margin_mode: Optional[MarginMode], # Only None when trading_mode = TradingMode.SPOT
margin_mode: MarginMode | None, # Only None when trading_mode = TradingMode.SPOT
):
"""
Checks if freqtrade can perform trades using the configured
@@ -856,7 +856,7 @@ class Exchange:
f"Freqtrade does not support {mm_value} {trading_mode} on {self.name}"
)
def get_option(self, param: str, default: Optional[Any] = None) -> Any:
def get_option(self, param: str, default: Any | None = None) -> Any:
"""
Get parameter value from _ft_has
"""
@@ -873,7 +873,7 @@ class Exchange:
return self._ft_has["exchange_has_overrides"][endpoint]
return endpoint in self._api_async.has and self._api_async.has[endpoint]
def get_precision_amount(self, pair: str) -> Optional[float]:
def get_precision_amount(self, pair: str) -> float | None:
"""
Returns the amount precision of the exchange.
:param pair: Pair to get precision for
@@ -881,7 +881,7 @@ class Exchange:
"""
return self.markets.get(pair, {}).get("precision", {}).get("amount", None)
def get_precision_price(self, pair: str) -> Optional[float]:
def get_precision_price(self, pair: str) -> float | None:
"""
Returns the price precision of the exchange.
:param pair: Pair to get precision for
@@ -921,8 +921,8 @@ class Exchange:
return 1 / pow(10, precision)
def get_min_pair_stake_amount(
self, pair: str, price: float, stoploss: float, leverage: Optional[float] = 1.0
) -> Optional[float]:
self, pair: str, price: float, stoploss: float, leverage: float | None = 1.0
) -> float | None:
return self._get_stake_amount_limit(pair, price, stoploss, "min", leverage)
def get_max_pair_stake_amount(self, pair: str, price: float, leverage: float = 1.0) -> float:
@@ -940,8 +940,8 @@ class Exchange:
price: float,
stoploss: float,
limit: Literal["min", "max"],
leverage: Optional[float] = 1.0,
) -> Optional[float]:
leverage: float | None = 1.0,
) -> float | None:
isMin = limit == "min"
try:
@@ -1002,7 +1002,7 @@ class Exchange:
amount: float,
rate: float,
leverage: float,
params: Optional[dict] = None,
params: dict | None = None,
stop_loss: bool = False,
) -> CcxtOrder:
now = dt_now()
@@ -1033,7 +1033,7 @@ class Exchange:
dry_order[self._ft_has["stop_price_prop"]] = dry_order["price"]
# Workaround to avoid filling stoploss orders immediately
dry_order["ft_order_type"] = "stoploss"
orderbook: Optional[OrderBook] = None
orderbook: OrderBook | None = None
if self.exchange_has("fetchL2OrderBook"):
orderbook = self.fetch_l2_order_book(pair, 20)
if ordertype == "limit" and orderbook:
@@ -1088,7 +1088,7 @@ class Exchange:
return dry_order
def get_dry_market_fill_price(
self, pair: str, side: str, amount: float, rate: float, orderbook: Optional[OrderBook]
self, pair: str, side: str, amount: float, rate: float, orderbook: OrderBook | None
) -> float:
"""
Get the market order fill price based on orderbook interpolation
@@ -1136,7 +1136,7 @@ class Exchange:
pair: str,
side: str,
limit: float,
orderbook: Optional[OrderBook] = None,
orderbook: OrderBook | None = None,
offset: float = 0.0,
) -> bool:
if not self.exchange_has("fetchL2OrderBook"):
@@ -1158,7 +1158,7 @@ class Exchange:
return False
def check_dry_limit_order_filled(
self, order: CcxtOrder, immediate: bool = False, orderbook: Optional[OrderBook] = None
self, order: CcxtOrder, immediate: bool = False, orderbook: OrderBook | None = None
) -> CcxtOrder:
"""
Check dry-run limit order fill and update fee (if it filled).
@@ -1494,7 +1494,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) -> CcxtOrder:
def fetch_order(self, order_id: str, pair: str, params: dict | None = None) -> CcxtOrder:
if self._config["dry_run"]:
return self.fetch_dry_run_order(order_id)
if params is None:
@@ -1524,7 +1524,7 @@ class Exchange:
raise OperationalException(e) from e
def fetch_stoploss_order(
self, order_id: str, pair: str, params: Optional[dict] = None
self, order_id: str, pair: str, params: dict | None = None
) -> CcxtOrder:
return self.fetch_order(order_id, pair, params)
@@ -1551,9 +1551,7 @@ class Exchange:
return order.get("status") in NON_OPEN_EXCHANGE_STATES and order.get("filled") == 0.0
@retrier
def cancel_order(
self, order_id: str, pair: str, params: Optional[dict] = None
) -> dict[str, Any]:
def cancel_order(self, order_id: str, pair: str, params: dict | None = None) -> dict[str, Any]:
if self._config["dry_run"]:
try:
order = self.fetch_dry_run_order(order_id)
@@ -1581,9 +1579,7 @@ class Exchange:
except ccxt.BaseError as e:
raise OperationalException(e) from e
def cancel_stoploss_order(
self, order_id: str, pair: str, params: Optional[dict] = None
) -> dict:
def cancel_stoploss_order(self, order_id: str, pair: str, params: dict | None = None) -> dict:
return self.cancel_order(order_id, pair, params)
def is_cancel_order_result_suitable(self, corder) -> TypeGuard[CcxtOrder]:
@@ -1668,7 +1664,7 @@ class Exchange:
raise OperationalException(e) from e
@retrier
def fetch_positions(self, pair: Optional[str] = None) -> list[CcxtPosition]:
def fetch_positions(self, pair: str | None = None) -> list[CcxtPosition]:
"""
Fetch positions from the exchange.
If no pair is given, all positions are returned.
@@ -1703,7 +1699,7 @@ class Exchange:
@retrier(retries=0)
def fetch_orders(
self, pair: str, since: datetime, params: Optional[dict] = None
self, pair: str, since: datetime, params: dict | None = None
) -> list[CcxtOrder]:
"""
Fetch all orders for a pair "since"
@@ -1767,7 +1763,7 @@ class Exchange:
raise OperationalException(e) from e
@retrier
def fetch_bids_asks(self, symbols: Optional[list[str]] = None, cached: bool = False) -> dict:
def fetch_bids_asks(self, symbols: list[str] | None = None, cached: bool = False) -> dict:
"""
:param symbols: List of symbols to fetch
:param cached: Allow cached result
@@ -1800,7 +1796,7 @@ class Exchange:
raise OperationalException(e) from e
@retrier
def get_tickers(self, symbols: Optional[list[str]] = None, cached: bool = False) -> Tickers:
def get_tickers(self, symbols: list[str] | None = None, cached: bool = False) -> Tickers:
"""
:param cached: Allow cached result
:return: fetch_tickers result
@@ -1860,7 +1856,7 @@ class Exchange:
@staticmethod
def get_next_limit_in_list(
limit: int, limit_range: Optional[list[int]], range_required: bool = True
limit: int, limit_range: list[int] | None, range_required: bool = True
):
"""
Get next greater value in the list.
@@ -1924,8 +1920,8 @@ class Exchange:
refresh: bool,
side: EntryExit,
is_short: bool,
order_book: Optional[OrderBook] = None,
ticker: Optional[Ticker] = None,
order_book: OrderBook | None = None,
ticker: Ticker | None = None,
) -> float:
"""
Calculates bid/ask target
@@ -1974,7 +1970,7 @@ class Exchange:
def _get_rate_from_ticker(
self, side: EntryExit, ticker: Ticker, conf_strategy: dict[str, Any], price_side: BidAsk
) -> Optional[float]:
) -> float | None:
"""
Get rate from ticker.
"""
@@ -2053,7 +2049,7 @@ class Exchange:
@retrier
def get_trades_for_order(
self, order_id: str, pair: str, since: datetime, params: Optional[dict] = None
self, order_id: str, pair: str, since: datetime, params: dict | None = None
) -> list:
"""
Fetch Orders using the "fetch_my_trades" endpoint and filter them by order-id.
@@ -2168,7 +2164,7 @@ class Exchange:
def calculate_fee_rate(
self, fee: dict, symbol: str, cost: float, amount: float
) -> Optional[float]:
) -> float | None:
"""
Calculate fee rate if it's not given by the exchange.
:param fee: ccxt Fee dict - must contain cost / currency / rate
@@ -2208,7 +2204,7 @@ class Exchange:
def extract_cost_curr_rate(
self, fee: dict[str, Any], symbol: str, cost: float, amount: float
) -> tuple[float, str, Optional[float]]:
) -> tuple[float, str, float | None]:
"""
Extract tuple of cost, currency, rate.
Requires order_has_fee to run first!
@@ -2233,7 +2229,7 @@ class Exchange:
since_ms: int,
candle_type: CandleType,
is_new_pair: bool = False,
until_ms: Optional[int] = None,
until_ms: int | None = None,
) -> DataFrame:
"""
Get candle history using asyncio and returns the list of candles.
@@ -2267,7 +2263,7 @@ class Exchange:
candle_type: CandleType,
is_new_pair: bool = False,
raise_: bool = False,
until_ms: Optional[int] = None,
until_ms: int | None = None,
) -> OHLCVResponse:
"""
Download historic ohlcv
@@ -2312,7 +2308,7 @@ class Exchange:
pair: str,
timeframe: str,
candle_type: CandleType,
since_ms: Optional[int],
since_ms: int | None,
cache: bool,
) -> Coroutine[Any, Any, OHLCVResponse]:
not_all_data = cache and self.required_candle_call_count > 1
@@ -2381,7 +2377,7 @@ class Exchange:
)
def _build_ohlcv_dl_jobs(
self, pair_list: ListPairsWithTimeframes, since_ms: Optional[int], cache: bool
self, pair_list: ListPairsWithTimeframes, since_ms: int | None, cache: bool
) -> tuple[list[Coroutine], list[PairWithTimeframe]]:
"""
Build Coroutines to execute as part of refresh_latest_ohlcv
@@ -2458,9 +2454,9 @@ class Exchange:
self,
pair_list: ListPairsWithTimeframes,
*,
since_ms: Optional[int] = None,
since_ms: int | None = None,
cache: bool = True,
drop_incomplete: Optional[bool] = None,
drop_incomplete: bool | None = None,
) -> dict[PairWithTimeframe, DataFrame]:
"""
Refresh in-memory OHLCV asynchronously and set `_klines` with the result
@@ -2554,7 +2550,7 @@ class Exchange:
pair: str,
timeframe: str,
candle_type: CandleType,
since_ms: Optional[int] = None,
since_ms: int | None = None,
) -> OHLCVResponse:
"""
Asynchronously get candle history data using fetch_ohlcv
@@ -2628,7 +2624,7 @@ class Exchange:
pair: str,
timeframe: str,
limit: int,
since_ms: Optional[int] = None,
since_ms: int | None = None,
) -> list[list]:
"""
Fetch funding rate history - used to selectively override this by subclasses.
@@ -2687,7 +2683,7 @@ class Exchange:
async def _build_trades_dl_jobs(
self, pairwt: PairWithTimeframe, data_handler, cache: bool
) -> tuple[PairWithTimeframe, Optional[DataFrame]]:
) -> tuple[PairWithTimeframe, DataFrame | None]:
"""
Build coroutines to refresh trades for (they're then called through async.gather)
"""
@@ -2831,7 +2827,7 @@ class Exchange:
@retrier_async
async def _async_fetch_trades(
self, pair: str, since: Optional[int] = None, params: Optional[dict] = None
self, pair: str, since: int | None = None, params: dict | None = None
) -> tuple[list[list], Any]:
"""
Asynchronously gets trade history using fetch_trades.
@@ -2891,7 +2887,7 @@ class Exchange:
return trades[-1].get("timestamp")
async def _async_get_trade_history_id(
self, pair: str, until: int, since: Optional[int] = None, from_id: Optional[str] = None
self, pair: str, until: int, since: int | None = None, from_id: str | None = None
) -> tuple[str, list[list]]:
"""
Asynchronously gets trade history using fetch_trades
@@ -2946,7 +2942,7 @@ class Exchange:
return (pair, trades)
async def _async_get_trade_history_time(
self, pair: str, until: int, since: Optional[int] = None
self, pair: str, until: int, since: int | None = None
) -> tuple[str, list[list]]:
"""
Asynchronously gets trade history using fetch_trades,
@@ -2987,9 +2983,9 @@ class Exchange:
async def _async_get_trade_history(
self,
pair: str,
since: Optional[int] = None,
until: Optional[int] = None,
from_id: Optional[str] = None,
since: int | None = None,
until: int | None = None,
from_id: str | None = None,
) -> tuple[str, list[list]]:
"""
Async wrapper handling downloading trades using either time or id based methods.
@@ -3018,9 +3014,9 @@ class Exchange:
def get_historic_trades(
self,
pair: str,
since: Optional[int] = None,
until: Optional[int] = None,
from_id: Optional[str] = None,
since: int | None = None,
until: int | None = None,
from_id: str | None = None,
) -> tuple[str, list]:
"""
Get trade history data using asyncio.
@@ -3049,7 +3045,7 @@ class Exchange:
return self.loop.run_until_complete(task)
@retrier
def _get_funding_fees_from_exchange(self, pair: str, since: Union[datetime, int]) -> float:
def _get_funding_fees_from_exchange(self, pair: str, since: datetime | int) -> float:
"""
Returns the sum of all funding fees that were exchanged for a pair within a timeframe
Dry-run handling happens as part of _calculate_funding_fees.
@@ -3180,8 +3176,8 @@ class Exchange:
file_dump_json(filename, data)
def load_cached_leverage_tiers(
self, stake_currency: str, cache_time: Optional[timedelta] = None
) -> Optional[dict[str, list[dict]]]:
self, stake_currency: str, cache_time: timedelta | None = None
) -> dict[str, list[dict]] | None:
"""
Load cached leverage tiers from disk
:param cache_time: The maximum age of the cache before it is considered outdated
@@ -3226,7 +3222,7 @@ class Exchange:
"maintAmt": float(info["cum"]) if "cum" in info else None,
}
def get_max_leverage(self, pair: str, stake_amount: Optional[float]) -> float:
def get_max_leverage(self, pair: str, stake_amount: float | None) -> float:
"""
Returns the maximum leverage that a pair can be traded at
:param pair: The base/quote currency pair being traded
@@ -3304,7 +3300,7 @@ class Exchange:
def _set_leverage(
self,
leverage: float,
pair: Optional[str] = None,
pair: str | None = None,
accept_fail: bool = False,
):
"""
@@ -3356,7 +3352,7 @@ class Exchange:
pair: str,
margin_mode: MarginMode,
accept_fail: bool = False,
params: Optional[dict] = None,
params: dict | None = None,
):
"""
Set's the margin mode on the exchange to cross or isolated for a specific pair
@@ -3391,7 +3387,7 @@ class Exchange:
amount: float,
is_short: bool,
open_date: datetime,
close_date: Optional[datetime] = None,
close_date: datetime | None = None,
) -> float:
"""
Fetches and calculates the sum of all funding fees that occurred for a pair
@@ -3444,7 +3440,7 @@ class Exchange:
@staticmethod
def combine_funding_and_mark(
funding_rates: DataFrame, mark_rates: DataFrame, futures_funding_rate: Optional[int] = None
funding_rates: DataFrame, mark_rates: DataFrame, futures_funding_rate: int | None = None
) -> DataFrame:
"""
Combine funding-rates and mark-rates dataframes
@@ -3485,7 +3481,7 @@ class Exchange:
is_short: bool,
open_date: datetime,
close_date: datetime,
time_in_ratio: Optional[float] = None,
time_in_ratio: float | None = None,
) -> float:
"""
calculates the sum of all funding fees that occurred for a pair during a futures trade
@@ -3543,8 +3539,8 @@ class Exchange:
stake_amount: float,
leverage: float,
wallet_balance: float,
open_trades: Optional[list] = None,
) -> Optional[float]:
open_trades: list | None = None,
) -> float | None:
"""
Set's the margin mode on the exchange to cross or isolated for a specific pair
"""
@@ -3592,7 +3588,7 @@ class Exchange:
leverage: float,
wallet_balance: float, # Or margin balance
open_trades: list,
) -> Optional[float]:
) -> float | None:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
PERPETUAL:
@@ -3643,7 +3639,7 @@ class Exchange:
self,
pair: str,
notional_value: float,
) -> tuple[float, Optional[float]]:
) -> tuple[float, float | None]:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
:param pair: Market symbol