def price_converted_to_usd(self,
                               currency_symbol,
                               exchange_name='aggregate'):
        result = WeightedAverage()
        for a in self.alive_exchanges:
            if a.currency_symbol != currency_symbol:
                continue
            if a.price_usd is not None and a.price_usd != 0:
                price_in_usd = a.price_usd
                volume_in_usd = 0 if a.volume_usd is None else a.volume_usd
            elif a.price_dai is not None and a.price_dai != 0:
                price_in_usd = a.price_dai
                volume_in_usd = 0 if a.volume_dai is None else a.volume_dai
            elif a.price_eth is not None and a.price_eth != 0:
                price_in_usd = a.price_eth * self.eth_price_usd()
                volume_in_usd = 0 if a.volume_eth is None else a.volume_eth * self.eth_price_usd(
                )
            elif a.price_btc is not None and a.price_btc != 0:
                price_in_usd = a.price_btc * self.eth_price_usd()
                volume_in_usd = 0 if a.volume_btc is None else a.volume_btc * self.eth_price_usd(
                )

            if exchange_name == 'aggregate' or a.exchange_name == exchange_name:
                result.add(price_in_usd, volume_in_usd)
        return result.average()
예제 #2
0
    def __init__(self, slam_data_filepath, sensor_list_filepath,
                 smarthome_data_filepath, config):
        # variables
        self.map = None
        self.slam_weight = 1.0
        self.wa_weight = 0.1
        self.path_weight = 1500.0

        # load slam map
        self.slam_map = slam_map = SlamMap(slam_data_filepath, config)

        # load reachability map
        self.reachability_map = reachability_map = ReachabilityMap(slam_map)

        # load heatmap
        self.static_heatmap = static_heatmap = StaticHeatmap(
            sensor_list_filepath, smarthome_data_filepath, config)
        static_heatmap.set_offset(slam_map.origin[0], slam_map.origin[1])

        # load path map
        self.path_map_array = PathMap(self.static_heatmap).get_as_array()

        # load weighted average
        self.weighted_average = WeightedAverage(static_heatmap)
        self.average_point = self.weighted_average.get_weighted_average_point()

        self._build_map()
예제 #3
0
 def btc_price_usd(self, api_name='aggregate'):
     result = WeightedAverage()
     for a in self.alive_apis:
         if a.btc_price_usd == None:
             continue
         if api_name == 'aggregate' or a.api_name == api_name:
             result.add(a.btc_price_usd, a.volume_eth)
     return result.average()
예제 #4
0
 def change_24h(self, currency_symbol='0xBTC', api_name='aggregate'):
     result = WeightedAverage()
     for a in self.alive_apis:
         if a.currency_symbol != currency_symbol:
             continue
         if a.change_24h == None:
             continue
         if api_name == 'aggregate' or a.api_name == api_name:
             result.add(a.change_24h, a.volume_eth)
     return result.average()
