def update_running_pure_mm(pure_mm_strategy: PureMarketMakingStrategy, key: str, new_value: Any): if key == "bid_spread": pure_mm_strategy.bid_spread = new_value / Decimal("100") return True elif key == "ask_spread": pure_mm_strategy.ask_spread = new_value / Decimal("100") return True return False
def setUp(self): self.clock_tick_size = 1 self._last_clock_tick = 0 self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp) self.market: BacktestMarket = BacktestMarket() self.book_data: MockOrderBookLoader = MockOrderBookLoader( self.trading_pair, self.base_asset, self.quote_asset) self.mid_price = 100 self.bid_spread = 0.01 self.ask_spread = 0.01 self.order_refresh_time = 30 self.book_data.set_balanced_order_book(mid_price=self.mid_price, min_price=1, max_price=200, price_step_size=1, volume_step_size=10) self.market.add_data(self.book_data) self.market.set_balance("HBOT", 500) self.market.set_balance("ETH", 5000) self.market.set_quantization_param( QuantizationParams(self.trading_pair, 6, 6, 6, 6)) self.market_info = MarketTradingPairTuple(self.market, self.trading_pair, self.base_asset, self.quote_asset) self.clock.add_iterator(self.market) self.one_level_strategy = PureMarketMakingStrategy( self.market_info, bid_spread=Decimal("0.01"), ask_spread=Decimal("0.01"), order_amount=Decimal("1"), order_refresh_time=5.0, filled_order_delay=5.0, order_refresh_tolerance_pct=-1, minimum_spread=-1, ) self.multi_levels_strategy = PureMarketMakingStrategy( self.market_info, bid_spread=Decimal("0.01"), ask_spread=Decimal("0.01"), order_amount=Decimal("1"), order_refresh_time=5.0, filled_order_delay=5.0, order_refresh_tolerance_pct=-1, order_levels=3, order_level_spread=Decimal("0.01"), order_level_amount=Decimal("1"), minimum_spread=-1, ) self._ev_loop = asyncio.get_event_loop()
def main(): # Define the data cache path. hummingsim.set_data_path(os.path.join(os.environ["PWD"], "data")) # Define the parameters for the backtest. start = pd.Timestamp("2019-01-01", tz="UTC") end = pd.Timestamp("2019-01-02", tz="UTC") binance_trading_pair = ("ETHUSDT", "ETH", "USDT") # ddex_trading_pair = ("WETH-DAI", "WETH", "DAI") binance_market = BacktestMarket() ddex_market = BacktestMarket() binance_market.config = MarketConfig(AssetType.BASE_CURRENCY, 0.001, AssetType.QUOTE_CURRENCY, 0.001, {}) ddex_market.config = MarketConfig(AssetType.BASE_CURRENCY, 0.001, AssetType.QUOTE_CURRENCY, 0.001, {}) binance_loader = BinanceOrderBookLoaderV2(*binance_trading_pair) #ddex_loader = DDEXOrderBookLoader(*ddex_trading_pair) binance_market.add_data(binance_loader) #ddex_market.add_data(ddex_loader) binance_market.set_quantization_param( QuantizationParams("ETHUSDT", 5, 3, 5, 3)) #ddex_market.set_quantization_param(QuantizationParams("WETH-DAI", 5, 3, 5, 3)) market_pair = PureMarketPair(*([binance_market] + list(binance_trading_pair))) strategy = PureMarketMakingStrategy( [market_pair], order_size=50000, bid_place_threshold=0.003, ask_place_threshold=0.003, logging_options=PureMarketMakingStrategy.OPTION_LOG_ALL) clock = Clock(ClockMode.BACKTEST, tick_size=60, start_time=start.timestamp(), end_time=end.timestamp()) clock.add_iterator(binance_market) #clock.add_iterator(ddex_market) clock.add_iterator(strategy) binance_market.set_balance("ETH", 100000.0) binance_market.set_balance("USDT", 100000000.0) ddex_market.set_balance("WETH", 100000.0) ddex_market.set_balance("DAI", 1000.0) current = start.timestamp() step = 60 while current <= end.timestamp(): current += step clock.backtest_til(current) print("clock ticked") binance_loader.close()
def setUp(self): self.clock: Clock = Clock(ClockMode.BACKTEST, 60.0, self.start_timestamp, self.end_timestamp) self.clock_tick_size = 60 self.maker_market: BacktestMarket = BacktestMarket() self.maker_data: MockOrderBookLoader = MockOrderBookLoader( *self.maker_symbols) self.mid_price = 100 self.bid_threshold = 0.01 self.ask_threshold = 0.01 self.cancel_order_wait_time = 45 self.maker_data.set_balanced_order_book(mid_price=self.mid_price, min_price=1, max_price=200, price_step_size=1, volume_step_size=10) self.maker_market.add_data(self.maker_data) self.maker_market.set_balance("COINALPHA", 500) self.maker_market.set_balance("WETH", 500) self.maker_market.set_balance("QETH", 500) self.maker_market.set_quantization_param( QuantizationParams(self.maker_symbols[0], 5, 5, 5, 5)) self.market_pair: PureMarketPair = PureMarketPair( *([self.maker_market] + self.maker_symbols)) logging_options: int = ( PureMarketMakingStrategy.OPTION_LOG_ALL & (~PureMarketMakingStrategy.OPTION_LOG_NULL_ORDER_SIZE)) self.strategy: {PureMarketMakingStrategy} = PureMarketMakingStrategy( [self.market_pair], order_size=1, bid_place_threshold=self.bid_threshold, ask_place_threshold=self.ask_threshold, cancel_order_wait_time=45, logging_options=logging_options) self.logging_options = logging_options self.clock.add_iterator(self.maker_market) self.clock.add_iterator(self.strategy) self.maker_order_fill_logger: EventLogger = EventLogger() self.cancel_order_logger: EventLogger = EventLogger() self.maker_market.add_listener(MarketEvent.OrderFilled, self.maker_order_fill_logger) self.maker_market.add_listener(MarketEvent.OrderCancelled, self.cancel_order_logger)
async def start_market_making(self, strategy_name: str): strategy_cm = get_strategy_config_map(strategy_name) if strategy_name == "cross_exchange_market_making": maker_market = strategy_cm.get("maker_market").value.lower() taker_market = strategy_cm.get("taker_market").value.lower() raw_maker_symbol = strategy_cm.get( "maker_market_symbol").value.upper() raw_taker_symbol = strategy_cm.get( "taker_market_symbol").value.upper() min_profitability = strategy_cm.get("min_profitability").value trade_size_override = strategy_cm.get("trade_size_override").value strategy_report_interval = global_config_map.get( "strategy_report_interval").value limit_order_min_expiration = strategy_cm.get( "limit_order_min_expiration").value cancel_order_threshold = strategy_cm.get( "cancel_order_threshold").value active_order_canceling = strategy_cm.get( "active_order_canceling").value top_depth_tolerance_rules = [(re.compile(re_str), value) for re_str, value in strategy_cm.get( "top_depth_tolerance").value] top_depth_tolerance = 0.0 for regex, tolerance_value in top_depth_tolerance_rules: if regex.match(raw_maker_symbol) is not None: top_depth_tolerance = tolerance_value try: maker_assets: Tuple[str, str] = SymbolSplitter.split( maker_market, raw_maker_symbol) taker_assets: Tuple[str, str] = SymbolSplitter.split( taker_market, raw_taker_symbol) except ValueError as e: self.app.log(str(e)) return market_names: List[Tuple[str, List[str]]] = [ (maker_market, [raw_maker_symbol]), (taker_market, [raw_taker_symbol]) ] self._initialize_wallet( token_symbols=list(set(maker_assets + taker_assets))) self._initialize_markets(market_names) self.assets = set(maker_assets + taker_assets) self.market_pair = CrossExchangeMarketPair( *([self.markets[maker_market], raw_maker_symbol] + list(maker_assets) + [self.markets[taker_market], raw_taker_symbol] + list(taker_assets) + [top_depth_tolerance])) strategy_logging_options = ( CrossExchangeMarketMakingStrategy.OPTION_LOG_CREATE_ORDER | CrossExchangeMarketMakingStrategy.OPTION_LOG_ADJUST_ORDER | CrossExchangeMarketMakingStrategy.OPTION_LOG_MAKER_ORDER_FILLED | CrossExchangeMarketMakingStrategy.OPTION_LOG_REMOVING_ORDER | CrossExchangeMarketMakingStrategy.OPTION_LOG_STATUS_REPORT | CrossExchangeMarketMakingStrategy.OPTION_LOG_MAKER_ORDER_HEDGED ) self.strategy = CrossExchangeMarketMakingStrategy( market_pairs=[self.market_pair], min_profitability=min_profitability, status_report_interval=strategy_report_interval, logging_options=strategy_logging_options, trade_size_override=trade_size_override, limit_order_min_expiration=limit_order_min_expiration, cancel_order_threshold=cancel_order_threshold, active_order_canceling=active_order_canceling) elif strategy_name == "arbitrage": primary_market = strategy_cm.get("primary_market").value.lower() secondary_market = strategy_cm.get( "secondary_market").value.lower() raw_primary_symbol = strategy_cm.get( "primary_market_symbol").value.upper() raw_secondary_symbol = strategy_cm.get( "secondary_market_symbol").value.upper() min_profitability = strategy_cm.get("min_profitability").value try: primary_assets: Tuple[str, str] = SymbolSplitter.split( primary_market, raw_primary_symbol) secondary_assets: Tuple[str, str] = SymbolSplitter.split( secondary_market, raw_secondary_symbol) except ValueError as e: self.app.log(str(e)) return market_names: List[Tuple[str, List[str]]] = [ (primary_market, [raw_primary_symbol]), (secondary_market, [raw_secondary_symbol]) ] self._initialize_wallet( token_symbols=list(set(primary_assets + secondary_assets))) self._initialize_markets(market_names) self.assets = set(primary_assets + secondary_assets) self.market_pair = ArbitrageMarketPair( *([self.markets[primary_market], raw_primary_symbol] + list(primary_assets) + [self.markets[secondary_market], raw_secondary_symbol] + list(secondary_assets))) strategy_logging_options = ArbitrageStrategy.OPTION_LOG_ALL self.strategy = ArbitrageStrategy( market_pairs=[self.market_pair], min_profitability=min_profitability, logging_options=strategy_logging_options) elif strategy_name == "pure_market_making": order_size = strategy_cm.get("order_amount").value cancel_order_wait_time = strategy_cm.get( "cancel_order_wait_time").value bid_place_threshold = strategy_cm.get("bid_place_threshold").value ask_place_threshold = strategy_cm.get("ask_place_threshold").value maker_market = strategy_cm.get("maker_market").value.lower() raw_maker_symbol = strategy_cm.get( "maker_market_symbol").value.upper() try: primary_assets: Tuple[str, str] = SymbolSplitter.split( maker_market, raw_maker_symbol) except ValueError as e: self.app.log(str(e)) return market_names: List[Tuple[str, List[str]]] = [(maker_market, [raw_maker_symbol])] self._initialize_wallet(token_symbols=list(set(primary_assets))) self._initialize_markets(market_names) self.assets = set(primary_assets) self.market_pair = PureMarketPair( *([self.markets[maker_market], raw_maker_symbol] + list(primary_assets))) strategy_logging_options = PureMarketMakingStrategy.OPTION_LOG_ALL self.strategy = PureMarketMakingStrategy( market_pairs=[self.market_pair], order_size=order_size, bid_place_threshold=bid_place_threshold, ask_place_threshold=ask_place_threshold, cancel_order_wait_time=cancel_order_wait_time, logging_options=strategy_logging_options) elif strategy_name == "discovery": try: market_1 = strategy_cm.get("primary_market").value.lower() market_2 = strategy_cm.get("secondary_market").value.lower() target_symbol_1 = list( strategy_cm.get("target_symbol_1").value) target_symbol_2 = list( strategy_cm.get("target_symbol_2").value) target_profitability = float( strategy_cm.get("target_profitability").value) target_amount = float(strategy_cm.get("target_amount").value) equivalent_token: List[List[str]] = list( strategy_cm.get("equivalent_tokens").value) if not target_symbol_2: target_symbol_2 = SymbolFetcher.get_instance().symbols.get( market_2, []) if not target_symbol_1: target_symbol_1 = SymbolFetcher.get_instance().symbols.get( market_1, []) market_names: List[Tuple[str, List[str]]] = [ (market_1, target_symbol_1), (market_2, target_symbol_2) ] target_base_quote_1: List[Tuple[str, str]] = [ SymbolSplitter.split(market_1, symbol) for symbol in target_symbol_1 ] target_base_quote_2: List[Tuple[str, str]] = [ SymbolSplitter.split(market_2, symbol) for symbol in target_symbol_2 ] self._trading_required = False self._initialize_wallet( token_symbols=[] ) # wallet required only for dex hard dependency self._initialize_markets(market_names) self.market_pair = DiscoveryMarketPair(*([ self.markets[market_1], self.markets[market_1].get_active_exchange_markets ] + [ self.markets[market_2], self.markets[market_2].get_active_exchange_markets ])) self.strategy = DiscoveryStrategy( market_pairs=[self.market_pair], target_symbols=target_base_quote_1 + target_base_quote_2, equivalent_token=equivalent_token, target_profitability=target_profitability, target_amount=target_amount) except Exception as e: self.app.log(str(e)) self.logger().error("Error initializing strategy.", exc_info=True) else: raise NotImplementedError try: self.clock = Clock(ClockMode.REALTIME) if self.wallet is not None: self.clock.add_iterator(self.wallet) for market in self.markets.values(): if market is not None: self.clock.add_iterator(market) if self.strategy: self.clock.add_iterator(self.strategy) self.strategy_task: asyncio.Task = asyncio.ensure_future( self._run_clock()) self.app.log( f"\n '{strategy_name}' strategy started.\n" f" You can use the `status` command to query the progress.") self.starting_balances = await self.wait_till_ready( self.balance_snapshot) self.stop_loss_tracker = StopLossTracker( self.data_feed, list(self.assets), list(self.markets.values()), lambda *args, **kwargs: asyncio.ensure_future( self.stop(*args, **kwargs))) await self.wait_till_ready(self.stop_loss_tracker.start) except Exception as e: self.logger().error(str(e), exc_info=True)