Example #1
0
 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)
Example #2
0
 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)
Example #3
0
 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)
Example #4
0
 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)
Example #5
0
 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
Example #6
0
 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))
Example #7
0
 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))
Example #8
0
 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)
Example #9
0
    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"
                )