예제 #5
0
 def price_usd(self, currency_symbol, exchange_name='aggregate'):
     result = WeightedAverage()
     for a in self.alive_exchanges:
         if a.currency_symbol != currency_symbol:
             continue
         if a.price_usd == None:
             continue
         if a.volume_eth == None:
             continue
         if exchange_name == 'aggregate' or a.exchange_name == exchange_name:
             result.add(a.price_usd, a.volume_eth)
     return result.average()
    async def _update_all_values(self, should_update_volume=False, timeout=10):

        if should_update_volume:
            current_eth_block = self._w3.eth.blockNumber

        # get price of eth
        eth_prices = [
            get_price(self._w3, "DAI", "WETH"),
            get_price(self._w3, "USDT", "WETH"),
            get_price(self._w3, "USDC", "WETH"),
        ]
        self.eth_price_usd = sum(eth_prices) / len(eth_prices)  # TODO: should be weighted average

        # get token price (in USD), liquidity (in tokens), and volume (in tokens) for
        # each pair. Note if liquidity is low for a pair, its voluem is not checked.
        price_usd_weighted_average = WeightedAverage()
        total_liquidity_tokens = 0
        total_volume_tokens = 0
        for exchange_contract in self._exchanges:
            try:
                price_usd, liquidity_tokens = await self._get_price_and_liquidity_at_exchange_contract(exchange_contract)
            except (NoTokenMatchError, PairNotDefinedError) as e:
                logging.warning(f"Failed to update quickswap exchange: {str(e)}")
                continue
            except NoLiquidityException:
                # no liquidity is not an error; simply skip this exchange
                continue
            else:
                price_usd_weighted_average.add(price_usd, liquidity_tokens)
                total_liquidity_tokens += liquidity_tokens

                if should_update_volume and liquidity_tokens > _MINIMUM_ALLOWED_LIQUIDITY_TOKENS_TO_CHECK_VOLUME:
                    try:
                        volume_tokens, volume_pair = await self._get_volume_at_exchange_contract(exchange_contract, current_eth_block=current_eth_block, timeout=timeout)
                        total_volume_tokens += volume_tokens
                    except requests.exceptions.ReadTimeout:
                        logging.warning(f"Failed to update SushiSwapPolygonAPI volume: ReadTimeout")

        self.price_usd = price_usd_weighted_average.average()
        self.price_eth = self.price_usd / self.eth_price_usd
        self.liquidity_tokens = total_liquidity_tokens
        self.liquidity_eth = self.liquidity_tokens * self.price_eth
        if should_update_volume:
            self.hourly_volume_tokens.append(total_volume_tokens)
            # trim list to 168 hours (7 days)
            self.hourly_volume_tokens = self.hourly_volume_tokens[-168:]
            # use last 24 hours for volume
            self.volume_tokens = sum(self.hourly_volume_tokens[-24:])
            self.volume_eth = self.volume_tokens * self.price_eth
            # NOTE: this sets _time_volume_last_updated even if all volume updates
            #       failed. This is OK for now, it throttles struggling APIs (matic) but
            #       may not be the ideal behavior.
            self._mark_volume_as_updated()
예제 #7
0
def main():
    # get command line arguments
    slam_data_filepath = sys.argv[1]
    smarthome_data_filepath = sys.argv[2]
    sensor_map_filepath = sys.argv[3]
    config_filepath = sys.argv[4]

    # load the config
    config = Config(config_filepath)

    ### get all the things to plot
    # get slam map
    slam_map = SlamMap(slam_data_filepath, config)

    # get heatmap
    heatmap = StaticHeatmap(sensor_map_filepath, smarthome_data_filepath, config)
    heatmap.set_offset(slam_map.origin[0], slam_map.origin[1])

    # get path map
    path_map = PathMap(heatmap)

    # get the weighted average
    weighted_average = WeightedAverage(heatmap)

    # get the reachability map
    reachability_map = ReachabilityMap(slam_map)

    ### plot all the things to plot
    # plot the path map
    path_array = path_map.get_as_array()
    #plt.imshow(np.transpose(path_array), cmap='hot', interpolation='nearest')

    # plot the heatmap
    heatmap = heatmap.get_heatmap_array()
    plt.imshow(np.transpose(heatmap), cmap=get_custom_colormap_blue(), interpolation='nearest')

    # plot the slam map
    plt.imshow(np.transpose(slam_map.map), cmap=get_custom_colormap_green(), interpolation='nearest')

    # plot the weighted average
    average_point = weighted_average.get_weighted_average_point()
    #plt.plot(average_point[0], average_point[1], 'go')

    # plot the reachability map
    #plt.imshow(np.transpose(reachability_map.map), cmap=get_custom_colormap_blue(), interpolation='nearest')

    # flip y axis
    axis = plt.gca()
    axis.set_ylim(axis.get_ylim()[::-1])

    plt.show()
 def price_eth(self, currency_symbol, exchange_name='aggregate'):
     result = WeightedAverage()
     for a in self.alive_exchanges:
         if a.currency_symbol != currency_symbol:
             continue
         if a.price_eth == None:
             continue
         if a.volume_eth == None:
             # use 0 eth as fallback so it does not affect weighted price
             volume = 0
         else:
             volume = a.volume_eth
         if exchange_name == 'aggregate' or a.exchange_name == exchange_name:
             result.add(a.price_eth, volume)
     return result.average()
