Merge develop

This commit is contained in:
hroff-1902
2019-12-05 01:08:38 +03:00
46 changed files with 927 additions and 414 deletions

View File

@@ -325,7 +325,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -351,7 +351,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -376,7 +376,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -401,7 +401,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -426,7 +426,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -451,7 +451,7 @@ def get_markets():
},
'price': 500000,
'cost': {
'min': 1,
'min': 0.0001,
'max': 500000,
},
},
@@ -479,7 +479,7 @@ def get_markets():
'max': None
},
'cost': {
'min': 0.001,
'min': 0.0001,
'max': None
}
},
@@ -980,6 +980,28 @@ def tickers():
'quoteVolume': 62.68220262,
'info': {}
},
'BTC/USDT': {
'symbol': 'BTC/USDT',
'timestamp': 1573758371399,
'datetime': '2019-11-14T19:06:11.399Z',
'high': 8800.0,
'low': 8582.6,
'bid': 8648.16,
'bidVolume': 0.238771,
'ask': 8648.72,
'askVolume': 0.016253,
'vwap': 8683.13647806,
'open': 8759.7,
'close': 8648.72,
'last': 8648.72,
'previousClose': 8759.67,
'change': -110.98,
'percentage': -1.267,
'average': None,
'baseVolume': 35025.943355,
'quoteVolume': 304135046.4242901,
'info': {}
},
'ETH/USDT': {
'symbol': 'ETH/USDT',
'timestamp': 1522014804118,
@@ -1067,7 +1089,29 @@ def tickers():
'baseVolume': 59698.79897,
'quoteVolume': 29132399.743954,
'info': {}
}
},
'XRP/BTC': {
'symbol': 'XRP/BTC',
'timestamp': 1573758257534,
'datetime': '2019-11-14T19:04:17.534Z',
'high': 3.126e-05,
'low': 3.061e-05,
'bid': 3.093e-05,
'bidVolume': 27901.0,
'ask': 3.095e-05,
'askVolume': 10551.0,
'vwap': 3.091e-05,
'open': 3.119e-05,
'close': 3.094e-05,
'last': 3.094e-05,
'previousClose': 3.117e-05,
'change': -2.5e-07,
'percentage': -0.802,
'average': None,
'baseVolume': 37334921.0,
'quoteVolume': 1154.19266394,
'info': {}
},
})
@@ -1317,8 +1361,8 @@ def rpc_balance():
'used': 0.0
},
'XRP': {
'total': 1.0,
'free': 1.0,
'total': 0.1,
'free': 0.01,
'used': 0.0
},
'EUR': {
@@ -1343,7 +1387,7 @@ def import_fails() -> None:
realimport = builtins.__import__
def mockedimport(name, *args, **kwargs):
if name in ["filelock"]:
if name in ["filelock", 'systemd.journal']:
raise ImportError(f"No module named '{name}'")
return realimport(name, *args, **kwargs)

View File

@@ -74,8 +74,8 @@ def test_load_data_30min_ticker(mocker, caplog, default_conf, testdatadir) -> No
def test_load_data_7min_ticker(mocker, caplog, default_conf, testdatadir) -> None:
ld = history.load_pair_history(pair='UNITTEST/BTC', timeframe='7m', datadir=testdatadir)
assert not isinstance(ld, DataFrame)
assert ld is None
assert isinstance(ld, DataFrame)
assert ld.empty
assert log_has(
'No history data for pair: "UNITTEST/BTC", timeframe: 7m. '
'Use `freqtrade download-data` to download the data', caplog

View File

@@ -494,7 +494,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) ->
def get_timeframe(input1):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=None))
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame()))
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
patch_exchange(mocker)

View File

