Merge pull request #665 from xmatthias/fix_fiat_convert
Fix fiat convert
This commit is contained in:
commit
91f90920c2
@ -5,6 +5,7 @@ e.g BTC to USD
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from coinmarketcap import Market
|
from coinmarketcap import Market
|
||||||
|
|
||||||
@ -73,12 +74,7 @@ class CryptoToFiatConverter(object):
|
|||||||
"RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD"
|
"RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD"
|
||||||
]
|
]
|
||||||
|
|
||||||
CRYPTOMAP = {
|
_cryptomap: Dict = {}
|
||||||
'BTC': 'bitcoin',
|
|
||||||
'ETH': 'ethereum',
|
|
||||||
'USDT': 'thether',
|
|
||||||
'BNB': 'binance-coin'
|
|
||||||
}
|
|
||||||
|
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
if CryptoToFiatConverter.__instance is None:
|
if CryptoToFiatConverter.__instance is None:
|
||||||
@ -91,6 +87,15 @@ class CryptoToFiatConverter(object):
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._pairs = []
|
self._pairs = []
|
||||||
|
self._load_cryptomap()
|
||||||
|
|
||||||
|
def _load_cryptomap(self) -> None:
|
||||||
|
try:
|
||||||
|
coinlistings = self._coinmarketcap.listings()
|
||||||
|
self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"])),
|
||||||
|
coinlistings["data"]))
|
||||||
|
except ValueError:
|
||||||
|
logger.error("Could not load FIAT Cryptocurrency map")
|
||||||
|
|
||||||
def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float:
|
def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float:
|
||||||
"""
|
"""
|
||||||
@ -182,16 +187,17 @@ class CryptoToFiatConverter(object):
|
|||||||
if not self._is_supported_fiat(fiat=fiat_symbol):
|
if not self._is_supported_fiat(fiat=fiat_symbol):
|
||||||
raise ValueError('The fiat {} is not supported.'.format(fiat_symbol))
|
raise ValueError('The fiat {} is not supported.'.format(fiat_symbol))
|
||||||
|
|
||||||
if crypto_symbol not in self.CRYPTOMAP:
|
if crypto_symbol not in self._cryptomap:
|
||||||
# return 0 for unsupported stake currencies (fiat-convert should not break the bot)
|
# return 0 for unsupported stake currencies (fiat-convert should not break the bot)
|
||||||
logger.warning("unsupported crypto-symbol %s - returning 0.0", crypto_symbol)
|
logger.warning("unsupported crypto-symbol %s - returning 0.0", crypto_symbol)
|
||||||
return 0.0
|
return 0.0
|
||||||
try:
|
try:
|
||||||
return float(
|
return float(
|
||||||
self._coinmarketcap.ticker(
|
self._coinmarketcap.ticker(
|
||||||
currency=self.CRYPTOMAP[crypto_symbol],
|
currency=self._cryptomap[crypto_symbol],
|
||||||
convert=fiat_symbol
|
convert=fiat_symbol
|
||||||
)[0]['price_' + fiat_symbol.lower()]
|
)['data']['quotes'][fiat_symbol.upper()]['price']
|
||||||
)
|
)
|
||||||
except BaseException:
|
except BaseException as ex:
|
||||||
|
logger.error("Error in _find_price: %s", ex)
|
||||||
return 0.0
|
return 0.0
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Dict, Optional
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
@ -34,7 +35,8 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
|
|||||||
:param config: Config to pass to the bot
|
:param config: Config to pass to the bot
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
mocker.patch('freqtrade.fiat_convert.Market', {'price_usd': 12345.0})
|
# mocker.patch('freqtrade.fiat_convert.Market', {'price_usd': 12345.0})
|
||||||
|
patch_coinmarketcap(mocker, {'price_usd': 12345.0})
|
||||||
mocker.patch('freqtrade.freqtradebot.Analyze', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.Analyze', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
@ -46,6 +48,27 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
|
|||||||
return FreqtradeBot(config, create_engine('sqlite://'))
|
return FreqtradeBot(config, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
|
||||||
|
def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> None:
|
||||||
|
"""
|
||||||
|
Mocker to coinmarketcap to speed up tests
|
||||||
|
:param mocker: mocker to patch coinmarketcap class
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
tickermock = MagicMock(return_value={'price_usd': 12345.0})
|
||||||
|
listmock = MagicMock(return_value={'data': [{'id': 1, 'name': 'Bitcoin', 'symbol': 'BTC',
|
||||||
|
'website_slug': 'bitcoin'},
|
||||||
|
{'id': 1027, 'name': 'Ethereum', 'symbol': 'ETH',
|
||||||
|
'website_slug': 'ethereum'}
|
||||||
|
]})
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.fiat_convert.Market',
|
||||||
|
ticker=tickermock,
|
||||||
|
listings=listmock,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def default_conf():
|
def default_conf():
|
||||||
""" Returns validated configuration suitable for most tests """
|
""" Returns validated configuration suitable for most tests """
|
||||||
|
@ -7,6 +7,7 @@ from unittest.mock import MagicMock
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter
|
from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter
|
||||||
|
from freqtrade.tests.conftest import patch_coinmarketcap
|
||||||
|
|
||||||
|
|
||||||
def test_pair_convertion_object():
|
def test_pair_convertion_object():
|
||||||
@ -123,12 +124,23 @@ def test_fiat_convert_get_price(mocker):
|
|||||||
assert fiat_convert._pairs[0]._expiration is not expiration
|
assert fiat_convert._pairs[0]._expiration is not expiration
|
||||||
|
|
||||||
|
|
||||||
|
def test_loadcryptomap(mocker):
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
|
||||||
|
fiat_convert = CryptoToFiatConverter()
|
||||||
|
assert len(fiat_convert._cryptomap) == 2
|
||||||
|
|
||||||
|
assert fiat_convert._cryptomap["BTC"] == "1"
|
||||||
|
|
||||||
|
|
||||||
def test_fiat_convert_without_network():
|
def test_fiat_convert_without_network():
|
||||||
# Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap
|
# Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap
|
||||||
|
|
||||||
fiat_convert = CryptoToFiatConverter()
|
fiat_convert = CryptoToFiatConverter()
|
||||||
|
|
||||||
|
cmc_temp = CryptoToFiatConverter._coinmarketcap
|
||||||
CryptoToFiatConverter._coinmarketcap = None
|
CryptoToFiatConverter._coinmarketcap = None
|
||||||
|
|
||||||
assert fiat_convert._coinmarketcap is None
|
assert fiat_convert._coinmarketcap is None
|
||||||
assert fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='USD') == 0.0
|
assert fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='USD') == 0.0
|
||||||
|
CryptoToFiatConverter._coinmarketcap = cmc_temp
|
||||||
|
@ -8,7 +8,6 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import Dict, Optional
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
@ -20,7 +19,7 @@ from freqtrade import DependencyException, OperationalException, TemporaryError
|
|||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
from freqtrade.tests.conftest import log_has
|
from freqtrade.tests.conftest import log_has, patch_coinmarketcap
|
||||||
|
|
||||||
|
|
||||||
# Functions for recurrent object patching
|
# Functions for recurrent object patching
|
||||||
@ -64,20 +63,6 @@ def patch_RPCManager(mocker) -> MagicMock:
|
|||||||
return rpc_mock
|
return rpc_mock
|
||||||
|
|
||||||
|
|
||||||
def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> None:
|
|
||||||
"""
|
|
||||||
Mocker to coinmarketcap to speed up tests
|
|
||||||
:param mocker: mocker to patch coinmarketcap class
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
mock = MagicMock()
|
|
||||||
|
|
||||||
if value:
|
|
||||||
mock.ticker = {'price_usd': 12345.0}
|
|
||||||
|
|
||||||
mocker.patch('freqtrade.fiat_convert.Market', mock)
|
|
||||||
|
|
||||||
|
|
||||||
# Unit tests
|
# Unit tests
|
||||||
def test_freqtradebot_object() -> None:
|
def test_freqtradebot_object() -> None:
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user