예제 #9
0
    async def _update(self, timeout=10.0):
        if self.market_id_vs_eth is None:
            self.market_id_vs_eth = await self._get_market_id(
                self.currency_symbol, "ETH")
        if self.market_id_vs_btc is None:
            self.market_id_vs_btc = await self._get_market_id(
                self.currency_symbol, "BTC")
        if self.market_id_eth_btc is None:
            self.market_id_eth_btc = await self._get_market_id("ETH", "BTC")

        if self.market_id_vs_eth is None or self.market_id_vs_btc is None:
            raise RuntimeError(
                "Failed to get market ids for asset code '{}'".format(
                    self.currency_symbol))

        # grab market data for the desired currency vs ETH and BTC
        self.price_eth, self.volume_eth, change_eth = await self._fetch_market_data(
            self.market_id_vs_eth)
        self.price_btc, self.volume_btc, change_btc = await self._fetch_market_data(
            self.market_id_vs_btc)

        # grab market data for ETH/BTC so we can interpret relative data
        eth_price_in_btc, _, _ = await self._fetch_market_data(
            self.market_id_eth_btc)

        if self.volume_btc == 0:
            ratio_of_eth_vs_btc_volume = 100000
        else:
            ratio_of_eth_vs_btc_volume = self.volume_eth / (self.volume_btc /
                                                            eth_price_in_btc)

        average = WeightedAverage()
        average.add(change_eth, ratio_of_eth_vs_btc_volume)
        average.add(change_btc, 1)
        self.change_24h = average.average()
 def btc_price_usd(self, exchange_name='aggregate'):
     result = WeightedAverage()
     for a in self.alive_exchanges:
         if a.btc_price_usd == None:
             continue
         if exchange_name == 'aggregate' or a.exchange_name == exchange_name:
             if a.currency_symbol == 'BTC':
                 result.add(a.price_usd, a.volume_usd / a.price_usd)
             else:
                 result.add(a.btc_price_usd, a.volume_btc)
     return result.average()
예제 #11
0
    async def _update(self, timeout=10.0):
        total_liquidity_eth = 0
        total_liquidity_dai = 0
        total_liquidity_tokens = 0

        price_eth_avg = WeightedAverage()
        price_dai_avg = WeightedAverage()

        for exchange_address in self._exchange_addresses:
            liquidity_eth, liquidity_dai, liquidity_tokens, price_eth, price_dai = await self._get_liquidity_and_price_at_pool_addr(
                exchange_address)

            price_eth_avg.add(price_eth, liquidity_eth)
            price_dai_avg.add(price_dai, liquidity_dai)

            total_liquidity_eth += liquidity_eth
            total_liquidity_dai += liquidity_dai
            total_liquidity_tokens += liquidity_tokens

        if total_liquidity_tokens == 0:
            raise NoLiquidityException("Pool has no liquidity")

        self.liquidity_dai = total_liquidity_dai
        self.liquidity_eth = total_liquidity_eth
        self.liquidity_tokens = total_liquidity_tokens

        self.price_eth = price_eth_avg.average()
        self.price_usd = price_dai_avg.average(
        )  # note: this is usually 0 because there are no dai pairs defined on balancer

        # update volume once every hour since it (potentially) loads eth api
        if time.time() - self._time_volume_last_updated > 60 * 60:
            try:
                await self._update_volume()
            except requests.exceptions.ReadTimeout:
                logging.warning(
                    f"Failed to update QuickSwapAPI volume: ReadTimeout")

            self._time_volume_last_updated = time.time()