@@ -27,7 +27,7 @@ from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
@pytest.fixture(scope='function')
def hyperopt(default_conf, mocker):
default_conf.update({
'spaces': ['all'],
'spaces': ['default'],
'hyperopt': 'DefaultHyperOpt',
})
patch_exchange(mocker)
@@ -113,7 +113,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
'--enable-position-stacking',
'--disable-max-market-positions',
'--epochs', '1000',
'--spaces', 'all',
'--spaces', 'default',
'--print-all'
]
@@ -249,7 +249,7 @@ def test_start(mocker, default_conf, caplog) -> None:
def test_start_no_data(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=None))
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
@@ -442,7 +442,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
'hyperopt': 'DefaultHyperOpt',
'epochs': 1,
'timerange': None,
'spaces': 'all',
'spaces': 'default',
'hyperopt_jobs': 1, })
hyperopt = Hyperopt(default_conf)
@@ -507,14 +507,38 @@ def test_format_results(hyperopt):
assert result.find('Total profit 1.00000000 EUR')
def test_has_space(hyperopt):
hyperopt.config.update({'spaces': ['buy', 'roi']})
assert hyperopt.has_space('roi')
assert hyperopt.has_space('buy')
assert not hyperopt.has_space('stoploss')
hyperopt.config.update({'spaces': ['all']})
assert hyperopt.has_space('buy')
@pytest.mark.parametrize("spaces, expected_results", [
(['buy'],
{'buy': True, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False}),
(['sell'],
{'buy': False, 'sell': True, 'roi': False, 'stoploss': False, 'trailing': False}),
(['roi'],
{'buy': False, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
(['stoploss'],
{'buy': False, 'sell': False, 'roi': False, 'stoploss': True, 'trailing': False}),
(['trailing'],
{'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': True}),
(['buy', 'sell', 'roi', 'stoploss'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
(['buy', 'sell', 'roi', 'stoploss', 'trailing'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
(['buy', 'roi'],
{'buy': True, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
(['all'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
(['default'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
(['default', 'trailing'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
(['all', 'buy'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
(['default', 'buy'],
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
])
def test_has_space(hyperopt, spaces, expected_results):
for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']:
hyperopt.config.update({'spaces': spaces})
assert hyperopt.has_space(s) == expected_results[s]
def test_populate_indicators(hyperopt, testdatadir) -> None:
@@ -609,6 +633,10 @@ def test_generate_optimizer(mocker, default_conf) -> None:
'roi_p2': 0.01,
'roi_p3': 0.1,
'stoploss': -0.4,
'trailing_stop': True,
'trailing_stop_positive': 0.02,
'trailing_stop_positive_offset': 0.1,
'trailing_only_offset_is_reached': False,
}
response_expected = {
'loss': 1.9840569076926293,
@@ -637,7 +665,11 @@ def test_generate_optimizer(mocker, default_conf) -> None:
'sell-rsi-enabled': False,
'sell-rsi-value': 0,
'sell-trigger': 'macd_cross_signal'},
'stoploss': {'stoploss': -0.4}},
'stoploss': {'stoploss': -0.4},
'trailing': {'trailing_only_offset_is_reached': False,
'trailing_stop': True,
'trailing_stop_positive': 0.02,
'trailing_stop_positive_offset': 0.1}},
'params_dict': optimizer_param,
'results_metrics': {'avg_profit': 2.3117,
'duration': 100.0,
@@ -659,7 +691,7 @@ def test_clean_hyperopt(mocker, default_conf, caplog):
'hyperopt': 'DefaultHyperOpt',
'epochs': 1,
'timerange': None,
'spaces': 'all',
'spaces': 'default',
'hyperopt_jobs': 1,
})
mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True))
@@ -676,7 +708,7 @@ def test_continue_hyperopt(mocker, default_conf, caplog):
'hyperopt': 'DefaultHyperOpt',
'epochs': 1,
'timerange': None,
'spaces': 'all',
'spaces': 'default',
'hyperopt_jobs': 1,
'hyperopt_continue': True
})
@@ -702,7 +734,8 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None:
MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {},
'params_details': {'buy': {'mfi-value': None},
'sell': {'sell-mfi-value': None},
'roi': {}, 'stoploss': {'stoploss': None}}}])
'roi': {}, 'stoploss': {'stoploss': None},
'trailing': {'trailing_stop': None}}}])
)
patch_exchange(mocker)
@@ -723,6 +756,48 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None:
parallel.assert_called_once()
out, err = capsys.readouterr()
assert '{"params":{"mfi-value":null,"sell-mfi-value":null},"minimal_roi":{},"stoploss":null,"trailing_stop":null}' in out # noqa: E501
assert dumper.called
# Should be called twice, once for tickerdata, once to save evaluations
assert dumper.call_count == 2
def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None:
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
parallel = mocker.patch(
'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {},
'params_details': {'buy': {'mfi-value': None},
'sell': {'sell-mfi-value': None},
'roi': {}, 'stoploss': {'stoploss': None}}}])
)
patch_exchange(mocker)
default_conf.update({'config': 'config.json.example',
'hyperopt': 'DefaultHyperOpt',
'epochs': 1,
'timerange': None,
'spaces': 'default',
'hyperopt_jobs': 1,
'print_json': True,
})
hyperopt = Hyperopt(default_conf)
hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
parallel.assert_called_once()
out, err = capsys.readouterr()
assert '{"params":{"mfi-value":null,"sell-mfi-value":null},"minimal_roi":{},"stoploss":null}' in out # noqa: E501
assert dumper.called

