Merge pull request #2417 from freqtrade/whitelist_docs

DynamicPairlist - pair_whitelist
This commit is contained in:
Matthias 2019-10-28 15:25:17 +01:00 committed by GitHub
commit b947f3c2a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 221 additions and 222 deletions

View File

@ -75,8 +75,8 @@ Mandatory parameters are marked as **Required**, which means that they are requi
| `exchange.key` | '' | API key to use for the exchange. Only required when you are in production mode. ***Keep it in secrete, do not disclose publicly.*** | `exchange.key` | '' | API key to use for the exchange. Only required when you are in production mode. ***Keep it in secrete, do not disclose publicly.***
| `exchange.secret` | '' | API secret to use for the exchange. Only required when you are in production mode. ***Keep it in secrete, do not disclose publicly.*** | `exchange.secret` | '' | API secret to use for the exchange. Only required when you are in production mode. ***Keep it in secrete, do not disclose publicly.***
| `exchange.password` | '' | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests. ***Keep it in secrete, do not disclose publicly.*** | `exchange.password` | '' | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests. ***Keep it in secrete, do not disclose publicly.***
| `exchange.pair_whitelist` | [] | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Can be overriden by dynamic pairlists (see [below](#dynamic-pairlists)). | `exchange.pair_whitelist` | [] | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Not used by VolumePairList (see [below](#dynamic-pairlists)).
| `exchange.pair_blacklist` | [] | List of pairs the bot must absolutely avoid for trading and backtesting. Can be overriden by dynamic pairlists (see [below](#dynamic-pairlists)). | `exchange.pair_blacklist` | [] | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#dynamic-pairlists)).
| `exchange.ccxt_config` | None | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) | `exchange.ccxt_config` | None | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
| `exchange.ccxt_async_config` | None | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) | `exchange.ccxt_async_config` | None | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
| `exchange.markets_refresh_interval` | 60 | The interval in minutes in which markets are reloaded. | `exchange.markets_refresh_interval` | 60 | The interval in minutes in which markets are reloaded.
@ -425,10 +425,16 @@ section of the configuration.
`askVolume`, `bidVolume` and `quoteVolume`, defaults to `quoteVolume`. `askVolume`, `bidVolume` and `quoteVolume`, defaults to `quoteVolume`.
* There is a possibility to filter low-value coins that would not allow setting a stop loss * There is a possibility to filter low-value coins that would not allow setting a stop loss
(set `precision_filter` parameter to `true` for this). (set `precision_filter` parameter to `true` for this).
* `VolumePairList` does not consider `pair_whitelist`, but builds this automatically based the pairlist configuration.
* Pairs in `pair_blacklist` are not considered for VolumePairList, even if all other filters would match.
Example: Example:
```json ```json
"exchange": {
"pair_whitelist": [],
"pair_blacklist": ["BNB/BTC"]
},
"pairlist": { "pairlist": {
"method": "VolumePairList", "method": "VolumePairList",
"config": { "config": {

View File

@ -5,7 +5,7 @@ from jsonschema import Draft4Validator, validators
from jsonschema.exceptions import ValidationError, best_match from jsonschema.exceptions import ValidationError, best_match
from freqtrade import constants, OperationalException from freqtrade import constants, OperationalException
from freqtrade.state import RunMode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -64,6 +64,7 @@ def validate_config_consistency(conf: Dict[str, Any]) -> None:
# validating trailing stoploss # validating trailing stoploss
_validate_trailing_stoploss(conf) _validate_trailing_stoploss(conf)
_validate_edge(conf) _validate_edge(conf)
_validate_whitelist(conf)
def _validate_trailing_stoploss(conf: Dict[str, Any]) -> None: def _validate_trailing_stoploss(conf: Dict[str, Any]) -> None:
@ -111,3 +112,15 @@ def _validate_edge(conf: Dict[str, Any]) -> None:
"Edge and VolumePairList are incompatible, " "Edge and VolumePairList are incompatible, "
"Edge will override whatever pairs VolumePairlist selects." "Edge will override whatever pairs VolumePairlist selects."
) )
def _validate_whitelist(conf: Dict[str, Any]) -> None:
"""
Dynamic whitelist does not require pair_whitelist to be set - however StaticWhitelist does.
"""
if conf.get('runmode', RunMode.OTHER) in [RunMode.OTHER, RunMode.PLOT]:
return
if (conf.get('pairlist', {}).get('method', 'StaticPairList') == 'StaticPairList'
and not conf.get('exchange', {}).get('pair_whitelist')):
raise OperationalException("StaticPairList requires pair_whitelist to be set.")

View File

@ -179,6 +179,9 @@ class Configuration:
config['exchange']['name'] = self.args["exchange"] config['exchange']['name'] = self.args["exchange"]
logger.info(f"Using exchange {config['exchange']['name']}") logger.info(f"Using exchange {config['exchange']['name']}")
if 'pair_whitelist' not in config['exchange']:
config['exchange']['pair_whitelist'] = []
if 'user_data_dir' in self.args and self.args["user_data_dir"]: if 'user_data_dir' in self.args and self.args["user_data_dir"]:
config.update({'user_data_dir': self.args["user_data_dir"]}) config.update({'user_data_dir': self.args["user_data_dir"]})
elif 'user_data_dir' not in config: elif 'user_data_dir' not in config:

View File

@ -235,7 +235,7 @@ CONF_SCHEMA = {
'ccxt_config': {'type': 'object'}, 'ccxt_config': {'type': 'object'},
'ccxt_async_config': {'type': 'object'} 'ccxt_async_config': {'type': 'object'}
}, },
'required': ['name', 'pair_whitelist'] 'required': ['name']
}, },
'edge': { 'edge': {
'type': 'object', 'type': 'object',

View File

@ -77,7 +77,7 @@ class FreqtradeBot:
self.edge = Edge(self.config, self.exchange, self.strategy) if \ self.edge = Edge(self.config, self.exchange, self.strategy) if \
self.config.get('edge', {}).get('enabled', False) else None self.config.get('edge', {}).get('enabled', False) else None
self.active_pair_whitelist: List[str] = self.config['exchange']['pair_whitelist'] self.active_pair_whitelist = self._refresh_whitelist()
persistence.init(self.config.get('db_url', None), persistence.init(self.config.get('db_url', None),
clean_open_orders=self.config.get('dry_run', False)) clean_open_orders=self.config.get('dry_run', False))
@ -123,21 +123,10 @@ class FreqtradeBot:
# Check whether markets have to be reloaded # Check whether markets have to be reloaded
self.exchange._reload_markets() self.exchange._reload_markets()
# Refresh whitelist
self.pairlists.refresh_pairlist()
self.active_pair_whitelist = self.pairlists.whitelist
# Calculating Edge positioning
if self.edge:
self.edge.calculate()
self.active_pair_whitelist = self.edge.adjust(self.active_pair_whitelist)
# Query trades from persistence layer # Query trades from persistence layer
trades = Trade.get_open_trades() trades = Trade.get_open_trades()
# Extend active-pair whitelist with pairs from open trades self.active_pair_whitelist = self._refresh_whitelist(trades)
# It ensures that tickers are downloaded for open trades
self._extend_whitelist_with_trades(self.active_pair_whitelist, trades)
# Refreshing candles # Refreshing candles
self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist), self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist),
@ -160,11 +149,24 @@ class FreqtradeBot:
logger.info(f"Bot heartbeat. PID={getpid()}") logger.info(f"Bot heartbeat. PID={getpid()}")
self._heartbeat_msg = arrow.utcnow().timestamp self._heartbeat_msg = arrow.utcnow().timestamp
def _extend_whitelist_with_trades(self, whitelist: List[str], trades: List[Any]): def _refresh_whitelist(self, trades: List[Trade] = []) -> List[str]:
""" """
Extend whitelist with pairs from open trades Refresh whitelist from pairlist or edge and extend it with trades.
""" """
whitelist.extend([trade.pair for trade in trades if trade.pair not in whitelist]) # Refresh whitelist
self.pairlists.refresh_pairlist()
_whitelist = self.pairlists.whitelist
# Calculating Edge positioning
if self.edge:
self.edge.calculate()
_whitelist = self.edge.adjust(_whitelist)
if trades:
# Extend active-pair whitelist with pairs from open trades
# It ensures that tickers are downloaded for open trades
_whitelist.extend([trade.pair for trade in trades if trade.pair not in _whitelist])
return _whitelist
def _create_pair_whitelist(self, pairs: List[str]) -> List[Tuple[str, str]]: def _create_pair_whitelist(self, pairs: List[str]) -> List[Tuple[str, str]]:
""" """

View File

@ -54,7 +54,7 @@ class VolumePairList(IPairList):
""" """
# Generate dynamic whitelist # Generate dynamic whitelist
self._whitelist = self._gen_pair_whitelist( self._whitelist = self._gen_pair_whitelist(
self._config['stake_currency'], self._sort_key)[:self._number_pairs] self._config['stake_currency'], self._sort_key)
@cached(TTLCache(maxsize=1, ttl=1800)) @cached(TTLCache(maxsize=1, ttl=1800))
def _gen_pair_whitelist(self, base_currency: str, key: str) -> List[str]: def _gen_pair_whitelist(self, base_currency: str, key: str) -> List[str]:
@ -91,6 +91,6 @@ class VolumePairList(IPairList):
valid_tickers.remove(t) valid_tickers.remove(t)
pairs = [s['symbol'] for s in valid_tickers] pairs = [s['symbol'] for s in valid_tickers]
logger.info(f"Searching pairs: {self._whitelist}") logger.info(f"Searching pairs: {pairs[:self._number_pairs]}")
return pairs return pairs

View File

@ -55,13 +55,16 @@ def patched_configuration_load_config_file(mocker, config) -> None:
) )
def patch_exchange(mocker, api_mock=None, id='bittrex') -> None: def patch_exchange(mocker, api_mock=None, id='bittrex', mock_markets=True) -> None:
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id)) mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id))
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value=id.title())) mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value=id.title()))
if mock_markets:
mocker.patch('freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=get_markets()))
if api_mock: if api_mock:
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
@ -69,8 +72,9 @@ def patch_exchange(mocker, api_mock=None, id='bittrex') -> None:
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock()) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock())
def get_patched_exchange(mocker, config, api_mock=None, id='bittrex') -> Exchange: def get_patched_exchange(mocker, config, api_mock=None, id='bittrex',
patch_exchange(mocker, api_mock, id) mock_markets=True) -> Exchange:
patch_exchange(mocker, api_mock, id, mock_markets)
config["exchange"]["name"] = id config["exchange"]["name"] = id
try: try:
exchange = ExchangeResolver(id, config).exchange exchange = ExchangeResolver(id, config).exchange
@ -85,6 +89,11 @@ def patch_wallet(mocker, free=999.9) -> None:
)) ))
def patch_whitelist(mocker, conf) -> None:
mocker.patch('freqtrade.freqtradebot.FreqtradeBot._refresh_whitelist',
MagicMock(return_value=conf['exchange']['pair_whitelist']))
def patch_edge(mocker) -> None: def patch_edge(mocker) -> None:
# "ETH/BTC", # "ETH/BTC",
# "LTC/BTC", # "LTC/BTC",
@ -120,6 +129,7 @@ def patch_freqtradebot(mocker, config) -> None:
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch('freqtrade.freqtradebot.RPCManager._init', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager._init', MagicMock())
mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock())
patch_whitelist(mocker, config)
def get_patched_freqtradebot(mocker, config) -> FreqtradeBot: def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
@ -287,6 +297,10 @@ def ticker_sell_down():
@pytest.fixture @pytest.fixture
def markets(): def markets():
return get_markets()
def get_markets():
return { return {
'ETH/BTC': { 'ETH/BTC': {
'id': 'ethbtc', 'id': 'ethbtc',
@ -369,7 +383,7 @@ def markets():
'symbol': 'LTC/BTC', 'symbol': 'LTC/BTC',
'base': 'LTC', 'base': 'LTC',
'quote': 'BTC', 'quote': 'BTC',
'active': False, 'active': True,
'precision': { 'precision': {
'price': 8, 'price': 8,
'amount': 8, 'amount': 8,
@ -394,7 +408,7 @@ def markets():
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'base': 'XRP', 'base': 'XRP',
'quote': 'BTC', 'quote': 'BTC',
'active': False, 'active': True,
'precision': { 'precision': {
'price': 8, 'price': 8,
'amount': 8, 'amount': 8,
@ -419,7 +433,7 @@ def markets():
'symbol': 'NEO/BTC', 'symbol': 'NEO/BTC',
'base': 'NEO', 'base': 'NEO',
'quote': 'BTC', 'quote': 'BTC',
'active': False, 'active': True,
'precision': { 'precision': {
'price': 8, 'price': 8,
'amount': 8, 'amount': 8,
@ -444,7 +458,7 @@ def markets():
'symbol': 'BTT/BTC', 'symbol': 'BTT/BTC',
'base': 'BTT', 'base': 'BTT',
'quote': 'BTC', 'quote': 'BTC',
'active': True, 'active': False,
'precision': { 'precision': {
'base': 8, 'base': 8,
'quote': 8, 'quote': 8,
@ -494,7 +508,7 @@ def markets():
'symbol': 'LTC/USDT', 'symbol': 'LTC/USDT',
'base': 'LTC', 'base': 'LTC',
'quote': 'USDT', 'quote': 'USDT',
'active': True, 'active': False,
'precision': { 'precision': {
'amount': 8, 'amount': 8,
'price': 8 'price': 8

View File

@ -533,21 +533,22 @@ def test_refresh_backtest_ohlcv_data(mocker, default_conf, markets, caplog, test
def test_download_data_no_markets(mocker, default_conf, caplog, testdatadir): def test_download_data_no_markets(mocker, default_conf, caplog, testdatadir):
dl_mock = mocker.patch('freqtrade.data.history.download_pair_history', MagicMock()) dl_mock = mocker.patch('freqtrade.data.history.download_pair_history', MagicMock())
ex = get_patched_exchange(mocker, default_conf)
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}) 'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={})
) )
ex = get_patched_exchange(mocker, default_conf)
timerange = TimeRange.parse_timerange("20190101-20190102") timerange = TimeRange.parse_timerange("20190101-20190102")
unav_pairs = refresh_backtest_ohlcv_data(exchange=ex, pairs=["ETH/BTC", "XRP/BTC"], unav_pairs = refresh_backtest_ohlcv_data(exchange=ex, pairs=["BTT/BTC", "LTC/USDT"],
timeframes=["1m", "5m"], timeframes=["1m", "5m"],
dl_path=testdatadir, dl_path=testdatadir,
timerange=timerange, erase=False timerange=timerange, erase=False
) )
assert dl_mock.call_count == 0 assert dl_mock.call_count == 0
assert "ETH/BTC" in unav_pairs assert "BTT/BTC" in unav_pairs
assert "XRP/BTC" in unav_pairs assert "LTC/USDT" in unav_pairs
assert log_has("Skipping pair ETH/BTC...", caplog) assert log_has("Skipping pair BTT/BTC...", caplog)
def test_refresh_backtest_trades_data(mocker, default_conf, markets, caplog, testdatadir): def test_refresh_backtest_trades_data(mocker, default_conf, markets, caplog, testdatadir):

View File

@ -177,16 +177,11 @@ def test_symbol_amount_prec(default_conf, mocker):
''' '''
Test rounds down to 4 Decimal places Test rounds down to 4 Decimal places
''' '''
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
})
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='binance'))
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}}) markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}})
type(api_mock).markets = markets
exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange = get_patched_exchange(mocker, default_conf, id="binance")
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
amount = 2.34559 amount = 2.34559
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -198,16 +193,10 @@ def test_symbol_price_prec(default_conf, mocker):
''' '''
Test rounds up to 4 decimal places Test rounds up to 4 decimal places
''' '''
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
})
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='binance'))
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}}) markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}})
type(api_mock).markets = markets
exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange = get_patched_exchange(mocker, default_conf, id="binance")
mocker.patch('freqtrade.exchange.Exchange.markets', markets)
price = 2.34559 price = 2.34559
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -279,7 +268,7 @@ def test__load_markets(default_conf, mocker, caplog):
api_mock.load_markets = MagicMock(return_value=expected_return) api_mock.load_markets = MagicMock(return_value=expected_return)
type(api_mock).markets = expected_return type(api_mock).markets = expected_return
default_conf['exchange']['pair_whitelist'] = ['ETH/BTC'] default_conf['exchange']['pair_whitelist'] = ['ETH/BTC']
ex = get_patched_exchange(mocker, default_conf, api_mock, id="binance") ex = get_patched_exchange(mocker, default_conf, api_mock, id="binance", mock_markets=False)
assert ex.markets == expected_return assert ex.markets == expected_return
@ -294,7 +283,8 @@ def test__reload_markets(default_conf, mocker, caplog):
api_mock.load_markets = load_markets api_mock.load_markets = load_markets
type(api_mock).markets = initial_markets type(api_mock).markets = initial_markets
default_conf['exchange']['markets_refresh_interval'] = 10 default_conf['exchange']['markets_refresh_interval'] = 10
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance",
mock_markets=False)
exchange._last_markets_refresh = arrow.utcnow().timestamp exchange._last_markets_refresh = arrow.utcnow().timestamp
updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}} updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}}
@ -1715,15 +1705,16 @@ def test_get_valid_pair_combination(default_conf, mocker, markets):
'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# active markets # active markets
([], [], False, True, ([], [], False, True,
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/USD', 'LTC/USDT', ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC',
'TKN/BTC', 'XLTCUSDT']), 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# all pairs # all pairs
([], [], True, False, ([], [], True, False,
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD',
'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']), 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']),
# active pairs # active pairs
([], [], True, True, ([], [], True, True,
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/USD', 'LTC/USDT', 'TKN/BTC']), ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC',
'TKN/BTC', 'XRP/BTC']),
# all markets, base=ETH, LTC # all markets, base=ETH, LTC
(['ETH', 'LTC'], [], False, False, (['ETH', 'LTC'], [], False, False,
['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), ['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),

View File

@ -80,7 +80,7 @@ def test_refresh_pairlist_dynamic(mocker, markets, tickers, whitelist_conf):
freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
# argument: use the whitelist dynamically by exchange-volume # argument: use the whitelist dynamically by exchange-volume
whitelist = ['ETH/BTC', 'TKN/BTC', 'BTT/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC', 'LTC/BTC']
freqtradebot.pairlists.refresh_pairlist() freqtradebot.pairlists.refresh_pairlist()
assert whitelist == freqtradebot.pairlists.whitelist assert whitelist == freqtradebot.pairlists.whitelist
@ -108,12 +108,12 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
@pytest.mark.parametrize("precision_filter,base_currency,key,whitelist_result", [ @pytest.mark.parametrize("precision_filter,base_currency,key,whitelist_result", [
(False, "BTC", "quoteVolume", ['ETH/BTC', 'TKN/BTC', 'BTT/BTC']), (False, "BTC", "quoteVolume", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC']),
(False, "BTC", "bidVolume", ['BTT/BTC', 'TKN/BTC', 'ETH/BTC']), (False, "BTC", "bidVolume", ['LTC/BTC', 'TKN/BTC', 'ETH/BTC']),
(False, "USDT", "quoteVolume", ['ETH/USDT', 'LTC/USDT']), (False, "USDT", "quoteVolume", ['ETH/USDT']),
(False, "ETH", "quoteVolume", []), # this replaces tests that were removed from test_exchange (False, "ETH", "quoteVolume", []), # this replaces tests that were removed from test_exchange
(True, "BTC", "quoteVolume", ["ETH/BTC", "TKN/BTC"]), (True, "BTC", "quoteVolume", ["LTC/BTC", "ETH/BTC", "TKN/BTC"]),
(True, "BTC", "bidVolume", ["TKN/BTC", "ETH/BTC"]) (True, "BTC", "bidVolume", ["LTC/BTC", "TKN/BTC", "ETH/BTC"])
]) ])
def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers, base_currency, key, def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers, base_currency, key,
whitelist_result, precision_filter) -> None: whitelist_result, precision_filter) -> None:
@ -127,7 +127,7 @@ def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers,
freqtrade.pairlists._precision_filter = precision_filter freqtrade.pairlists._precision_filter = precision_filter
freqtrade.config['stake_currency'] = base_currency freqtrade.config['stake_currency'] = base_currency
whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency=base_currency, key=key) whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency=base_currency, key=key)
assert whitelist == whitelist_result assert sorted(whitelist) == sorted(whitelist_result)
def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None: def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None:
@ -160,7 +160,7 @@ def test_pairlist_class(mocker, whitelist_conf, markets, pairlist):
(['ETH/BTC', 'TKN/BTC', 'TRX/ETH'], "is not compatible with exchange"), # TRX/ETH wrong stake (['ETH/BTC', 'TKN/BTC', 'TRX/ETH'], "is not compatible with exchange"), # TRX/ETH wrong stake
(['ETH/BTC', 'TKN/BTC', 'BCH/BTC'], "is not compatible with exchange"), # BCH/BTC not available (['ETH/BTC', 'TKN/BTC', 'BCH/BTC'], "is not compatible with exchange"), # BCH/BTC not available
(['ETH/BTC', 'TKN/BTC', 'BLK/BTC'], "is not compatible with exchange"), # BLK/BTC in blacklist (['ETH/BTC', 'TKN/BTC', 'BLK/BTC'], "is not compatible with exchange"), # BLK/BTC in blacklist
(['ETH/BTC', 'TKN/BTC', 'LTC/BTC'], "Market is not active") # LTC/BTC is inactive (['ETH/BTC', 'TKN/BTC', 'BTT/BTC'], "Market is not active") # BTT/BTC is inactive
]) ])
def test_validate_whitelist(mocker, whitelist_conf, markets, pairlist, whitelist, caplog, def test_validate_whitelist(mocker, whitelist_conf, markets, pairlist, whitelist, caplog,
log_message): log_message):

