Merge branch 'develop' into pr/mkavinkumar1/6545
This commit is contained in:
@@ -112,11 +112,8 @@ def patch_exchange(
|
||||
mock_supported_modes=True
|
||||
) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock(return_value={}))
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_config', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
|
||||
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.precisionMode', PropertyMock(return_value=2))
|
||||
|
||||
@@ -153,6 +153,25 @@ class TestCCXTExchange():
|
||||
assert isinstance(markets[pair], dict)
|
||||
assert exchange.market_is_spot(markets[pair])
|
||||
|
||||
def test_has_validations(self, exchange):
|
||||
|
||||
exchange, exchangename = exchange
|
||||
|
||||
exchange.validate_ordertypes({
|
||||
'entry': 'limit',
|
||||
'exit': 'limit',
|
||||
'stoploss': 'limit',
|
||||
})
|
||||
|
||||
if exchangename == 'gateio':
|
||||
# gateio doesn't have market orders on spot
|
||||
return
|
||||
exchange.validate_ordertypes({
|
||||
'entry': 'market',
|
||||
'exit': 'market',
|
||||
'stoploss': 'market',
|
||||
})
|
||||
|
||||
def test_load_markets_futures(self, exchange_futures):
|
||||
exchange, exchangename = exchange_futures
|
||||
if not exchange:
|
||||
|
||||
@@ -1078,10 +1078,9 @@ def test_validate_ordertypes(default_conf, mocker):
|
||||
'stoploss': 'market',
|
||||
'stoploss_on_exchange': False
|
||||
}
|
||||
# TODO: Revert once createMarketOrder is available again.
|
||||
# with pytest.raises(OperationalException,
|
||||
# match=r'Exchange .* does not support market orders.'):
|
||||
# Exchange(default_conf)
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'Exchange .* does not support market orders.'):
|
||||
Exchange(default_conf)
|
||||
|
||||
default_conf['order_types'] = {
|
||||
'entry': 'limit',
|
||||
@@ -1187,7 +1186,58 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverag
|
||||
assert order["symbol"] == "ETH/BTC"
|
||||
assert order["amount"] == 1
|
||||
assert order["leverage"] == leverage
|
||||
assert order["cost"] == 1 * 200 / leverage
|
||||
assert order["cost"] == 1 * 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize('side,is_short,order_reason', [
|
||||
("buy", False, "entry"),
|
||||
("sell", False, "exit"),
|
||||
("buy", True, "exit"),
|
||||
("sell", True, "entry"),
|
||||
])
|
||||
@pytest.mark.parametrize("order_type,price_side,fee", [
|
||||
("limit", "same", 1.0),
|
||||
("limit", "other", 2.0),
|
||||
("market", "same", 2.0),
|
||||
("market", "other", 2.0),
|
||||
])
|
||||
def test_create_dry_run_order_fees(
|
||||
default_conf,
|
||||
mocker,
|
||||
side,
|
||||
order_type,
|
||||
is_short,
|
||||
order_reason,
|
||||
price_side,
|
||||
fee,
|
||||
):
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_fee',
|
||||
side_effect=lambda symbol, taker_or_maker: 2.0 if taker_or_maker == 'taker' else 1.0
|
||||
)
|
||||
mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled',
|
||||
return_value=price_side == 'other')
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
|
||||
order = exchange.create_dry_run_order(
|
||||
pair='LTC/USDT',
|
||||
ordertype=order_type,
|
||||
side=side,
|
||||
amount=10,
|
||||
rate=2.0,
|
||||
leverage=1.0
|
||||
)
|
||||
if price_side == 'other' or order_type == 'market':
|
||||
assert order['fee']['rate'] == fee
|
||||
return
|
||||
else:
|
||||
assert order['fee'] is None
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled',
|
||||
return_value=price_side != 'other')
|
||||
|
||||
order1 = exchange.fetch_dry_run_order(order['id'])
|
||||
assert order1['fee']['rate'] == fee
|
||||
|
||||
|
||||
@pytest.mark.parametrize("side,startprice,endprice", [
|
||||
|
||||
@@ -53,6 +53,25 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker):
|
||||
assert fetch_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC'
|
||||
assert fetch_order_mock.call_args_list[0][1]['params'] == {'stop': True}
|
||||
|
||||
default_conf['trading_mode'] = 'futures'
|
||||
default_conf['margin_mode'] = 'isolated'
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id='gateio')
|
||||
|
||||
exchange.fetch_order = MagicMock(return_value={
|
||||
'status': 'closed',
|
||||
'id': '1234',
|
||||
'stopPrice': 5.62,
|
||||
'info': {
|
||||
'trade_id': '222555'
|
||||
}
|
||||
})
|
||||
|
||||
exchange.fetch_stoploss_order('1234', 'ETH/BTC')
|
||||
assert exchange.fetch_order.call_count == 2
|
||||
assert exchange.fetch_order.call_args_list[0][1]['order_id'] == '1234'
|
||||
assert exchange.fetch_order.call_args_list[1][1]['order_id'] == '222555'
|
||||
|
||||
|
||||
def test_cancel_stoploss_order_gateio(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id='gateio')
|
||||
|
||||
@@ -18,11 +18,11 @@ def hyperopt_conf(default_conf):
|
||||
'runmode': RunMode.HYPEROPT,
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'hyperopt_loss': 'ShortTradeDurHyperOptLoss',
|
||||
'hyperopt_path': str(Path(__file__).parent / 'hyperopts'),
|
||||
'epochs': 1,
|
||||
'timerange': None,
|
||||
'spaces': ['default'],
|
||||
'hyperopt_jobs': 1,
|
||||
'hyperopt_path': str(Path(__file__).parent / 'hyperopts'),
|
||||
'epochs': 1,
|
||||
'timerange': None,
|
||||
'spaces': ['default'],
|
||||
'hyperopt_jobs': 1,
|
||||
'hyperopt_min_trades': 1,
|
||||
})
|
||||
return hyperconf
|
||||
|
||||
@@ -90,28 +90,6 @@ def load_data_test(what, testdatadir):
|
||||
fill_missing=True)}
|
||||
|
||||
|
||||
def simple_backtest(config, contour, mocker, testdatadir) -> None:
|
||||
patch_exchange(mocker)
|
||||
config['timeframe'] = '1m'
|
||||
backtesting = Backtesting(config)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
|
||||
data = load_data_test(contour, testdatadir)
|
||||
processed = backtesting.strategy.advise_all_indicators(data)
|
||||
min_date, max_date = get_timerange(processed)
|
||||
assert isinstance(processed, dict)
|
||||
results = backtesting.backtest(
|
||||
processed=processed,
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
enable_protections=config.get('enable_protections', False),
|
||||
)
|
||||
# results :: <class 'pandas.core.frame.DataFrame'>
|
||||
return results
|
||||
|
||||
|
||||
# FIX: fixturize this?
|
||||
def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC'):
|
||||
data = history.load_data(datadir=datadir, timeframe='1m', pairs=[pair])
|
||||
@@ -942,6 +920,7 @@ def test_backtest_dataprovider_analyzed_df(default_conf, fee, mocker, testdatadi
|
||||
def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatadir) -> None:
|
||||
# While this test IS a copy of test_backtest_pricecontours, it's needed to ensure
|
||||
# results do not carry-over to the next run, which is not given by using parametrize.
|
||||
patch_exchange(mocker)
|
||||
default_conf['protections'] = [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
@@ -949,6 +928,7 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad
|
||||
}]
|
||||
|
||||
default_conf['enable_protections'] = True
|
||||
default_conf['timeframe'] = '1m'
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf'))
|
||||
@@ -959,12 +939,27 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad
|
||||
['sine', 9],
|
||||
['raise', 10],
|
||||
]
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
|
||||
# While entry-signals are unrealistic, running backtesting
|
||||
# over and over again should not cause different results
|
||||
for [contour, numres] in tests:
|
||||
# Debug output for random test failure
|
||||
print(f"{contour}, {numres}")
|
||||
assert len(simple_backtest(default_conf, contour, mocker, testdatadir)['results']) == numres
|
||||
data = load_data_test(contour, testdatadir)
|
||||
processed = backtesting.strategy.advise_all_indicators(data)
|
||||
min_date, max_date = get_timerange(processed)
|
||||
assert isinstance(processed, dict)
|
||||
results = backtesting.backtest(
|
||||
processed=processed,
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
enable_protections=default_conf.get('enable_protections', False),
|
||||
)
|
||||
assert len(results['results']) == numres
|
||||
|
||||
|
||||
@pytest.mark.parametrize('protections,contour,expected', [
|
||||
@@ -990,7 +985,25 @@ def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir,
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
# While entry-signals are unrealistic, running backtesting
|
||||
# over and over again should not cause different results
|
||||
assert len(simple_backtest(default_conf, contour, mocker, testdatadir)['results']) == expected
|
||||
|
||||
patch_exchange(mocker)
|
||||
default_conf['timeframe'] = '1m'
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
|
||||
data = load_data_test(contour, testdatadir)
|
||||
processed = backtesting.strategy.advise_all_indicators(data)
|
||||
min_date, max_date = get_timerange(processed)
|
||||
assert isinstance(processed, dict)
|
||||
results = backtesting.backtest(
|
||||
processed=processed,
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
enable_protections=default_conf.get('enable_protections', False),
|
||||
)
|
||||
assert len(results['results']) == expected
|
||||
|
||||
|
||||
def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# pragma pylint: disable=missing-docstring,W0212,C0103
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from unittest.mock import ANY, MagicMock
|
||||
from unittest.mock import ANY, MagicMock, PropertyMock
|
||||
|
||||
import pandas as pd
|
||||
import pytest
|
||||
@@ -18,8 +18,8 @@ from freqtrade.optimize.hyperopt_tools import HyperoptTools
|
||||
from freqtrade.optimize.optimize_reports import generate_strategy_stats
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.strategy import IntParameter
|
||||
from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has, log_has_re, patch_exchange,
|
||||
patched_configuration_load_config_file)
|
||||
from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, get_markets, log_has, log_has_re,
|
||||
patch_exchange, patched_configuration_load_config_file)
|
||||
|
||||
|
||||
def generate_result_metrics():
|
||||
@@ -855,7 +855,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'user_data_dir': Path(tmpdir),
|
||||
'hyperopt_random_state': 42,
|
||||
'spaces': ['all']
|
||||
'spaces': ['all'],
|
||||
})
|
||||
hyperopt = Hyperopt(hyperopt_conf)
|
||||
hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
|
||||
@@ -883,6 +883,45 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
hyperopt.get_optimizer([], 2)
|
||||
|
||||
|
||||
def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_config', MagicMock())
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
mocker.patch('freqtrade.exchange.Exchange._load_markets')
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets',
|
||||
PropertyMock(return_value=get_markets()))
|
||||
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
|
||||
# No hyperopt needed
|
||||
hyperopt_conf.update({
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'user_data_dir': Path(tmpdir),
|
||||
'hyperopt_random_state': 42,
|
||||
'spaces': ['all'],
|
||||
# Enforce parallelity
|
||||
'epochs': 2,
|
||||
'hyperopt_jobs': 2,
|
||||
'fee': fee.return_value,
|
||||
})
|
||||
hyperopt = Hyperopt(hyperopt_conf)
|
||||
hyperopt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0
|
||||
hyperopt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 1.0
|
||||
hyperopt.backtesting.exchange.get_max_pair_stake_amount = lambda *x, **xx: 100.0
|
||||
|
||||
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
|
||||
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
|
||||
assert hyperopt.backtesting.strategy.bot_loop_started is True
|
||||
|
||||
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
|
||||
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
|
||||
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
|
||||
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
|
||||
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
|
||||
assert isinstance(buy_rsi_range, range)
|
||||
# Range from 0 - 50 (inclusive)
|
||||
assert len(list(buy_rsi_range)) == 51
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
|
||||
def test_SKDecimal():
|
||||
space = SKDecimal(1, 2, decimals=2)
|
||||
assert 1.5 in space
|
||||
|
||||
@@ -1398,6 +1398,7 @@ def test_api_strategies(botclient):
|
||||
|
||||
assert rc.json() == {'strategies': [
|
||||
'HyperoptableStrategy',
|
||||
'HyperoptableStrategyV2',
|
||||
'InformativeDecoratorTest',
|
||||
'StrategyTestV2',
|
||||
'StrategyTestV3',
|
||||
|
||||
@@ -12,6 +12,7 @@ from unittest.mock import ANY, MagicMock
|
||||
|
||||
import arrow
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
from telegram import Chat, Message, ReplyKeyboardMarkup, Update
|
||||
from telegram.error import BadRequest, NetworkError, TelegramError
|
||||
|
||||
@@ -1661,8 +1662,17 @@ def test_show_config_handle(default_conf, update, mocker) -> None:
|
||||
(RPCMessageType.ENTRY, 'Long', 'long_signal_01', 1.0),
|
||||
(RPCMessageType.ENTRY, 'Long', 'long_signal_01', 5.0),
|
||||
(RPCMessageType.ENTRY, 'Short', 'short_signal_01', 2.0)])
|
||||
def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
|
||||
enter, enter_signal, leverage) -> None:
|
||||
def test_send_msg_enter_notification(default_conf, mocker, caplog, message_type,
|
||||
enter, enter_signal, leverage) -> None:
|
||||
default_conf['telegram']['notification_settings']['show_candle'] = 'ohlc'
|
||||
df = DataFrame({
|
||||
'open': [1.1],
|
||||
'high': [2.2],
|
||||
'low': [1.0],
|
||||
'close': [1.5],
|
||||
})
|
||||
mocker.patch('freqtrade.data.dataprovider.DataProvider.get_analyzed_dataframe',
|
||||
return_value=(df, 1))
|
||||
|
||||
msg = {
|
||||
'type': message_type,
|
||||
@@ -1680,6 +1690,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
|
||||
'fiat_currency': 'USD',
|
||||
'current_rate': 1.099e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'analyzed_candle': {'open': 1.1, 'high': 2.2, 'low': 1.0, 'close': 1.5},
|
||||
'open_date': arrow.utcnow().shift(hours=-1)
|
||||
}
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
@@ -1689,6 +1700,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
|
||||
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
f'\N{LARGE BLUE CIRCLE} *Binance (dry):* {enter} ETH/BTC (#1)\n'
|
||||
'*Candle OHLC*: `1.1, 2.2, 1.0, 1.5`\n'
|
||||
f'*Enter Tag:* `{enter_signal}`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
f'{leverage_text}'
|
||||
@@ -1716,7 +1728,8 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
|
||||
@pytest.mark.parametrize('message_type,enter_signal', [
|
||||
(RPCMessageType.ENTRY_CANCEL, 'long_signal_01'),
|
||||
(RPCMessageType.ENTRY_CANCEL, 'short_signal_01')])
|
||||
def test_send_msg_buy_cancel_notification(default_conf, mocker, message_type, enter_signal) -> None:
|
||||
def test_send_msg_enter_cancel_notification(
|
||||
default_conf, mocker, message_type, enter_signal) -> None:
|
||||
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
from pandas import DataFrame
|
||||
from strategy_test_v2 import StrategyTestV2
|
||||
from strategy_test_v3 import StrategyTestV3
|
||||
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter
|
||||
|
||||
|
||||
class HyperoptableStrategy(StrategyTestV2):
|
||||
class HyperoptableStrategy(StrategyTestV3):
|
||||
"""
|
||||
Default Strategy provided by freqtrade bot.
|
||||
Please do not modify this strategy, it's intended for internal use only.
|
||||
|
||||
54
tests/strategy/strats/hyperoptable_strategy_v2.py
Normal file
54
tests/strategy/strats/hyperoptable_strategy_v2.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
from strategy_test_v2 import StrategyTestV2
|
||||
|
||||
from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter
|
||||
|
||||
|
||||
class HyperoptableStrategyV2(StrategyTestV2):
|
||||
"""
|
||||
Default Strategy provided by freqtrade bot.
|
||||
Please do not modify this strategy, it's intended for internal use only.
|
||||
Please look at the SampleStrategy in the user_data/strategy directory
|
||||
or strategy repository https://github.com/freqtrade/freqtrade-strategies
|
||||
for samples and inspiration.
|
||||
"""
|
||||
|
||||
buy_params = {
|
||||
'buy_rsi': 35,
|
||||
# Intentionally not specified, so "default" is tested
|
||||
# 'buy_plusdi': 0.4
|
||||
}
|
||||
|
||||
sell_params = {
|
||||
'sell_rsi': 74,
|
||||
'sell_minusdi': 0.4
|
||||
}
|
||||
|
||||
buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy')
|
||||
sell_rsi = IntParameter(low=50, high=100, default=70, space='sell')
|
||||
sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell',
|
||||
load=False)
|
||||
protection_enabled = BooleanParameter(default=True)
|
||||
protection_cooldown_lookback = IntParameter([0, 50], default=30)
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
prot = []
|
||||
if self.protection_enabled.value:
|
||||
prot.append({
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": self.protection_cooldown_lookback.value
|
||||
})
|
||||
return prot
|
||||
|
||||
bot_loop_started = False
|
||||
|
||||
def bot_loop_start(self):
|
||||
self.bot_loop_started = True
|
||||
|
||||
def bot_start(self, **kwargs) -> None:
|
||||
"""
|
||||
Parameters can also be defined here ...
|
||||
"""
|
||||
self.buy_rsi = IntParameter([0, 50], default=30, space='buy')
|
||||
@@ -916,7 +916,7 @@ def test_hyperopt_parameters():
|
||||
|
||||
|
||||
def test_auto_hyperopt_interface(default_conf):
|
||||
default_conf.update({'strategy': 'HyperoptableStrategy'})
|
||||
default_conf.update({'strategy': 'HyperoptableStrategyV2'})
|
||||
PairLocks.timeframe = default_conf['timeframe']
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
strategy.ft_bot_start()
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_search_all_strategies_no_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=False)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 6
|
||||
assert len(strategies) == 7
|
||||
assert isinstance(strategies[0], dict)
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ def test_search_all_strategies_with_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=True)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 7
|
||||
assert len(strategies) == 8
|
||||
# with enum_failed=True search_all_objects() shall find 2 good strategies
|
||||
# and 1 which fails to load
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 6
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 7
|
||||
assert len([x for x in strategies if x['class'] is None]) == 1
|
||||
|
||||
|
||||
|
||||
@@ -2059,8 +2059,9 @@ def test_update_trade_state_orderexception(mocker, default_conf_usdt, caplog) ->
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_update_trade_state_sell(
|
||||
default_conf_usdt, trades_for_order, limit_order_open, limit_order, is_short, mocker,
|
||||
default_conf_usdt, trades_for_order, limit_order_open, limit_order, is_short, mocker
|
||||
):
|
||||
buy_order = limit_order[entry_side(is_short)]
|
||||
open_order = limit_order_open[exit_side(is_short)]
|
||||
l_order = limit_order[exit_side(is_short)]
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||
@@ -2087,6 +2088,9 @@ def test_update_trade_state_sell(
|
||||
leverage=1,
|
||||
is_short=is_short,
|
||||
)
|
||||
order = Order.parse_from_ccxt_object(buy_order, 'LTC/ETH', entry_side(is_short))
|
||||
trade.orders.append(order)
|
||||
|
||||
order = Order.parse_from_ccxt_object(open_order, 'LTC/ETH', exit_side(is_short))
|
||||
trade.orders.append(order)
|
||||
assert order.status == 'open'
|
||||
@@ -2790,6 +2794,7 @@ def test_manage_open_orders_partial(
|
||||
rpc_mock = patch_RPCManager(mocker)
|
||||
open_trade.is_short = is_short
|
||||
open_trade.leverage = leverage
|
||||
open_trade.orders[0].ft_order_side = 'sell' if is_short else 'buy'
|
||||
limit_buy_order_old_partial['id'] = open_trade.open_order_id
|
||||
limit_buy_order_old_partial['side'] = 'sell' if is_short else 'buy'
|
||||
limit_buy_canceled = deepcopy(limit_buy_order_old_partial)
|
||||
@@ -2875,6 +2880,7 @@ def test_manage_open_orders_partial_except(
|
||||
limit_buy_order_old_partial_canceled, mocker
|
||||
) -> None:
|
||||
open_trade.is_short = is_short
|
||||
open_trade.orders[0].ft_order_side = 'sell' if is_short else 'buy'
|
||||
rpc_mock = patch_RPCManager(mocker)
|
||||
limit_buy_order_old_partial_canceled['id'] = open_trade.open_order_id
|
||||
limit_buy_order_old_partial['id'] = open_trade.open_order_id
|
||||
@@ -3638,7 +3644,7 @@ def test_execute_trade_exit_market_order(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt,
|
||||
get_fee=fee,
|
||||
_is_dry_limit_order_filled=MagicMock(return_value=False),
|
||||
_is_dry_limit_order_filled=MagicMock(return_value=True),
|
||||
)
|
||||
patch_whitelist(mocker, default_conf_usdt)
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
@@ -3654,7 +3660,8 @@ def test_execute_trade_exit_market_order(
|
||||
# Increase the price and sell it
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt_sell_up
|
||||
fetch_ticker=ticker_usdt_sell_up,
|
||||
_is_dry_limit_order_filled=MagicMock(return_value=False),
|
||||
)
|
||||
freqtrade.config['order_types']['exit'] = 'market'
|
||||
|
||||
@@ -3667,7 +3674,7 @@ def test_execute_trade_exit_market_order(
|
||||
assert not trade.is_open
|
||||
assert trade.close_profit == profit_ratio
|
||||
|
||||
assert rpc_mock.call_count == 3
|
||||
assert rpc_mock.call_count == 4
|
||||
last_msg = rpc_mock.call_args_list[-2][0][0]
|
||||
assert {
|
||||
'type': RPCMessageType.EXIT,
|
||||
|
||||
@@ -72,7 +72,7 @@ def test_add_indicators(default_conf, testdatadir, caplog):
|
||||
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
# Generate buy/sell signals and indicators
|
||||
# Generate entry/exit signals and indicators
|
||||
data = strategy.analyze_ticker(data, {'pair': pair})
|
||||
fig = generate_empty_figure()
|
||||
|
||||
@@ -113,7 +113,7 @@ def test_add_areas(default_conf, testdatadir, caplog):
|
||||
ind_plain = {"macd": {"fill_to": "macdhist"}}
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
# Generate buy/sell signals and indicators
|
||||
# Generate entry/exit signals and indicators
|
||||
data = strategy.analyze_ticker(data, {'pair': pair})
|
||||
fig = generate_empty_figure()
|
||||
|
||||
@@ -165,24 +165,24 @@ def test_plot_trades(testdatadir, caplog):
|
||||
fig = plot_trades(fig, trades)
|
||||
figure = fig1.layout.figure
|
||||
|
||||
# Check buys - color, should be in first graph, ...
|
||||
trade_buy = find_trace_in_fig_data(figure.data, 'Trade buy')
|
||||
assert isinstance(trade_buy, go.Scatter)
|
||||
assert trade_buy.yaxis == 'y'
|
||||
assert len(trades) == len(trade_buy.x)
|
||||
assert trade_buy.marker.color == 'cyan'
|
||||
assert trade_buy.marker.symbol == 'circle-open'
|
||||
assert trade_buy.text[0] == '3.99%, buy_tag, roi, 15 min'
|
||||
# Check entry - color, should be in first graph, ...
|
||||
trade_entries = find_trace_in_fig_data(figure.data, 'Trade entry')
|
||||
assert isinstance(trade_entries, go.Scatter)
|
||||
assert trade_entries.yaxis == 'y'
|
||||
assert len(trades) == len(trade_entries.x)
|
||||
assert trade_entries.marker.color == 'cyan'
|
||||
assert trade_entries.marker.symbol == 'circle-open'
|
||||
assert trade_entries.text[0] == '3.99%, buy_tag, roi, 15 min'
|
||||
|
||||
trade_sell = find_trace_in_fig_data(figure.data, 'Sell - Profit')
|
||||
assert isinstance(trade_sell, go.Scatter)
|
||||
assert trade_sell.yaxis == 'y'
|
||||
assert len(trades.loc[trades['profit_ratio'] > 0]) == len(trade_sell.x)
|
||||
assert trade_sell.marker.color == 'green'
|
||||
assert trade_sell.marker.symbol == 'square-open'
|
||||
assert trade_sell.text[0] == '3.99%, buy_tag, roi, 15 min'
|
||||
trade_exit = find_trace_in_fig_data(figure.data, 'Exit - Profit')
|
||||
assert isinstance(trade_exit, go.Scatter)
|
||||
assert trade_exit.yaxis == 'y'
|
||||
assert len(trades.loc[trades['profit_ratio'] > 0]) == len(trade_exit.x)
|
||||
assert trade_exit.marker.color == 'green'
|
||||
assert trade_exit.marker.symbol == 'square-open'
|
||||
assert trade_exit.text[0] == '3.99%, buy_tag, roi, 15 min'
|
||||
|
||||
trade_sell_loss = find_trace_in_fig_data(figure.data, 'Sell - Loss')
|
||||
trade_sell_loss = find_trace_in_fig_data(figure.data, 'Exit - Loss')
|
||||
assert isinstance(trade_sell_loss, go.Scatter)
|
||||
assert trade_sell_loss.yaxis == 'y'
|
||||
assert len(trades.loc[trades['profit_ratio'] <= 0]) == len(trade_sell_loss.x)
|
||||
|
||||
Reference in New Issue
Block a user