View File

@@ -100,7 +100,7 @@ def test_refresh_pairlist_dynamic(mocker, shitcoinmarkets, tickers, whitelist_co
markets=PropertyMock(return_value=shitcoinmarkets),
)
# argument: use the whitelist dynamically by exchange-volume
whitelist = ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'HOT/BTC', 'FUEL/BTC']
whitelist = ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'HOT/BTC']
bot.pairlists.refresh_pairlist()
assert whitelist == bot.pairlists.whitelist
@@ -135,10 +135,10 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
@pytest.mark.parametrize("pairlists,base_currency,whitelist_result", [
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}],
"BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'HOT/BTC', 'FUEL/BTC']),
"BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'HOT/BTC']),
# Different sorting depending on quote or bid volume
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}],
"BTC", ['HOT/BTC', 'FUEL/BTC', 'LTC/BTC', 'TKN/BTC', 'ETH/BTC']),
"BTC", ['HOT/BTC', 'FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']),
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}],
"USDT", ['ETH/USDT']),
# No pair for ETH ...
@@ -146,19 +146,19 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
"ETH", []),
# Precisionfilter and quote volume
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
{"method": "PrecisionFilter"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'FUEL/BTC']),
{"method": "PrecisionFilter"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']),
# Precisionfilter bid
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"},
{"method": "PrecisionFilter"}], "BTC", ['FUEL/BTC', 'LTC/BTC', 'TKN/BTC', 'ETH/BTC']),
{"method": "PrecisionFilter"}], "BTC", ['FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']),
# PriceFilter and VolumePairList
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
{"method": "PriceFilter", "low_price_ratio": 0.03}],
"BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'FUEL/BTC']),
"BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']),
# Hot is removed by precision_filter, Fuel by low_price_filter.
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
([{"method": "VolumePairList", "number_assets": 6, "sort_key": "quoteVolume"},
{"method": "PrecisionFilter"},
{"method": "PriceFilter", "low_price_ratio": 0.02}
], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC']),
], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']),
# StaticPairlist Only
([{"method": "StaticPairList"},
], "BTC", ['ETH/BTC', 'TKN/BTC']),
@@ -285,12 +285,7 @@ def test_volumepairlist_caching(mocker, markets, whitelist_conf, tickers):
def test_pairlistmanager_no_pairlist(mocker, markets, whitelist_conf, caplog):
del whitelist_conf['pairlists'][0]['method']
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
with pytest.raises(OperationalException,
match=r"No Pairlist defined!"):
get_patched_freqtradebot(mocker, whitelist_conf)
assert log_has_re("No method in .*", caplog)
whitelist_conf['pairlists'] = []

View File