View File

@ -9,12 +9,11 @@ from numpy import isnan
from freqtrade import DependencyException, TemporaryError from freqtrade import DependencyException, TemporaryError
from freqtrade.edge import PairInfo from freqtrade.edge import PairInfo
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPC, RPCException from freqtrade.rpc import RPC, RPCException
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
from freqtrade.state import State from freqtrade.state import State
from tests.conftest import patch_exchange, patch_get_signal from tests.conftest import patch_get_signal, get_patched_freqtradebot
# Functions for recurrent object patching # Functions for recurrent object patching
@ -26,17 +25,15 @@ def prec_satoshi(a, b) -> float:
# Unit tests # Unit tests
def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None: def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
@ -98,17 +95,15 @@ def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None:
} == results[0] } == results[0]
def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None: def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
@ -134,7 +129,6 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
def test_rpc_daily_profit(default_conf, update, ticker, fee, def test_rpc_daily_profit(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None: limit_buy_order, limit_sell_order, markets, mocker) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
@ -143,7 +137,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
markets=PropertyMock(return_value=markets) markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
stake_currency = default_conf['stake_currency'] stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency'] fiat_display_currency = default_conf['fiat_display_currency']
@ -181,22 +175,20 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None: limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.rpc.fiat_convert.Market', 'freqtrade.rpc.fiat_convert.Market',
ticker=MagicMock(return_value={'price_usd': 15000.0}), ticker=MagicMock(return_value={'price_usd': 15000.0}),
) )
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
stake_currency = default_conf['stake_currency'] stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency'] fiat_display_currency = default_conf['fiat_display_currency']
@ -267,9 +259,8 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
# Test that rpc_trade_statistics can handle trades that lacks # Test that rpc_trade_statistics can handle trades that lacks
# trade.open_rate (it is set to None) # trade.open_rate (it is set to None)
def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets, def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
ticker_sell_up, limit_buy_order, limit_sell_order): ticker_sell_up, limit_buy_order, limit_sell_order):
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.rpc.fiat_convert.Market', 'freqtrade.rpc.fiat_convert.Market',
ticker=MagicMock(return_value={'price_usd': 15000.0}), ticker=MagicMock(return_value={'price_usd': 15000.0}),
@ -281,10 +272,9 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
stake_currency = default_conf['stake_currency'] stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency'] fiat_display_currency = default_conf['fiat_display_currency']
@ -343,7 +333,6 @@ def test_rpc_balance_handle_error(default_conf, mocker):
'freqtrade.rpc.fiat_convert.Market', 'freqtrade.rpc.fiat_convert.Market',
ticker=MagicMock(return_value={'price_usd': 15000.0}), ticker=MagicMock(return_value={'price_usd': 15000.0}),
) )
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
@ -352,7 +341,7 @@ def test_rpc_balance_handle_error(default_conf, mocker):
get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx'))
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter() rpc._fiat_converter = CryptoToFiatConverter()
@ -394,7 +383,6 @@ def test_rpc_balance_handle(default_conf, mocker):
'freqtrade.rpc.fiat_convert.Market', 'freqtrade.rpc.fiat_convert.Market',
ticker=MagicMock(return_value={'price_usd': 15000.0}), ticker=MagicMock(return_value={'price_usd': 15000.0}),
) )
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
@ -406,7 +394,7 @@ def test_rpc_balance_handle(default_conf, mocker):
side_effect=lambda a, b: f"{b}/{a}" if a == "PAX" else f"{a}/{b}") side_effect=lambda a, b: f"{b}/{a}" if a == "PAX" else f"{a}/{b}")
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter() rpc._fiat_converter = CryptoToFiatConverter()
@ -438,14 +426,13 @@ def test_rpc_balance_handle(default_conf, mocker):
def test_rpc_start(mocker, default_conf) -> None: def test_rpc_start(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=MagicMock() get_ticker=MagicMock()
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
freqtradebot.state = State.STOPPED freqtradebot.state = State.STOPPED
@ -460,14 +447,13 @@ def test_rpc_start(mocker, default_conf) -> None:
def test_rpc_stop(mocker, default_conf) -> None: def test_rpc_stop(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=MagicMock() get_ticker=MagicMock()
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING freqtradebot.state = State.RUNNING
@ -483,14 +469,13 @@ def test_rpc_stop(mocker, default_conf) -> None:
def test_rpc_stopbuy(mocker, default_conf) -> None: def test_rpc_stopbuy(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=MagicMock() get_ticker=MagicMock()
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING freqtradebot.state = State.RUNNING
@ -501,8 +486,7 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
assert freqtradebot.config['max_open_trades'] == 0 assert freqtradebot.config['max_open_trades'] == 0
def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None: def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
@ -518,10 +502,9 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
} }
), ),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
@ -606,18 +589,16 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
def test_performance_handle(default_conf, ticker, limit_buy_order, fee, def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, markets, mocker) -> None: limit_sell_order, mocker) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
@ -641,18 +622,16 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
assert prec_satoshi(res[0]['profit'], 6.2) assert prec_satoshi(res[0]['profit'], 6.2)
def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None: def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
@ -665,9 +644,8 @@ def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None:
assert counts["current"] == 1 assert counts["current"] == 1
def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order) -> None: def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order) -> None:
default_conf['forcebuy_enable'] = True default_conf['forcebuy_enable'] = True
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
buy_mm = MagicMock(return_value={'id': limit_buy_order['id']}) buy_mm = MagicMock(return_value={'id': limit_buy_order['id']})
mocker.patch.multiple( mocker.patch.multiple(
@ -675,11 +653,10 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
buy=buy_mm buy=buy_mm
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -704,7 +681,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order
# Test not buying # Test not buying
default_conf['stake_amount'] = 0.0000001 default_conf['stake_amount'] = 0.0000001
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
pair = 'TKN/BTC' pair = 'TKN/BTC'
@ -715,10 +692,9 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order
def test_rpcforcebuy_stopped(mocker, default_conf) -> None: def test_rpcforcebuy_stopped(mocker, default_conf) -> None:
default_conf['forcebuy_enable'] = True default_conf['forcebuy_enable'] = True
default_conf['initial_state'] = 'stopped' default_conf['initial_state'] = 'stopped'
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -727,10 +703,9 @@ def test_rpcforcebuy_stopped(mocker, default_conf) -> None:
def test_rpcforcebuy_disabled(mocker, default_conf) -> None: def test_rpcforcebuy_disabled(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -739,10 +714,9 @@ def test_rpcforcebuy_disabled(mocker, default_conf) -> None:
def test_rpc_whitelist(mocker, default_conf) -> None: def test_rpc_whitelist(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
ret = rpc._rpc_whitelist() ret = rpc._rpc_whitelist()
assert ret['method'] == 'StaticPairList' assert ret['method'] == 'StaticPairList'
@ -750,14 +724,13 @@ def test_rpc_whitelist(mocker, default_conf) -> None:
def test_rpc_whitelist_dynamic(mocker, default_conf) -> None: def test_rpc_whitelist_dynamic(mocker, default_conf) -> None:
patch_exchange(mocker)
default_conf['pairlist'] = {'method': 'VolumePairList', default_conf['pairlist'] = {'method': 'VolumePairList',
'config': {'number_assets': 4} 'config': {'number_assets': 4}
} }
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
ret = rpc._rpc_whitelist() ret = rpc._rpc_whitelist()
assert ret['method'] == 'VolumePairList' assert ret['method'] == 'VolumePairList'
@ -766,10 +739,9 @@ def test_rpc_whitelist_dynamic(mocker, default_conf) -> None:
def test_rpc_blacklist(mocker, default_conf) -> None: def test_rpc_blacklist(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
ret = rpc._rpc_blacklist(None) ret = rpc._rpc_blacklist(None)
assert ret['method'] == 'StaticPairList' assert ret['method'] == 'StaticPairList'
@ -785,23 +757,21 @@ def test_rpc_blacklist(mocker, default_conf) -> None:
def test_rpc_edge_disabled(mocker, default_conf) -> None: def test_rpc_edge_disabled(mocker, default_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
with pytest.raises(RPCException, match=r'Edge is not enabled.'): with pytest.raises(RPCException, match=r'Edge is not enabled.'):
rpc._rpc_edge() rpc._rpc_edge()
def test_rpc_edge_enabled(mocker, edge_conf) -> None: def test_rpc_edge_enabled(mocker, edge_conf) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock(
return_value={ return_value={
'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60), 'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60),
} }
)) ))
freqtradebot = FreqtradeBot(edge_conf) freqtradebot = get_patched_freqtradebot(mocker, edge_conf)
rpc = RPC(freqtradebot) rpc = RPC(freqtradebot)
ret = rpc._rpc_edge() ret = rpc._rpc_edge()

View File

@ -22,7 +22,7 @@ from freqtrade.rpc.telegram import Telegram, authorized_only
from freqtrade.state import State from freqtrade.state import State
from freqtrade.strategy.interface import SellType from freqtrade.strategy.interface import SellType
from tests.conftest import (get_patched_freqtradebot, log_has, patch_exchange, from tests.conftest import (get_patched_freqtradebot, log_has, patch_exchange,
patch_get_signal) patch_get_signal, patch_whitelist)
class DummyCls(Telegram): class DummyCls(Telegram):
@ -143,17 +143,15 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
assert log_has('Exception occurred within Telegram module', caplog) assert log_has('Exception occurred within Telegram module', caplog)
def test_status(default_conf, update, mocker, fee, ticker, markets) -> None: def test_status(default_conf, update, mocker, fee, ticker,) -> None:
update.message.chat.id = 123 update.message.chat.id = 123
default_conf['telegram']['enabled'] = False default_conf['telegram']['enabled'] = False
default_conf['telegram']['chat_id'] = 123 default_conf['telegram']['chat_id'] = 123
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
status_table = MagicMock() status_table = MagicMock()
@ -184,9 +182,8 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
_status_table=status_table, _status_table=status_table,
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -204,13 +201,11 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
assert status_table.call_count == 1 assert status_table.call_count == 1
def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> None: def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
status_table = MagicMock() status_table = MagicMock()
@ -220,9 +215,9 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
_status_table=status_table, _status_table=status_table,
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -256,14 +251,12 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
assert 'ETH/BTC' in msg_mock.call_args_list[0][0][0] assert 'ETH/BTC' in msg_mock.call_args_list[0][0][0]
def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker) -> None: def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': 'mocked_order_id'}), buy=MagicMock(return_value={'id': 'mocked_order_id'}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -271,10 +264,9 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
_init=MagicMock(), _init=MagicMock(),
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
default_conf['stake_amount'] = 15.0 default_conf['stake_amount'] = 15.0
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -307,8 +299,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
limit_sell_order, markets, mocker) -> None: limit_sell_order, mocker) -> None:
patch_exchange(mocker)
default_conf['max_open_trades'] = 1 default_conf['max_open_trades'] = 1
mocker.patch( mocker.patch(
'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
@ -318,7 +309,6 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -326,9 +316,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
_init=MagicMock(), _init=MagicMock(),
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -382,7 +371,6 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker get_ticker=ticker
@ -393,9 +381,8 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
_init=MagicMock(), _init=MagicMock(),
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -420,14 +407,12 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None: limit_buy_order, limit_sell_order, mocker) -> None:
patch_exchange(mocker)
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -435,9 +420,8 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
_init=MagicMock(), _init=MagicMock(),
_send_msg=msg_mock _send_msg=msg_mock
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -724,16 +708,16 @@ def test_reload_conf_handle(default_conf, update, mocker) -> None:
def test_forcesell_handle(default_conf, update, ticker, fee, def test_forcesell_handle(default_conf, update, ticker, fee,
ticker_sell_up, markets, mocker) -> None: ticker_sell_up, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
patch_exchange(mocker) patch_exchange(mocker)
patch_whitelist(mocker, default_conf)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -775,17 +759,18 @@ def test_forcesell_handle(default_conf, update, ticker, fee,
def test_forcesell_down_handle(default_conf, update, ticker, fee, def test_forcesell_down_handle(default_conf, update, ticker, fee,
ticker_sell_down, markets, mocker) -> None: ticker_sell_down, mocker) -> None:
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
return_value=15000.0) return_value=15000.0)
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
patch_exchange(mocker) patch_exchange(mocker)
patch_whitelist(mocker, default_conf)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -830,17 +815,17 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee,
} == last_msg } == last_msg
def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker) -> None: def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None:
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
return_value=15000.0) return_value=15000.0)
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
patch_whitelist(mocker, default_conf)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
default_conf['max_open_trades'] = 4 default_conf['max_open_trades'] = 4
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -885,9 +870,8 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
_init=MagicMock(), _init=MagicMock(),
_send_msg=msg_mock _send_msg=msg_mock
) )
patch_exchange(mocker)
freqtradebot = FreqtradeBot(default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -980,8 +964,7 @@ def test_forcebuy_handle_exception(default_conf, update, markets, mocker) -> Non
def test_performance_handle(default_conf, update, ticker, fee, def test_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None: limit_buy_order, limit_sell_order, mocker) -> None:
patch_exchange(mocker)
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.rpc.telegram.Telegram', 'freqtrade.rpc.telegram.Telegram',
@ -992,10 +975,8 @@ def test_performance_handle(default_conf, update, ticker, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(markets),
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot = FreqtradeBot(default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)
@ -1018,8 +999,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0] assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0]
def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> None: def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
patch_exchange(mocker)
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.rpc.telegram.Telegram', 'freqtrade.rpc.telegram.Telegram',
@ -1030,10 +1010,9 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': 'mocked_order_id'}), buy=MagicMock(return_value={'id': 'mocked_order_id'}),
markets=PropertyMock(markets) get_fee=fee,
) )
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot = FreqtradeBot(default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot) telegram = Telegram(freqtradebot)