예제 #12
0
    def get_landing_zone(self, data=None):
        # Use the dynamic_heatmap to grab the weighted average
        weighted_average = WeightedAverage(
            self.dynamic_heatmap).get_weighted_average_point()
        self.average_point = weighted_average
        landing_zone = weighted_average

        self._build_map()

        landing_zone = self.get_best_point()
        self.dynamic_heatmap.mark_spot_on_map(landing_zone)

        self._move_ras_to(landing_zone)
        return landing_zone
    def _estimated_hashrate_n_days(self, days):
        # MUST CALL UPDATE() BEFORE THIS FUNCTION
        eth_blocks_in_window = int(days * 60 * 60 * 24 / SECONDS_PER_ETH_BLOCK)
        eth_block_at_start = self._current_eth_block - eth_blocks_in_window
        epoch_at_start = self._contract.functions.epochCount().call(
            block_identifier=-eth_blocks_in_window)
        #epoch_at_start = self._w3.toInt(self._w3.eth.getStorageAt(self.address, 0x7, eth_block_at_start))
        epochs_in_window = self._epoch_count - epoch_at_start
        epochs_per_eth_block = epochs_in_window / eth_blocks_in_window
        epochs_per_second = epochs_per_eth_block / SECONDS_PER_ETH_BLOCK
        seconds_per_reward = 1 / epochs_per_second

        # if current diff started before beginning of the window, the math is
        # simple - one difficulty only
        if self.last_difficulty_start_block <= eth_block_at_start:
            estimated_hashrate_24h = self.difficulty * 2**22 / seconds_per_reward
        else:
            # difficulty changed within the window - so calculation must
            # consider multiple difficulties
            previous_mining_target = self._contract.functions.getMiningTarget(
            ).call(block_identifier=self.last_difficulty_start_block - 1)
            previous_difficulty = int(self.max_target / previous_mining_target)

            # load the eth block where the difficulty changed to the *previous*
            # difficulty. If it is inside the window, exit completely, because
            # it means the window contains 3 or more difficulties.
            eth_block_two_readjustments_ago = self._contract.functions.latestDifficultyPeriodStarted(
            ).call(block_identifier=self.last_difficulty_start_block - 1)
            if eth_block_two_readjustments_ago >= eth_block_at_start:
                raise RuntimeError(
                    "Average window too large: this function only supports at most two difficulty periods."
                )

            from weighted_average import WeightedAverage
            wa = WeightedAverage()
            # add hashrate based on current difficulty weighted by how many eth
            # blocks occured during that difficulty
            wa.add(self.difficulty * 2**22 / seconds_per_reward,
                   self._current_eth_block - self.last_difficulty_start_block)
            # add hashrate based on last difficulty weighted by how many eth
            # blocks occured during that difficulty
            wa.add(previous_difficulty * 2**22 / seconds_per_reward,
                   self.last_difficulty_start_block - eth_block_at_start)
            estimated_hashrate_24h = wa.average()

        return estimated_hashrate_24h