@@ -355,29 +355,18 @@ def test_rpc_balance_handle_error(default_conf, mocker):
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=mock_balance),
get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx'))
get_tickers=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx'))
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
result = rpc._rpc_balance(default_conf['fiat_display_currency'])
assert prec_satoshi(result['total'], 12)
assert prec_satoshi(result['value'], 180000)
assert 'USD' == result['symbol']
assert result['currencies'] == [{
'currency': 'BTC',
'free': 10.0,
'balance': 12.0,
'used': 2.0,
'est_btc': 12.0,
}]
assert result['total'] == 12.0
with pytest.raises(RPCException, match="Error getting current tickers."):
rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency'])
def test_rpc_balance_handle(default_conf, mocker):
def test_rpc_balance_handle(default_conf, mocker, tickers):
mock_balance = {
'BTC': {
'free': 10.0,
@@ -389,7 +378,7 @@ def test_rpc_balance_handle(default_conf, mocker):
'total': 5.0,
'used': 4.0,
},
'PAX': {
'USDT': {
'free': 5.0,
'total': 10.0,
'used': 5.0,
@@ -405,10 +394,9 @@ def test_rpc_balance_handle(default_conf, mocker):
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=mock_balance),
get_ticker=MagicMock(
side_effect=lambda p, r: {'bid': 100} if p == "BTC/PAX" else {'bid': 0.01}),
get_tickers=tickers,
get_valid_pair_combination=MagicMock(
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 == "USDT" else f"{a}/{b}")
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
@@ -416,30 +404,35 @@ def test_rpc_balance_handle(default_conf, mocker):
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
result = rpc._rpc_balance(default_conf['fiat_display_currency'])
assert prec_satoshi(result['total'], 12.15)
assert prec_satoshi(result['value'], 182250)
result = rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency'])
assert prec_satoshi(result['total'], 12.309096315)
assert prec_satoshi(result['value'], 184636.44472997)
assert 'USD' == result['symbol']
assert result['currencies'] == [
{'currency': 'BTC',
'free': 10.0,
'balance': 12.0,
'used': 2.0,
'est_btc': 12.0,
'free': 10.0,
'balance': 12.0,
'used': 2.0,
'est_stake': 12.0,
'stake': 'BTC',
},
{'free': 1.0,
'balance': 5.0,
'currency': 'ETH',
'est_btc': 0.05,
'used': 4.0
'est_stake': 0.30794,
'used': 4.0,
'stake': 'BTC',
},
{'free': 5.0,
'balance': 10.0,
'currency': 'PAX',
'est_btc': 0.1,
'used': 5.0}
'currency': 'USDT',
'est_stake': 0.0011563153318162476,
'used': 5.0,
'stake': 'BTC',
}
]
assert result['total'] == 12.15
assert result['total'] == 12.309096315331816
def test_rpc_start(mocker, default_conf) -> None:
@@ -697,8 +690,8 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order) -> None
pair = 'XRP/BTC'
# Test not buying
default_conf['stake_amount'] = 0.0000001
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot.config['stake_amount'] = 0.0000001
patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot)
pair = 'TKN/BTC'

View File

