def test_should_use_new_spreads_even_if_config_not_changed(self, tmpdir): # given reloadable_config = ReloadableConfig(self.write_spread_importing_config(tmpdir)) reloadable_config.logger = MagicMock() # when spread_feed = { "buySpread": "0.1", "sellSpread": "1.0" } config = reloadable_config.get_config(spread_feed) # then assert config["usedBuySpread"] == 0.2 assert config["usedSellSpread"] == 3.0 # and # [a log message that the config was loaded gets generated] assert reloadable_config.logger.info.call_count == 1 # when spread_feed = { "buySpread": "0.2", "sellSpread": "0.5" } config = reloadable_config.get_config(spread_feed) # then assert config["usedBuySpread"] == 0.4 assert config["usedSellSpread"] == 1.5 # and # [a log message that the config was reloaded gets generated] assert reloadable_config.logger.info.call_count == 2
def test_should_use_new_spreads_even_if_config_not_changed(self, tmpdir): # given reloadable_config = ReloadableConfig(self.write_spread_importing_config(tmpdir)) reloadable_config.logger = MagicMock() # when spread_feed = { "buySpread": "0.1", "sellSpread": "1.0" } config = reloadable_config.get_config(spread_feed) # then assert config["usedBuySpread"] == 0.2 assert config["usedSellSpread"] == 3.0 # and # [a log message that the config was loaded gets generated] assert reloadable_config.logger.info.call_count == 1 # when spread_feed = { "buySpread": "0.2", "sellSpread": "0.5" } config = reloadable_config.get_config(spread_feed) # then assert config["usedBuySpread"] == 0.4 assert config["usedSellSpread"] == 1.5 # and # [no log message that the config was reloaded gets generated] # [as it was only parsed again] assert reloadable_config.logger.info.call_count == 1
def test_should_read_file_again_if_changed(self, tmpdir): # given reloadable_config = ReloadableConfig(self.write_advanced_config(tmpdir, "b")) reloadable_config.logger = MagicMock() # when config = reloadable_config.get_config({}) # then assert config["a"] == "b" # and # [a log message that the config was loaded gets generated] assert reloadable_config.logger.info.call_count == 1 # when self.write_advanced_config(tmpdir, "z") config = reloadable_config.get_config({}) # then assert config["a"] == "z" # and # [a log message that the config was reloaded gets generated] assert reloadable_config.logger.info.call_count == 2
def test_airswap_read_no_adjacent_bands(tmpdir): sell_bands_file = BandConfig.two_adjacent_sell_bands_config(tmpdir) sell_bands_config = ReloadableConfig(str(sell_bands_file)) airswap_sell_bands = AirswapBands.read(sell_bands_config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History()) assert len(airswap_sell_bands.sell_bands) == 0 buy_bands_file = BandConfig.two_adjacent_buy_bands_config(tmpdir) buy_bands_config = ReloadableConfig(str(buy_bands_file)) airswap_buy_bands = AirswapBands.read(buy_bands_config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History()) assert len(airswap_buy_bands.buy_bands) == 0
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='etherdelta-market-maker-keeper') self.add_arguments(parser=parser) parser.set_defaults(cancel_on_shutdown=False, withdraw_on_shutdown=False) self.arguments = parser.parse_args(args) setup_logging(self.arguments) provider = HTTPProvider( endpoint_uri=self.arguments.rpc_host, request_kwargs={'timeout': self.arguments.rpc_timeout}) self.web3: Web3 = kwargs['web3'] if 'web3' in kwargs else Web3( provider) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.tub = Tub(web3=self.web3, address=Address(self.arguments.tub_address)) self.sai = ERC20Token(web3=self.web3, address=self.tub.sai()) self.gem = ERC20Token(web3=self.web3, address=self.tub.gem()) self.bands_config = ReloadableConfig(self.arguments.config) self.eth_reserve = Wad.from_number(self.arguments.eth_reserve) self.min_eth_balance = Wad.from_number(self.arguments.min_eth_balance) self.min_eth_deposit = Wad.from_number(self.arguments.min_eth_deposit) self.min_sai_deposit = Wad.from_number(self.arguments.min_sai_deposit) self.gas_price = GasPriceFactory().create_gas_price(self.arguments) self.price_feed = PriceFeedFactory().create_price_feed( self.arguments, self.tub) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) if self.eth_reserve <= self.min_eth_balance: raise Exception( "--eth-reserve must be higher than --min-eth-balance") assert (self.arguments.order_expiry_threshold >= 0) assert (self.arguments.order_no_cancel_threshold >= self.arguments.order_expiry_threshold) self.history = History() self.etherdelta = EtherDelta(web3=self.web3, address=Address( self.arguments.etherdelta_address)) self.etherdelta_api = EtherDeltaApi( client_tool_directory="lib/pymaker/utils/etherdelta-client", client_tool_command="node main.js", api_server=self.arguments.etherdelta_socket, number_of_attempts=self.arguments.etherdelta_number_of_attempts, retry_interval=self.arguments.etherdelta_retry_interval, timeout=self.arguments.etherdelta_timeout) self.our_orders = list()
def __init__(self, args: list): parser = argparse.ArgumentParser(prog='bitzlato-market-maker-keeper') self.add_arguments(parser) self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History() self.bittrex_api = BittrexApi( api_server=self.arguments.bittrex_api_server, api_key=self.arguments.bittrex_api_key, secret_key=self.arguments.bittrex_secret_key, timeout=self.arguments.bittrex_timeout) self.order_book_manager = OrderBookManager( refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with( lambda: self.bittrex_api.get_orders(self.pair())) self.order_book_manager.get_balances_with( lambda: self.bittrex_api.get_balances()) self.order_book_manager.cancel_orders_with( lambda order: self.bittrex_api.cancel_order(order.order_id)) self.order_book_manager.enable_history_reporting( self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start()
class GasPriceFile(GasPrice): """Gas price configuration dynamically reloadable from a file. It is roughly an equivalent of implementation of :py:class:`pymaker.gas.IncreasingGasPrice`, but it uses `ReloadableConfig` to read the gas parameters from a file, and will dynamically reload that file whenever it changes. It allows to update the gas price dynamically for running keepers. Attributes: filename: Filename of the configuration file. """ def __init__(self, filename: str): assert(isinstance(filename, str)) self.reloadable_config = ReloadableConfig(filename) def get_gas_price(self, time_elapsed: int) -> Optional[int]: assert(isinstance(time_elapsed, int)) config = self.reloadable_config.get_config() gas_price = config.get('gasPrice', None) gas_price_increase = config.get('gasPriceIncrease', None) gas_price_increase_every = config.get('gasPriceIncreaseEvery', None) gas_price_max = config.get('gasPriceMax', None) if gas_price is not None: if gas_price_increase and gas_price_increase_every: strategy = IncreasingGasPrice(gas_price, gas_price_increase, gas_price_increase_every, gas_price_max) else: strategy = FixedGasPrice(gas_price) else: strategy = DefaultGasPrice() return strategy.get_gas_price(time_elapsed=time_elapsed)
def test_should_read_simple_file(self, tmpdir): # when config = ReloadableConfig(self.write_sample_config(tmpdir)).get_config({}) # then assert len(config) == 1 assert config["a"] == "b"
def _parse_configs(data: dict) -> (list, dict): pairs = [] configs = {} for market in data['markets']: pair = ImtokenPair(market['pair']) pairs.append(pair) band_config = ReloadableConfig(market['bands']) market_args = MarketArgs(market) price_feed = PriceFeedFactory().create_price_feed(market_args) spread_feed = create_spread_feed(market_args) control_feed = create_control_feed(market_args) config = { 'bands_config': band_config, 'price_feed': price_feed, 'spread_feed': spread_feed, 'control_feed': control_feed, 'history': History() } configs[pair.base_pair] = config configs[pair.counter_pair] = config return pairs, configs
def read(reloadable_config: ReloadableConfig, spread_feed: Feed, history: History): assert (isinstance(reloadable_config, ReloadableConfig)) assert (isinstance(history, History)) try: config = reloadable_config.get_config(spread_feed.get()[0]) buy_bands = list(map(BuyBand, config['buyBands'])) buy_limits = SideLimits( config['buyLimits'] if 'buyLimits' in config else [], history.buy_history) sell_bands = list(map(SellBand, config['sellBands'])) sell_limits = SideLimits( config['sellLimits'] if 'sellLimits' in config else [], history.sell_history) except Exception as e: logging.getLogger().warning( f"Config file is invalid ({e}). Treating the config file as it has no bands." ) buy_bands = [] buy_limits = SideLimits([], history.buy_history) sell_bands = [] sell_limits = SideLimits([], history.buy_history) return Bands(buy_bands=buy_bands, buy_limits=buy_limits, sell_bands=sell_bands, sell_limits=sell_limits)
def test_new_sell_orders_taker_amount_success_case(tmpdir): bands_file = BandConfig.sample_config_dif_margins(tmpdir) bands_config = ReloadableConfig(str(bands_file)) airswap_bands = AirswapBands.read(bands_config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History()) # maker_amount -> denominated in WETH maker_amount = Wad(0) taker_amount = Wad(1770600000000000000) our_sell_balance = Wad(1562000000000000000000) sell_limit = Wad(1562000000000000000000) target_price = WebSocketPriceFeed(FakeFeed({"buyPrice": "120", "sellPrice": "130"})).get_price() new_order = airswap_bands._new_side_orders('sell', maker_amount, taker_amount, our_sell_balance, sell_limit, airswap_bands.sell_bands[0], target_price.sell_price) # -- pricing logic -- # sellPrice = 130 * avgMargin = 0.05 = 6.5 # 130 + 6.5 = 136.5 # taker_amount = 1.7706 / 136.5 = 0.01297142857142857142857 assert new_order['maker_amount'].__float__() == 0.01297142857142857142857 assert new_order['taker_amount'].__float__() == 1.7706
def __init__(self, arguments: Namespace, pyex_api: PyexAPI): setup_logging(arguments) if arguments.__contains__('web3'): self.web3 = arguments.web3 else: web3_endpoint = f"http://{self.arguments.rpc_host}:{self.arguments.rpc_port}" web3_options = {"timeout": self.arguments.rpc_timeout} self.web3 = Web3(HTTPProvider(endpoint_uri=web3_endpoint, request_kwargs=web3_options)) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.bands_config = ReloadableConfig(arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(arguments) self.spread_feed = create_spread_feed(arguments) self.control_feed = create_control_feed(arguments) self.order_history_reporter = create_order_history_reporter(arguments) self.history = History() self.init_order_book_manager(arguments, pyex_api)
def test_should_read_file_again_if_changed(self, tmpdir): # given reloadable_config = ReloadableConfig(self.write_advanced_config(tmpdir, "b")) # when config = reloadable_config.get_config({}) # then assert config["a"] == "b" # when self.write_advanced_config(tmpdir, "z") config = reloadable_config.get_config({}) # then assert config["a"] == "z"
def create_bands(config_file): config = ReloadableConfig(str(config_file)) return Bands.read(config, EmptyFeed(), FixedFeed({ 'canBuy': True, 'canSell': True }), History())
def test_new_buy_orders_taker_amount_exceed_buy_balance_fail_case(tmpdir): bands_file = BandConfig.sample_config(tmpdir) bands_config = ReloadableConfig(str(bands_file)) airswap_bands = AirswapBands.read(bands_config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History()) # maker_amount -> denominated in DAI maker_amount = Wad(0) taker_amount = Wad(11360000000000000000) our_buy_balance = Wad(50000000000000000) buy_limit = Wad(1562000000000000000000) target_price = WebSocketPriceFeed(FakeFeed({"buyPrice": "120", "sellPrice": "130"})).get_price() new_order = airswap_bands._new_side_orders('buy', maker_amount, taker_amount, our_buy_balance, buy_limit, airswap_bands.buy_bands[0], target_price.buy_price) # -- pricing logic -- # buyPrice = 120 * minMargin = 0.02 = 117.6 # maker_amount = 11.36000 / 117.6 = 0.09659863945 # our_buy_balance = 0.050000000000000000 !!BREAK!! assert new_order == {}
def test_new_buy_orders_taker_amount_success_case(tmpdir): bands_file = BandConfig.sample_config(tmpdir) bands_config = ReloadableConfig(str(bands_file)) airswap_bands = AirswapBands.read(bands_config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History()) # maker_amount -> denominated in DAI maker_amount = Wad(0) taker_amount = Wad(11360000000000000000) our_buy_balance = Wad(1562000000000000000000) buy_limit = Wad(1562000000000000000000) target_price = WebSocketPriceFeed(FakeFeed({"buyPrice": "120", "sellPrice": "130"})).get_price() new_order = airswap_bands._new_side_orders('buy', maker_amount, taker_amount, our_buy_balance, buy_limit, airswap_bands.buy_bands[0], target_price.buy_price) # -- pricing logic -- # buyPrice = 120 * minMargin = 0.04 = 4.8 # 120 - 4.8 = 115.2 # maker_amount = 11.36000 / 115.2 = 0.09861111111111111111111 assert new_order['taker_amount'].__float__() == 11.36000 assert new_order['maker_amount'].__float__() == 0.09861111111111111111111
def test_should_read_file_again_if_changed(self, tmpdir): # given reloadable_config = ReloadableConfig( self.write_advanced_config(tmpdir, "b")) # when config = reloadable_config.get_config() # then assert config["a"] == "b" # when self.write_advanced_config(tmpdir, "z") config = reloadable_config.get_config() # then assert config["a"] == "z"
def test_should_read_advanced_file(self, tmpdir): # when config = ReloadableConfig(self.write_advanced_config(tmpdir, "b")).get_config({}) # then assert len(config) == 2 assert config["a"] == "b" assert config["c"] == "b"
def test_should_import_other_config_file(self, tmpdir): # when self.write_global_config(tmpdir, 17.0, 11.0) config = ReloadableConfig(self.write_importing_config(tmpdir)).get_config({}) # then assert len(config) == 2 assert config["firstValueMultiplied"] == 34.0 assert config["secondValueMultiplied"] == 33.0
def __init__(self, reloadable_config: ReloadableConfig): assert (isinstance(reloadable_config, ReloadableConfig)) config = reloadable_config.get_config() self.buy_bands = list(map(BuyBand, config['buyBands'])) self.sell_bands = list(map(SellBand, config['sellBands'])) if self._bands_overlap(self.buy_bands) or self._bands_overlap( self.sell_bands): raise Exception(f"Bands in the config file overlap")
def read(reloadable_config: ReloadableConfig, spread_feed: Feed, control_feed: Feed, history: History): assert (isinstance(reloadable_config, ReloadableConfig)) assert (isinstance(spread_feed, Feed)) assert (isinstance(control_feed, Feed)) assert (isinstance(history, History)) try: config = reloadable_config.get_config(spread_feed.get()[0]) control_feed_value = control_feed.get()[0] buy_bands = list(map(BuyBand, config['buyBands'])) buy_limits = SideLimits( config['buyLimits'] if 'buyLimits' in config else [], history.buy_history) sell_bands = list(map(SellBand, config['sellBands'])) sell_limits = SideLimits( config['sellLimits'] if 'sellLimits' in config else [], history.sell_history) if 'canBuy' not in control_feed_value or 'canSell' not in control_feed_value: logging.getLogger().warning( "Control feed expired. Assuming no buy bands and no sell bands." ) buy_bands = [] sell_bands = [] else: if not control_feed_value['canBuy']: logging.getLogger().warning( "Control feed says we shall not buy. Assuming no buy bands." ) buy_bands = [] if not control_feed_value['canSell']: logging.getLogger().warning( "Control feed says we shall not sell. Assuming no sell bands." ) sell_bands = [] except Exception as e: logging.getLogger().exception( f"Config file is invalid ({e}). Treating the config file as it has no bands." ) buy_bands = [] buy_limits = SideLimits([], history.buy_history) sell_bands = [] sell_limits = SideLimits([], history.buy_history) return Bands(buy_bands=buy_bands, buy_limits=buy_limits, sell_bands=sell_bands, sell_limits=sell_limits)
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='paradex-market-maker-keeper') self.add_arguments(parser=parser) self.arguments = parser.parse_args(args) setup_logging(self.arguments) provider = HTTPProvider( endpoint_uri=self.arguments.rpc_host, request_kwargs={'timeout': self.arguments.rpc_timeout}) self.web3: Web3 = kwargs['web3'] if 'web3' in kwargs else Web3( provider) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.pair = self.arguments.pair.upper() self.token_buy = ERC20Token(web3=self.web3, address=Address( self.arguments.buy_token_address)) self.token_sell = ERC20Token(web3=self.web3, address=Address( self.arguments.sell_token_address)) self.bands_config = ReloadableConfig(self.arguments.config) self.price_max_decimals = None self.amount_max_decimals = None self.gas_price = GasPriceFactory().create_gas_price(self.arguments) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History() self.zrx_exchange = ZrxExchangeV2(web3=self.web3, address=Address( self.arguments.exchange_address)) self.paradex_api = ParadexApi(self.zrx_exchange, self.arguments.paradex_api_server, self.arguments.paradex_api_key, self.arguments.paradex_api_timeout) self.order_book_manager = OrderBookManager( refresh_frequency=self.arguments.refresh_frequency, max_workers=1) self.order_book_manager.get_orders_with( lambda: self.paradex_api.get_orders(self.pair)) self.order_book_manager.get_balances_with(lambda: self.get_balances()) self.order_book_manager.cancel_orders_with( lambda order: self.paradex_api.cancel_order(order.order_id)) self.order_book_manager.enable_history_reporting( self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start()
def test_should_reevaluate_if_other_config_file_changed(self, tmpdir): # given reloadable_config = ReloadableConfig(self.write_importing_config(tmpdir)) # when self.write_global_config(tmpdir, 17.0, 11.0) config = reloadable_config.get_config({}) # then assert len(config) == 2 assert config["firstValueMultiplied"] == 34.0 assert config["secondValueMultiplied"] == 33.0 # when self.write_global_config(tmpdir, 18.0, 3.0) config = reloadable_config.get_config({}) # then assert len(config) == 2 assert config["firstValueMultiplied"] == 36.0 assert config["secondValueMultiplied"] == 9.0
def create_bands(config_file, rules=None): if rules is None: rules = BinanceUsRules(pair="ETH-USDC", min_price=Wad.from_number(0.01), max_price=Wad.from_number(100000.0), tick_size=Wad.from_number(0.01), min_quantity=Wad.from_number(0.00001), max_quantity=Wad.from_number(9000.0), step_size=Wad.from_number(0.00001)) config = ReloadableConfig(str(config_file)) return BinanceBands.read(config, EmptyFeed(), FixedFeed({'canBuy': True, 'canSell': True}), History(), rules)
def test_should_import_spreads(self, tmpdir): # given spread_feed = {"buySpread": "0.1", "sellSpread": "1.0"} # when config = ReloadableConfig( self.write_spread_importing_config(tmpdir)).get_config(spread_feed) # then assert len(config) == 2 assert config["usedBuySpread"] == 0.2 assert config["usedSellSpread"] == 3.0
def __init__(self, args: list): parser = argparse.ArgumentParser(prog='bibox-market-maker-keeper') parser.add_argument("--bibox-api-server", type=str, default="https://api.bibox.com", help="Address of the Bibox API server (default: 'https://api.bibox.com')") parser.add_argument("--bibox-api-key", type=str, required=True, help="API key for the Bibox API") parser.add_argument("--bibox-secret", type=str, required=True, help="Secret for the Bibox API") parser.add_argument("--bibox-timeout", type=float, default=9.5, help="Timeout for accessing the Bibox API (in seconds, default: 9.5)") parser.add_argument("--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument("--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--spread-feed", type=str, help="Source of spread feed") parser.add_argument("--spread-feed-expiry", type=int, default=3600, help="Maximum age of the spread feed (in seconds, default: 3600)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.history = History() self.bibox_api = BiboxApi(api_server=self.arguments.bibox_api_server, api_key=self.arguments.bibox_api_key, secret=self.arguments.bibox_secret, timeout=self.arguments.bibox_timeout) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.order_book_manager = OrderBookManager(refresh_frequency=3) self.order_book_manager.get_orders_with(lambda: self.bibox_api.get_orders(pair=self.pair(), retry=True)) self.order_book_manager.get_balances_with(lambda: self.bibox_api.coin_list(retry=True)) self.order_book_manager.start()
def __init__(self, arguments: Namespace, pyex_api: PyexAPI): setup_logging(arguments) self.bands_config = ReloadableConfig(arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(arguments) self.spread_feed = create_spread_feed(arguments) self.control_feed = create_control_feed(arguments) self.order_history_reporter = create_order_history_reporter(arguments) self.history = History() self.init_order_book_manager(arguments, pyex_api)
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='0x-market-maker-keeper') self.add_arguments(parser=parser) self.arguments = parser.parse_args(args) setup_logging(self.arguments) provider = HTTPProvider( endpoint_uri=self.arguments.rpc_host, request_kwargs={'timeout': self.arguments.rpc_timeout}) self.web3: Web3 = kwargs['web3'] if 'web3' in kwargs else Web3( provider) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.eth_address = Address(self.arguments.eth_token_address) self.min_eth_balance = Wad.from_number(self.arguments.min_eth_balance) self.bands_config = ReloadableConfig(self.arguments.config) self.gas_price = GasPriceFactory().create_gas_price(self.arguments) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History() # Delegate 0x specific init to a function to permit overload for 0xv3 self.zrx_exchange = None self.zrx_relayer_api = None self.zrx_api = None self.pair = None self.init_zrx() self.placed_zrx_orders = [] self.placed_zrx_orders_lock = Lock() self.order_book_manager = OrderBookManager( refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with(lambda: self.get_orders()) self.order_book_manager.get_balances_with(lambda: self.get_balances()) self.order_book_manager.place_orders_with(self.place_order_function) self.order_book_manager.cancel_orders_with(self.cancel_order_function) self.order_book_manager.enable_history_reporting( self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start()
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='idex-market-maker-keeper') self.add_arguments(parser=parser) parser.set_defaults(cancel_on_shutdown=False, withdraw_on_shutdown=False) self.arguments = parser.parse_args(args) setup_logging(self.arguments) provider = HTTPProvider( endpoint_uri=self.arguments.rpc_host, request_kwargs={'timeout': self.arguments.rpc_timeout}) self.web3: Web3 = kwargs['web3'] if 'web3' in kwargs else Web3( provider) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.tub = Tub(web3=self.web3, address=Address(self.arguments.tub_address)) self.sai = ERC20Token(web3=self.web3, address=self.tub.sai()) self.gem = ERC20Token(web3=self.web3, address=self.tub.gem()) self.bands_config = ReloadableConfig(self.arguments.config) self.eth_reserve = Wad.from_number(self.arguments.eth_reserve) self.min_eth_balance = Wad.from_number(self.arguments.min_eth_balance) self.min_eth_deposit = Wad.from_number(self.arguments.min_eth_deposit) self.min_sai_deposit = Wad.from_number(self.arguments.min_sai_deposit) self.gas_price = GasPriceFactory().create_gas_price(self.arguments) self.price_feed = PriceFeedFactory().create_price_feed( self.arguments, self.tub) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) if self.eth_reserve <= self.min_eth_balance: raise Exception( "--eth-reserve must be higher than --min-eth-balance") self.history = History() self.idex = IDEX(self.web3, Address(self.arguments.idex_address)) self.idex_api = IDEXApi(self.idex, self.arguments.idex_api_server, self.arguments.idex_timeout)
def __init__(self, reloadable_config: ReloadableConfig, history: History): assert (isinstance(reloadable_config, ReloadableConfig)) assert (isinstance(history, History)) config = reloadable_config.get_config() self.buy_bands = list(map(BuyBand, config['buyBands'])) self.buy_limits = SideLimits( config['buyLimits'] if 'buyLimits' in config else [], history.buy_history) self.sell_bands = list(map(SellBand, config['sellBands'])) self.sell_limits = SideLimits( config['sellLimits'] if 'sellLimits' in config else [], history.sell_history) if self._bands_overlap(self.buy_bands) or self._bands_overlap( self.sell_bands): raise Exception(f"Bands in the config file overlap")
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument("--gateio-api-server", type=str, default="https://data.gate.io", help="Address of the Gate.io API server (default: 'https://data.gate.io')") parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument("--gateio-timeout", type=float, default=9.5, help="Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument("--pair", type=str, required=True, help="Token pair on which the keeper should operate") parser.add_argument("--config", type=str, required=True, help="Buy/sell bands configuration file") parser.add_argument("--price-feed", type=str, help="Source of price feed") parser.add_argument("--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) logging.basicConfig(format='%(asctime)-15s %(levelname)-8s %(message)s', level=(logging.DEBUG if self.arguments.debug else logging.INFO)) logging.getLogger('urllib3.connectionpool').setLevel(logging.INFO) logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.INFO) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments.price_feed, self.arguments.price_feed_expiry) self.gateio_api = GateIOApi(api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='airswap-market-maker-keeper') self.add_arguments(parser=parser) self.arguments = parser.parse_args(args) setup_logging(self.arguments) provider = HTTPProvider( endpoint_uri=self.arguments.rpc_host, request_kwargs={'timeout': self.arguments.rpc_timeout}) self.web3: Web3 = kwargs['web3'] if 'web3' in kwargs else Web3( provider) self.web3.eth.defaultAccount = self.arguments.eth_from self.our_address = Address(self.arguments.eth_from) register_keys(self.web3, self.arguments.eth_key) self.airswap_api = AirswapApi(self.arguments.airswap_api_server, self.arguments.airswap_api_timeout) if self.arguments.buy_token_address == '0x0000000000000000000000000000000000000000': self.token_buy = EthToken(web3=self.web3, address=Address( self.arguments.buy_token_address)) else: self.token_buy = ERC20Token(web3=self.web3, address=Address( self.arguments.buy_token_address)) self.eth_token_sell = EthToken( web3=self.web3, address=Address(self.arguments.eth_sell_token_address)) self.weth_token_sell = ERC20Token( web3=self.web3, address=Address(self.arguments.weth_sell_token_address)) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History()
def __init__(self, reloadable_config: ReloadableConfig, spread_feed: Feed, history: History): assert(isinstance(reloadable_config, ReloadableConfig)) assert(isinstance(history, History)) try: config = reloadable_config.get_config(spread_feed.get()[0]) self.buy_bands = list(map(BuyBand, config['buyBands'])) self.buy_limits = SideLimits(config['buyLimits'] if 'buyLimits' in config else [], history.buy_history) self.sell_bands = list(map(SellBand, config['sellBands'])) self.sell_limits = SideLimits(config['sellLimits'] if 'sellLimits' in config else [], history.sell_history) except Exception as e: self.logger.warning(f"Config file is invalid ({e}). Treating the config file as it has no bands.") self.buy_bands = [] self.buy_limits = SideLimits([], history.buy_history) self.sell_bands = [] self.sell_limits = SideLimits([], history.buy_history) if self._bands_overlap(self.buy_bands) or self._bands_overlap(self.sell_bands): self.logger.warning("Bands in the config file overlap. Treating the config file as it has no bands.") self.buy_bands = [] self.sell_bands = []