mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-15 20:53:58 +00:00
Merge branch 'freqtrade:develop' into develop
This commit is contained in:
commit
2a82e00857
|
@ -568,7 +568,14 @@ The possible values are: `GTC` (default), `FOK` or `IOC`.
|
|||
This is ongoing work. For now, it is supported only for binance, gate and kucoin.
|
||||
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
||||
|
||||
### What values can be used for fiat_display_currency?
|
||||
### Fiat conversion
|
||||
|
||||
Freqtrade uses the Coingecko API to convert the coin value to it's corresponding fiat value for the Telegram reports.
|
||||
The FIAT currency can be set in the configuration file as `fiat_display_currency`.
|
||||
|
||||
Removing `fiat_display_currency` completely from the configuration will skip initializing coingecko, and will not show any FIAT currency conversion. This has no importance for the correct functioning of the bot.
|
||||
|
||||
#### What values can be used for fiat_display_currency?
|
||||
|
||||
The `fiat_display_currency` configuration parameter sets the base currency to use for the
|
||||
conversion from coin to fiat in the bot Telegram reports.
|
||||
|
@ -587,7 +594,25 @@ The valid values are:
|
|||
"BTC", "ETH", "XRP", "LTC", "BCH", "BNB"
|
||||
```
|
||||
|
||||
Removing `fiat_display_currency` completely from the configuration will skip initializing coingecko, and will not show any FIAT currency conversion. This has no importance for the correct functioning of the bot.
|
||||
#### Coingecko Rate limit problems
|
||||
|
||||
On some IP ranges, coingecko is heavily rate-limiting.
|
||||
In such cases, you may want to add your coingecko API key to the configuration.
|
||||
|
||||
``` json
|
||||
{
|
||||
"fiat_display_currency": "USD",
|
||||
"coingecko": {
|
||||
"api_key": "your-api",
|
||||
"is_demo": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Freqtrade supports both Demo and Pro coingecko API keys.
|
||||
|
||||
The Coingecko API key is NOT required for the bot to function correctly.
|
||||
It is only used for the conversion of coin to fiat in the Telegram reports, which usually also work without API key.
|
||||
|
||||
## Using Dry-run mode
|
||||
|
||||
|
|
|
@ -100,7 +100,10 @@ def ask_user_config() -> Dict[str, Any]:
|
|||
{
|
||||
"type": "text",
|
||||
"name": "fiat_display_currency",
|
||||
"message": "Please insert your display Currency (for reporting):",
|
||||
"message": (
|
||||
"Please insert your display Currency for reporting "
|
||||
"(leave empty to disable FIAT conversion):"
|
||||
),
|
||||
"default": "USD",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -156,6 +156,7 @@ SUPPORTED_FIAT = [
|
|||
"LTC",
|
||||
"BCH",
|
||||
"BNB",
|
||||
"", # Allow empty field in config.
|
||||
]
|
||||
|
||||
MINIMAL_CONFIG = {
|
||||
|
@ -322,6 +323,14 @@ CONF_SCHEMA = {
|
|||
},
|
||||
"required": REQUIRED_ORDERTIF,
|
||||
},
|
||||
"coingecko": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"is_demo": {"type": "boolean", "default": True},
|
||||
"api_key": {"type": "string"},
|
||||
},
|
||||
"required": ["is_demo", "api_key"],
|
||||
},
|
||||
"exchange": {"$ref": "#/definitions/exchange"},
|
||||
"edge": {"$ref": "#/definitions/edge"},
|
||||
"freqai": {"$ref": "#/definitions/freqai"},
|
||||
|
|
|
@ -24569,6 +24569,120 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"NOT/USDT:USDT": [
|
||||
{
|
||||
"tier": 1.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 0.0,
|
||||
"maxNotional": 5000.0,
|
||||
"maintenanceMarginRate": 0.015,
|
||||
"maxLeverage": 50.0,
|
||||
"info": {
|
||||
"bracket": "1",
|
||||
"initialLeverage": "50",
|
||||
"notionalCap": "5000",
|
||||
"notionalFloor": "0",
|
||||
"maintMarginRatio": "0.015",
|
||||
"cum": "0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 2.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 5000.0,
|
||||
"maxNotional": 25000.0,
|
||||
"maintenanceMarginRate": 0.025,
|
||||
"maxLeverage": 20.0,
|
||||
"info": {
|
||||
"bracket": "2",
|
||||
"initialLeverage": "20",
|
||||
"notionalCap": "25000",
|
||||
"notionalFloor": "5000",
|
||||
"maintMarginRatio": "0.025",
|
||||
"cum": "50.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 3.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 25000.0,
|
||||
"maxNotional": 100000.0,
|
||||
"maintenanceMarginRate": 0.05,
|
||||
"maxLeverage": 10.0,
|
||||
"info": {
|
||||
"bracket": "3",
|
||||
"initialLeverage": "10",
|
||||
"notionalCap": "100000",
|
||||
"notionalFloor": "25000",
|
||||
"maintMarginRatio": "0.05",
|
||||
"cum": "675.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 4.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 100000.0,
|
||||
"maxNotional": 200000.0,
|
||||
"maintenanceMarginRate": 0.1,
|
||||
"maxLeverage": 5.0,
|
||||
"info": {
|
||||
"bracket": "4",
|
||||
"initialLeverage": "5",
|
||||
"notionalCap": "200000",
|
||||
"notionalFloor": "100000",
|
||||
"maintMarginRatio": "0.1",
|
||||
"cum": "5675.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 5.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 200000.0,
|
||||
"maxNotional": 500000.0,
|
||||
"maintenanceMarginRate": 0.125,
|
||||
"maxLeverage": 4.0,
|
||||
"info": {
|
||||
"bracket": "5",
|
||||
"initialLeverage": "4",
|
||||
"notionalCap": "500000",
|
||||
"notionalFloor": "200000",
|
||||
"maintMarginRatio": "0.125",
|
||||
"cum": "10675.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 6.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 500000.0,
|
||||
"maxNotional": 1000000.0,
|
||||
"maintenanceMarginRate": 0.25,
|
||||
"maxLeverage": 2.0,
|
||||
"info": {
|
||||
"bracket": "6",
|
||||
"initialLeverage": "2",
|
||||
"notionalCap": "1000000",
|
||||
"notionalFloor": "500000",
|
||||
"maintMarginRatio": "0.25",
|
||||
"cum": "73175.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tier": 7.0,
|
||||
"currency": "USDT",
|
||||
"minNotional": 1000000.0,
|
||||
"maxNotional": 2000000.0,
|
||||
"maintenanceMarginRate": 0.5,
|
||||
"maxLeverage": 1.0,
|
||||
"info": {
|
||||
"bracket": "7",
|
||||
"initialLeverage": "1",
|
||||
"notionalCap": "2000000",
|
||||
"notionalFloor": "1000000",
|
||||
"maintMarginRatio": "0.5",
|
||||
"cum": "323175.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"NTRN/USDT:USDT": [
|
||||
{
|
||||
"tier": 1.0,
|
||||
|
|
|
@ -8,12 +8,12 @@ import logging
|
|||
from typing import Any, Dict, List
|
||||
|
||||
from cachetools import TTLCache
|
||||
from pycoingecko import CoinGeckoAPI
|
||||
|
||||
from freqtrade.constants import Config
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange.types import Tickers
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter
|
||||
from freqtrade.util.coin_gecko import FtCoinGeckoApi
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -44,7 +44,13 @@ class MarketCapPairList(IPairList):
|
|||
self._refresh_period = self._pairlistconfig.get("refresh_period", 86400)
|
||||
self._marketcap_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period)
|
||||
self._def_candletype = self._config["candle_type_def"]
|
||||
self._coingecko: CoinGeckoAPI = CoinGeckoAPI()
|
||||
|
||||
_coingecko_config = config.get("coingecko", {})
|
||||
|
||||
self._coingecko: FtCoinGeckoApi = FtCoinGeckoApi(
|
||||
api_key=_coingecko_config.get("api_key", ""),
|
||||
is_demo=_coingecko_config.get("is_demo", True),
|
||||
)
|
||||
|
||||
if self._max_rank > 250:
|
||||
raise OperationalException("This filter only support marketcap rank up to 250.")
|
||||
|
|
|
@ -5,14 +5,14 @@ e.g BTC to USD
|
|||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict, List
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from cachetools import TTLCache
|
||||
from pycoingecko import CoinGeckoAPI
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from freqtrade.constants import SUPPORTED_FIAT
|
||||
from freqtrade.constants import SUPPORTED_FIAT, Config
|
||||
from freqtrade.mixins.logging_mixin import LoggingMixin
|
||||
from freqtrade.util.coin_gecko import FtCoinGeckoApi
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -40,28 +40,28 @@ class CryptoToFiatConverter(LoggingMixin):
|
|||
"""
|
||||
|
||||
__instance = None
|
||||
_coingecko: CoinGeckoAPI = None
|
||||
|
||||
_coinlistings: List[Dict] = []
|
||||
_backoff: float = 0.0
|
||||
|
||||
def __new__(cls):
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
|
||||
"""
|
||||
This class is a singleton - cannot be instantiated twice.
|
||||
Singleton pattern to ensure only one instance is created.
|
||||
"""
|
||||
if CryptoToFiatConverter.__instance is None:
|
||||
CryptoToFiatConverter.__instance = object.__new__(cls)
|
||||
try:
|
||||
# Limit retires to 1 (0 and 1)
|
||||
# otherwise we risk bot impact if coingecko is down.
|
||||
CryptoToFiatConverter._coingecko = CoinGeckoAPI(retries=1)
|
||||
except BaseException:
|
||||
CryptoToFiatConverter._coingecko = None
|
||||
return CryptoToFiatConverter.__instance
|
||||
if not cls.__instance:
|
||||
cls.__instance = super().__new__(cls)
|
||||
return cls.__instance
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, config: Config) -> None:
|
||||
# Timeout: 6h
|
||||
self._pair_price: TTLCache = TTLCache(maxsize=500, ttl=6 * 60 * 60)
|
||||
|
||||
_coingecko_config = config.get("coingecko", {})
|
||||
self._coingecko = FtCoinGeckoApi(
|
||||
api_key=_coingecko_config.get("api_key", ""),
|
||||
is_demo=_coingecko_config.get("is_demo", True),
|
||||
retries=1,
|
||||
)
|
||||
LoggingMixin.__init__(self, logger, 3600)
|
||||
self._load_cryptomap()
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class RPC:
|
|||
self._freqtrade = freqtrade
|
||||
self._config: Config = freqtrade.config
|
||||
if self._config.get("fiat_display_currency"):
|
||||
self._fiat_converter = CryptoToFiatConverter()
|
||||
self._fiat_converter = CryptoToFiatConverter(self._config)
|
||||
|
||||
@staticmethod
|
||||
def _rpc_show_config(
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"stake_currency": "{{ stake_currency }}",
|
||||
"stake_amount": {{ stake_amount }},
|
||||
"tradable_balance_ratio": 0.99,
|
||||
"fiat_display_currency": "{{ fiat_display_currency }}",{{ ('\n "timeframe": "' + timeframe + '",') if timeframe else '' }}
|
||||
{{- ('\n "fiat_display_currency": "' + fiat_display_currency + '",') if fiat_display_currency else ''}}
|
||||
{{- ('\n "timeframe": "' + timeframe + '",') if timeframe else '' }}
|
||||
"dry_run": {{ dry_run | lower }},
|
||||
"dry_run_wallet": 1000,
|
||||
"cancel_open_orders_on_exit": false,
|
||||
|
|
26
freqtrade/util/coin_gecko.py
Normal file
26
freqtrade/util/coin_gecko.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from pycoingecko import CoinGeckoAPI
|
||||
|
||||
|
||||
class FtCoinGeckoApi(CoinGeckoAPI):
|
||||
"""
|
||||
Simple wrapper around pycoingecko's api to support Demo API keys.
|
||||
|
||||
"""
|
||||
|
||||
__API_URL_BASE = "https://api.coingecko.com/api/v3/"
|
||||
__PRO_API_URL_BASE = "https://pro-api.coingecko.com/api/v3/"
|
||||
_api_key: str = ""
|
||||
|
||||
def __init__(self, api_key: str = "", *, is_demo=True, retries=5):
|
||||
super().__init__(retries=retries)
|
||||
# Doint' pass api_key to parent, instead set the header on the session directly
|
||||
self._api_key = api_key
|
||||
|
||||
if api_key and not is_demo:
|
||||
self.api_base_url = self.__PRO_API_URL_BASE
|
||||
self.session.params.update({"x_cg_pro_api_key": api_key})
|
||||
else:
|
||||
# Use demo api key
|
||||
self.api_base_url = self.__API_URL_BASE
|
||||
if api_key:
|
||||
self.session.params.update({"x_cg_demo_api_key": api_key})
|
|
@ -1,3 +1,3 @@
|
|||
# Requirements for freqtrade client library
|
||||
requests==2.31.0
|
||||
requests==2.32.2
|
||||
python-rapidjson==1.17
|
||||
|
|
|
@ -11,7 +11,7 @@ python-telegram-bot==21.1.1
|
|||
httpx>=0.24.1
|
||||
humanize==4.9.0
|
||||
cachetools==5.3.3
|
||||
requests==2.31.0
|
||||
requests==2.32.2
|
||||
urllib3==2.2.1
|
||||
jsonschema==4.22.0
|
||||
TA-Lib==0.4.28
|
||||
|
|
|
@ -539,7 +539,7 @@ def patch_coingecko(mocker) -> None:
|
|||
]
|
||||
)
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_price=tickermock,
|
||||
get_coins_list=listmock,
|
||||
)
|
||||
|
|
|
@ -2306,7 +2306,7 @@ def test_MarketCapPairList_filter(
|
|||
)
|
||||
|
||||
mocker.patch(
|
||||
"freqtrade.plugins.pairlist.MarketCapPairList.CoinGeckoAPI.get_coins_markets",
|
||||
"freqtrade.plugins.pairlist.MarketCapPairList.FtCoinGeckoApi.get_coins_markets",
|
||||
return_value=test_value,
|
||||
)
|
||||
|
||||
|
@ -2344,7 +2344,7 @@ def test_MarketCapPairList_timing(mocker, default_conf_usdt, markets, time_machi
|
|||
)
|
||||
|
||||
mocker.patch(
|
||||
"freqtrade.plugins.pairlist.MarketCapPairList.CoinGeckoAPI.get_coins_markets",
|
||||
"freqtrade.plugins.pairlist.MarketCapPairList.FtCoinGeckoApi.get_coins_markets",
|
||||
return_value=test_value,
|
||||
)
|
||||
|
||||
|
|
|
@ -8,11 +8,20 @@ import pytest
|
|||
from requests.exceptions import RequestException
|
||||
|
||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||
from freqtrade.util.coin_gecko import FtCoinGeckoApi
|
||||
from tests.conftest import log_has, log_has_re
|
||||
|
||||
|
||||
def test_fiat_convert_is_supported(mocker):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
def test_fiat_convert_is_singleton():
|
||||
fiat_convert = CryptoToFiatConverter({"a": 22})
|
||||
fiat_convert2 = CryptoToFiatConverter({})
|
||||
|
||||
assert fiat_convert is fiat_convert2
|
||||
assert id(fiat_convert) == id(fiat_convert2)
|
||||
|
||||
|
||||
def test_fiat_convert_is_supported():
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
assert fiat_convert._is_supported_fiat(fiat="USD") is True
|
||||
assert fiat_convert._is_supported_fiat(fiat="usd") is True
|
||||
assert fiat_convert._is_supported_fiat(fiat="abc") is False
|
||||
|
@ -20,7 +29,7 @@ def test_fiat_convert_is_supported(mocker):
|
|||
|
||||
|
||||
def test_fiat_convert_find_price(mocker):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
|
||||
fiat_convert._coinlistings = {}
|
||||
fiat_convert._backoff = 0
|
||||
|
@ -48,7 +57,7 @@ def test_fiat_convert_find_price(mocker):
|
|||
|
||||
def test_fiat_convert_unsupported_crypto(mocker, caplog):
|
||||
mocker.patch("freqtrade.rpc.fiat_convert.CryptoToFiatConverter._coinlistings", return_value=[])
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
assert fiat_convert._find_price(crypto_symbol="CRYPTO_123", fiat_symbol="EUR") == 0.0
|
||||
assert log_has("unsupported crypto-symbol CRYPTO_123 - returning 0.0", caplog)
|
||||
|
||||
|
@ -58,7 +67,7 @@ def test_fiat_convert_get_price(mocker):
|
|||
"freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price", return_value=28000.0
|
||||
)
|
||||
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
|
||||
with pytest.raises(ValueError, match=r"The fiat us dollar is not supported."):
|
||||
fiat_convert.get_price(crypto_symbol="btc", fiat_symbol="US Dollar")
|
||||
|
@ -77,20 +86,20 @@ def test_fiat_convert_get_price(mocker):
|
|||
assert find_price.call_count == 1
|
||||
|
||||
|
||||
def test_fiat_convert_same_currencies(mocker):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
def test_fiat_convert_same_currencies():
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
|
||||
assert fiat_convert.get_price(crypto_symbol="USD", fiat_symbol="USD") == 1.0
|
||||
|
||||
|
||||
def test_fiat_convert_two_FIAT(mocker):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
def test_fiat_convert_two_FIAT():
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
|
||||
assert fiat_convert.get_price(crypto_symbol="USD", fiat_symbol="EUR") == 0.0
|
||||
|
||||
|
||||
def test_loadcryptomap(mocker):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
def test_loadcryptomap():
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
assert len(fiat_convert._coinlistings) == 2
|
||||
|
||||
assert fiat_convert._get_gecko_id("btc") == "bitcoin"
|
||||
|
@ -100,28 +109,28 @@ def test_fiat_init_network_exception(mocker):
|
|||
# Because CryptoToFiatConverter is a Singleton we reset the listings
|
||||
listmock = MagicMock(side_effect=RequestException)
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_coins_list=listmock,
|
||||
)
|
||||
# with pytest.raises(RequestEsxception):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
fiat_convert._coinlistings = {}
|
||||
fiat_convert._load_cryptomap()
|
||||
|
||||
assert len(fiat_convert._coinlistings) == 0
|
||||
|
||||
|
||||
def test_fiat_convert_without_network(mocker):
|
||||
def test_fiat_convert_without_network():
|
||||
# Because CryptoToFiatConverter is a Singleton we reset the value of _coingecko
|
||||
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
|
||||
cmc_temp = CryptoToFiatConverter._coingecko
|
||||
CryptoToFiatConverter._coingecko = None
|
||||
cmc_temp = fiat_convert._coingecko
|
||||
fiat_convert._coingecko = None
|
||||
|
||||
assert fiat_convert._coingecko is None
|
||||
assert fiat_convert._find_price(crypto_symbol="btc", fiat_symbol="usd") == 0.0
|
||||
CryptoToFiatConverter._coingecko = cmc_temp
|
||||
fiat_convert._coingecko = cmc_temp
|
||||
|
||||
|
||||
def test_fiat_too_many_requests_response(mocker, caplog):
|
||||
|
@ -129,11 +138,11 @@ def test_fiat_too_many_requests_response(mocker, caplog):
|
|||
req_exception = "429 Too Many Requests"
|
||||
listmock = MagicMock(return_value="{}", side_effect=RequestException(req_exception))
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_coins_list=listmock,
|
||||
)
|
||||
# with pytest.raises(RequestEsxception):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
fiat_convert._coinlistings = {}
|
||||
fiat_convert._load_cryptomap()
|
||||
|
||||
|
@ -144,8 +153,8 @@ def test_fiat_too_many_requests_response(mocker, caplog):
|
|||
)
|
||||
|
||||
|
||||
def test_fiat_multiple_coins(mocker, caplog):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
def test_fiat_multiple_coins(caplog):
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
fiat_convert._coinlistings = [
|
||||
{"id": "helium", "symbol": "hnt", "name": "Helium"},
|
||||
{"id": "hymnode", "symbol": "hnt", "name": "Hymnode"},
|
||||
|
@ -165,11 +174,11 @@ def test_fiat_invalid_response(mocker, caplog):
|
|||
# Because CryptoToFiatConverter is a Singleton we reset the listings
|
||||
listmock = MagicMock(return_value=None)
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_coins_list=listmock,
|
||||
)
|
||||
# with pytest.raises(RequestEsxception):
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
fiat_convert._coinlistings = []
|
||||
fiat_convert._load_cryptomap()
|
||||
|
||||
|
@ -182,7 +191,7 @@ def test_fiat_invalid_response(mocker, caplog):
|
|||
def test_convert_amount(mocker):
|
||||
mocker.patch("freqtrade.rpc.fiat_convert.CryptoToFiatConverter.get_price", return_value=12345.0)
|
||||
|
||||
fiat_convert = CryptoToFiatConverter()
|
||||
fiat_convert = CryptoToFiatConverter({})
|
||||
result = fiat_convert.convert_amount(crypto_amount=1.23, crypto_symbol="BTC", fiat_symbol="USD")
|
||||
assert result == 15184.35
|
||||
|
||||
|
@ -193,3 +202,18 @@ def test_convert_amount(mocker):
|
|||
crypto_amount="1.23", crypto_symbol="BTC", fiat_symbol="BTC"
|
||||
)
|
||||
assert result == 1.23
|
||||
|
||||
|
||||
def test_FtCoinGeckoApi():
|
||||
ftc = FtCoinGeckoApi()
|
||||
assert ftc._api_key == ""
|
||||
assert ftc.api_base_url == "https://api.coingecko.com/api/v3/"
|
||||
|
||||
# defaults to demo
|
||||
ftc = FtCoinGeckoApi(api_key="123456")
|
||||
assert ftc._api_key == "123456"
|
||||
assert ftc.api_base_url == "https://api.coingecko.com/api/v3/"
|
||||
|
||||
ftc = FtCoinGeckoApi(api_key="123456", is_demo=False)
|
||||
assert ftc._api_key == "123456"
|
||||
assert ftc.api_base_url == "https://pro-api.coingecko.com/api/v3/"
|
||||
|
|
|
@ -225,7 +225,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
|||
|
||||
def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_price=MagicMock(return_value={"bitcoin": {"usd": 15000.0}}),
|
||||
)
|
||||
mocker.patch("freqtrade.rpc.rpc.CryptoToFiatConverter._find_price", return_value=15000.0)
|
||||
|
@ -266,7 +266,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
|||
assert "-0.00" == f"{fiat_profit_sum:.2f}"
|
||||
|
||||
# Test with fiat convert
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf["stake_currency"], "USD")
|
||||
assert "Since" in headers
|
||||
assert "Pair" in headers
|
||||
|
@ -312,7 +312,7 @@ def test__rpc_timeunit_profit(
|
|||
fiat_display_currency = default_conf_usdt["fiat_display_currency"]
|
||||
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
|
||||
# Try valid data
|
||||
days = rpc._rpc_timeunit_profit(7, stake_currency, fiat_display_currency)
|
||||
|
@ -344,7 +344,7 @@ def test_rpc_trade_history(mocker, default_conf, markets, fee, is_short):
|
|||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
create_mock_trades(fee, is_short)
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
trades = rpc._rpc_trade_history(2)
|
||||
assert len(trades["trades"]) == 2
|
||||
assert trades["trades_count"] == 2
|
||||
|
@ -434,7 +434,7 @@ def test_rpc_trade_statistics(default_conf_usdt, ticker, fee, mocker) -> None:
|
|||
fiat_display_currency = default_conf_usdt["fiat_display_currency"]
|
||||
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
|
||||
res = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
|
||||
assert res["trade_count"] == 0
|
||||
|
@ -495,7 +495,7 @@ def test_rpc_balance_handle_error(default_conf, mocker):
|
|||
# ETH will be skipped due to mocked Error below
|
||||
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_price=MagicMock(return_value={"bitcoin": {"usd": 15000.0}}),
|
||||
)
|
||||
mocker.patch("freqtrade.rpc.rpc.CryptoToFiatConverter._find_price", return_value=15000.0)
|
||||
|
@ -509,7 +509,7 @@ def test_rpc_balance_handle_error(default_conf, mocker):
|
|||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
with pytest.raises(RPCException, match="Error getting current tickers."):
|
||||
rpc._rpc_balance(default_conf["stake_currency"], default_conf["fiat_display_currency"])
|
||||
|
||||
|
@ -558,7 +558,7 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers):
|
|||
]
|
||||
|
||||
mocker.patch.multiple(
|
||||
"freqtrade.rpc.fiat_convert.CoinGeckoAPI",
|
||||
"freqtrade.rpc.fiat_convert.FtCoinGeckoApi",
|
||||
get_price=MagicMock(return_value={"bitcoin": {"usd": 1.2}}),
|
||||
)
|
||||
mocker.patch("freqtrade.rpc.rpc.CryptoToFiatConverter._find_price", return_value=1.2)
|
||||
|
@ -578,7 +578,7 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers):
|
|||
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
patch_get_signal(freqtradebot)
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
rpc._fiat_converter = CryptoToFiatConverter({})
|
||||
|
||||
result = rpc._rpc_balance(
|
||||
default_conf_usdt["stake_currency"], default_conf_usdt["fiat_display_currency"]
|
||||
|
|
|
@ -2564,10 +2564,14 @@ def test_send_msg_buy_notification_no_fiat(
|
|||
("Short", "short_signal_01", 2.0),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("fiat", ["", None])
|
||||
def test_send_msg_exit_notification_no_fiat(
|
||||
default_conf, mocker, direction, enter_signal, leverage, time_machine
|
||||
default_conf, mocker, direction, enter_signal, leverage, time_machine, fiat
|
||||
) -> None:
|
||||
if fiat is None:
|
||||
del default_conf["fiat_display_currency"]
|
||||
else:
|
||||
default_conf["fiat_display_currency"] = fiat
|
||||
time_machine.move_to("2022-05-02 00:00:00 +00:00", tick=False)
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
|
|
|
@ -659,6 +659,16 @@ def test_validate_default_conf(default_conf) -> None:
|
|||
validate_config_schema(default_conf)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fiat", ["EUR", "USD", "", None])
|
||||
def test_validate_fiat_currency_options(default_conf, fiat) -> None:
|
||||
# Validate via our validator - we allow setting defaults!
|
||||
if fiat is not None:
|
||||
default_conf["fiat_display_currency"] = fiat
|
||||
else:
|
||||
del default_conf["fiat_display_currency"]
|
||||
validate_config_schema(default_conf)
|
||||
|
||||
|
||||
def test_validate_max_open_trades(default_conf):
|
||||
default_conf["max_open_trades"] = float("inf")
|
||||
default_conf["stake_amount"] = "unlimited"
|
||||
|
|
Loading…
Reference in New Issue
Block a user