View File

@ -729,6 +729,30 @@ def test_validate_edge(edge_conf):
validate_config_consistency(edge_conf) validate_config_consistency(edge_conf)
def test_validate_whitelist(default_conf):
default_conf['runmode'] = RunMode.DRY_RUN
# Test regular case - has whitelist and uses StaticPairlist
validate_config_consistency(default_conf)
conf = deepcopy(default_conf)
del conf['exchange']['pair_whitelist']
# Test error case
with pytest.raises(OperationalException,
match="StaticPairList requires pair_whitelist to be set."):
validate_config_consistency(conf)
conf = deepcopy(default_conf)
conf.update({"pairlist": {
"method": "VolumePairList",
}})
# Dynamic whitelist should not care about pair_whitelist
validate_config_consistency(conf)
del conf['exchange']['pair_whitelist']
validate_config_consistency(conf)
def test_load_config_test_comments() -> None: def test_load_config_test_comments() -> None:
""" """
Load config with comments Load config with comments
@ -801,7 +825,7 @@ def test_pairlist_resolving():
args = Arguments(arglist).get_parsed_arg() args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args) configuration = Configuration(args, RunMode.OTHER)
config = configuration.get_config() config = configuration.get_config()
assert config['pairs'] == ['ETH/BTC', 'XRP/BTC'] assert config['pairs'] == ['ETH/BTC', 'XRP/BTC']
@ -895,7 +919,7 @@ def test_pairlist_resolving_fallback(mocker):
# Fix flaky tests if config.json exists # Fix flaky tests if config.json exists
args["config"] = None args["config"] = None
configuration = Configuration(args) configuration = Configuration(args, RunMode.OTHER)
config = configuration.get_config() config = configuration.get_config()
assert config['pairs'] == ['ETH/BTC', 'XRP/BTC'] assert config['pairs'] == ['ETH/BTC', 'XRP/BTC']