@@ -23,7 +23,7 @@ _TEST_PASS = "SuperSecurePassword1!"
def botclient(default_conf, mocker):
default_conf.update({"api_server": {"enabled": True,
"listen_ip_address": "127.0.0.1",
"listen_port": "8080",
"listen_port": 8080,
"username": _TEST_USER,
"password": _TEST_PASS,
}})
@@ -133,7 +133,10 @@ def test_api__init__(default_conf, mocker):
def test_api_run(default_conf, mocker, caplog):
default_conf.update({"api_server": {"enabled": True,
"listen_ip_address": "127.0.0.1",
"listen_port": "8080"}})
"listen_port": 8080,
"username": "TestUser",
"password": "testPass",
}})
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
@@ -146,7 +149,7 @@ def test_api_run(default_conf, mocker, caplog):
apiserver.run()
assert server_mock.call_count == 1
assert server_mock.call_args_list[0][0][0] == "127.0.0.1"
assert server_mock.call_args_list[0][0][1] == "8080"
assert server_mock.call_args_list[0][0][1] == 8080
assert isinstance(server_mock.call_args_list[0][0][2], Flask)
assert hasattr(apiserver, "srv")
@@ -158,14 +161,14 @@ def test_api_run(default_conf, mocker, caplog):
server_mock.reset_mock()
apiserver._config.update({"api_server": {"enabled": True,
"listen_ip_address": "0.0.0.0",
"listen_port": "8089",
"listen_port": 8089,
"password": "",
}})
apiserver.run()
assert server_mock.call_count == 1
assert server_mock.call_args_list[0][0][0] == "0.0.0.0"
assert server_mock.call_args_list[0][0][1] == "8089"
assert server_mock.call_args_list[0][0][1] == 8089
assert isinstance(server_mock.call_args_list[0][0][2], Flask)
assert log_has("Starting HTTP Server at 0.0.0.0:8089", caplog)
assert log_has("Starting Local Rest Server.", caplog)
@@ -186,7 +189,10 @@ def test_api_run(default_conf, mocker, caplog):
def test_api_cleanup(default_conf, mocker, caplog):
default_conf.update({"api_server": {"enabled": True,
"listen_ip_address": "127.0.0.1",
"listen_port": "8080"}})
"listen_port": 8080,
"username": "TestUser",
"password": "testPass",
}})
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
mocker.patch('freqtrade.rpc.api_server.make_server', MagicMock())
@@ -224,28 +230,10 @@ def test_api_stopbuy(botclient):
def test_api_balance(botclient, mocker, rpc_balance):
ftbot, client = botclient
def mock_ticker(symbol, refresh):
if symbol == 'BTC/USDT':
return {
'bid': 10000.00,
'ask': 10000.00,
'last': 10000.00,
}
elif symbol == 'XRP/BTC':
return {
'bid': 0.00001,
'ask': 0.00001,
'last': 0.00001,
}
return {
'bid': 0.1,
'ask': 0.1,
'last': 0.1,
}
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker)
mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination',
side_effect=lambda a, b: f"{a}/{b}")
ftbot.wallets.update()
rc = client_get(client, f"{BASE_URI}/balance")
assert_response(rc)
@@ -256,7 +244,8 @@ def test_api_balance(botclient, mocker, rpc_balance):
'free': 12.0,
'balance': 12.0,
'used': 0.0,
'est_btc': 12.0,
'est_stake': 12.0,
'stake': 'BTC',
}

View File

@@ -173,7 +173,10 @@ def test_init_apiserver_enabled(mocker, default_conf, caplog) -> None:
default_conf["telegram"]["enabled"] = False
default_conf["api_server"] = {"enabled": True,
"listen_ip_address": "127.0.0.1",
"listen_port": "8080"}
"listen_port": 8080,
"username": "TestUser",
"password": "TestPass",
}
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
# Sleep to allow the thread to start

View File

