Exemplo n.º 1
0
    def calculate_liquidity_args(self, token_a_balance: Wad, token_b_balance: Wad) -> Optional[dict]:
        """ Returns dictionary containing arguments for addLiquidity transactions

        Calculate amount of both tokens, given the current reserve ratio on uniswap
        Use accepted_slippage to calculate min off of available balance + liquidity

        If eth is in the pair, at least 1 eth should be left for gas
        """

        if self.is_eth:
            if self.eth_position == 0:
                token_a_balance = token_a_balance - Wad.from_number(1)
                if token_a_balance < Wad.from_number(0):
                    self.logger.info(f"Insufficient Eth balance.")
                    return
            elif self.eth_position == 1:
                token_b_balance = token_b_balance - Wad.from_number(1)
                if token_b_balance < Wad.from_number(0):
                    self.logger.info(f"Insufficient Eth balance.")
                    return

        token_a_desired = min(token_a_balance, token_b_balance / self.uniswap_current_exchange_price)
        token_a_min = token_a_desired - (token_a_desired * self.max_add_liquidity_slippage)
        token_b_desired = min(token_b_balance, token_a_desired * self.uniswap_current_exchange_price)
        token_b_min = token_b_desired - (token_b_desired * self.max_add_liquidity_slippage)

        add_liquidity_args = {
            'amount_a_desired': self.token_a.unnormalize_amount(token_a_desired),
            'amount_b_desired': self.token_b.unnormalize_amount(token_b_desired),
            'amount_a_min': self.token_a.unnormalize_amount(token_a_min),
            'amount_b_min': self.token_b.unnormalize_amount(token_b_min)
        }
        return add_liquidity_args
Exemplo n.º 2
0
 def from_message(trade, pair: str) -> Trade:
     return Trade(trade_id=trade['orderId'],
                  timestamp=int(trade['timestamp']),
                  pair=pair,
                  is_sell=True if trade['type'] == 'ask' else False,
                  price=Wad.from_number(float(trade["price"])),
                  amount=Wad.from_number(float(trade['qty'])))
Exemplo n.º 3
0
    def test_past_take_with_filter(self):
        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()

        # and
        self.otc.approve([self.token2], directly())
        self.otc.take(1, Wad.from_number(0.5)).transact()

        # then
        assert len(
            self.otc.past_take(PAST_BLOCKS,
                               {'maker': self.our_address.address})) == 1
        assert len(
            self.otc.past_take(PAST_BLOCKS,
                               {'taker': self.our_address.address})) == 1
        assert len(
            self.otc.past_take(
                PAST_BLOCKS,
                {'maker': '0x0101010101020202020203030303030404040404'})) == 0
        assert len(
            self.otc.past_take(
                PAST_BLOCKS,
                {'taker': '0x0101010101020202020203030303030404040404'})) == 0
Exemplo n.º 4
0
    def test_approve_and_make_and_getters(self):

        if isinstance(self.otc, MatchingMarket):
            pay_val = self.token1_tokenclass
            buy_val = self.token2_tokenclass
        else:
            pay_val = self.token1.address
            buy_val = self.token2.address

        # given
        assert self.otc.get_last_order_id() == 0

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_val, Wad.from_number(1), buy_val,
                      Wad.from_number(2)).transact()

        # then
        assert self.otc.get_last_order_id() == 1

        # and
        assert self.otc.get_order(1).order_id == 1
        assert self.otc.get_order(1).pay_token == self.token1.address
        assert self.otc.get_order(1).pay_amount == Wad.from_number(1)
        assert self.otc.get_order(1).buy_token == self.token2.address
        assert self.otc.get_order(1).buy_amount == Wad.from_number(2)
        assert self.otc.get_order(1).maker == self.our_address
        assert self.otc.get_order(1).timestamp != 0

        # and
        assert self.otc.get_orders() == [self.otc.get_order(1)]
Exemplo n.º 5
0
 def to_order(pair: str, item):
     return Order(order_id=item['orderid'],
                  pair=pair,
                  is_sell=True if item['type'] == 'sell-limit' else False,
                  price=Wad.from_number(item['price']),
                  amount=Wad.from_number(item['orderquantity']),
                  filled_amount=Wad.from_number(item['filledquantity']))
