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()
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 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()
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()
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()
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()
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()
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()
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
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
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()