diff --git a/freqtrade/arguments.py b/freqtrade/arguments.py index 88f183a4a..371b79745 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/arguments.py @@ -165,6 +165,11 @@ class Arguments(object): @staticmethod def optimizer_shared_options(parser: argparse.ArgumentParser) -> None: + """ + Parses given common arguments for Backtesting and Hyperopt scripts. + :param parser: + :return: + """ parser.add_argument( '-i', '--ticker-interval', help='specify ticker interval (1m, 5m, 30m, 1h, 1d)', @@ -298,28 +303,34 @@ class Arguments(object): '--pairs-file', help='File containing a list of pairs to download', dest='pairs_file', - default=None + default=None, + metavar='PATH', ) self.parser.add_argument( '--export', help='Export files to given dir', dest='export', - default=None) + default=None, + metavar='PATH', + ) self.parser.add_argument( '--days', help='Download data for number of days', dest='days', type=int, - default=None) + metavar='INT', + default=None + ) self.parser.add_argument( '--exchange', help='Exchange name (default: %(default)s)', dest='exchange', type=str, - default='bittrex') + default='bittrex' + ) self.parser.add_argument( '-t', '--timeframes', diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index 3fc8acb3c..5a588c2d2 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -192,6 +192,7 @@ class CryptoToFiatConverter(object): # return 0 for unsupported stake currencies (fiat-convert should not break the bot) logger.warning("unsupported crypto-symbol %s - returning 0.0", crypto_symbol) return 0.0 + try: return float( self._coinmarketcap.ticker( diff --git a/freqtrade/tests/test_arguments.py b/freqtrade/tests/test_arguments.py index a7237d7c4..8a41e3379 100644 --- a/freqtrade/tests/test_arguments.py +++ b/freqtrade/tests/test_arguments.py @@ -174,3 +174,19 @@ def test_parse_args_hyperopt_custom() -> None: assert call_args.subparser == 'hyperopt' assert call_args.spaces == ['buy'] assert call_args.func is not None + + +def test_testdata_dl_options() -> None: + args = [ + '--pairs-file', 'file_with_pairs', + '--export', 'export/folder', + '--days', '30', + '--exchange', 'binance' + ] + arguments = Arguments(args, '') + arguments.testdata_dl_options() + args = arguments.parse_args() + assert args.pairs_file == 'file_with_pairs' + assert args.export == 'export/folder' + assert args.days == 30 + assert args.exchange == 'binance' diff --git a/freqtrade/tests/test_fiat_convert.py b/freqtrade/tests/test_fiat_convert.py index faf7462c0..24f0f776b 100644 --- a/freqtrade/tests/test_fiat_convert.py +++ b/freqtrade/tests/test_fiat_convert.py @@ -9,7 +9,7 @@ import pytest from requests.exceptions import RequestException from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter -from freqtrade.tests.conftest import patch_coinmarketcap +from freqtrade.tests.conftest import log_has, patch_coinmarketcap def test_pair_convertion_object(): @@ -90,6 +90,13 @@ def test_fiat_convert_find_price(mocker): assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='EUR') == 13000.2 +def test_fiat_convert_unsupported_crypto(mocker, caplog): + mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._cryptomap', return_value=[]) + fiat_convert = CryptoToFiatConverter() + assert fiat_convert._find_price(crypto_symbol='CRYPTO_123', fiat_symbol='EUR') == 0.0 + assert log_has('unsupported crypto-symbol CRYPTO_123 - returning 0.0', caplog.record_tuples) + + def test_fiat_convert_get_price(mocker): api_mock = MagicMock(return_value={ 'price_usd': 28000.0, @@ -161,7 +168,8 @@ def test_fiat_init_network_exception(mocker): fiat_convert._cryptomap = {} fiat_convert._load_cryptomap() - assert len(fiat_convert._cryptomap) == 0 + length_cryptomap = len(fiat_convert._cryptomap) + assert length_cryptomap == 0 def test_fiat_convert_without_network(): @@ -175,3 +183,22 @@ def test_fiat_convert_without_network(): assert fiat_convert._coinmarketcap is None assert fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='USD') == 0.0 CryptoToFiatConverter._coinmarketcap = cmc_temp + + +def test_convert_amount(mocker): + mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter.get_price', return_value=12345.0) + + fiat_convert = CryptoToFiatConverter() + result = fiat_convert.convert_amount( + crypto_amount=1.23, + crypto_symbol="BTC", + fiat_symbol="USD" + ) + assert result == 15184.35 + + result = fiat_convert.convert_amount( + crypto_amount=1.23, + crypto_symbol="BTC", + fiat_symbol="BTC" + ) + assert result == 1.23 diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 8f39c71a8..aca6dce2f 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -569,8 +569,10 @@ def test_process_maybe_execute_sell(mocker, default_conf, limit_buy_order, caplo trade.open_fee = 0.001 assert not freqtrade.process_maybe_execute_sell(trade) # Test amount not modified by fee-logic - assert not log_has('Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format( - trade), caplog.record_tuples) + assert not log_has( + 'Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format(trade), + caplog.record_tuples + ) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) # test amount modified by fee-logic @@ -581,6 +583,38 @@ def test_process_maybe_execute_sell(mocker, default_conf, limit_buy_order, caplo # Assert we call handle_trade() if trade is feasible for execution assert freqtrade.process_maybe_execute_sell(trade) + regexp = re.compile('Found open order for.*') + assert filter(regexp.match, caplog.record_tuples) + + +def test_process_maybe_execute_sell_exception(mocker, default_conf, + limit_buy_order, caplog) -> None: + """ + Test the exceptions in process_maybe_execute_sell() + """ + freqtrade = get_patched_freqtradebot(mocker, default_conf) + mocker.patch('freqtrade.freqtradebot.exchange.get_order', return_value=limit_buy_order) + + trade = MagicMock() + trade.open_order_id = '123' + trade.open_fee = 0.001 + + # Test raise of OperationalException exception + mocker.patch( + 'freqtrade.freqtradebot.FreqtradeBot.get_real_amount', + side_effect=OperationalException() + ) + freqtrade.process_maybe_execute_sell(trade) + assert log_has('could not update trade amount: ', caplog.record_tuples) + + # Test raise of DependencyException exception + mocker.patch( + 'freqtrade.freqtradebot.FreqtradeBot.get_real_amount', + side_effect=DependencyException() + ) + freqtrade.process_maybe_execute_sell(trade) + assert log_has('Unable to sell trade: ', caplog.record_tuples) + def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mocker) -> None: """ @@ -1355,7 +1389,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker): caplog.record_tuples) -def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, caplog, mocker): +def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mocker): """ Test get_real_amount - fees in Stake currency """ @@ -1507,3 +1541,28 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, freqtrade = FreqtradeBot(default_conf) # Amount does not change assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + + +def test_get_real_amount_open_trade(default_conf, mocker): + """ + Test get_real_amount condition trade.fee_open == 0 or order['status'] == 'open' + """ + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + amount = 12345 + trade = Trade( + pair='LTC/ETH', + amount=amount, + exchange='binance', + open_rate=0.245441, + open_order_id="123456" + ) + order = { + 'id': 'mocked_order', + 'amount': amount, + 'status': 'open', + } + freqtrade = FreqtradeBot(default_conf) + assert freqtrade.get_real_amount(trade, order) == amount diff --git a/setup.cfg b/setup.cfg index 6ffad0824..473f50639 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,3 +5,6 @@ max-complexity = 12 [mypy] ignore_missing_imports = True + +[mypy-freqtrade.tests.*] +ignore_errors = True