Exemplo n.º 6
0
    def test_on_kill(self):
        # given
        on_kill_mock = Mock()
        self.otc.on_kill(on_kill_mock)

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()

        # and
        self.otc.kill(1).transact()

        # then
        on_kill = wait_until_mock_called(on_kill_mock)[0]
        assert on_kill.order_id == 1
        assert on_kill.maker == self.our_address
        assert on_kill.pay_token == self.token1.address
        assert on_kill.pay_amount == Wad.from_number(1)
        assert on_kill.buy_token == self.token2.address
        assert on_kill.buy_amount == Wad.from_number(2)
        assert on_kill.timestamp != 0
        assert on_kill.raw['blockNumber'] > 0
Exemplo n.º 7
0
    def test_past_take_with_filter(self):

        if isinstance(self.otc, MatchingMarket):
            pay_val = self.token1_tokenclass
            buy_val = self.token2_tokenclass
        else:
            pay_val = self.token1.address
            buy_val = self.token2.address

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_val, Wad.from_number(1), buy_val,
                      Wad.from_number(2)).transact()

        # and
        self.otc.approve([self.token2], directly())
        self.otc.take(1, Wad.from_number(0.5)).transact()

        # then
        assert len(
            self.otc.past_take(PAST_BLOCKS,
                               {'maker': self.our_address.address})) == 1
        assert len(
            self.otc.past_take(PAST_BLOCKS,
                               {'taker': self.our_address.address})) == 1
        assert len(
            self.otc.past_take(
                PAST_BLOCKS,
                {'maker': '0x0101010101020202020203030303030404040404'})) == 0
        assert len(
            self.otc.past_take(
                PAST_BLOCKS,
                {'taker': '0x0101010101020202020203030303030404040404'})) == 0
Exemplo n.º 8
0
 def to_order(item):
     return Order(order_id=item['id'],
                  pair=item['currency_pair_code'],
                  is_sell=True if item['side'] == 'sell' else False,
                  price=Wad.from_number(item['price']),
                  amount=Wad.from_number(item['quantity']),
                  filled_amount=Wad.from_number(item['filled_quantity']))
Exemplo n.º 9
0
 def from_trade(pair, trade):
     return BinanceUsTrade(trade_id=str(trade['id']),
                           timestamp=trade['time'],
                           pair=pair,
                           is_sell=not trade['isBuyerMaker'],
                           price=Wad.from_number(trade['price']),
                           amount=Wad.from_number(trade['qty']))
Exemplo n.º 10
0
    def _convert_balance_to_wad(self, balance: dict, decimals: int) -> dict:
        wei_balance = float(balance['wei'])
        pending_balance = float(balance['pendingWei'])

        ## DyDx can have negative balances from native margin trading
        is_negative = False
        if wei_balance < 0:
            is_negative = True

        converted_balance = from_wei(abs(int(wei_balance)), 'ether')
        converted_pending_balance = from_wei(abs(int(pending_balance)), 'ether')

        if decimals == 6:
            converted_balance = from_wei(abs(int(wei_balance)), 'mwei')
            converted_pending_balance = from_wei(abs(int(pending_balance)), 'mwei')

        # reconvert Wad to negative value if balance is negative
        if is_negative == True:
            converted_balance = converted_balance * -1

        # Handle the edge case where orders are filled but balance change is still pending
        if converted_balance > 0:
            balance['wad'] = Wad.from_number(converted_balance) - Wad.from_number(converted_pending_balance)
        else:
            balance['wad'] = Wad.from_number(converted_balance) + Wad.from_number(converted_pending_balance)

        return balance
Exemplo n.º 11
0
 def to_trade(pair, trade):
     return Trade(trade_id=str(trade['id']),
                  timestamp=int(trade['created_at']),
                  pair=pair,
                  is_sell=trade['taker_side'] == 'buy',
                  price=Wad.from_number(trade['price']),
                  amount=Wad.from_number(trade['quantity']))
Exemplo n.º 12
0
 def from_list(item: dict, pair: str):
     return Order(order_id=item["id"],
                  timestamp=item["timestamp"],
                  pair=pair,
                  is_sell=True if item["type"] == "ask" else False,
                  price=Wad.from_number(item["price"]["value"]),
                  amount=Wad.from_number(item["total"]["value"]))
Exemplo n.º 13
0
 def from_all_list(pair, trade):
     return Trade(trade_id=int(trade["tid"]),
                  timestamp=trade["timestamp"],
                  pair=pair,
                  is_sell=True if trade["type"] == "sell" else False,
                  price=Wad.from_number(trade["price"]),
                  amount=Wad.from_number(trade["amount"]))