예제 #14
0
class BasePlacer:
    """ Finds where the robot should be placed based on our metrics

    Loads up the heatmap, slam map, path map, and weighted average.
    Then uses each of these metrics to find the best point by finding
    a weighted value for every point on the map.

    """
    def __init__(self, slam_data_filepath, sensor_list_filepath,
                 smarthome_data_filepath, config):
        # variables
        self.map = None
        self.slam_weight = 1.0
        self.wa_weight = 0.1
        self.path_weight = 1500.0

        # load slam map
        self.slam_map = slam_map = SlamMap(slam_data_filepath, config)

        # load reachability map
        self.reachability_map = reachability_map = ReachabilityMap(slam_map)

        # load heatmap
        self.static_heatmap = static_heatmap = StaticHeatmap(
            sensor_list_filepath, smarthome_data_filepath, config)
        static_heatmap.set_offset(slam_map.origin[0], slam_map.origin[1])

        # load path map
        self.path_map_array = PathMap(self.static_heatmap).get_as_array()

        # load weighted average
        self.weighted_average = WeightedAverage(static_heatmap)
        self.average_point = self.weighted_average.get_weighted_average_point()

        self._build_map()

    def _build_map(self):

        # find the value of each point
        placement_map = np.zeros_like(self.static_heatmap.get_heatmap_array())

        for i in range(placement_map.shape[0]):
            for j in range(placement_map.shape[1]):
                # find the value of a given location
                placement_map[i, j] = self.find_value(i, j)

        # rescale to between zero and 1
        # note that all values in the map are less than zero
        amin = np.amin(placement_map)
        placement_map = np.subtract(placement_map, amin)
        amax = np.amax(placement_map)
        placement_map = np.true_divide(placement_map, amax)

        # apply reachability mask
        placement_map = self.apply_reachability_mask(placement_map)

        self.map = placement_map

    def apply_reachability_mask(self, placement_map):
        reachability_map = self.reachability_map.map

        masked_map = np.zeros_like(reachability_map, dtype="float")

        for i in range(reachability_map.shape[0]):
            for j in range(reachability_map.shape[1]):
                # skip values outside the placement map
                if i >= placement_map.shape[0] or j >= placement_map.shape[1]:
                    continue

                if reachability_map[i, j] > 0:
                    masked_map[i, j] = placement_map[i, j]

        return masked_map

    def find_value(self, i, j):
        """
        
        find the placement value at the given array location

        """

        # get weighted average value
        p1 = (i, j)
        p2 = self.average_point
        wa_value = -(get_point_distance(p1, p2)**2) * self.wa_weight

        # get path map value
        path_value = -self.path_map_array[i, j] * self.path_weight

        return wa_value + path_value

    def get_best_point(self):
        """ get the location of the best point

        returns:
            tuple (x, y) - indecies of the best scoring map location
        """
        max_value = 0.0  # minimum value of the map is 0.0
        best_point = (-1, -1)

        for i in range(self.map.shape[0]):
            for j in range(self.map.shape[1]):
                if self.map[i, j] > max_value:
                    max_value = self.map[i, j]
                    best_point = (i, j)

        return best_point

    def display_as_heatmap(self):
        best_point = self.get_best_point()

        # display
        plt.imshow(np.transpose(self.map), cmap='hot', interpolation='nearest')
        plt.plot(best_point[0], best_point[1], 'go')

        axis = plt.gca()
        axis.set_ylim(axis.get_ylim()[::-1])
        plt.show()

    def display_top(self, top_percent=0.1):
        top_map = np.copy(self.map)

        minimum = np.amin(top_map)
        maximum = np.amax(top_map)

        value_range = maximum - minimum
        cutoff = maximum - value_range * top_percent

        # clip any values below the desired percentage
        full = np.full_like(top_map, cutoff)
        top_map = np.maximum(top_map, full)
        top_map = np.subtract(top_map, full)

        # scale to between 0 and 1
        amax = np.amax(top_map)
        top_map = np.true_divide(top_map, amax)

        plt.imshow(np.transpose(top_map), cmap='hot', interpolation='nearest')
        plt.imshow(np.transpose(self.slam_map.map),
                   cmap=get_custom_colormap_green(),
                   interpolation='nearest')

        axis = plt.gca()
        axis.set_ylim(axis.get_ylim()[::-1])
        plt.show()
    def _update(self, timeout=10.0):
        method = "/coin/{}".format(self.currency_symbol)

        response = urlopen(self._SERVER_URL+method, timeout=timeout)
        response = response.read().decode("utf-8") 
        try:
            data = json.loads(response)
        except json.decoder.JSONDecodeError:
            if "be right back" in response:
                raise TimeoutError("api is down - got 404 page")
            else:
            	raise TimeoutError("api sent bad data ({})".format(repr(response)))
            

        volume_usd = 0

        wavg_eth_price_usd = WeightedAverage()
        wavg_btc_price_usd = WeightedAverage()

        wavg_price_eth = WeightedAverage()
        wavg_price_usd = WeightedAverage()

        for exchange_data in data['data']:
            # skip reverse-pairings
            if exchange_data['base'] != self.currency_symbol:
                continue

            # last_price_in_usd = data['data'][0]['usd']
            # last_price_in_eth = data['data'][0]['rate']
            # last_eth_price = data['data'][0]['lastq']
            base_pair = exchange_data['quote']
            relative_volume = float(exchange_data['volumep'])

            # NOTE: this entire if statement is ONLY to collect price of eth and btc
            if base_pair == "ETH":
                # average price of base pairs, they are NOT all the same
                wavg_eth_price_usd.add(exchange_data['lastq'], relative_volume)
                wavg_price_eth.add(exchange_data['rate'], relative_volume)
            elif (base_pair in ["AUD", "CAD", "CNY", "DAI", "EUR", "EURO", "GBP", "JPY", "KRW", "RUB", "USDT", "USD"]):
                # allow all fiat pairings to count towards volume
                pass
            elif (base_pair in ["BTC"]):
                # average price of base pairs, they are NOT all the same
                wavg_btc_price_usd.add(exchange_data['lastq'], relative_volume)
                # allow BTC pairings to count towards volume
                pass
            else:
                #pprint.pprint(exchange_data)
                logging.debug('Unknown base_pair {}'.format(base_pair))
                # if base pair is unknown, don't use for calcualted volume/price
                continue

            # only let allowed_apis to count toward price
            if self.allowed_apis == 'all' or exchange_data['exchange'] in self.allowed_apis:
                wavg_price_usd.add(exchange_data['usd'], relative_volume)
                volume_usd += exchange_data['volume']



        self.price_usd = wavg_price_usd.average()

        self.eth_price_usd = wavg_eth_price_usd.average()
        self.btc_price_usd = wavg_btc_price_usd.average()

        if self.currency_symbol == "ETH":
            self.price_eth = 1
            self.eth_price_usd = self.price_usd
        else:
            self.price_eth = wavg_price_eth.average()

        self.volume_usd = volume_usd

        if self.eth_price_usd != None and self.eth_price_usd != 0:
            # TODO: volume_eth should really represent quantity of volume in eth,
            # not quantity of all volume converted to price of eth. This
            # calculation includes btc in eth volume.
            self.volume_eth = self.volume_usd / self.eth_price_usd

        if self.currency_symbol == "BTC":
            self.btc_price_usd = self.price_usd
    async def _update(self, timeout=10.0):
        eth_prices = [
            get_price(self._w3, "DAI", "WETH"),
            get_price(self._w3, "USDT", "WETH"),
            get_price(self._w3, "USDC", "WETH"),
        ]
        # TODO: weighted average would be better than a simple average
        self.eth_price_usd = sum(eth_prices) / len(eth_prices)

        # matic_price_eth = get_price(self._w3, "WETH", "WMATIC")
        # self.matic_price_usd = matic_price_eth * self.eth_price_usd

        # swam_price_eth = get_price(self._w3, "WETH", "SWAM")
        # self.swam_price_usd = swam_price_eth * self.eth_price_usd

        total_liquidity_tokens = 0
        price_usd_weighted_average = WeightedAverage()
        # check each token that <self.currency_symbol> is paired with
        for exchange_contract in self._exchanges:
            token0_address = exchange_contract.functions.token0().call().lower(
            )
            token1_address = exchange_contract.functions.token1().call().lower(
            )
            paired_token_address = token0_address if token1_address.lower(
            ) == Token().from_symbol(
                self.currency_symbol).address.lower() else token1_address
            try:
                paired_token_symbol = Token().from_address(
                    paired_token_address).symbol
            except NoTokenMatchError:
                logging.warning(
                    f"no token with address {paired_token_address} found (need to edit token_class.py); skipping"
                )
                continue

            try:
                liquidity_tokens, liquidity_pair = get_reserves(
                    self._w3, self.currency_symbol, paired_token_symbol)
            except PairNotDefinedError:
                logging.warning(
                    f"pair {self.currency_symbol}-{paired_token_symbol} not found; skipping"
                )
                continue

            if liquidity_tokens < 0.001:
                continue

            total_liquidity_tokens += liquidity_tokens

            if paired_token_symbol == "WETH":
                self.price_eth = get_price(self._w3, paired_token_symbol,
                                           self.currency_symbol)
                price_usd_weighted_average.add(
                    self.price_eth * self.eth_price_usd, liquidity_tokens)
                self.liquidity_eth = liquidity_pair
            else:

                # get the paired token's price in Eth. If there is less than $500 in
                # liquidity to determine this, then skip this pair when determining price.
                try:
                    liquidity_eth, _ = get_reserves(self._w3, "WETH",
                                                    paired_token_symbol)
                except PairNotDefinedError:
                    logging.warning(
                        f"pair WETH-{paired_token_symbol} not found; skipping")
                    continue

                if liquidity_eth < 500 / self.eth_price_usd:
                    continue

                paired_token_price_in_eth = get_price(self._w3, "WETH",
                                                      paired_token_symbol)
                paired_token_price_in_usd = paired_token_price_in_eth * self.eth_price_usd

                # get the price <self.currency_symbol> in terms of the paired token
                price_in_paired_token = get_price(self._w3,
                                                  paired_token_symbol,
                                                  self.currency_symbol)

                price_usd_weighted_average.add(
                    price_in_paired_token * paired_token_price_in_usd,
                    liquidity_tokens)

        self.liquidity_tokens = total_liquidity_tokens
        self.price_usd = price_usd_weighted_average.average()

        try:
            self.price_eth = get_price(self._w3, "WETH", self.currency_symbol)
        except PairNotDefinedError:
            logging.warning(
                f"Failed to get WETH pair for {self.currency_symbol}; calculating backwards using average USD price"
            )
            self.price_eth = self.price_usd / self.eth_price_usd

        self.volume_tokens = await self._update_24h_volume()
        self.volume_eth = self.volume_tokens * self.price_eth
