Merge remote-tracking branch 'origin/develop' into dev-merge-rl
This commit is contained in:
@@ -480,7 +480,7 @@ def test_validate_backtest_data(default_conf, mocker, caplog, testdatadir) -> No
|
||||
default_conf.update({'strategy': CURRENT_TEST_STRATEGY})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
timerange = TimeRange('index', 'index', 200, 250)
|
||||
timerange = TimeRange()
|
||||
data = strategy.advise_all_indicators(
|
||||
load_data(
|
||||
datadir=testdatadir,
|
||||
|
85
tests/exchange/test_exchange_utils.py
Normal file
85
tests/exchange/test_exchange_utils.py
Normal file
@@ -0,0 +1,85 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange.check_exchange import check_exchange
|
||||
from tests.conftest import log_has_re
|
||||
|
||||
|
||||
def test_check_exchange(default_conf, caplog) -> None:
|
||||
# Test an officially supported by Freqtrade team exchange
|
||||
default_conf['runmode'] = RunMode.DRY_RUN
|
||||
default_conf.get('exchange').update({'name': 'BITTREX'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an officially supported by Freqtrade team exchange
|
||||
default_conf.get('exchange').update({'name': 'binance'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(
|
||||
r"Exchange \"binance\" is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an officially supported by Freqtrade team exchange
|
||||
default_conf.get('exchange').update({'name': 'binanceus'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(
|
||||
r"Exchange \"binanceus\" is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an officially supported by Freqtrade team exchange - with remapping
|
||||
default_conf.get('exchange').update({'name': 'okex'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(
|
||||
r"Exchange \"okex\" is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
# Test an available exchange, supported by ccxt
|
||||
default_conf.get('exchange').update({'name': 'huobipro'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(r"Exchange .* is known to the the ccxt library, available for the bot, "
|
||||
r"but not officially supported "
|
||||
r"by the Freqtrade development team\. .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test a 'bad' exchange, which known to have serious problems
|
||||
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Exchange .* will not work with Freqtrade\..*"):
|
||||
check_exchange(default_conf)
|
||||
caplog.clear()
|
||||
|
||||
# Test a 'bad' exchange with check_for_bad=False
|
||||
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||
assert check_exchange(default_conf, False)
|
||||
assert log_has_re(r"Exchange .* is known to the the ccxt library, available for the bot, "
|
||||
r"but not officially supported "
|
||||
r"by the Freqtrade development team\. .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an invalid exchange
|
||||
default_conf.get('exchange').update({'name': 'unknown_exchange'})
|
||||
with pytest.raises(
|
||||
OperationalException,
|
||||
match=r'Exchange "unknown_exchange" is not known to the ccxt library '
|
||||
r'and therefore not available for the bot.*'
|
||||
):
|
||||
check_exchange(default_conf)
|
||||
|
||||
# Test no exchange...
|
||||
default_conf.get('exchange').update({'name': ''})
|
||||
default_conf['runmode'] = RunMode.PLOT
|
||||
assert check_exchange(default_conf)
|
||||
|
||||
# Test no exchange...
|
||||
default_conf.get('exchange').update({'name': ''})
|
||||
default_conf['runmode'] = RunMode.UTIL_EXCHANGE
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'This command requires a configured exchange.*'):
|
||||
check_exchange(default_conf)
|
@@ -71,7 +71,7 @@ def test_use_DBSCAN_to_remove_outliers(mocker, freqai_conf, caplog):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
# freqai_conf['freqai']['feature_parameters'].update({"outlier_protection_percentage": 1})
|
||||
freqai.dk.use_DBSCAN_to_remove_outliers(predict=False)
|
||||
assert log_has_re(r"DBSCAN found eps of 1.75", caplog)
|
||||
assert log_has_re(r"DBSCAN found eps of 1\.7\d\.", caplog)
|
||||
|
||||
|
||||
def test_compute_distances(mocker, freqai_conf):
|
||||
|
@@ -8,8 +8,10 @@ import pytest
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
|
||||
from freqtrade.freqai.utils import download_all_data_for_training, get_required_data_timerange
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||
from tests.conftest import get_patched_exchange, log_has_re
|
||||
@@ -245,7 +247,7 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat):
|
||||
model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()]
|
||||
|
||||
assert len(model_folders) == num_files
|
||||
Trade.use_db = True
|
||||
Backtesting.cleanup()
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
|
||||
|
@@ -297,6 +297,7 @@ def test_params_no_optimize_details(hyperopt) -> None:
|
||||
def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
@@ -530,6 +531,7 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
@@ -581,6 +583,7 @@ def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
mocker.patch(
|
||||
@@ -622,6 +625,7 @@ def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None:
|
||||
def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
@@ -663,6 +667,7 @@ def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
|
||||
def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
@@ -736,6 +741,7 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None:
|
||||
def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
@@ -778,6 +784,7 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
|
||||
def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
mocker.patch('freqtrade.optimize.hyperopt.calculate_market_change', return_value=1.5)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
MagicMock(return_value=(MagicMock(), None)))
|
||||
|
@@ -188,15 +188,19 @@ async def test_emc_create_connection_success(default_conf, caplog, mocker):
|
||||
emc.shutdown()
|
||||
|
||||
|
||||
async def test_emc_create_connection_invalid_port(default_conf, caplog, mocker):
|
||||
@pytest.mark.parametrize('host,port', [
|
||||
(_TEST_WS_HOST, -1),
|
||||
("10000.1241..2121/", _TEST_WS_PORT),
|
||||
])
|
||||
async def test_emc_create_connection_invalid_url(default_conf, caplog, mocker, host, port):
|
||||
default_conf.update({
|
||||
"external_message_consumer": {
|
||||
"enabled": True,
|
||||
"producers": [
|
||||
{
|
||||
"name": "default",
|
||||
"host": _TEST_WS_HOST,
|
||||
"port": -1,
|
||||
"host": host,
|
||||
"port": port,
|
||||
"ws_token": _TEST_WS_TOKEN
|
||||
}
|
||||
],
|
||||
@@ -207,38 +211,13 @@ async def test_emc_create_connection_invalid_port(default_conf, caplog, mocker):
|
||||
})
|
||||
|
||||
dp = DataProvider(default_conf, None, None, None)
|
||||
# Handle start explicitly to avoid messing with threading in tests
|
||||
mocker.patch("freqtrade.rpc.external_message_consumer.ExternalMessageConsumer.start",)
|
||||
emc = ExternalMessageConsumer(default_conf, dp)
|
||||
|
||||
try:
|
||||
await asyncio.sleep(0.01)
|
||||
assert log_has_re(r".+ is an invalid WebSocket URL .+", caplog)
|
||||
finally:
|
||||
emc.shutdown()
|
||||
|
||||
|
||||
async def test_emc_create_connection_invalid_host(default_conf, caplog, mocker):
|
||||
default_conf.update({
|
||||
"external_message_consumer": {
|
||||
"enabled": True,
|
||||
"producers": [
|
||||
{
|
||||
"name": "default",
|
||||
"host": "10000.1241..2121/",
|
||||
"port": _TEST_WS_PORT,
|
||||
"ws_token": _TEST_WS_TOKEN
|
||||
}
|
||||
],
|
||||
"wait_timeout": 60,
|
||||
"ping_timeout": 60,
|
||||
"sleep_timeout": 60
|
||||
}
|
||||
})
|
||||
|
||||
dp = DataProvider(default_conf, None, None, None)
|
||||
emc = ExternalMessageConsumer(default_conf, dp)
|
||||
|
||||
try:
|
||||
await asyncio.sleep(0.01)
|
||||
emc._running = True
|
||||
await emc._create_connection(emc.producers[0], asyncio.Lock())
|
||||
assert log_has_re(r".+ is an invalid WebSocket URL .+", caplog)
|
||||
finally:
|
||||
emc.shutdown()
|
||||
|
@@ -11,7 +11,7 @@ import pytest
|
||||
from jsonschema import ValidationError
|
||||
|
||||
from freqtrade.commands import Arguments
|
||||
from freqtrade.configuration import Configuration, check_exchange, validate_config_consistency
|
||||
from freqtrade.configuration import Configuration, validate_config_consistency
|
||||
from freqtrade.configuration.config_validation import validate_config_schema
|
||||
from freqtrade.configuration.deprecated_settings import (check_conflicting_settings,
|
||||
process_deprecated_setting,
|
||||
@@ -584,67 +584,6 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
|
||||
assert config['runmode'] == RunMode.HYPEROPT
|
||||
|
||||
|
||||
def test_check_exchange(default_conf, caplog) -> None:
|
||||
# Test an officially supported by Freqtrade team exchange
|
||||
default_conf['runmode'] = RunMode.DRY_RUN
|
||||
default_conf.get('exchange').update({'name': 'BITTREX'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an officially supported by Freqtrade team exchange
|
||||
default_conf.get('exchange').update({'name': 'binance'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an available exchange, supported by ccxt
|
||||
default_conf.get('exchange').update({'name': 'huobipro'})
|
||||
assert check_exchange(default_conf)
|
||||
assert log_has_re(r"Exchange .* is known to the the ccxt library, available for the bot, "
|
||||
r"but not officially supported "
|
||||
r"by the Freqtrade development team\. .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test a 'bad' exchange, which known to have serious problems
|
||||
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Exchange .* will not work with Freqtrade\..*"):
|
||||
check_exchange(default_conf)
|
||||
caplog.clear()
|
||||
|
||||
# Test a 'bad' exchange with check_for_bad=False
|
||||
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||
assert check_exchange(default_conf, False)
|
||||
assert log_has_re(r"Exchange .* is known to the the ccxt library, available for the bot, "
|
||||
r"but not officially supported "
|
||||
r"by the Freqtrade development team\. .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Test an invalid exchange
|
||||
default_conf.get('exchange').update({'name': 'unknown_exchange'})
|
||||
with pytest.raises(
|
||||
OperationalException,
|
||||
match=r'Exchange "unknown_exchange" is not known to the ccxt library '
|
||||
r'and therefore not available for the bot.*'
|
||||
):
|
||||
check_exchange(default_conf)
|
||||
|
||||
# Test no exchange...
|
||||
default_conf.get('exchange').update({'name': ''})
|
||||
default_conf['runmode'] = RunMode.PLOT
|
||||
assert check_exchange(default_conf)
|
||||
|
||||
# Test no exchange...
|
||||
default_conf.get('exchange').update({'name': ''})
|
||||
default_conf['runmode'] = RunMode.UTIL_EXCHANGE
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'This command requires a configured exchange.*'):
|
||||
check_exchange(default_conf)
|
||||
|
||||
|
||||
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
|
||||
|
@@ -28,6 +28,7 @@ from tests.conftest import (create_mock_trades, create_mock_trades_usdt, get_pat
|
||||
from tests.conftest_trades import (MOCK_TRADE_COUNT, entry_side, exit_side, mock_order_1,
|
||||
mock_order_2, mock_order_2_sell, mock_order_3, mock_order_3_sell,
|
||||
mock_order_4, mock_order_5_stoploss, mock_order_6_sell)
|
||||
from tests.conftest_trades_usdt import mock_trade_usdt_4
|
||||
|
||||
|
||||
def patch_RPCManager(mocker) -> MagicMock:
|
||||
@@ -1060,6 +1061,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.is_short = is_short
|
||||
trade.open_order_id = None
|
||||
@@ -1101,6 +1103,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
|
||||
# First case: when stoploss is not yet set but the order is open
|
||||
# should get the stoploss order id immediately
|
||||
# and should return false as no trade actually happened
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.is_short = is_short
|
||||
trade.is_open = True
|
||||
@@ -1879,6 +1882,7 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog
|
||||
return_value=limit_order[entry_side(is_short)])
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.is_short = is_short
|
||||
trade.open_order_id = '123'
|
||||
@@ -1902,6 +1906,7 @@ def test_exit_positions_exception(mocker, default_conf_usdt, limit_order, caplog
|
||||
order = limit_order[entry_side(is_short)]
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.is_short = is_short
|
||||
trade.open_order_id = None
|
||||
@@ -2042,6 +2047,7 @@ def test_update_trade_state_exception(mocker, default_conf_usdt, is_short, limit
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.open_order_id = '123'
|
||||
trade.amount = 123
|
||||
@@ -2060,6 +2066,7 @@ def test_update_trade_state_orderexception(mocker, default_conf_usdt, caplog) ->
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
|
||||
MagicMock(side_effect=InvalidOrderException))
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
trade.open_order_id = '123'
|
||||
|
||||
@@ -2980,7 +2987,7 @@ def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_short) -> None:
|
||||
def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_short, fee) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
l_order = limit_order[entry_side(is_short)]
|
||||
@@ -2994,16 +3001,12 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
freqtrade._notify_enter_cancel = MagicMock()
|
||||
|
||||
# TODO: Convert to real trade
|
||||
trade = MagicMock()
|
||||
trade.pair = 'LTC/USDT'
|
||||
trade.open_rate = 200
|
||||
trade.is_short = False
|
||||
trade.entry_side = "buy"
|
||||
trade.amount = 100
|
||||
trade = mock_trade_usdt_4(fee, is_short)
|
||||
Trade.query.session.add(trade)
|
||||
Trade.commit()
|
||||
|
||||
l_order['filled'] = 0.0
|
||||
l_order['status'] = 'open'
|
||||
trade.nr_of_successful_entries = 0
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
assert freqtrade.handle_cancel_enter(trade, l_order, reason)
|
||||
assert cancel_order_mock.call_count == 1
|
||||
@@ -3035,7 +3038,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@pytest.mark.parametrize("limit_buy_order_canceled_empty", ['binance', 'ftx', 'kraken', 'bittrex'],
|
||||
indirect=['limit_buy_order_canceled_empty'])
|
||||
def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_short,
|
||||
def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_short, fee,
|
||||
limit_buy_order_canceled_empty) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
@@ -3046,11 +3049,10 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
# TODO: Convert to real trade
|
||||
trade = MagicMock()
|
||||
trade.nr_of_successful_entries = 0
|
||||
trade.pair = 'LTC/ETH'
|
||||
trade.entry_side = "sell" if is_short else "buy"
|
||||
|
||||
trade = mock_trade_usdt_4(fee, is_short)
|
||||
Trade.query.session.add(trade)
|
||||
Trade.commit()
|
||||
assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason)
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert log_has_re(
|
||||
@@ -3068,7 +3070,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho
|
||||
'String Return value',
|
||||
123
|
||||
])
|
||||
def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order, is_short,
|
||||
def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order, is_short, fee,
|
||||
cancelorder) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
@@ -3076,20 +3078,15 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
|
||||
cancel_order_mock = MagicMock(return_value=cancelorder)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
cancel_order=cancel_order_mock
|
||||
cancel_order=cancel_order_mock,
|
||||
fetch_order=MagicMock(side_effect=InvalidOrderException)
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
freqtrade._notify_enter_cancel = MagicMock()
|
||||
# TODO: Convert to real trade
|
||||
trade = MagicMock()
|
||||
trade.pair = 'LTC/USDT'
|
||||
trade.entry_side = "buy"
|
||||
trade.open_rate = 200
|
||||
trade.entry_side = "buy"
|
||||
trade.open_order_id = "open_order_noop"
|
||||
trade.nr_of_successful_entries = 0
|
||||
trade.amount = 100
|
||||
trade = mock_trade_usdt_4(fee, is_short)
|
||||
Trade.query.session.add(trade)
|
||||
Trade.commit()
|
||||
l_order['filled'] = 0.0
|
||||
l_order['status'] = 'open'
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
@@ -3098,6 +3095,9 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
|
||||
|
||||
cancel_order_mock.reset_mock()
|
||||
l_order['filled'] = 1.0
|
||||
order = deepcopy(l_order)
|
||||
order['status'] = 'canceled'
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
|
||||
assert not freqtrade.handle_cancel_enter(trade, l_order, reason)
|
||||
assert cancel_order_mock.call_count == 1
|
||||
|
||||
@@ -3111,6 +3111,9 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
cancel_order=cancel_order_mock,
|
||||
)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_rate', return_value=0.245441)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_min_pair_stake_amount', return_value=0.2)
|
||||
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_order_fee')
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
|
||||
@@ -3175,10 +3178,13 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
assert send_msg_mock.call_count == 1
|
||||
assert trade.close_rate is None
|
||||
assert trade.exit_reason is None
|
||||
assert trade.open_order_id is None
|
||||
|
||||
send_msg_mock.reset_mock()
|
||||
|
||||
# Partial exit - below exit threshold
|
||||
order['amount'] = 2
|
||||
order['filled'] = 1.9
|
||||
assert not freqtrade.handle_cancel_exit(trade, order, reason)
|
||||
# Assert cancel_order was not called (callcount remains unchanged)
|
||||
assert cancel_order_mock.call_count == 1
|
||||
@@ -3188,12 +3194,21 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
|
||||
assert not freqtrade.handle_cancel_exit(trade, order, reason)
|
||||
|
||||
send_msg_mock.call_args_list[0][0][0]['reason'] = CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
|
||||
assert (send_msg_mock.call_args_list[0][0][0]['reason']
|
||||
== CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'])
|
||||
|
||||
# Message should not be iterated again
|
||||
assert trade.exit_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
|
||||
assert send_msg_mock.call_count == 1
|
||||
|
||||
send_msg_mock.reset_mock()
|
||||
|
||||
order['filled'] = 1
|
||||
assert freqtrade.handle_cancel_exit(trade, order, reason)
|
||||
assert send_msg_mock.call_count == 1
|
||||
assert (send_msg_mock.call_args_list[0][0][0]['reason']
|
||||
== CANCEL_REASON['PARTIALLY_FILLED'])
|
||||
|
||||
|
||||
def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
@@ -3204,6 +3219,7 @@ def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None:
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
|
||||
# TODO: should not be magicmock
|
||||
trade = MagicMock()
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
order = {'remaining': 1,
|
||||
|
@@ -351,8 +351,13 @@ def test_dca_short(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.nr_of_successful_exits == 1
|
||||
|
||||
|
||||
def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
@pytest.mark.parametrize('leverage', [
|
||||
1, 2
|
||||
])
|
||||
def test_dca_order_adjust(default_conf_usdt, ticker_usdt, leverage, fee, mocker) -> None:
|
||||
default_conf_usdt['position_adjustment_enable'] = True
|
||||
default_conf_usdt['trading_mode'] = 'futures'
|
||||
default_conf_usdt['margin_mode'] = 'isolated'
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
mocker.patch.multiple(
|
||||
@@ -363,9 +368,14 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
price_to_precision=lambda s, x, y: y,
|
||||
)
|
||||
mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=False)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_leverage", return_value=10)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_funding_fees", return_value=0)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_maintenance_ratio_and_amt", return_value=(0, 0))
|
||||
|
||||
patch_get_signal(freqtrade)
|
||||
freqtrade.strategy.custom_entry_price = lambda **kwargs: ticker_usdt['ask'] * 0.96
|
||||
freqtrade.strategy.leverage = MagicMock(return_value=leverage)
|
||||
freqtrade.strategy.minimal_roi = {0: 0.2}
|
||||
|
||||
freqtrade.enter_positions()
|
||||
|
||||
@@ -377,6 +387,8 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_rate == 1.96
|
||||
assert trade.stop_loss_pct is None
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.leverage == leverage
|
||||
assert trade.stake_amount == 60
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.initial_stop_loss_pct is None
|
||||
# No adjustment
|
||||
@@ -396,6 +408,7 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_rate == 1.96
|
||||
assert trade.stop_loss_pct is None
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.stake_amount == 60
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.initial_stop_loss_pct is None
|
||||
|
||||
@@ -407,9 +420,10 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_order_id is None
|
||||
# Open rate is not adjusted yet
|
||||
assert trade.open_rate == 1.99
|
||||
assert trade.stake_amount == 60
|
||||
assert trade.stop_loss_pct == -0.1
|
||||
assert trade.stop_loss == 1.99 * 0.9
|
||||
assert trade.initial_stop_loss == 1.99 * 0.9
|
||||
assert pytest.approx(trade.stop_loss) == 1.99 * (1 - 0.1 / leverage)
|
||||
assert pytest.approx(trade.initial_stop_loss) == 1.99 * (1 - 0.1 / leverage)
|
||||
assert trade.initial_stop_loss_pct == -0.1
|
||||
|
||||
# 2nd order - not filling
|
||||
@@ -422,7 +436,7 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_order_id is not None
|
||||
assert trade.open_rate == 1.99
|
||||
assert trade.orders[-1].price == 1.96
|
||||
assert trade.orders[-1].cost == 120
|
||||
assert trade.orders[-1].cost == 120 * leverage
|
||||
|
||||
# Replace new order with diff. order at a lower price
|
||||
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1.95)
|
||||
@@ -432,8 +446,9 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert len(trade.orders) == 4
|
||||
assert trade.open_order_id is not None
|
||||
assert trade.open_rate == 1.99
|
||||
assert trade.stake_amount == 60
|
||||
assert trade.orders[-1].price == 1.95
|
||||
assert pytest.approx(trade.orders[-1].cost) == 120
|
||||
assert pytest.approx(trade.orders[-1].cost) == 120 * leverage
|
||||
|
||||
# Fill DCA order
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=None)
|
||||
@@ -446,13 +461,13 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert trade.open_order_id is None
|
||||
assert pytest.approx(trade.open_rate) == 1.963153456
|
||||
assert trade.orders[-1].price == 1.95
|
||||
assert pytest.approx(trade.orders[-1].cost) == 120
|
||||
assert pytest.approx(trade.orders[-1].cost) == 120 * leverage
|
||||
assert trade.orders[-1].status == 'closed'
|
||||
|
||||
assert pytest.approx(trade.amount) == 91.689215
|
||||
assert pytest.approx(trade.amount) == 91.689215 * leverage
|
||||
# Check the 2 filled orders equal the above amount
|
||||
assert pytest.approx(trade.orders[1].amount) == 30.150753768
|
||||
assert pytest.approx(trade.orders[-1].amount) == 61.538461232
|
||||
assert pytest.approx(trade.orders[1].amount) == 30.150753768 * leverage
|
||||
assert pytest.approx(trade.orders[-1].amount) == 61.538461232 * leverage
|
||||
|
||||
|
||||
@pytest.mark.parametrize('leverage', [1, 2])
|
||||
|
@@ -63,7 +63,7 @@ def test_init_plotscript(default_conf, mocker, testdatadir):
|
||||
|
||||
def test_add_indicators(default_conf, testdatadir, caplog):
|
||||
pair = "UNITTEST/BTC"
|
||||
timerange = TimeRange(None, 'line', 0, -1000)
|
||||
timerange = TimeRange()
|
||||
|
||||
data = history.load_pair_history(pair=pair, timeframe='1m',
|
||||
datadir=testdatadir, timerange=timerange)
|
||||
|
Reference in New Issue
Block a user