Exemplo n.º 14
0
    def place_liquidity(self):
        """
        Main control function of Uniswap Keeper lifecycle. 
        It will determine whether liquidity should be added, or removed
        and then create and submit transactions to the Uniswap Router Contract to update liquidity levels.
        """

        exchange_token_a_balance = Wad.from_number(0) if self.uniswap.is_new_pool else self.uniswap.get_exchange_balance(self.token_a, self.uniswap.pair_address)
        exchange_token_b_balance = Wad.from_number(0) if self.uniswap.is_new_pool else self.uniswap.get_exchange_balance(self.token_b, self.uniswap.pair_address)

        self.logger.info(f"Exchange Contract {self.token_a.name} amount: {exchange_token_a_balance}; "
                         f"Exchange Contract {self.token_b.name} amount: {exchange_token_b_balance}")

        add_liquidity, remove_liquidity = self.determine_liquidity_action()

        self.logger.info(f"Add Liquidity: {add_liquidity}; Remove Liquidity: {remove_liquidity}")
        
        if add_liquidity:
            receipt = self.add_liquidity()
            if receipt is not None:
                self.logger.info(f"Current liquidity tokens after adding {self.uniswap.get_current_liquidity()}")

        if remove_liquidity:
            receipt = self.remove_liquidity()
            if receipt is not None:
                self.logger.info(f"Current liquidity tokens after removing {self.uniswap.get_current_liquidity()}")
Exemplo n.º 15
0
 def from_all_list(pair, trade):
     return Trade(trade_id=None,
                  timestamp=int(trade['date']),
                  pair=pair,
                  is_sell=True if trade['side'] == 'sell' else False,
                  price=Wad.from_number(trade['price']),
                  amount=Wad.from_number(trade['volume']))
Exemplo n.º 16
0
def test_local_accounts_register_key():
    # given
    # [that address is not recognized by ganache, this way we can be sure it's the local account being used for signing]
    web3 = Web3(HTTPProvider("http://localhost:8555"))
    web3.eth.defaultAccount = Address(
        '0x13314e21cd6d343ceb857073f3f6d9368919d1ef').address

    # and
    keyfile_path = pkg_resources.resource_filename(
        __name__, "accounts/4_0x13314e21cd6d343ceb857073f3f6d9368919d1ef.json")
    passfile_path = pkg_resources.resource_filename(__name__, "accounts/pass")
    register_key(web3, f"key_file={keyfile_path},pass_file={passfile_path}")

    # and
    # [as ganache does not know this address, we need to send some ETH to it first]
    eth_transfer(web3, Address(web3.eth.defaultAccount), Wad.from_number(100)) \
        .transact(from_address=Address(web3.eth.accounts[0]))

    # when
    # [we deploy some test contract and mint some tokens]
    token = DSToken.deploy(web3, 'XYZ')
    token.mint(Wad.from_number(150000)).transact()

    # then
    # [these operations were successful]
    assert token.balance_of(Address(
        web3.eth.defaultAccount)) == Wad.from_number(150000)
Exemplo n.º 17
0
    def test_on_take_wih_filter(self):
        # given
        on_take_filter1_mock = Mock()
        on_take_filter2_mock = Mock()
        self.otc.on_take(on_take_filter1_mock,
                         {'maker': self.our_address.address})
        self.otc.on_take(
            on_take_filter2_mock,
            {'maker': '0x0101010101020202020201010101010303030303'})

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()

        # and
        self.otc.approve([self.token2], directly())
        self.otc.take(1, Wad.from_number(0.5)).transact()

        # then
        assert len(wait_until_mock_called(on_take_filter1_mock)) == 1

        # and
        time.sleep(2)
        assert not on_take_filter2_mock.called
Exemplo n.º 18
0
    def get_trades(self, pair: str, page_number: int = 1) -> List[Trade]:
        assert (isinstance(pair, str))
        assert (isinstance(page_number, int))

        result = self._http_post("/v0/trades", {
            'market': pair,
            'page': page_number,
            'per_page': 100
        })['trades']

        result = filter(lambda item: item['state'] == 'confirmed', result)

        trades = list(
            map(
                lambda item: Trade(
                    trade_id=int(item['id']),
                    timestamp=int(
                        dateutil.parser.parse(item['createdAt']).timestamp()),
                    pair=pair,
                    is_sell=item['type'] == 'sell',
                    price=Wad.from_number(item['price']),
                    amount=Wad.from_number(item['amount']),
                    money=Wad.from_number(item['amount']) * Wad.from_number(
                        item['price'])), result))

        return sort_trades(trades)