View File

@ -23,7 +23,7 @@ from freqtrade.strategy.interface import SellCheckTuple, SellType
from freqtrade.worker import Worker from freqtrade.worker import Worker
from tests.conftest import (get_patched_freqtradebot, get_patched_worker, from tests.conftest import (get_patched_freqtradebot, get_patched_worker,
log_has, log_has_re, patch_edge, patch_exchange, log_has, log_has_re, patch_edge, patch_exchange,
patch_get_signal, patch_wallet) patch_get_signal, patch_wallet, patch_whitelist)
def patch_RPCManager(mocker) -> MagicMock: def patch_RPCManager(mocker) -> MagicMock:
@ -1247,11 +1247,10 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog, def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
markets, limit_buy_order, limit_sell_order) -> None: limit_buy_order, limit_sell_order) -> None:
# When trailing stoploss is set # When trailing stoploss is set
stoploss_limit = MagicMock(return_value={'id': 13434334}) stoploss_limit = MagicMock(return_value={'id': 13434334})
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=MagicMock(return_value={ get_ticker=MagicMock(return_value={
@ -1262,7 +1261,6 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
@ -1272,7 +1270,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
# disabling ROI # disabling ROI
default_conf['minimal_roi']['0'] = 999999999 default_conf['minimal_roi']['0'] = 999999999
freqtrade = FreqtradeBot(default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
# enabling stoploss on exchange # enabling stoploss on exchange
freqtrade.strategy.order_types['stoploss_on_exchange'] = True freqtrade.strategy.order_types['stoploss_on_exchange'] = True
@ -1825,20 +1823,18 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
def test_handle_trade_roi(default_conf, ticker, limit_buy_order, def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
fee, mocker, markets, caplog) -> None: fee, mocker, caplog) -> None:
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtrade, value=(True, False)) patch_get_signal(freqtrade, value=(True, False))
freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
@ -1859,20 +1855,18 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
def test_handle_trade_use_sell_signal( def test_handle_trade_use_sell_signal(
default_conf, ticker, limit_buy_order, fee, mocker, markets, caplog) -> None: default_conf, ticker, limit_buy_order, fee, mocker, caplog) -> None:
# use_sell_signal is True buy default # use_sell_signal is True buy default
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trades() freqtrade.create_trades()
@ -2237,6 +2231,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets) markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2283,6 +2278,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets) markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2332,6 +2328,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets) markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2648,6 +2645,7 @@ def test_execute_sell_market_order(default_conf, ticker, fee,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets) markets=PropertyMock(return_value=markets)
) )
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2815,14 +2813,13 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, marke
assert trade.sell_reason == SellType.SELL_SIGNAL.value assert trade.sell_reason == SellType.SELL_SIGNAL.value
def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, markets, mocker, caplog) -> None: def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2852,7 +2849,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, markets, mock
assert log_has(f"Pair {trade.pair} is currently locked.", caplog) assert log_has(f"Pair {trade.pair} is currently locked.", caplog)
def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, mocker) -> None: def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2864,7 +2861,6 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets)
) )
default_conf['ask_strategy'] = { default_conf['ask_strategy'] = {
'ignore_roi_if_buy_signal': True 'ignore_roi_if_buy_signal': True
@ -2886,7 +2882,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m
assert trade.sell_reason == SellType.ROI.value assert trade.sell_reason == SellType.ROI.value
def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, mocker) -> None: def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -2898,9 +2894,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
@ -2938,7 +2934,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog,
assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value
def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets, def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee,
caplog, mocker) -> None: caplog, mocker) -> None:
buy_price = limit_buy_order['price'] buy_price = limit_buy_order['price']
patch_RPCManager(mocker) patch_RPCManager(mocker)
@ -2952,10 +2948,11 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0.01 default_conf['trailing_stop_positive'] = 0.01
patch_whitelist(mocker, default_conf)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
@ -2995,7 +2992,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets
def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
caplog, mocker, markets) -> None: caplog, mocker) -> None:
buy_price = limit_buy_order['price'] buy_price = limit_buy_order['price']
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -3008,9 +3005,8 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
patch_whitelist(mocker, default_conf)
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0.01 default_conf['trailing_stop_positive'] = 0.01
default_conf['trailing_stop_positive_offset'] = 0.011 default_conf['trailing_stop_positive_offset'] = 0.011
@ -3055,7 +3051,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee,
caplog, mocker, markets) -> None: caplog, mocker) -> None:
buy_price = limit_buy_order['price'] buy_price = limit_buy_order['price']
# buy_price: 0.00001099 # buy_price: 0.00001099
@ -3070,9 +3066,8 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
markets=PropertyMock(return_value=markets),
) )
patch_whitelist(mocker, default_conf)
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0.05 default_conf['trailing_stop_positive'] = 0.05
default_conf['trailing_stop_positive_offset'] = 0.055 default_conf['trailing_stop_positive_offset'] = 0.055

