diff --git a/lbry/extras/daemon/exchange_rate_manager.py b/lbry/extras/daemon/exchange_rate_manager.py index 3d6b104b4..b9ca80ba8 100644 --- a/lbry/extras/daemon/exchange_rate_manager.py +++ b/lbry/extras/daemon/exchange_rate_manager.py @@ -2,6 +2,7 @@ import json import time import asyncio import logging +from statistics import median from decimal import Decimal from typing import Optional, Iterable, Type from aiohttp.client_exceptions import ContentTypeError @@ -239,20 +240,23 @@ class ExchangeRateManager: source.stop() def convert_currency(self, from_currency, to_currency, amount): - rates = [market.rate for market in self.market_feeds] - log.debug("Converting %f %s to %s, rates: %s", amount, from_currency, to_currency, rates) + log.debug( + "Converting %f %s to %s, rates: %s", + amount, from_currency, to_currency, + [market.rate for market in self.market_feeds] + ) if from_currency == to_currency: return round(amount, 8) + rates = [] for market in self.market_feeds: if (market.has_rate and market.is_online and market.rate.currency_pair == (from_currency, to_currency)): - return round(amount * Decimal(market.rate.spot), 8) - for market in self.market_feeds: - if (market.has_rate and market.is_online and - market.rate.currency_pair[0] == from_currency): - return round(self.convert_currency( - market.rate.currency_pair[1], to_currency, amount * Decimal(market.rate.spot)), 8) + rates.append(market.rate.spot) + + if rates: + return round(amount * Decimal(median(rates)), 8) + raise CurrencyConversionError( f'Unable to convert {amount} from {from_currency} to {to_currency}') diff --git a/tests/unit/lbrynet_daemon/test_exchange_rate_manager.py b/tests/unit/lbrynet_daemon/test_exchange_rate_manager.py index 2f9cbe169..39801c442 100644 --- a/tests/unit/lbrynet_daemon/test_exchange_rate_manager.py +++ b/tests/unit/lbrynet_daemon/test_exchange_rate_manager.py @@ -5,7 +5,8 @@ from lbry.schema.claim import Claim from lbry.extras.daemon.exchange_rate_manager import ( ExchangeRate, ExchangeRateManager, CurrencyConversionError, CryptonatorUSDFeed, CryptonatorBTCFeed, - BittrexUSDFeed, BittrexBTCFeed + BittrexUSDFeed, BittrexBTCFeed, + CoinExBTCFeed ) from lbry.testcase import AsyncioTestCase, FakeExchangeRateManager, get_fake_exchange_rate_manager from lbry.error import InvalidExchangeRateResponseError @@ -106,3 +107,15 @@ class ExchangeRateManagerTests(AsyncioTestCase): manager.start() await asyncio.sleep(1) self.addCleanup(manager.stop) + + async def test_median_rate_used(self): + manager = ExchangeRateManager([BittrexBTCFeed, CryptonatorBTCFeed, CoinExBTCFeed]) + for feed in manager.market_feeds: + feed.last_check = time() + bittrex, cryptonator, coinex = manager.market_feeds + bittrex.rate = ExchangeRate(bittrex.market, 1.0, time()) + cryptonator.rate = ExchangeRate(cryptonator.market, 2.0, time()) + coinex.rate = ExchangeRate(coinex.market, 3.0, time()) + self.assertEqual(14.0, manager.convert_currency("BTC", "LBC", Decimal(7.0))) + cryptonator.rate.spot = 4.0 + self.assertEqual(21.0, manager.convert_currency("BTC", "LBC", Decimal(7.0)))