Exemplo n.º 19
0
    def get_trades(self, pair: str, page_number: int = 1) -> List[Trade]:
        assert(isinstance(pair, str))
        assert(isinstance(page_number, int))

        per_page = 100
        page_filter = f"page={page_number}&per_page={per_page}"
        result = self._http_get_signed(f"/v2/markets/{pair}/trades/mine?{page_filter}", {})['data']
        totalPages = result['totalPages']
        currentPage = result['currentPage']
        self.logger.debug(f'totalPages={totalPages};currentPage={currentPage}')

        # Oldest trades are on first page

        trades  = result['trades']
        trades = list(filter(lambda item: item['status'] == 'successful', trades))

        trades = list(map(lambda item: Trade(trade_id=item['transactionId'],
                                             timestamp=int(item['executedAt']/1000),
                                             pair=pair,
                                             is_sell= Address(item['buyer']) != Address(self.web3.eth.defaultAccount),
                                             price=Wad.from_number(item['price']),
                                             amount=Wad.from_number(item['amount']),
                                             createdAt=int(item['createdAt']/1000)), trades))

        return sort_trades(trades)
Exemplo n.º 20
0
 def from_message(item: dict):
     return Order(order_id=item['oid'],
                  timestamp=item['created_at'],
                  pair=item['book'],
                  is_sell=True if item['side'] == 'sell' else False,
                  price=Wad.from_number(item['price']),
                  amount=Wad.from_number(item['amount']))
Exemplo n.º 21
0
    def test_past_kill(self):

        if isinstance(self.otc, MatchingMarket):
            pay_val = self.token1_tokenclass
            buy_val = self.token2_tokenclass
        else:
            pay_val = self.token1.address
            buy_val = self.token2.address

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_val, Wad.from_number(1), buy_val,
                      Wad.from_number(2)).transact()

        # and
        self.otc.kill(1).transact()

        # then
        past_kill = self.otc.past_kill(PAST_BLOCKS)
        assert len(past_kill) == 1
        assert past_kill[0].order_id == 1
        assert past_kill[0].maker == self.our_address
        assert past_kill[0].pay_token == self.token1.address
        assert past_kill[0].pay_amount == Wad.from_number(1)
        assert past_kill[0].buy_token == self.token2.address
        assert past_kill[0].buy_amount == Wad.from_number(2)
        assert past_kill[0].timestamp != 0
        assert past_kill[0].raw['blockNumber'] > 0
Exemplo n.º 22
0
 def from_all_list(pair, trade):
     return Trade(trade_id=trade['trade_id'],
                  timestamp=int(dateutil.parser.parse(trade['time']).timestamp()),
                  pair=pair,
                  is_sell=True if trade['side'] == 'sell' else False,
                  price=Wad.from_number(trade['price']),
                  amount=Wad.from_number(trade['size']))
Exemplo n.º 23
0
 def to_trade(pair: str, trade):
     return Trade(trade_id=trade['tradeId'],
                  timestamp=int(float(trade['time'])) // 1000,
                  pair=pair,
                  is_sell=trade['take'] == 'sell',
                  price=Wad.from_number(trade['price']),
                  amount=Wad.from_number(trade['quantity']))
Exemplo n.º 24
0
    def get_trades(self, pair: str, **kwargs) -> List[Trade]:
        assert (isinstance(pair, str))

        result = self._http_post("/v0/trades", {'market': pair})

        result = filter(lambda item: item['completedAt'] is not None, result)
        trades = list(
            map(
                lambda item: Trade(trade_id=int(item['id']),
                                   timestamp=int(
                                       dateutil.parser.parse(item[
                                           'completedAt']).timestamp()),
                                   pair=pair,
                                   is_sell=item['type'] == 'sell',
                                   price=Wad.from_number(item['price']),
                                   amount=Wad.from_number(item['amount']),
                                   amount_symbol=item['baseToken'],
                                   money=Wad.from_number(item['amount']) * Wad.
                                   from_number(item['price']),
                                   money_symbol=item['quoteToken'],
                                   base_fee=Wad.from_number(item['baseFee']),
                                   trading_fee=Wad.from_number(item[
                                       'tradingFee'])), result))

        trades = sort_trades(trades)
        trades = filter_trades(trades, **kwargs)

        return trades
Exemplo n.º 25
0
 def from_message(item: list, pair: str) -> Order:
     return Order(order_id=item['orderId'],
                  timestamp=int(item['timestamp']),
                  pair=pair,
                  is_sell=True if item['type'] == 'ask' else False,
                  price=Wad.from_number(float(item["price"])),
                  amount=Wad.from_number(float(item['qty'])))