View File

@ -188,8 +188,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 8 active markets: " assert ("Exchange Bittrex has 9 active markets: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/USD, LTC/USDT, TKN/BTC, XLTCUSDT.\n" "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XLTCUSDT, XRP/BTC.\n"
in captured.out) in captured.out)
patch_exchange(mocker, api_mock=api_mock, id="binance") patch_exchange(mocker, api_mock=api_mock, id="binance")
@ -202,7 +202,7 @@ def test_list_markets(mocker, markets, capsys):
pargs['config'] = None pargs['config'] = None
start_list_markets(pargs, False) start_list_markets(pargs, False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert re.match("\nExchange Binance has 8 active markets:\n", assert re.match("\nExchange Binance has 9 active markets:\n",
captured.out) captured.out)
patch_exchange(mocker, api_mock=api_mock, id="bittrex") patch_exchange(mocker, api_mock=api_mock, id="bittrex")
@ -227,8 +227,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), True) start_list_markets(get_args(args), True)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 7 active pairs: " assert ("Exchange Bittrex has 8 active pairs: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/USD, LTC/USDT, TKN/BTC.\n" "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n"
in captured.out) in captured.out)
# Test list-pairs subcommand with --all: all pairs # Test list-pairs subcommand with --all: all pairs
@ -254,7 +254,7 @@ def test_list_markets(mocker, markets, capsys):
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 5 active markets with ETH, LTC as base currencies: " assert ("Exchange Bittrex has 5 active markets with ETH, LTC as base currencies: "
"ETH/BTC, ETH/USDT, LTC/USD, LTC/USDT, XLTCUSDT.\n" "ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, base=LTC # active markets, base=LTC
@ -267,7 +267,7 @@ def test_list_markets(mocker, markets, capsys):
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 3 active markets with LTC as base currency: " assert ("Exchange Bittrex has 3 active markets with LTC as base currency: "
"LTC/USD, LTC/USDT, XLTCUSDT.\n" "LTC/BTC, LTC/USD, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, quote=USDT, USD # active markets, quote=USDT, USD
@ -279,8 +279,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 4 active markets with USDT, USD as quote currencies: " assert ("Exchange Bittrex has 3 active markets with USDT, USD as quote currencies: "
"ETH/USDT, LTC/USD, LTC/USDT, XLTCUSDT.\n" "ETH/USDT, LTC/USD, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, quote=USDT # active markets, quote=USDT
@ -292,8 +292,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 3 active markets with USDT as quote currency: " assert ("Exchange Bittrex has 2 active markets with USDT as quote currency: "
"ETH/USDT, LTC/USDT, XLTCUSDT.\n" "ETH/USDT, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, base=LTC, quote=USDT # active markets, base=LTC, quote=USDT
@ -305,21 +305,21 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 2 active markets with LTC as base currency and " assert ("Exchange Bittrex has 1 active market with LTC as base currency and "
"with USDT as quote currency: LTC/USDT, XLTCUSDT.\n" "with USDT as quote currency: XLTCUSDT.\n"
in captured.out) in captured.out)
# active pairs, base=LTC, quote=USDT # active pairs, base=LTC, quote=USDT
args = [ args = [
'--config', 'config.json.example', '--config', 'config.json.example',
"list-pairs", "list-pairs",
"--base", "LTC", "--quote", "USDT", "--base", "LTC", "--quote", "USD",
"--print-list", "--print-list",
] ]
start_list_markets(get_args(args), True) start_list_markets(get_args(args), True)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 1 active pair with LTC as base currency and " assert ("Exchange Bittrex has 1 active pair with LTC as base currency and "
"with USDT as quote currency: LTC/USDT.\n" "with USD as quote currency: LTC/USD.\n"
in captured.out) in captured.out)
# active markets, base=LTC, quote=USDT, NONEXISTENT # active markets, base=LTC, quote=USDT, NONEXISTENT
@ -331,8 +331,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 2 active markets with LTC as base currency and " assert ("Exchange Bittrex has 1 active market with LTC as base currency and "
"with USDT, NONEXISTENT as quote currencies: LTC/USDT, XLTCUSDT.\n" "with USDT, NONEXISTENT as quote currencies: XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, base=LTC, quote=NONEXISTENT # active markets, base=LTC, quote=NONEXISTENT
@ -355,7 +355,7 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 8 active markets:\n" assert ("Exchange Bittrex has 9 active markets:\n"
in captured.out) in captured.out)
# Test tabular output, no markets found # Test tabular output, no markets found
@ -378,7 +378,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ('["BLK/BTC","BTT/BTC","ETH/BTC","ETH/USDT","LTC/USD","LTC/USDT","TKN/BTC","XLTCUSDT"]' assert ('["BLK/BTC","ETH/BTC","ETH/USDT","LTC/BTC","LTC/USD","NEO/BTC",'
'"TKN/BTC","XLTCUSDT","XRP/BTC"]'
in captured.out) in captured.out)
# Test --print-csv # Test --print-csv
@ -391,7 +392,7 @@ def test_list_markets(mocker, markets, capsys):
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Id,Symbol,Base,Quote,Active,Is pair" in captured.out) assert ("Id,Symbol,Base,Quote,Active,Is pair" in captured.out)
assert ("blkbtc,BLK/BTC,BLK,BTC,True,True" in captured.out) assert ("blkbtc,BLK/BTC,BLK,BTC,True,True" in captured.out)
assert ("BTTBTC,BTT/BTC,BTT,BTC,True,True" in captured.out) assert ("USD-LTC,LTC/USD,LTC,USD,True,True" in captured.out)
# Test --one-column # Test --one-column
args = [ args = [
@ -402,7 +403,7 @@ def test_list_markets(mocker, markets, capsys):
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert re.search(r"^BLK/BTC$", captured.out, re.MULTILINE) assert re.search(r"^BLK/BTC$", captured.out, re.MULTILINE)
assert re.search(r"^BTT/BTC$", captured.out, re.MULTILINE) assert re.search(r"^LTC/USD$", captured.out, re.MULTILINE)
def test_create_datadir_failed(caplog): def test_create_datadir_failed(caplog):