@@ -144,9 +144,9 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> 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']['chat_id'] = 123
default_conf['telegram']['chat_id'] = "123"
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -461,29 +461,10 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance) -> None:
def mock_ticker(symbol, refresh):
if symbol == 'BTC/USDT':
return {
'bid': 10000.00,
'ask': 10000.00,
'last': 10000.00,
}
elif symbol == 'XRP/BTC':
return {
'bid': 0.00001,
'ask': 0.00001,
'last': 0.00001,
}
return {
'bid': 0.1,
'ask': 0.1,
'last': 0.1,
}
def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tickers) -> None:
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker)
mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers)
mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination',
side_effect=lambda a, b: f"{a}/{b}")
@@ -564,7 +545,8 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None
'free': 1.0,
'used': 0.5,
'balance': i,
'est_btc': 1
'est_stake': 1,
'stake': 'BTC',
})
mocker.patch('freqtrade.rpc.rpc.RPC._rpc_balance', return_value={
'currencies': balances,

View File

@@ -113,7 +113,7 @@ def test_send_msg(default_conf, mocker):
def test_exception_send_msg(default_conf, mocker, caplog):
default_conf["webhook"] = get_webhook_dict()
default_conf["webhook"]["webhookbuy"] = None
del default_conf["webhook"]["webhookbuy"]
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
webhook.send_msg({'type': RPCMessageType.BUY_NOTIFICATION})

View File

@@ -1,6 +1,7 @@
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
import json
import logging
import sys
import warnings
from copy import deepcopy
from pathlib import Path
@@ -19,7 +20,7 @@ from freqtrade.configuration.deprecated_settings import (
process_temporary_deprecated_settings)
from freqtrade.configuration.load_config import load_config_file
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
from freqtrade.loggers import _set_loggers
from freqtrade.loggers import _set_loggers, setup_logging
from freqtrade.state import RunMode
from tests.conftest import (log_has, log_has_re,
patched_configuration_load_config_file)
@@ -40,10 +41,16 @@ def test_load_config_invalid_pair(default_conf) -> None:
def test_load_config_missing_attributes(default_conf) -> None:
default_conf.pop('exchange')
conf = deepcopy(default_conf)
conf.pop('exchange')
with pytest.raises(ValidationError, match=r".*'exchange' is a required property.*"):
validate_config_schema(default_conf)
validate_config_schema(conf)
conf = deepcopy(default_conf)
conf.pop('stake_currency')
with pytest.raises(ValidationError, match=r".*'stake_currency' is a required property.*"):
validate_config_schema(conf)
def test_load_config_incorrect_stake_amount(default_conf) -> None:
@@ -100,7 +107,6 @@ def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
assert validated_conf['max_open_trades'] == 0
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog)
def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
@@ -132,7 +138,6 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
assert validated_conf['exchange']['pair_whitelist'] == conf2['exchange']['pair_whitelist']
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog)
def test_from_config(default_conf, mocker, caplog) -> None:
@@ -159,7 +164,6 @@ def test_from_config(default_conf, mocker, caplog) -> None:
assert validated_conf['exchange']['pair_whitelist'] == conf2['exchange']['pair_whitelist']
assert validated_conf['fiat_display_currency'] == "EUR"
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog)
assert isinstance(validated_conf['user_data_dir'], Path)
@@ -191,7 +195,6 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) ->
assert validated_conf['max_open_trades'] > 999999999
assert validated_conf['max_open_trades'] == float('inf')
assert log_has('Validating configuration ...', caplog)
assert "runmode" in validated_conf
assert validated_conf['runmode'] == RunMode.DRY_RUN
@@ -636,6 +639,56 @@ def test_set_loggers() -> None:
assert logging.getLogger('telegram').level is logging.INFO
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
def test_set_loggers_syslog(mocker):
logger = logging.getLogger()
orig_handlers = logger.handlers
logger.handlers = []
config = {'verbosity': 2,
'logfile': 'syslog:/dev/log',
}
setup_logging(config)
assert len(logger.handlers) == 2
assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler]
assert [x for x in logger.handlers if type(x) == logging.StreamHandler]
# reset handlers to not break pytest
logger.handlers = orig_handlers
@pytest.mark.skip(reason="systemd is not installed on every system, so we're not testing this.")
def test_set_loggers_journald(mocker):
logger = logging.getLogger()
orig_handlers = logger.handlers
logger.handlers = []
config = {'verbosity': 2,
'logfile': 'journald',
}
setup_logging(config)
assert len(logger.handlers) == 2
assert [x for x in logger.handlers if type(x).__name__ == "JournaldLogHandler"]
assert [x for x in logger.handlers if type(x) == logging.StreamHandler]
# reset handlers to not break pytest
logger.handlers = orig_handlers
def test_set_loggers_journald_importerror(mocker, import_fails):
logger = logging.getLogger()
orig_handlers = logger.handlers
logger.handlers = []
config = {'verbosity': 2,
'logfile': 'journald',
}
with pytest.raises(OperationalException,
match=r'You need the systemd python package.*'):
setup_logging(config)
logger.handlers = orig_handlers
def test_set_logfile(default_conf, mocker):
patched_configuration_load_config_file(mocker, default_conf)

