diff --git a/config/__init__.py b/config/__init__.py index fb835e438..6bd91cc58 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -476,6 +476,14 @@ class ExchangeConstantsMarketStatusInfoColumns(Enum): MAX_QTY = "maxQty" +class ExchangeConstantsOrderBookInfoColumns(Enum): + BIDS = "bids" + ASKS = "asks" + TIMESTAMP = "timestamp" + DATETIME = "datetime" + NONCE = "nonce" + + class ExchangeConstantsOrderColumns(Enum): INFO = "info" ID = "id" diff --git a/evaluator/RealTime/realtime_evaluator.py b/evaluator/RealTime/realtime_evaluator.py index 99040758b..c9902b99c 100644 --- a/evaluator/RealTime/realtime_evaluator.py +++ b/evaluator/RealTime/realtime_evaluator.py @@ -129,6 +129,12 @@ async def _get_data_from_exchange(self, time_frame, limit=None, return_list=Fals return await self.exchange.get_symbol_prices(self.symbol, time_frame, limit=limit, return_list=return_list) + async def _get_order_book_from_exchange(self, limit=None): + return await self.exchange.get_order_book(self.symbol, limit=limit) + + async def _get_recent_trades_from_exchange(self, limit=None): + return await self.exchange.get_recent_trades(self.symbol, limit=limit) + @staticmethod def _compare_data(new_data, old_data): try: diff --git a/evaluator/Strategies/strategies_evaluator.py b/evaluator/Strategies/strategies_evaluator.py index 725e262c1..de02e88d7 100644 --- a/evaluator/Strategies/strategies_evaluator.py +++ b/evaluator/Strategies/strategies_evaluator.py @@ -82,3 +82,11 @@ class MixedStrategiesEvaluator(StrategiesEvaluator): @abstractmethod async def eval_impl(self) -> None: raise NotImplementedError("Eval_impl not implemented") + + +class MarketMakingStrategiesEvaluator(StrategiesEvaluator): + __metaclass__ = StrategiesEvaluator + + @abstractmethod + async def eval_impl(self) -> None: + raise NotImplementedError("Eval_impl not implemented") diff --git a/trading/exchanges/exchange_dispatcher.py b/trading/exchanges/exchange_dispatcher.py index f51365e7d..4a91e6fb4 100644 --- a/trading/exchanges/exchange_dispatcher.py +++ b/trading/exchanges/exchange_dispatcher.py @@ -157,10 +157,15 @@ async def _handle_web_socket_reset(self): # return bid and asks on each side of the order book stack # careful here => can be for binance limit > 100 has a 5 weight and > 500 a 10 weight ! async def get_order_book(self, symbol, limit=50): - if not self._web_socket_available(): - await self.exchange.get_order_book(symbol, limit) + symbol_data = self.get_symbol_data(symbol) + + if not self._web_socket_available() or not symbol_data.order_book_is_initialized(): + if not self._web_socket_available() or \ + (self._web_socket_available() and self.exchange_web_socket.handles_order_book()): + symbol_data.init_order_book() + await self.exchange.get_order_book(symbol=symbol, limit=limit) - return self.get_symbol_data(symbol).get_symbol_order_book(limit) + return symbol_data.get_symbol_order_book() async def get_recent_trades(self, symbol, limit=50): symbol_data = self.get_symbol_data(symbol) @@ -171,7 +176,7 @@ async def get_recent_trades(self, symbol, limit=50): symbol_data.init_recent_trades() await self.exchange.get_recent_trades(symbol=symbol, limit=limit) - return symbol_data.get_symbol_recent_trades(limit) + return symbol_data.get_symbol_recent_trades() # A price ticker contains statistics for a particular market/symbol for some period of time in recent past (24h) async def get_price_ticker(self, symbol): diff --git a/trading/exchanges/exchange_symbol_data.py b/trading/exchanges/exchange_symbol_data.py index 0c77c5800..c9a038928 100644 --- a/trading/exchanges/exchange_symbol_data.py +++ b/trading/exchanges/exchange_symbol_data.py @@ -14,12 +14,12 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. -from tools.logging.logging_util import get_logger import time import numpy as np from config import PriceIndexes, TimeFramesMinutes, MINUTE_TO_SECONDS +from tools.logging.logging_util import get_logger class SymbolData: @@ -38,6 +38,7 @@ def __init__(self, symbol): self.previous_candle_time = {} self.are_recent_trades_initialized = False + self.is_order_book_initialized = False self.logger = get_logger(f"{self.__class__.__name__} - {self.symbol}") ''' @@ -70,7 +71,7 @@ def ensure_data_validity(self, time_frame): # if update time from the previous time frame is greater than this given time frame: # data did not get updated => data are invalid if current_time - previous_candle_timestamp > \ - TimeFramesMinutes[time_frame]*MINUTE_TO_SECONDS*error_allowance: + TimeFramesMinutes[time_frame] * MINUTE_TO_SECONDS * error_allowance: return False return True @@ -106,11 +107,11 @@ def get_symbol_ticker(self): return self.symbol_ticker # order book functions - def get_symbol_order_book(self, limit=None): + def get_symbol_order_book(self): return self.order_book # recent trade functions - def get_symbol_recent_trades(self, limit=None): + def get_symbol_recent_trades(self): return self.recent_trades # private functions @@ -143,6 +144,12 @@ def recent_trades_are_initialized(self): def init_recent_trades(self): self.are_recent_trades_initialized = True + def order_book_is_initialized(self): + return self.is_order_book_initialized + + def init_order_book(self): + self.is_order_book_initialized = True + class CandleData: def __init__(self, all_candles_data): @@ -209,7 +216,7 @@ def get_symbol_volume_candles(self, limit=None, return_list=False): return self.extract_limited_data(self.volume_candles_array, limit) def get_symbol_prices(self, limit=None, return_list=False): - symbol_prices = [None]*len(PriceIndexes) + symbol_prices = [None] * len(PriceIndexes) symbol_prices[PriceIndexes.IND_PRICE_CLOSE.value] = self.get_symbol_close_candles(limit, return_list) symbol_prices[PriceIndexes.IND_PRICE_OPEN.value] = self.get_symbol_open_candles(limit, return_list) symbol_prices[PriceIndexes.IND_PRICE_HIGH.value] = self.get_symbol_high_candles(limit, return_list) @@ -292,12 +299,12 @@ def sanitize_last_candle(close_candle_data, high_candle_data, low_candle_data): low_candle_data[-1] = close_last_candle if high_candle_data[-1] < close_last_candle: high_candle_data[-1] = close_last_candle - + @staticmethod def set_last_candle_arrays(list_updated, array_to_update): if array_to_update is not None: array_to_update[-1] = list_updated[-1] - + @staticmethod def convert_list_to_array(list_to_convert): return np.array(list_to_convert) diff --git a/trading/exchanges/rest_exchanges/rest_exchange.py b/trading/exchanges/rest_exchanges/rest_exchange.py index ba18cef0a..dbffbdc47 100644 --- a/trading/exchanges/rest_exchanges/rest_exchange.py +++ b/trading/exchanges/rest_exchanges/rest_exchange.py @@ -137,8 +137,9 @@ async def get_symbol_prices(self, symbol, time_frame, limit=None, return_list=Tr self.get_symbol_data(symbol).update_symbol_candles(time_frame, candles, replace_all=True) # return up to ten bidasks on each side of the order book stack - async def get_order_book(self, symbol, limit=30): - self.get_symbol_data(symbol).update_order_book(await self.client.fetch_order_book(symbol, limit)) + async def get_order_book(self, symbol, limit=5): + order_book = await self.client.fetch_order_book(symbol, limit) + self.get_symbol_data(symbol).update_order_book(order_book) async def get_recent_trades(self, symbol, limit=50): trades = await self.client.fetch_trades(symbol, limit=limit)