def test_eth_transfer(self): # given initial_balance = eth_balance(self.web3, self.second_address) # when eth_transfer(self.web3, self.second_address, Wad.from_number(1.5)).transact() # then assert eth_balance(self.web3, self.second_address) == initial_balance + Wad.from_number(1.5)
def test_eth_transfer_from_other_account(self): # given initial_balance_second_address = eth_balance(self.web3, self.second_address) initial_balance_third_address = eth_balance(self.web3, self.third_address) # when eth_transfer(self.web3, self.third_address, Wad.from_number(1.5)).transact(from_address=self.second_address) # then assert eth_balance(self.web3, self.second_address) < initial_balance_second_address assert eth_balance(self.web3, self.third_address) == initial_balance_third_address + Wad.from_number(1.5)
def synchronize_price(self): # market_maker = MarketMaker(self.uniswap_router) # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning("Keeper ETH balance below minimum.") return if self.first_token.balance_of(self.our_address) < Wad.from_number( self.arguments.min_first_token_balance): self.logger.warning( f"Keeper {self.token_first.name} balance below minimum.") return if self.second_token.balance_of(self.our_address) < Wad.from_number( self.arguments.min_second_token_balance): self.logger.warning( f"Keeper {self.token_second.name} balance below minimum.") return target_price = self.price_feed.get_price() transaction = self.set_price( market_price=target_price.buy_price, first_token=self.first_token.address, second_token=self.second_token.address, max_delta_on_percent=self.max_delta_on_percent) if transaction is not None: transact = transaction.transact() if transact is not None and transact.successful: self.logger.info("The price was set successfully")
def synchronize_orders(self): if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning("Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_orders(self.our_orders()) return bands = Bands(self.bands_config, self.spread_feed, self.history) our_orders = self.our_orders() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance(self.token_buy) - Bands.total_amount(self.our_buy_orders(our_orders)) our_sell_balance = self.our_total_balance(self.token_sell) - Bands.total_amount(self.our_sell_orders(our_orders)) # Place new orders self.place_orders(bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price)[0])
def synchronize_orders(self): # If market is closed, cancel all orders but do not terminate the keeper. if self.otc.is_closed(): self.logger.warning("Market is closed. Cancelling all orders.") self.cancel_all_orders() return # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config) our_orders = self.our_orders() target_price = self.price() # If the is no target price feed, cancel all orders but do not terminate the keeper. # The moment the price feed comes back, the keeper will resume placing orders. if target_price is None: self.logger.warning( "No price feed available. Cancelling all orders.") self.cancel_all_orders() return # If there are any orders to be cancelled, cancel them. It is deliberate that we wait with topping-up # bands until the next block. This way we would create new orders based on the most recent price and # order book state. We could theoretically retrieve both (`target_price` and `our_orders`) again here, # but it just seems cleaner to do it in one place instead of in two. cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # If there are any new orders to be created, create them. new_orders = bands.new_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_balance(self.token_buy()), our_sell_balance=self.our_balance(self.token_sell()), target_price=target_price) if len(new_orders) > 0: self.create_orders(new_orders) # We do wait some time after the orders have been created. The reason for that is sometimes # orders that have been just placed were not picked up by the next `our_orders()` call # (one can presume the block hasn't been fully imported into the node yet), which made # the keeper try to place same order(s) again. Of course the second transaction did fail, but it # resulted in wasted gas and significant delay in keeper operation. # # There is no specific reason behind choosing to wait exactly 3s. time.sleep(3)
def synchronize_orders(self): """Update our positions in the order book to reflect keeper parameters.""" if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_orders(self.our_orders()) return bands = Bands(self.bands_config) our_orders = self.our_orders() target_price = self.price() if target_price is None: self.logger.warning( "Cancelling all orders as no price feed available.") self.cancel_orders(our_orders) return # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Place new orders self.create_orders( bands.new_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_balance(self.token_buy()), our_sell_balance=self.our_balance(self.token_sell()), target_price=target_price))
def synchronize_orders(self): """Update our positions in the order book to reflect keeper parameters.""" if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning("Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_orders(self.our_orders()) return bands = Bands(self.bands_config, self.history) our_orders = self.our_orders() target_price = self.price_feed.get_price() if target_price is None: self.logger.warning("Cancelling all orders as no price feed available.") self.cancel_orders(our_orders) return # Cancel orders cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance(self.token_buy) - Bands.total_amount(self.our_buy_orders(our_orders)) our_sell_balance = self.our_total_balance(self.token_sell) - Bands.total_amount(self.our_sell_orders(our_orders)) # Place new orders self.place_orders(bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price)[0])
def synchronize_orders(self): """Update our positions in the order book to reflect keeper parameters.""" if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.lifecycle.terminate( "Keeper balance is below the minimum, terminating.") self.cancel_orders(self.our_orders()) return bands = Bands(self.bands_config) our_orders = self.our_orders() target_price = self.price_feed.get_price() if target_price is None: self.logger.warning( "Cancelling all orders as no price feed available.") self.cancel_orders(our_orders) return self.cancel_orders( itertools.chain( bands.excessive_buy_orders(self.our_buy_orders(our_orders), target_price), bands.excessive_sell_orders(self.our_sell_orders(our_orders), target_price), bands.outside_orders(self.our_buy_orders(our_orders), self.our_sell_orders(our_orders), target_price))) self.top_up_bands(our_orders, bands.buy_bands, bands.sell_bands, target_price)
def synchronize_orders(self): # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config) block_number = self.web3.eth.blockNumber target_price = self.price() # If the is no target price feed, cancel all orders but do not terminate the keeper. # The moment the price feed comes back, the keeper will resume placing orders. if target_price is None: self.logger.warning( "Cancelling all orders as no price feed available.") self.cancel_all_orders() return # Remove expired orders from the local order list self.remove_expired_orders(block_number) # Cancel orders cancellable_orders = bands.cancellable_orders(self.our_buy_orders(), self.our_sell_orders(), target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders, block_number) return # Place new orders self.top_up_bands(bands.buy_bands, bands.sell_bands, target_price)
def check_cup(self, cup_id: int): assert (isinstance(cup_id, int)) # If cup is undercollateralized and the amount of SAI we are holding is more than `--max-sai` # then we wipe some debt first so our balance reaches `--avg-sai`. Bear in mind that it is # possible that we pay all out debt this way and our SAI balance will still be higher # than `--max-sai`. if self.is_undercollateralized(cup_id) and self.sai.balance_of( self.our_address) > self.max_sai: amount_of_sai_to_wipe = self.calculate_sai_wipe() if amount_of_sai_to_wipe > Wad(0): self.tub.wipe( cup_id, amount_of_sai_to_wipe).transact(gas_price=self.gas_price()) # If cup is still undercollateralized, calculate the amount of SKR needed to top it up so # the collateralization level reaches `--top-up-margin`. If we have enough ETH, exchange # in to SKR and then top-up the cup. if self.is_undercollateralized(cup_id): top_up_amount = self.calculate_skr_top_up(cup_id) if top_up_amount <= eth_balance(self.web3, self.our_address): # TODO we do not always join with the same amount as the one we lock! self.tub.join(top_up_amount).transact( gas_price=self.gas_price()) self.tub.lock( cup_id, top_up_amount).transact(gas_price=self.gas_price()) else: self.logger.info( f"Cannot top-up as our balance is less than {top_up_amount} ETH." )
def synchronize_orders(self): # If market is closed, cancel all orders but do not terminate the keeper. if self.otc.is_closed(): self.logger.warning("Market is closed. Cancelling all orders.") self.order_book_manager.cancel_all_orders() return # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.order_book_manager.cancel_all_orders() return bands = Bands(self.bands_config, self.spread_feed, self.history) order_book = self.order_book_manager.get_order_book() target_price = self.price_feed.get_price() # If there are any orders to be cancelled, cancel them. It is deliberate that we wait with topping-up # bands until the next block. This way we would create new orders based on the most recent price and # order book state. We could theoretically retrieve both (`target_price` and `our_orders`) again here, # but it just seems cleaner to do it in one place instead of in two. cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), target_price=target_price) if len(cancellable_orders) > 0: simulated_book = list( set(order_book.orders) - set(cancellable_orders)) new_orders = bands.new_orders( our_buy_orders=self.our_buy_orders(simulated_book), our_sell_orders=self.our_sell_orders(simulated_book), our_buy_balance=self.our_available_balance(self.token_buy), our_sell_balance=self.our_available_balance(self.token_sell), target_price=target_price)[0] self.order_book_manager.replace_orders(cancellable_orders, new_orders) return # Do not place new orders if order book state is not confirmed if order_book.orders_being_placed or order_book.orders_being_cancelled: self.logger.debug( "Order book is in progress, not placing new orders") return # Place new orders self.order_book_manager.place_orders( bands.new_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), our_buy_balance=self.our_available_balance(self.token_buy), our_sell_balance=self.our_available_balance(self.token_sell), target_price=target_price)[0])
def depositable_balance(self, token: Address) -> Wad: if token == EtherDelta.ETH_TOKEN: return Wad.max( eth_balance(self.web3, self.our_address) - self.eth_reserve, Wad(0)) else: return ERC20Token(web3=self.web3, address=token).balance_of(self.our_address)
def test_eth_transfer_from_other_account(self): # given assert eth_balance(self.web3, self.second_address) == Wad.from_number(1000000) assert eth_balance(self.web3, self.third_address) == Wad.from_number(1000000) # when eth_transfer( self.web3, self.third_address, Wad.from_number(1.5)).transact(from_address=self.second_address) # then assert eth_balance(self.web3, self.second_address) < Wad.from_number(1000000) assert eth_balance(self.web3, self.third_address ) == Wad.from_number(1000000) + Wad.from_number(1.5)
def synchronize_orders(self): # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. # # The exception is when we can withdraw some ETH from EtherDelta. Then we do it and carry on. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: if self.etherdelta.balance_of(self.our_address) > self.eth_reserve: self.logger.warning(f"Keeper ETH balance below minimum, withdrawing {self.eth_reserve}.") self.etherdelta.withdraw(self.eth_reserve).transact() else: self.logger.warning(f"Keeper ETH balance below minimum, cannot withdraw. Cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config, self.spread_feed, self.history) block_number = self.web3.eth.blockNumber target_price = self.price_feed.get_price() # Remove expired orders from the local order list self.remove_expired_orders(block_number) # Cancel orders cancellable_orders = bands.cancellable_orders(self.our_buy_orders(), self.our_sell_orders(), target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders, block_number) return # In case of EtherDelta, balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance(self.token_buy()) - Bands.total_amount(self.our_buy_orders()) our_sell_balance = self.our_total_balance(self.token_sell()) - Bands.total_amount(self.our_sell_orders()) # Evaluate if we need to create new orders, and how much do we need to deposit new_orders, missing_buy_amount, missing_sell_amount = bands.new_orders(our_buy_orders=self.our_buy_orders(), our_sell_orders=self.our_sell_orders(), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price) # If deposited amount too low for placing buy orders, try to deposit. # If deposited amount too low for placing sell orders, try to deposit. made_deposit = False if missing_buy_amount > Wad(0): if self.deposit_for_buy_order(): made_deposit = True if missing_sell_amount > Wad(0): if self.deposit_for_sell_order(): made_deposit = True # If we managed to deposit something, do not do anything so we can reevaluate new orders to be created. # Otherwise, create new orders. if not made_deposit: self.place_orders(new_orders)
def deposit_for_sell_order(self): depositable_eth = Wad.max( eth_balance(self.web3, self.our_address) - self.eth_reserve, Wad(0)) if depositable_eth > self.min_eth_deposit: return self.etherdelta.deposit(depositable_eth).transact( gas_price=self.gas_price).successful else: return False
def synchronize_orders(self): # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning(f"Keeper ETH balance below minimum, cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config, self.spread_feed, self.history) our_balances = self.our_balances() our_orders = self.our_orders() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # If we detect that our total balance reported by the API is not equal to the # total balance reported by the Ethereum contract, it probably means that some # deposits are still pending being credited to our account. In this case # we also do not create any new orders, but at the same time existing orders # can still be cancelled. if not self.balances_match(our_balances): self.logger.info("Balances do not match, probably deposits are in progress, waiting.") return # Evaluate if we need to create new orders, and how much do we need to deposit new_orders, missing_buy_amount, missing_sell_amount = bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_available_balance(our_balances, self.token_buy()), our_sell_balance=self.our_available_balance(our_balances, self.token_sell()), target_price=target_price) # If deposited amount too low for placing buy orders, try to deposit. # If deposited amount too low for placing sell orders, try to deposit. made_deposit = False if missing_buy_amount > Wad(0): if self.deposit_for_buy_order(missing_buy_amount): made_deposit = True if missing_sell_amount > Wad(0): if missing_sell_amount > Wad(0): if self.deposit_for_sell_order(missing_sell_amount): made_deposit = True # If we managed to deposit something, do not do anything so we can reevaluate new orders to be placed. # Otherwise, place new orders. if not made_deposit: self.place_orders(new_orders)
def print_balances(self): sai_owned = self.sai.balance_of(self.our_address) sai_deposited = self.etherdelta.balance_of_token( self.sai.address, self.our_address) eth_owned = eth_balance(self.web3, self.our_address) eth_deposited = self.etherdelta.balance_of(self.our_address) self.logger.info( f"Keeper balances are {sai_owned} + {sai_deposited} SAI, {eth_owned} + {eth_deposited} ETH" )
def deposit_for_sell_order(self, missing_sell_amount: Wad): # We can never lock more than our available ETH balance. depositable_eth = eth_balance(self.web3, self.our_address) missing_sell_amount = Wad.min(missing_sell_amount, depositable_eth) # If we still can deposit something, and it's at least `min_eth_deposit`, then we do deposit. if missing_sell_amount > Wad(0): receipt = self.token_sell_wrapper.deposit(missing_sell_amount).transact(gas_price=self.gas_price) return receipt is not None and receipt.successful else: return False
def test_connect_to_testchain(self, our_address): uri = "http://0.0.0.0:8545" web3 = web3_via_http(uri, 63, 39) assert isinstance(web3.provider, HTTPProvider) assert web3.provider._request_kwargs['timeout'] == 63 for adapter in _get_session(uri).adapters.values(): assert adapter._pool_connections == 39 assert adapter._pool_maxsize == 39 assert isinstance(web3, Web3) assert eth_balance(web3, our_address) > Wad(0)
def deposit_for_sell_order(self, missing_sell_amount: Wad): # We always want to deposit at least `min_eth_deposit`. If `missing_sell_amount` is less # than that, we deposit `min_eth_deposit` anyway. if Wad(0) < missing_sell_amount < self.min_eth_deposit: missing_sell_amount = self.min_eth_deposit # We can never deposit more than our available ETH balance minus `eth_reserve` (reserve for gas). depositable_eth = Wad.max(eth_balance(self.web3, self.our_address) - self.eth_reserve, Wad(0)) missing_sell_amount = Wad.min(missing_sell_amount, depositable_eth) # If we still can deposit something, and it's at least `min_eth_deposit`, then we do deposit. if missing_sell_amount > Wad(0) and missing_sell_amount >= self.min_eth_deposit: receipt = self.idex.deposit(missing_sell_amount).transact(gas_price=self.gas_price) return receipt is not None and receipt.successful else: return False
def deposit_for_sell_order(self, missing_sell_amount: Wad): # We always want to deposit at least `min_eth_deposit`. If `missing_sell_amount` is less # than that, we deposit `min_eth_deposit` anyway. if Wad(0) < missing_sell_amount < self.min_eth_deposit: missing_sell_amount = self.min_eth_deposit # We can never deposit more than our available ETH balance minus `eth_reserve` (reserve for gas). depositable_eth = Wad.max(eth_balance(self.web3, self.our_address) - self.eth_reserve, Wad(0)) missing_sell_amount = Wad.min(missing_sell_amount, depositable_eth) # If we still can deposit something, and it's at least `min_eth_deposit`, then we do deposit. if missing_sell_amount > Wad(0) and missing_sell_amount >= self.min_eth_deposit: receipt = self.idex.deposit(missing_sell_amount).transact(gas_price=self.gas_price) return receipt is not None and receipt.successful else: return False
def synchronize_orders(self): # If market is closed, cancel all orders but do not terminate the keeper. if self.otc.is_closed(): self.logger.warning("Market is closed. Cancelling all orders.") self.order_book_manager.cancel_all_orders() return # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.order_book_manager.cancel_all_orders() return bands = Bands.read(self.bands_config, self.spread_feed, self.control_feed, self.history) order_book = self.order_book_manager.get_order_book() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), target_price=target_price) if len(cancellable_orders) > 0: self.order_book_manager.cancel_orders(cancellable_orders) return # Do not place new orders if other new orders are being placed. In contrary to other keepers, # we allow placing new orders when other orders are being cancelled. This is because Ethereum # transactions are ordered so we are sure that the order placement will not 'overtake' # order cancellation. if order_book.orders_being_placed: self.logger.debug( "Other orders are being placed, not placing new orders") return # Place new orders self.order_book_manager.place_orders( bands.new_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), our_buy_balance=self.our_available_balance(self.token_buy), our_sell_balance=self.our_available_balance(self.token_sell), target_price=target_price)[0])
def synchronize_orders(self): if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.order_book_manager.cancel_all_orders() return bands = Bands(self.bands_config, self.spread_feed, self.history) order_book = self.order_book_manager.get_order_book() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), target_price=target_price) if len(cancellable_orders) > 0: self.order_book_manager.cancel_orders(cancellable_orders) return # Do not place new orders if order book state is not confirmed if order_book.orders_being_placed or order_book.orders_being_cancelled: self.logger.debug( "Order book is in progress, not placing new orders") return # In case of Paradex, balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance( self.token_buy) - Bands.total_amount( self.our_buy_orders(order_book.orders)) our_sell_balance = self.our_total_balance( self.token_sell) - Bands.total_amount( self.our_sell_orders(order_book.orders)) # Place new orders self.place_orders( bands.new_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price)[0])
def synchronize_orders(self): # If market is closed, cancel all orders but do not terminate the keeper. if self.otc.is_closed(): self.logger.warning("Market is closed. Cancelling all orders.") self.cancel_all_orders() return # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning("Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config, self.spread_feed, self.history) order_book = self.order_book_manager.get_order_book() target_price = self.price_feed.get_price() # If there are any orders to be cancelled, cancel them. It is deliberate that we wait with topping-up # bands until the next block. This way we would create new orders based on the most recent price and # order book state. We could theoretically retrieve both (`target_price` and `our_orders`) again here, # but it just seems cleaner to do it in one place instead of in two. cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Do not place new orders if order book state is not confirmed if order_book.orders_being_placed or order_book.orders_being_cancelled: self.logger.debug("Order book is in progress, not placing new orders") return # Place new orders self.place_orders(bands.new_orders(our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), our_buy_balance=self.our_available_balance(self.token_buy), our_sell_balance=self.our_available_balance(self.token_sell), target_price=target_price)[0])
def synchronize_orders(self): if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning( "Keeper ETH balance below minimum. Cancelling all orders.") self.cancel_orders(self.our_orders()) return bands = Bands(self.bands_config, self.spread_feed, self.history) our_orders = self.our_orders() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # In case of Paradex, balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance( self.token_buy) - Bands.total_amount( self.our_buy_orders(our_orders)) our_sell_balance = self.our_total_balance( self.token_sell) - Bands.total_amount( self.our_sell_orders(our_orders)) # Place new orders self.place_orders( bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price)[0])
def depositable_balance(self, token: Address) -> Wad: if token == EtherDelta.ETH_TOKEN: return Wad.max(eth_balance(self.web3, self.our_address) - self.eth_reserve, Wad(0)) else: return ERC20Token(web3=self.web3, address=token).balance_of(self.our_address)
def synchronize_orders(self): # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: self.logger.warning(f"Keeper ETH balance below minimum, cancelling all orders.") self.cancel_all_orders() return bands = Bands(self.bands_config, self.history) our_balances = self.our_balances() our_orders = self.our_orders() target_price = self.price_feed.get_price() # If the is no target price feed, cancel all orders but do not terminate the keeper. # The moment the price feed comes back, the keeper will resume placing orders. if target_price is None: self.logger.warning("Cancelling all orders as no price feed available.") self.cancel_all_orders() return # Cancel orders cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # If we detect that our total balance reported by the API is not equal to the # total balance reported by the Ethereum contract, it probably means that some # deposits are still pending being credited to our account. In this case # we also do not create any new orders, but at the same time existing orders # can still be cancelled. if not self.balances_match(our_balances): self.logger.info("Balances do not match, probably deposits are in progress, waiting.") return # Evaluate if we need to create new orders, and how much do we need to deposit new_orders, missing_buy_amount, missing_sell_amount = bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_available_balance(our_balances, self.token_buy()), our_sell_balance=self.our_available_balance(our_balances, self.token_sell()), target_price=target_price) # If deposited amount too low for placing buy orders, try to deposit. # If deposited amount too low for placing sell orders, try to deposit. made_deposit = False if missing_buy_amount > Wad(0): if self.deposit_for_buy_order(missing_buy_amount): made_deposit = True if missing_sell_amount > Wad(0): if missing_sell_amount > Wad(0): if self.deposit_for_sell_order(missing_sell_amount): made_deposit = True # If we managed to deposit something, do not do anything so we can reevaluate new orders to be placed. # Otherwise, place new orders. if not made_deposit: self.place_orders(new_orders)
def get_balances(self): balances = self.zrx_api.get_balances(self.pair) return balances[0], balances[1], eth_balance(self.web3, self.our_address)
def synchronize_orders(self): # If keeper balance is below `--min-eth-balance`, cancel all orders but do not terminate # the keeper, keep processing blocks as the moment the keeper gets a top-up it should # resume activity straight away, without the need to restart it. # # The exception is when we can withdraw some ETH from EtherDelta. Then we do it and carry on. if eth_balance(self.web3, self.our_address) < self.min_eth_balance: if self.etherdelta.balance_of(self.our_address) > self.eth_reserve: self.logger.warning( f"Keeper ETH balance below minimum, withdrawing {self.eth_reserve}." ) self.etherdelta.withdraw(self.eth_reserve).transact() else: self.logger.warning( f"Keeper ETH balance below minimum, cannot withdraw. Cancelling all orders." ) self.cancel_all_orders() return bands = Bands.read(self.bands_config, self.spread_feed, self.control_feed, self.history) block_number = self.web3.eth.blockNumber target_price = self.price_feed.get_price() # Remove expired orders from the local order list self.remove_expired_orders(block_number) # Cancel orders cancellable_orders = bands.cancellable_orders(self.our_buy_orders(), self.our_sell_orders(), target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders, block_number) return # In case of EtherDelta, balances returned by `our_total_balance` still contain amounts "locked" # by currently open orders, so we need to explicitly subtract these amounts. our_buy_balance = self.our_total_balance( self.token_buy()) - Bands.total_amount(self.our_buy_orders()) our_sell_balance = self.our_total_balance( self.token_sell()) - Bands.total_amount(self.our_sell_orders()) # Evaluate if we need to create new orders, and how much do we need to deposit new_orders, missing_buy_amount, missing_sell_amount = bands.new_orders( our_buy_orders=self.our_buy_orders(), our_sell_orders=self.our_sell_orders(), our_buy_balance=our_buy_balance, our_sell_balance=our_sell_balance, target_price=target_price) # If deposited amount too low for placing buy orders, try to deposit. # If deposited amount too low for placing sell orders, try to deposit. made_deposit = False if missing_buy_amount > Wad(0): if self.deposit_for_buy_order(): made_deposit = True if missing_sell_amount > Wad(0): if self.deposit_for_sell_order(): made_deposit = True # If we managed to deposit something, do not do anything so we can reevaluate new orders to be created. # Otherwise, create new orders. if not made_deposit: self.place_orders(new_orders)
def get_balances(self): return self.token_sell.balance_of(self.our_address), \ self.token_buy.balance_of(self.our_address), \ eth_balance(self.web3, self.our_address)