コード例 #1
0
    def test_should_ignore_irrelevant_conversions(self, token1, token2, token3,
                                                  token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token1, token3, Ray.from_number(1.04),
                                 Wad.from_number(10000), 'met3')
        conversion4 = Conversion(token1, token4, Ray.from_number(1.07),
                                 Wad.from_number(10000), 'met4')
        conversion5 = Conversion(token2, token4, Ray.from_number(1.08),
                                 Wad.from_number(10000), 'met5')
        conversions = [
            conversion1, conversion2, conversion3, conversion4, conversion5
        ]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
コード例 #2
0
    def test_should_adjust_amounts_based_on_max_source_amount(
            self, token1, token2, token3, token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(2.0),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token3, Ray.from_number(1.6),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token3, token4, Ray.from_number(1.2),
                                 Wad.from_number(100), 'met3')
        conversion4 = Conversion(token4, token1, Ray.from_number(1.1),
                                 Wad.from_number(10000), 'met4')
        conversions = [conversion1, conversion4, conversion3, conversion2]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 4
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[0].source_amount == Wad.from_number(
            31.25)
        assert opportunities[0].steps[0].target_amount == Wad.from_number(62.5)
        assert opportunities[0].steps[1].method == "met2"
        assert opportunities[0].steps[1].source_amount == Wad.from_number(62.5)
        assert opportunities[0].steps[1].target_amount == Wad.from_number(100)
        assert opportunities[0].steps[2].method == "met3"
        assert opportunities[0].steps[2].source_amount == Wad.from_number(100)
        assert opportunities[0].steps[2].target_amount == Wad.from_number(120)
        assert opportunities[0].steps[3].method == "met4"
        assert opportunities[0].steps[3].source_amount == Wad.from_number(120)
        assert opportunities[0].steps[3].target_amount == Wad.from_number(132)
コード例 #3
0
 def test_divide(self):
     assert Ray.from_number(4) / Ray.from_number(2) == Ray.from_number(2)
     assert Ray(4) / Ray.from_number(2) == Ray(2)
     assert Ray(3) / Ray.from_number(2) == Ray(1)
     assert Ray(39) / Ray.from_number(20) == Ray(1)
     assert Ray(40) / Ray.from_number(20) == Ray(2)
     assert Ray.from_number(0.2) / Ray.from_number(0.1) == Ray.from_number(2)
コード例 #4
0
 def __init__(self):
     super().__init__()
     self.liquidation_ratio = self.tub.mat()
     self.minimum_ratio = self.liquidation_ratio + Ray.from_number(
         self.arguments.min_margin)
     self.target_ratio = self.liquidation_ratio + Ray.from_number(
         self.arguments.top_up_margin)
コード例 #5
0
    def test_should_identify_multi_step_opportunities(self, token1, token2,
                                                      token3, token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token3, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token3, token4, Ray.from_number(1.05),
                                 Wad.from_number(10000), 'met3')
        conversion4 = Conversion(token4, token1, Ray.from_number(1.07),
                                 Wad.from_number(10000), 'met4')
        conversions = [conversion1, conversion2, conversion3, conversion4]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 4
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
        assert opportunities[0].steps[2].method == "met3"
        assert opportunities[0].steps[3].method == "met4"
コード例 #6
0
    def test_coax_and_way(self, sai: SaiDeployment):
        # given
        assert sai.tub.way() == Ray.from_number(1)

        # when
        sai.tub.coax(Ray.from_number(1.00000000000000007))

        # then
        assert sai.tub.way() == Ray.from_number(1.00000000000000007)
コード例 #7
0
    def test_cuff_and_mat(self, sai: SaiDeployment):
        # given
        assert sai.tub.mat() == Ray.from_number(1)

        # when
        sai.tub.cuff(Ray.from_number(1.5))

        # then
        assert sai.tub.mat() == Ray.from_number(1.5)
コード例 #8
0
    def test_crop_and_tax(self, sai: SaiDeployment):
        # given
        assert sai.tub.tax() == Ray.from_number(1)

        # when
        sai.tub.crop(Ray.from_number(1.00000000000000002))

        # then
        assert sai.tub.tax() == Ray.from_number(1.00000000000000002)
コード例 #9
0
    def test_safe(self, sai: SaiDeployment):
        # given
        sai.tub.cuff(Ray.from_number(1.5))
        sai.tub.chop(Ray.from_number(1.2))

        # when
        sai.tub.open()

        # then
        assert sai.tub.safe(1)
コード例 #10
0
    def test_chop_and_axe(self, sai: SaiDeployment):
        # given
        assert sai.tub.axe() == Ray.from_number(1)
        sai.tub.cuff(Ray.from_number(1.5))

        # when
        sai.tub.chop(Ray.from_number(1.2))

        # then
        assert sai.tub.axe() == Ray.from_number(1.2)
コード例 #11
0
    def test_should_calculate_total_rate(self, token1, token2):
        # given
        step1 = Conversion(token1, token2, Ray.from_number(1.01),
                           Wad.from_number(1000), 'met1')
        step2 = Conversion(token2, token1, Ray.from_number(1.02),
                           Wad.from_number(1000), 'met2')

        # when
        sequence = Sequence([step1, step2])

        # then
        assert sequence.total_rate() == Ray.from_number(1.0302)