예제 #17
0
    async def _update_all_values(self,
                                 timeout=10.0,
                                 should_update_volume=False):

        if should_update_volume:
            current_eth_block = self._w3.eth.blockNumber

        self.price_eth = None

        eth_prices = [
            get_price(self._uniswap_api, "DAI", "WETH", _DEFAULT_PAIR_FEE),
            get_price(self._uniswap_api, "USDT", "WETH", _DEFAULT_PAIR_FEE),
            get_price(self._uniswap_api, "USDC", "WETH", _DEFAULT_PAIR_FEE),
        ]
        self.eth_price_usd = sum(eth_prices) / len(
            eth_prices)  # TODO: should be weighted average

        price_usd_weighted_average = WeightedAverage()
        total_liquidity_tokens = 0
        total_volume_tokens = 0

        for exchange_address in getExchangeAddressesForToken(
                self.currency_symbol):
            token0_name, token1_name, fee = getTokensFromExchangeAddress(
                exchange_address)
            token0_address = Token().from_symbol(token0_name).address
            token1_address = Token().from_symbol(token1_name).address
            #paired_token_address = token0_address if token1_address.lower() == Token().from_symbol(self.currency_symbol).address.lower() else token1_address
            #paired_token_symbol = Token().from_address(paired_token_address).symbol

            try:
                price_usd, liquidity_tokens = await self._get_price_and_liquidity_for_pair(
                    token0_address, token1_address, fee)
            except (NoTokenMatchError, PairNotDefinedError) as e:
                logging.warning(
                    f"Failed to update {self.exchange_name} pair: {str(e)}")
                continue
            except NoLiquidityException:
                # no liquidity is not an error; simply skip this exchange
                continue
            else:
                price_usd_weighted_average.add(price_usd, liquidity_tokens)
                total_liquidity_tokens += liquidity_tokens

                if should_update_volume and liquidity_tokens > _MINIMUM_ALLOWED_LIQUIDITY_TOKENS_TO_CHECK_VOLUME:
                    try:
                        volume_tokens, volume_pair = await self._get_volume_for_pair(
                            token0_address,
                            token1_address,
                            fee,
                            current_eth_block=current_eth_block,
                            timeout=timeout)
                        total_volume_tokens += volume_tokens
                    except requests.exceptions.ReadTimeout:
                        logging.warning(
                            f"Failed to update Uniswapv3API volume: ReadTimeout"
                        )

        self.price_usd = price_usd_weighted_average.average()
        self.price_eth = self.price_usd / self.eth_price_usd
        self.liquidity_tokens = total_liquidity_tokens
        self.liquidity_eth = self.liquidity_tokens * self.price_eth

        if should_update_volume:
            self.hourly_volume_tokens.append(total_volume_tokens)
            # trim list to 168 hours (7 days)
            self.hourly_volume_tokens = self.hourly_volume_tokens[-168:]
            # use last 24 hours for volume
            self.volume_tokens = sum(self.hourly_volume_tokens[-24:])
            self.volume_eth = self.volume_tokens * self.price_eth
            # NOTE: this sets _time_volume_last_updated even if all volume updates
            #       failed. This is OK for now, it throttles struggling APIs (matic) but
            #       may not be the ideal behavior.
            self._mark_volume_as_updated()
    async def _update(self, timeout=10.0):
        method = "/coin/{}".format(self.currency_symbol)

        data = await self._get_json_from_url(self._SERVER_URL+method)

        volume_usd = 0
        volume_usd_eth = 0
        volume_usd_btc = 0

        wavg_eth_price_usd = WeightedAverage()
        wavg_btc_price_usd = WeightedAverage()

        wavg_price_eth = WeightedAverage()
        wavg_price_btc = WeightedAverage()
        wavg_price_usd = WeightedAverage()

        for exchange_data in data['data']:
            # skip reverse-pairings
            if exchange_data['base'] != self.currency_symbol:
                continue

            # last_price_in_usd = data['data'][0]['usd']
            # last_price_in_eth = data['data'][0]['rate']
            # last_eth_price = data['data'][0]['lastq']
            base_pair = exchange_data['quote']
            relative_volume = float(exchange_data['volumep'])

            # NOTE: this entire if statement is ONLY to collect price of eth and btc
            if base_pair == "ETH":
                # average price of base pairs, they are NOT all the same
                wavg_eth_price_usd.add(exchange_data['lastq'], relative_volume)
            elif (base_pair in ["AUD", "CAD", "CNY", "DAI", "EUR", "EURO", "GBP", "JPY", "KRW", "RUB", "USDT", "USD"]):
                # allow all fiat pairings to count towards volume
                pass
            elif (base_pair in ["BTC"]):
                # average price of base pairs, they are NOT all the same
                wavg_btc_price_usd.add(exchange_data['lastq'], relative_volume)
                # allow BTC pairings to count towards volume
                pass
            else:
                # if base pair is unknown, don't use for calcualted volume/price
                continue

            # only let allowed_apis to count toward price
            if self.allowed_apis == 'all' or exchange_data['exchange'] in self.allowed_apis:
                wavg_price_usd.add(exchange_data['usd'], relative_volume)
                volume_usd += exchange_data['volume']
                
                if base_pair == "ETH":
                    wavg_price_eth.add(exchange_data['rate'], relative_volume)
                    volume_usd_eth += exchange_data['volume']
                
                if base_pair == "BTC":
                    wavg_price_btc.add(exchange_data['rate'], relative_volume)
                    volume_usd_btc += exchange_data['volume']

        self.price_usd = wavg_price_usd.average()

        self.eth_price_usd = wavg_eth_price_usd.average()
        self.btc_price_usd = wavg_btc_price_usd.average()

        if self.currency_symbol == "ETH":
            self.price_eth = 1
            self.eth_price_usd = self.price_usd
        else:
            self.price_eth = wavg_price_eth.average()

        self.volume_usd = volume_usd

        if self.eth_price_usd != None and self.eth_price_usd != 0:
            # TODO: volume_eth should really represent quantity of volume in eth,
            # not quantity of all volume converted to price of eth. This
            # calculation includes btc in eth volume.
            self.volume_eth = volume_usd_eth / self.eth_price_usd

        if self.btc_price_usd != None and self.btc_price_usd != 0:
            # TODO: volume_eth should really represent quantity of volume in eth,
            # not quantity of all volume converted to price of eth. This
            # calculation includes btc in eth volume.
            self.volume_btc = volume_usd_btc / self.btc_price_usd

        if self.currency_symbol == "BTC":
            self.price_btc = 1
            self.btc_price_usd = self.price_usd
        else:
            self.price_btc = wavg_price_btc.average()