def create_new_sell_order(self): """If our SAI engagement is below the minimum amount, create a new offer up to the maximum amount""" total_amount = self.total_amount(self.our_sell_orders()) if total_amount < self.min_sai_amount: our_balance = self.sai.balance_of( self.our_address) + self.etherdelta.balance_of_token( self.sai.address, self.our_address) have_amount = Wad.min(self.max_sai_amount, our_balance) - total_amount if have_amount > Wad(0): want_amount = self.fix_amount( have_amount * self.apply_sell_margin( self.target_rate(), self.avg_margin)) if self.offchain: self.etherdelta.place_order_offchain( token_get=EtherDelta.ETH_TOKEN, amount_get=want_amount, token_give=self.sai.address, amount_give=have_amount, expires=self.web3.eth.blockNumber + self.order_age) else: self.etherdelta.place_order_onchain( token_get=EtherDelta.ETH_TOKEN, amount_get=want_amount, token_give=self.sai.address, amount_give=have_amount, expires=self.web3.eth.blockNumber + self.order_age)
def deposit_for_sell_orders(self): order_total = self.total_amount(self.our_sell_orders()) currently_deposited = self.etherdelta.balance_of_token( self.sai.address, self.our_address) if order_total > currently_deposited: additional_deposit = Wad.min(order_total - currently_deposited, self.sai.balance_of(self.our_address)) if additional_deposit > Wad(0): self.etherdelta.deposit_token(self.sai.address, additional_deposit)
def deposit_for_buy_orders(self): order_total = self.total_amount(self.our_buy_orders()) currently_deposited = self.etherdelta.balance_of(self.our_address) if order_total > currently_deposited: depositable_eth = Wad.max( self.eth_balance(self.our_address) - self.eth_reserve, Wad(0)) additional_deposit = Wad.min(order_total - currently_deposited, depositable_eth) if additional_deposit > Wad(0): self.etherdelta.deposit(additional_deposit)
def create_new_sell_offer(self): """If our SAI engagement is below the minimum amount, create a new offer up to the maximum amount""" total_amount = self.total_amount(self.our_sell_offers()) if total_amount < self.min_sai_amount: our_balance = self.sai.balance_of(self.our_address) have_amount = Wad.min(self.max_sai_amount - total_amount, our_balance) if have_amount > Wad(0): want_amount = have_amount * self.apply_sell_margin( self.target_rate(), self.avg_margin) self.otc.make(have_token=self.sai.address, have_amount=have_amount, want_token=self.gem.address, want_amount=want_amount)
def profitable_opportunities(self): """Identify all profitable arbitrage opportunities within given limits.""" entry_amount = Wad.min(self.base_token.balance_of(self.our_address), self.max_engagement) opportunity_finder = OpportunityFinder( conversions=self.all_conversions()) opportunities = opportunity_finder.find_opportunities( self.base_token.address, entry_amount) opportunities = filter( lambda op: op.total_rate() > Ray.from_number(1.000001), opportunities) opportunities = filter( lambda op: op.net_profit(self.base_token.address) > self. min_profit, opportunities) opportunities = sorted( opportunities, key=lambda op: op.net_profit(self.base_token.address), reverse=True) return opportunities
def test_min_value_should_reject_comparison_with_ints(self): with pytest.raises(ArithmeticError): Wad.min(Wad(10), 20) with pytest.raises(ArithmeticError): Wad.min(20, Wad(10))
def test_min_value_should_reject_comparison_with_rays(self): with pytest.raises(ArithmeticError): Wad.min(Wad(10), Ray(20)) with pytest.raises(ArithmeticError): Wad.min(Ray(25), Wad(15))
def test_min_value(self): assert Wad.min(Wad(10), Wad(20)) == Wad(10) assert Wad.min(Wad(25), Wad(15)) == Wad(15) assert Wad.min(Wad(25), Wad(15), Wad(5)) == Wad(5)
def perform(self, auctionlet, context): auction = auctionlet.get_auction() # this strategy supports forward auctions only if not auction.is_forward(): return StrategyResult(f"Not a forward auction. Forgetting it.", forget=True) # we trade only on our token pair if (auction.selling != self.we_buy) or (auction.buying != self.we_sell): return StrategyResult("Unrecognized token pair. Forgetting it.", forget=True) # we do not do anything if we are already winning if auctionlet.last_bidder == context.trader_address: return StrategyResult( 'We are the highest bidder. Not doing anything.') # handle expired auctions, we either claim them or forget them if auctionlet.expired: if auctionlet.unclaimed: if auctionlet.last_bidder == context.trader_address: if auctionlet.claim(): return StrategyResult( "Expired and unclaimed, we won, claimed by us successfully. Forgetting it.", forget=True) else: return StrategyResult( "Expired and unclaimed, we won, tried to claim it but claim failed" ) else: return StrategyResult( 'Expired and unclaimed, waiting to be claimed by somebody else. Forgetting it.', forget=True) else: return StrategyResult('Expired and claimed. Forgetting it.', forget=True) # get the current buy amount and the minimum possible increase auction_current_bid = auctionlet.buy_amount auction_min_next_bid = auction_current_bid * Wad.from_number( (100 + auction.min_increase) / 100) assert (auction_min_next_bid >= auction_current_bid) # calculate our maximum bid our_max_bid = auctionlet.sell_amount / self.mkr_dai_rate # if the current auction bid amount has already reached our maximum bid # then we can not go higher, so we do not bid if auction_current_bid >= our_max_bid: return StrategyResult( f"Our maximum possible bid ({our_max_bid} {auction.buying.name()}) reached" ) # if the auction next minimum increase is greater than our maximum possible bid # then we can not go higher, so we do not bid if auction_min_next_bid > our_max_bid: return StrategyResult( f"Minimal increase ({auction_min_next_bid} {auction.buying.name()}) exceeds our maximum possible bid ({our_max_bid} {auction.buying.name()})" ) # if the our global minimal bid is greater than our maximum possible bid then we do not bid if self.minimal_bid > our_max_bid: return StrategyResult( f"Minimal allowed bid ({self.minimal_bid} {auction.buying.name()}) exceeds our maximum possible bid ({our_max_bid} {auction.buying.name()})" ) # we never bid if our available balance is below global minimal bid our_balance = auction.buying.balance_of(context.trader_address) if our_balance < self.minimal_bid: return StrategyResult( f"Not bidding as available balance ({our_balance} {auction.buying.name()}) is less than minimal allowed bid ({self.minimal_bid} {auction.buying.name()})" ) # this his how much we want to bid in ideal conditions... our_preferred_bid = auction_current_bid + ( our_max_bid - auction_current_bid) * self.step # ...but we can still end up bidding more (either because of the 'min_increase' auction parameter... our_preferred_bid = Wad.max(our_preferred_bid, auction_min_next_bid) # ...or because of the global minimal bid) our_preferred_bid = Wad.max(our_preferred_bid, self.minimal_bid) # at the end, we cannot bid more than we actually have in our account our_bid = Wad.min(our_preferred_bid, our_balance) if our_bid < auction_min_next_bid: if auctionlet.can_split(): our_preferred_rate = our_preferred_bid / auctionlet.sell_amount our_bid = our_balance quantity = our_balance / our_preferred_rate # we check our allowance, and raise it if necessary if not self._ensure_allowance(auction, context, our_bid): return StrategyResult( f"Tried to raise {auction.buying.name()} allowance, but the attempt failed" ) if auctionlet.bid(our_bid, quantity): return StrategyResult( f"Placed a new partial bid at {our_bid} {auction.buying.name()} (for {quantity} {auction.selling.name()}), bid was successful, new auctionlet got created" ) else: return StrategyResult( f"Tried to place a new bid at {our_bid} {auction.buying.name()} (partial bid for {quantity} {auction.selling.name()}), but the bid failed" ) else: return StrategyResult( f"Our available balance ({our_balance} {auction.buying.name()} is below minimal next bid ({auction_min_next_bid} {auction.buying.name()}) and splitting is unavailable" ) else: # we check our allowance, and raise it if necessary if not self._ensure_allowance(auction, context, our_bid): return StrategyResult( f"Tried to raise {auction.buying.name()} allowance, but the attempt failed" ) # a set of assertions to double-check our calculations assert (our_bid > auction_current_bid) assert (our_bid >= auction_min_next_bid) assert (our_bid <= our_max_bid) if auctionlet.bid(our_bid): if our_bid < our_max_bid: return StrategyResult( f"Placed a new bid at {our_bid} {auction.buying.name()}, bid was successful. Our maximum bid on this auctionlet is {our_max_bid} {auction.buying.name()}" ) else: return StrategyResult( f"Placed a new bid at {our_bid} {auction.buying.name()}, bid was successful" ) else: return StrategyResult( f"Tried to place a new bid at {our_bid} {auction.buying.name()}, but the bid failed" )