View File

@@ -299,7 +299,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
limit_buy_order, fee) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
default_conf['stake_amount'] = 0.0000098751
default_conf['stake_amount'] = 0.00098751
default_conf['max_open_trades'] = 2
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -313,7 +313,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
trade = Trade.query.first()
assert trade is not None
assert trade.stake_amount == 0.0000098751
assert trade.stake_amount == 0.00098751
assert trade.is_open
assert trade.open_date is not None
@@ -321,11 +321,11 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
trade = Trade.query.order_by(Trade.id.desc()).first()
assert trade is not None
assert trade.stake_amount == 0.0000098751
assert trade.stake_amount == 0.00098751
assert trade.is_open
assert trade.open_date is not None
assert Trade.total_open_trades_stakes() == 1.97502e-05
assert Trade.total_open_trades_stakes() == 1.97502e-03
def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
@@ -334,6 +334,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.stoploss = -0.05
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
# no pair found
mocker.patch(
'freqtrade.exchange.Exchange.markets',
@@ -425,7 +426,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == min(2, 2 * 2) / 0.9
assert result == max(2, 2 * 2) / 0.9
# min amount and cost are set (amount is minial)
markets["ETH/BTC"]["limits"] = {
@@ -437,7 +438,27 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == min(8, 2 * 2) / 0.9
assert result == max(8, 2 * 2) / 0.9
def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.stoploss = -0.05
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
# Real Binance data
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 0.0001},
'amount': {'min': 0.001}
}
mocker.patch(
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 0.020405)
assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8)
def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
@@ -522,8 +543,9 @@ def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_or
get_fee=fee,
)
default_conf['stake_amount'] = 0.000000005
freqtrade = FreqtradeBot(default_conf)
freqtrade.config['stake_amount'] = 0.000000005
patch_get_signal(freqtrade)
assert not freqtrade.create_trades()

View File

@@ -10,8 +10,9 @@ from freqtrade.utils import (setup_utils_configuration, start_create_userdir,
start_download_data, start_list_exchanges,
start_list_markets, start_list_timeframes,
start_new_hyperopt, start_new_strategy,
start_trading)
from tests.conftest import get_args, log_has, log_has_re, patch_exchange
start_test_pairlist, start_trading)
from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
patched_configuration_load_config_file)
def test_setup_utils_configuration():
@@ -573,7 +574,7 @@ def test_download_data_no_exchange(mocker, caplog):
)
args = [
"download-data",
]
]
pargs = get_args(args)
pargs['config'] = None
with pytest.raises(OperationalException,
@@ -623,3 +624,36 @@ def test_download_data_trades(mocker, caplog):
assert dl_mock.call_args[1]['timerange'].starttype == "date"
assert dl_mock.call_count == 1
assert convert_mock.call_count == 1
def test_start_test_pairlist(mocker, caplog, markets, tickers, default_conf, capsys):
mocker.patch.multiple('freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
exchange_has=MagicMock(return_value=True),
get_tickers=tickers
)
default_conf['pairlists'] = [
{
"method": "VolumePairList",
"number_assets": 5,
"sort_key": "quoteVolume",
},
{"method": "PrecisionFilter"},
{"method": "PriceFilter", "low_price_ratio": 0.02},
]
patched_configuration_load_config_file(mocker, default_conf)
args = [
'test-pairlist',
'-c', 'config.json.example'
]
start_test_pairlist(get_args(args))
assert log_has_re(r"^Using resolved pairlist VolumePairList.*", caplog)
assert log_has_re(r"^Using resolved pairlist PrecisionFilter.*", caplog)
assert log_has_re(r"^Using resolved pairlist PriceFilter.*", caplog)
captured = capsys.readouterr()
assert re.match(r"Pairs for .*", captured.out)
assert re.match("['ETH/BTC', 'TKN/BTC', 'BLK/BTC', 'LTC/BTC', 'XRP/BTC']", captured.out)