コード例 #12
0
 def __init__(self, tub: Tub):
     self.tub = tub
     super().__init__(source_token=self.tub.gem(),
                      target_token=self.tub.skr(),
                      rate=(Ray.from_number(1) / tub.jar_ask()),
                      max_source_amount=Wad.from_number(1000000),  #1 mio ETH = infinity ;)
                      method="tub.join()")
コード例 #13
0
    def total_rate(self) -> Ray:
        """Calculates the multiplication of all conversion rates forming this sequence.

        A `total_rate` > 1.0 is a general indication that executing this sequence may be profitable.
        """
        return reduce(operator.mul, map(lambda step: step.rate, self.steps),
                      Ray.from_number(1.0))
コード例 #14
0
 def test_multiply_by_ray(self):
     assert Wad.from_number(2) * Ray.from_number(3) == Wad.from_number(6)
     assert Wad.from_number(2) * Ray(3) == Wad(0)
     assert Wad(2) * Ray(499999999999999999999999999) == Wad(0)
     assert Wad(2) * Ray(500000000000000000000000000) == Wad(1)
     assert Wad(2) * Ray(999999999999999999999999999) == Wad(1)
     assert Wad(2) * Ray(1000000000000000000000000000) == Wad(2)
コード例 #15
0
    def test_should_recognize_if_there_are_no_opportunities(
            self, token1, token2, token3):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token3, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversions = [conversion1, conversion2]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 0
コード例 #16
0
 def __init__(self, tub: Tub, tap: Tap):
     self.tub = tub
     self.tap = tap
     super().__init__(source_token=self.tub.sai(),
                      target_token=self.tub.skr(),
                      rate=(Ray.from_number(1) / Ray(tap.ask())),
                      max_source_amount=self.bustable_amount_in_sai(tap),
                      method="tub.bust()")
コード例 #17
0
def test_nicely_convert_to_string_without_amounts(token1, token2):
    # given
    conversion = Conversion(token1, token2, Ray.from_number(1.01),
                            Wad.from_number(1000), 'met()')

    # expect
    assert str(
        conversion
    ) == "[TK1 -> TK2 @1.010000000000000000000000000 by met() (max=1000.000000000000000000 TK1)]"
コード例 #18
0
    def test_should_identify_opportunity(self, token1, token2):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversions = [conversion1, conversion2]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
コード例 #19
0
def test_nicely_convert_to_string_with_amounts(token1, token2):
    # given
    conversion = Conversion(token1, token2, Ray.from_number(1.01),
                            Wad.from_number(1000), 'met()')
    conversion.source_amount = Wad.from_number(50)
    conversion.target_amount = Wad.from_number(50.5)

    # expect
    assert str(conversion) == "[50.000000000000000000 TK1 -> 50.500000000000000000 TK2 @1.010000000000000000000000000" \
                              " by met() (max=1000.000000000000000000 TK1)]"
コード例 #20
0
    def test_should_identify_all_opportunities_regardless_whether_they_are_profitable(
            self, token1, token2):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.1),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(0.6),
                                 Wad.from_number(10000), 'met2')
        conversions = [conversion1, conversion2]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
コード例 #21
0
    def test_should_calculate_profit_and_net_profit(self, token1, token2):
        # given
        step1 = Conversion(token1, token2, Ray.from_number(1.01),
                           Wad.from_number(1000), 'met1')
        step1.source_amount = Wad.from_number(100)
        step1.target_amount = Wad.from_number(101)
        step2 = Conversion(token2, token1, Ray.from_number(1.02),
                           Wad.from_number(1000), 'met2')
        step2.source_amount = Wad.from_number(101)
        step2.target_amount = Wad.from_number(103.02)

        # when
        sequence = Sequence([step1, step2])

        # then
        assert sequence.profit(token1) == Wad.from_number(3.02)
        assert sequence.profit(token2) == Wad.from_number(0)
        assert sequence.net_profit(
            token1) == sequence.profit(token1) - sequence.tx_costs()
        assert sequence.net_profit(
            token2) == sequence.profit(token2) - sequence.tx_costs()
コード例 #22
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
コード例 #23
0
 def test_multiply_by_int(self):
     assert Ray.from_number(2) * 3 == Ray.from_number(6)
     assert Ray.from_number(2) * 1 == Ray.from_number(2)
コード例 #24
0
 def test_multiply(self):
     assert Ray.from_number(2) * Ray.from_number(3) == Ray.from_number(6)
     assert Ray.from_number(2) * Ray(3) == Ray(6)
     assert Ray.from_number(2.5) * Ray(3) == Ray(7)
     assert Ray.from_number(2.99999) * Ray(3) == Ray(8)
コード例 #25
0
 def test_per(self, sai: SaiDeployment):
     assert sai.tub.per() == Ray.from_number(1.0)
コード例 #26
0
 def test_multiply_by_wad(self):
     assert Ray.from_number(2) * Wad.from_number(3) == Ray.from_number(6)
     assert Ray.from_number(2) * Wad(3) == Ray(6000000000)
     assert Ray(2) * Wad(3) == Ray(0)
     assert Ray(2) * Wad(999999999999999999) == Ray(1)
     assert Ray(2) * Wad(1000000000000000000) == Ray(2)
コード例 #27
0
 def test_should_have_nice_printable_representation(self):
     for ray in [Ray(1), Ray(100), Ray.from_number(2.5), Ray(-1)]:
         assert repr(ray) == f"Ray({ray.value})"