Exemplo n.º 26
0
    def test_get_orders(self):
        buy_amount_order1 = Wad.from_number(5.124988526145090209)
        pay_amount_order1 = Wad.from_number(5.024999999999999500)

        buy_amount_order2 = Wad.from_number(5.102550000000000000)
        pay_amount_order2 = Wad.from_number(5.000000000000000000)

        # given
        self.otc.make(p_token=self.token2_tokenclass,
                      pay_amount=self.token2_tokenclass.unnormalize_amount(
                          pay_amount_order1),
                      b_token=self.token1_tokenclass,
                      buy_amount=buy_amount_order1).transact()

        self.otc.make(p_token=self.token1_tokenclass,
                      pay_amount=pay_amount_order2,
                      b_token=self.token2_tokenclass,
                      buy_amount=self.token2_tokenclass.unnormalize_amount(
                          buy_amount_order2)).transact()

        # then
        assert self.otc.get_orders(
            self.token1_tokenclass,
            self.token2_tokenclass)[0].buy_amount == buy_amount_order2
        assert self.token2_tokenclass.unnormalize_amount(
            self.otc.get_orders(self.token2_tokenclass,
                                self.token1_tokenclass)[0].pay_amount
        ) == self.token2_tokenclass.unnormalize_amount(pay_amount_order1)
Exemplo n.º 27
0
    def test_get_orders_by_maker(self):
        # given
        maker1 = self.our_address
        maker2 = Address(self.web3.eth.accounts[1])

        # and
        self.token1.transfer(maker2, Wad.from_number(500)).transact()

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()

        # and
        self.web3.eth.defaultAccount = self.web3.eth.accounts[1]
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()
        self.web3.eth.defaultAccount = self.web3.eth.accounts[0]

        # then
        assert len(self.otc.get_orders()) == 2
        assert len(self.otc.get_orders_by_maker(maker1)) == 1
        assert len(self.otc.get_orders_by_maker(maker2)) == 1

        # and
        assert self.otc.get_orders_by_maker(maker1)[0].maker == maker1
        assert self.otc.get_orders_by_maker(maker2)[0].maker == maker2
Exemplo n.º 28
0
 def from_our_list(pair, trade):
     return Trade(trade_id=trade['executionId'],
                  timestamp=int(int(trade['eventTime']) / 1000000),
                  pair=pair,
                  is_sell=True if trade['side'] == 'sell' else False,
                  price=Wad.from_number(trade['price']),
                  amount=Wad.from_number(trade['quantity']))
Exemplo n.º 29
0
    def test_approve_and_make_and_getters(self):
        # given
        assert self.otc.get_last_order_id() == 0

        # when
        self.otc.approve([self.token1], directly())
        self.otc.make(pay_token=self.token1.address,
                      pay_amount=Wad.from_number(1),
                      buy_token=self.token2.address,
                      buy_amount=Wad.from_number(2)).transact()

        # then
        assert self.otc.get_last_order_id() == 1

        # and
        assert self.otc.get_order(1).order_id == 1
        assert self.otc.get_order(1).pay_token == self.token1.address
        assert self.otc.get_order(1).pay_amount == Wad.from_number(1)
        assert self.otc.get_order(1).buy_token == self.token2.address
        assert self.otc.get_order(1).buy_amount == Wad.from_number(2)
        assert self.otc.get_order(1).maker == self.our_address
        assert self.otc.get_order(1).timestamp != 0

        # and
        assert self.otc.get_orders() == [self.otc.get_order(1)]
Exemplo n.º 30
0
    def get_all_trades(self, pair: str, page_number: int = 1) -> List[Trade]:
        assert (isinstance(pair, str))
        assert (isinstance(page_number, int))

        per_page = 100
        page_filter = f"page={page_number}&per_page={per_page}"
        result = self._http_get(
            f"/{self.version}/markets/{pair}/trades?{page_filter}", {})['data']
        totalPages = result['totalPages']
        currentPage = result['currentPage']
        self.logger.debug(f'totalPages={totalPages};currentPage={currentPage}')

        # Oldest trades are on first page

        trades = result['trades']
        trades = list(
            filter(lambda item: item['status'] == 'successful', trades))

        return list(
            map(
                lambda item: Trade(trade_id=None,
                                   timestamp=int(item['executedAt'] / 1000),
                                   pair=pair,
                                   is_sell=None,
                                   price=Wad.from_number(item['price']),
                                   amount=Wad.from_number(item['amount']),
                                   createdAt=int(item['createdAt'] / 1000)),
                trades))