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 bustable_amount_in_sai(self, tap: Tap): #TODO we always try to bust 10 SAI less than what the Tub reports #in order to discount the growth of `joy()` that might've have happened since the last drip #of course this is not the right solution and it won't even work properly if the last #drip happened enough time ago bustable_woe = tap.woe() - tap.joy() - Wad.from_number(10) # we deduct 0.000001 in order to avoid rounding errors bustable_fog = tap.fog() * tap.ask() - Wad.from_number(0.000001) return Wad.max(bustable_woe, bustable_fog, Wad.from_number(0))
def __init__(self, lpc: Lpc): self.lpc = lpc rate = Ray(self.lpc.par() / (self.lpc.tag() * self.lpc.gap())) #TODO we always leave 0.000001 in the liquidity pool, in case of some rounding errors max_entry_ref = Wad.max( (ERC20Token(web3=lpc.web3, address=lpc.alt()).balance_of( lpc.address) / Wad(rate)) - Wad.from_number(0.000001), Wad.from_number(0)) super().__init__(source_token=self.lpc.ref(), target_token=self.lpc.alt(), rate=rate, max_source_amount=max_entry_ref, method="lpc.take(alt)")
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" )
def boomable_amount_in_skr(self, tap: Tap): # we deduct 0.000001 in order to avoid rounding errors return Wad.max( Wad(self.boomable_amount_in_sai(tap) / (tap.bid())) - Wad.from_number(0.000001), Wad.from_number(0))
def boomable_amount_in_sai(self, tap: Tap): return Wad.max(tap.joy() - tap.woe(), Wad.from_number(0))
def test_max_value_should_reject_comparison_with_ints(self): with pytest.raises(ArithmeticError): Wad.max(Wad(10), 20) with pytest.raises(ArithmeticError): Wad.max(15, Wad(25))
def test_max_value_should_reject_comparison_with_rays(self): with pytest.raises(ArithmeticError): Wad.max(Wad(10), Ray(20)) with pytest.raises(ArithmeticError): Wad.max(Wad(25), Ray(15))
def test_max_value(self): assert Wad.max(Wad(10), Wad(20)) == Wad(20) assert Wad.max(Wad(25), Wad(15)) == Wad(25) assert Wad.max(Wad(25), Wad(15), Wad(40)) == Wad(40)