Updating delisting function to return the time when it will delist if it is delisting

This commit is contained in:
Jakub Werner (jakubikan) 2024-03-22 21:17:17 +01:00
parent 4ef45314dd
commit cbc98d384e
2 changed files with 39 additions and 34 deletions

View File

@ -5,6 +5,8 @@ from pathlib import Path
from typing import Dict, List, Optional, Tuple
import ccxt
from cachetools import TTLCache
from threading import Lock
from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode
from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError
@ -50,6 +52,11 @@ class Binance(Exchange):
(TradingMode.FUTURES, MarginMode.ISOLATED)
]
def __init__(self, *args, **kwargs) -> None:
super(Binance, self).__init__(*args, **kwargs)
self._spot_delist_schedule_cache: TTLCache = TTLCache(maxsize=100, ttl=300)
self._spot_delist_schedule_cache_lock = Lock()
def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers:
tickers = super().get_tickers(symbols=symbols, cached=cached)
if self.trading_mode == TradingMode.FUTURES:
@ -218,43 +225,41 @@ class Binance(Exchange):
else:
return {}
def get_spot_delist_schedule(self, refresh: bool) -> list:
def get_spot_pair_delist_time(self, pair, refresh: bool) -> int | None:
"""
Calculates bid/ask target
bid rate - between current ask price and last price
ask rate - either using ticker bid or first bid based on orderbook
or remain static in any other case since it's not updating.
:param pair: Pair to get rate for
:param refresh: allow cached data
:param side: "buy" or "sell"
:return: float: Price
:raises PricingError if orderbook price could not be determined.
Get the delisting time for a pair if it will be delisted
:param pair: Pair to get the delisting time for
:param refresh: true if you need fresh data
:return: int: delisting time None if not delisting
"""
cache = self._spot_delist_schedule_cache
lock = self._spot_delist_schedule_cache_lock
if not refresh:
with self._cache_lock:
rate = cache_rate.get(pair)
# Check if cache has been invalidated
if rate:
logger.debug(f"Using cached {side} rate for {pair}.")
return rate
with lock:
delist_time = cache.get(f"{pair}")
if delist_time:
return delist_time
try:
delist_schedule = self._api.sapi_get_spot_delist_schedule()
if conf_strategy.get('use_order_book', False):
if delist_schedule is None:
return
order_book_top = conf_strategy.get('order_book_top', 1)
if order_book is None:
order_book = self.fetch_l2_order_book(pair, order_book_top)
rate = self._get_rate_from_ob(pair, side, order_book, name, price_side,
order_book_top)
else:
logger.debug(f"Using Last {price_side.capitalize()} / Last Price")
if ticker is None:
ticker = self.fetch_ticker(pair)
rate = self._get_rate_from_ticker(side, ticker, conf_strategy, price_side)
with lock:
for schedule in delist_schedule:
for pair in schedule['symbols']:
cache[f"{pair}"] = int(schedule['delistTime'])
if rate is None:
raise PricingError(f"{name}-Rate for {pair} was empty.")
with self._cache_lock:
cache_rate[pair] = rate
with lock:
return cache.get(f"{pair}")
return delistings
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not get delist schedule {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e:
raise OperationalException(e) from e

View File

@ -621,7 +621,7 @@ def test_get_maintenance_ratio_and_amt_binance(
def test_get_spot_delist_schedule(mocker, default_conf) -> None:
exchange = get_patched_exchange(mocker, default_conf, id='binance')
exchange._api.sapi_get_spot_delist_schedule = get_mock_coro([{'delistTime': '1712113200000', 'symbols': ['DREPBTC', 'DREPUSDT', 'MOBBTC', 'MOBUSDT', 'PNTUSDT']}])
exchange._api.sapi_get_spot_delist_schedule = MagicMock(return_value=[{'delistTime': '1712113200000', 'symbols': ['DREPBTC', 'DREPUSDT', 'MOBBTC', 'MOBUSDT', 'PNTUSDT']}])
assert exchange.get_spot_delist_schedule(True) == ['DREP/BTC', 'DREP/USDT', 'MOB/BTC', 'MOB/USDT', 'PNT/USDT']
assert exchange.get_spot_pair_delist_time('DREP/USDT', False) == 1712113200000