Merge branch 'develop' into pr/cyberjunky/6615

This commit is contained in:
Matthias
2022-04-08 18:05:27 +02:00
86 changed files with 1353 additions and 1157 deletions

View File

@@ -826,8 +826,9 @@ def test_download_data_trades(mocker, caplog):
]
with pytest.raises(OperationalException,
match="Trade download not supported for futures."):
start_download_data(get_args(args))
pargs = get_args(args)
pargs['config'] = None
start_download_data(pargs)
def test_start_convert_trades(mocker, caplog):

View File

@@ -87,7 +87,7 @@ def get_mock_coro(return_value):
def patched_configuration_load_config_file(mocker, config) -> None:
mocker.patch(
'freqtrade.configuration.configuration.load_config_file',
'freqtrade.configuration.load_config.load_config_file',
lambda *args, **kwargs: config
)

View File

@@ -6,7 +6,7 @@ from freqtrade.persistence.models import Order, Trade
MOCK_TRADE_COUNT = 6
def enter_side(is_short: bool):
def entry_side(is_short: bool):
return "sell" if is_short else "buy"
@@ -23,7 +23,7 @@ def mock_order_1(is_short: bool):
'id': f'1234_{direc(is_short)}',
'symbol': 'ETH/BTC',
'status': 'closed',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.123,
'average': 0.123,
@@ -50,7 +50,7 @@ def mock_trade_1(fee, is_short: bool):
timeframe=5,
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_1(is_short), 'ETH/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_1(is_short), 'ETH/BTC', entry_side(is_short))
trade.orders.append(o)
return trade
@@ -60,7 +60,7 @@ def mock_order_2(is_short: bool):
'id': f'1235_{direc(is_short)}',
'symbol': 'ETC/BTC',
'status': 'closed',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.123,
'amount': 123.0,
@@ -104,12 +104,12 @@ def mock_trade_2(fee, is_short: bool):
strategy='StrategyTestV3',
timeframe=5,
enter_tag='TEST1',
sell_reason='sell_signal',
exit_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_2(is_short), 'ETC/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_2(is_short), 'ETC/BTC', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_2_sell(is_short), 'ETC/BTC', exit_side(is_short))
trade.orders.append(o)
@@ -121,7 +121,7 @@ def mock_order_3(is_short: bool):
'id': f'41231a12a_{direc(is_short)}',
'symbol': 'XRP/BTC',
'status': 'closed',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.05,
'amount': 123.0,
@@ -164,12 +164,12 @@ def mock_trade_3(fee, is_short: bool):
is_open=False,
strategy='StrategyTestV3',
timeframe=5,
sell_reason='roi',
exit_reason='roi',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc),
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_3(is_short), 'XRP/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_3(is_short), 'XRP/BTC', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_3_sell(is_short), 'XRP/BTC', exit_side(is_short))
trade.orders.append(o)
@@ -181,7 +181,7 @@ def mock_order_4(is_short: bool):
'id': f'prod_buy_{direc(is_short)}_12345',
'symbol': 'ETC/BTC',
'status': 'open',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.123,
'amount': 123.0,
@@ -210,7 +210,7 @@ def mock_trade_4(fee, is_short: bool):
timeframe=5,
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_4(is_short), 'ETC/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_4(is_short), 'ETC/BTC', entry_side(is_short))
trade.orders.append(o)
return trade
@@ -220,7 +220,7 @@ def mock_order_5(is_short: bool):
'id': f'prod_buy_{direc(is_short)}_3455',
'symbol': 'XRP/BTC',
'status': 'closed',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.123,
'amount': 123.0,
@@ -264,7 +264,7 @@ def mock_trade_5(fee, is_short: bool):
timeframe=5,
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_5(is_short), 'XRP/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_5(is_short), 'XRP/BTC', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_5_stoploss(is_short), 'XRP/BTC', 'stoploss')
trade.orders.append(o)
@@ -276,7 +276,7 @@ def mock_order_6(is_short: bool):
'id': f'prod_buy_{direc(is_short)}_6',
'symbol': 'LTC/BTC',
'status': 'closed',
'side': enter_side(is_short),
'side': entry_side(is_short),
'type': 'limit',
'price': 0.15,
'amount': 2.0,
@@ -320,7 +320,7 @@ def mock_trade_6(fee, is_short: bool):
timeframe=5,
is_short=is_short
)
o = Order.parse_from_ccxt_object(mock_order_6(is_short), 'LTC/BTC', enter_side(is_short))
o = Order.parse_from_ccxt_object(mock_order_6(is_short), 'LTC/BTC', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_6_sell(is_short), 'LTC/BTC', exit_side(is_short))
trade.orders.append(o)
@@ -401,7 +401,7 @@ def short_trade(fee):
open_order_id='dry_run_exit_short_12345',
strategy='DefaultStrategy',
timeframe=5,
sell_reason='sell_signal',
exit_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
# close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
is_short=True
@@ -490,7 +490,7 @@ def leverage_trade(fee):
open_order_id='dry_run_leverage_buy_12368',
strategy='DefaultStrategy',
timeframe=5,
sell_reason='sell_signal',
exit_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300),
close_date=datetime.now(tz=timezone.utc),
interest_rate=0.0005

View File

@@ -89,7 +89,7 @@ def mock_trade_usdt_2(fee):
open_order_id='dry_run_sell_12345',
strategy='StrategyTestV2',
timeframe=5,
sell_reason='sell_signal',
exit_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
)
@@ -148,7 +148,7 @@ def mock_trade_usdt_3(fee):
is_open=False,
strategy='StrategyTestV2',
timeframe=5,
sell_reason='roi',
exit_reason='roi',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc),
)

View File

@@ -95,8 +95,8 @@ tc1 = BTContainer(data=[
[6, 5000, 5025, 4975, 4987, 6172, 0, 0], # should sell
],
stop_loss=-0.99, roi={"0": float('inf')}, profit_perc=0.00,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=2),
BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=4, close_tick=6)]
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=2),
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=4, close_tick=6)]
)
# 3) Entered, sl 1%, candle drops 8% => Trade closed, 1% loss
@@ -107,7 +107,7 @@ tc2 = BTContainer(data=[
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
],
stop_loss=-0.01, roi={"0": float('inf')}, profit_perc=-0.01,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
)
# 4) Entered, sl 3 %, candle drops 4%, recovers to 1 % = > Trade closed, 3 % loss
@@ -118,7 +118,7 @@ tc3 = BTContainer(data=[
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
],
stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
)
# 5) Stoploss and sell are hit. should sell on stoploss
@@ -129,7 +129,7 @@ tc4 = BTContainer(data=[
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
],
stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
)
TESTS = [
@@ -162,7 +162,7 @@ def test_edge_results(edge_conf, mocker, caplog, data) -> None:
for c, trade in enumerate(data.trades):
res = results.iloc[c]
assert res.exit_type == trade.sell_reason
assert res.exit_type == trade.exit_reason
assert res.open_date == _get_frame_time_from_offset(trade.open_tick).replace(tzinfo=None)
assert res.close_date == _get_frame_time_from_offset(trade.close_tick).replace(tzinfo=None)
@@ -391,7 +391,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
'trade_duration': '',
'open_rate': 17,
'close_rate': 17,
'exit_type': 'sell_signal'},
'exit_type': 'exit_signal'},
{'pair': 'TEST/BTC',
'stoploss': -0.9,
@@ -402,7 +402,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
'trade_duration': '',
'open_rate': 20,
'close_rate': 20,
'exit_type': 'sell_signal'},
'exit_type': 'exit_signal'},
{'pair': 'TEST/BTC',
'stoploss': -0.9,
@@ -413,7 +413,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
'trade_duration': '',
'open_rate': 26,
'close_rate': 34,
'exit_type': 'sell_signal'}
'exit_type': 'exit_signal'}
]
trades_df = DataFrame(trades)

View File

@@ -2130,7 +2130,8 @@ async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog):
"kucoin GET https://openapi-v2.kucoin.com/api/v1/market/candles?"
"symbol=ETH-BTC&type=5min&startAt=1640268735&endAt=1640418735"
"429 Too Many Requests" '{"code":"429000","msg":"Too Many Requests"}'))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kucoin")
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="KuCoin")
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='KuCoin'))
msg = "Kucoin 429 error, avoid triggering DDosProtection backoff delay"
assert not num_log_has_re(msg, caplog)

View File

@@ -15,7 +15,7 @@ class BTrade(NamedTuple):
"""
Minimalistic Trade result used for functional backtesting
"""
sell_reason: ExitType
exit_reason: ExitType
open_tick: int
close_tick: int
enter_tag: Optional[str] = None
@@ -35,7 +35,7 @@ class BTContainer(NamedTuple):
trailing_only_offset_is_reached: bool = False
trailing_stop_positive: Optional[float] = None
trailing_stop_positive_offset: float = 0.0
use_sell_signal: bool = False
use_exit_signal: bool = False
use_custom_stoploss: bool = False
custom_entry_price: Optional[float] = None
custom_exit_price: Optional[float] = None

View File

@@ -44,7 +44,7 @@ def hyperopt_results():
'profit_abs': [-0.2, 0.4, -0.2, 0.6],
'trade_duration': [10, 30, 10, 10],
'amount': [0.1, 0.1, 0.1, 0.1],
'sell_reason': [ExitType.STOP_LOSS, ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI],
'exit_reason': [ExitType.STOP_LOSS, ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI],
'open_date':
[
datetime(2019, 1, 1, 9, 15, 0),

View File

@@ -22,8 +22,8 @@ tc0 = BTContainer(data=[
[3, 5010, 5010, 4980, 5010, 6172, 0, 1],
[4, 5010, 5011, 4977, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_sell_signal=True,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_exit_signal=True,
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 1: Stop-Loss Triggered 1% loss
@@ -37,7 +37,7 @@ tc1 = BTContainer(data=[
[4, 4977, 4995, 4977, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
)
@@ -52,7 +52,7 @@ tc2 = BTContainer(data=[
[4, 4962, 4987, 4937, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.03, roi={"0": 1}, profit_perc=-0.03,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)]
)
@@ -72,8 +72,8 @@ tc3 = BTContainer(data=[
[5, 4962, 4987, 4000, 4000, 6172, 0, 0], # exit with stoploss hit
[6, 4950, 4975, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.02, roi={"0": 1}, profit_perc=-0.04,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2),
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=4, close_tick=5)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2),
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=4, close_tick=5)]
)
# Test 4: Minus 3% / recovery +15%
@@ -89,7 +89,7 @@ tc4 = BTContainer(data=[
[4, 4962, 4987, 4937, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.02, roi={"0": 0.06}, profit_perc=-0.02,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 5: Drops 0.5% Closes +20%, ROI triggers 3% Gain
@@ -103,7 +103,7 @@ tc5 = BTContainer(data=[
[4, 4962, 4987, 4962, 4972, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 0.03}, profit_perc=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 6: Drops 3% / Recovers 6% Positive / Closes 1% positve, Stop-Loss triggers 2% Loss
@@ -117,7 +117,7 @@ tc6 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.02, roi={"0": 0.05}, profit_perc=-0.02,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 7: 6% Positive / 1% Negative / Close 1% Positve, ROI Triggers 3% Gain
@@ -131,7 +131,7 @@ tc7 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.02, roi={"0": 0.03}, profit_perc=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
@@ -145,7 +145,7 @@ tc8 = BTContainer(data=[
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.055, trailing_stop=True,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
@@ -159,7 +159,7 @@ tc9 = BTContainer(data=[
[3, 5000, 5200, 4550, 4850, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.064, trailing_stop=True,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 10: trailing_stop should raise so candle 3 causes a stoploss
@@ -175,7 +175,7 @@ tc10 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.1, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.10,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=4)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=4)]
)
# Test 11: trailing_stop should raise so candle 3 causes a stoploss
@@ -191,7 +191,7 @@ tc11 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.019, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 12: trailing_stop should raise in candle 2 and cause a stoploss in the same candle
@@ -207,7 +207,7 @@ tc12 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.019, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 13: Buy and sell ROI on same candle
@@ -220,7 +220,7 @@ tc13 = BTContainer(data=[
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
[4, 4750, 4950, 4750, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1)]
)
# Test 14 - Buy and Stoploss on same candle
@@ -233,7 +233,7 @@ tc14 = BTContainer(data=[
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.05, roi={"0": 0.10}, profit_perc=-0.05,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
)
@@ -247,8 +247,8 @@ tc15 = BTContainer(data=[
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.05, roi={"0": 0.01}, profit_perc=-0.04,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1),
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1),
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)]
)
# Test 16: Buy, hold for 65 min, then forcesell using roi=-1
@@ -263,7 +263,7 @@ tc16 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "65": -1}, profit_perc=-0.012,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 17: Buy, hold for 120 mins, then forcesell using roi=-1
@@ -279,7 +279,7 @@ tc17 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": -1}, profit_perc=-0.004,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
@@ -295,7 +295,7 @@ tc18 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.04,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 19: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
@@ -310,7 +310,7 @@ tc19 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4550, 4975, 4550, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.01,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 20: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
@@ -325,7 +325,7 @@ tc20 = BTContainer(data=[
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4925, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "119": 0.01}, profit_perc=0.01,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 21: trailing_stop ROI collision.
@@ -342,7 +342,7 @@ tc21 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
# Test 22: trailing_stop Raises in candle 2 - but ROI applies at the same time.
@@ -358,7 +358,7 @@ tc22 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
@@ -375,7 +375,7 @@ tc23 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=True)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=True)]
)
# Test 24: trailing_stop Raises in candle 2 (does not trigger)
@@ -394,7 +394,7 @@ tc24 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.1, "119": 0.03}, profit_perc=0.03, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 25: Sell with signal sell in candle 3 (stoploss also triggers on this candle)
@@ -408,8 +408,8 @@ tc25 = BTContainer(data=[
[3, 5010, 5010, 4855, 5010, 6172, 0, 1], # Triggers stoploss + sellsignal
[4, 5010, 5010, 4977, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01, use_sell_signal=True,
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)]
stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01, use_exit_signal=True,
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 26: Sell with signal sell in candle 3 (stoploss also triggers on this candle)
@@ -423,8 +423,8 @@ tc26 = BTContainer(data=[
[3, 5010, 5010, 4986, 5010, 6172, 0, 1],
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_sell_signal=True,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_exit_signal=True,
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 27: (copy of test26 with leverage)
@@ -439,9 +439,9 @@ tc27 = BTContainer(data=[
[3, 5010, 5010, 4986, 5010, 6172, 0, 1],
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True,
stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_exit_signal=True,
leverage=5.0,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 28: (copy of test26 with leverage and as short)
@@ -456,9 +456,9 @@ tc28 = BTContainer(data=[
[3, 5010, 5010, 4986, 5010, 6172, 0, 0, 0, 1],
[4, 4990, 5010, 4855, 4995, 6172, 0, 0, 0, 0], # Triggers stoploss + sellsignal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0, 0, 0]],
stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True,
stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_exit_signal=True,
leverage=5.0,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4, is_short=True)]
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)]
)
# Test 29: Sell with signal sell in candle 3 (ROI at signal candle)
# Stoploss at 10% (irrelevant), ROI at 5% (will trigger)
@@ -471,8 +471,8 @@ tc29 = BTContainer(data=[
[3, 5010, 5251, 4986, 5010, 6172, 0, 1], # Triggers ROI, sell-signal
[4, 5010, 5010, 4855, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.05, use_sell_signal=True,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.05, use_exit_signal=True,
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 30: Sell with signal sell in candle 3 (ROI at signal candle)
@@ -485,8 +485,8 @@ tc30 = BTContainer(data=[
[3, 5010, 5012, 4986, 5010, 6172, 0, 1], # sell-signal
[4, 5010, 5251, 4855, 4995, 6172, 0, 0], # Triggers ROI, sell-signal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.002, use_sell_signal=True,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.002, use_exit_signal=True,
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 31: trailing_stop should raise so candle 3 causes a stoploss
@@ -503,7 +503,7 @@ tc31 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.03, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 32: (Short of test 31) trailing_stop should raise so candle 3 causes a stoploss
@@ -521,7 +521,7 @@ tc32 = BTContainer(data=[
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[
BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True)
BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True)
]
)
@@ -537,7 +537,7 @@ tc33 = BTContainer(data=[
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.02, trailing_stop=True,
trailing_stop_positive=0.03,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 34: trailing_stop should be triggered immediately on trade open candle.
@@ -551,7 +551,7 @@ tc34 = BTContainer(data=[
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
trailing_stop_positive=0.01,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 35: trailing_stop should be triggered immediately on trade open candle.
@@ -566,7 +566,7 @@ tc35 = BTContainer(data=[
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.01, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 36: trailing_stop should be triggered immediately on trade open candle.
@@ -581,7 +581,7 @@ tc36 = BTContainer(data=[
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01, use_custom_stoploss=True,
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 37: trailing_stop should be triggered immediately on trade open candle.
@@ -597,7 +597,7 @@ tc37 = BTContainer(data=[
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01, use_custom_stoploss=True,
trades=[BTrade(
sell_reason=ExitType.TRAILING_STOP_LOSS,
exit_reason=ExitType.TRAILING_STOP_LOSS,
open_tick=1,
close_tick=1,
enter_tag='buy_signal_01'
@@ -617,7 +617,7 @@ tc38 = BTContainer(data=[
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01, use_custom_stoploss=True,
trades=[BTrade(
sell_reason=ExitType.TRAILING_STOP_LOSS,
exit_reason=ExitType.TRAILING_STOP_LOSS,
open_tick=1,
close_tick=1,
enter_tag='short_signal_01',
@@ -647,7 +647,7 @@ tc40 = BTContainer(data=[
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01,
custom_entry_price=7200, trades=[
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)
])
# Test 41: Custom-entry-price above all candles should have rate adjusted to "entry candle high"
@@ -661,7 +661,7 @@ tc41 = BTContainer(data=[
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01,
custom_entry_price=4000,
trades=[
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True)
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True)
]
)
@@ -678,7 +678,7 @@ tc42 = BTContainer(data=[
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01,
custom_entry_price=4952,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
# Test 43: Custom-entry-price around candle low
@@ -693,7 +693,7 @@ tc43 = BTContainer(data=[
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01,
custom_entry_price=4952,
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1)]
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1)]
)
# Test 44: Custom exit price below all candles
@@ -706,9 +706,9 @@ tc44 = BTContainer(data=[
[3, 5100, 5100, 4950, 4950, 6172, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01,
use_sell_signal=True,
use_exit_signal=True,
custom_exit_price=4552,
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=3)]
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=3)]
)
# Test 45: Custom exit price above all candles
@@ -721,9 +721,9 @@ tc45 = BTContainer(data=[
[3, 5100, 5100, 4950, 4950, 6172, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.0,
use_sell_signal=True,
use_exit_signal=True,
custom_exit_price=6052,
trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4)]
trades=[BTrade(exit_reason=ExitType.FORCE_EXIT, open_tick=1, close_tick=4)]
)
# Test 46: (Short of tc45) Custom short exit price above below candles
@@ -736,9 +736,9 @@ tc46 = BTContainer(data=[
[3, 5100, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.0,
use_sell_signal=True,
use_exit_signal=True,
custom_exit_price=4700,
trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4, is_short=True)]
trades=[BTrade(exit_reason=ExitType.FORCE_EXIT, open_tick=1, close_tick=4, is_short=True)]
)
# Test 47: Colliding long and short signal
@@ -750,7 +750,7 @@ tc47 = BTContainer(data=[
[3, 5100, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.0,
use_sell_signal=True,
use_exit_signal=True,
trades=[]
)
@@ -808,7 +808,7 @@ TESTS = [
@pytest.mark.parametrize("data", TESTS)
def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) -> None:
"""
run functional tests
"""
@@ -821,7 +821,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
if data.trailing_stop_positive is not None:
default_conf["trailing_stop_positive"] = data.trailing_stop_positive
default_conf["trailing_stop_positive_offset"] = data.trailing_stop_positive_offset
default_conf["use_sell_signal"] = data.use_sell_signal
default_conf["use_exit_signal"] = data.use_exit_signal
mocker.patch("freqtrade.exchange.Exchange.get_fee", return_value=0.0)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
@@ -861,7 +861,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
for c, trade in enumerate(data.trades):
res: BTrade = results.iloc[c]
assert res.sell_reason == trade.sell_reason.value
assert res.exit_reason == trade.exit_reason.value
assert res.enter_tag == trade.enter_tag
assert res.open_date == _get_frame_time_from_offset(trade.open_tick)
assert res.close_date == _get_frame_time_from_offset(trade.close_tick)

View File

@@ -504,7 +504,7 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti
def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -563,7 +563,7 @@ def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None:
default_conf_usdt['use_sell_signal'] = False
default_conf_usdt['use_exit_signal'] = False
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'))
@@ -645,7 +645,7 @@ def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None:
def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -713,7 +713,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
# No data available.
res = backtesting._get_sell_trade_entry(trade, row_sell)
assert res is not None
assert res.sell_reason == ExitType.ROI.value
assert res.exit_reason == ExitType.ROI.value
assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc)
# Enter new trade
@@ -732,7 +732,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
res = backtesting._get_sell_trade_entry(trade, row_sell)
assert res is not None
assert res.sell_reason == ExitType.ROI.value
assert res.exit_reason == ExitType.ROI.value
# Sell at minute 3 (not available above!)
assert res.close_date_utc == datetime(2020, 1, 1, 5, 3, tzinfo=timezone.utc)
sell_order = res.select_order('sell', True)
@@ -740,7 +740,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -781,7 +781,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
'trade_duration': [235, 40],
'profit_ratio': [0.0, 0.0],
'profit_abs': [0.0, 0.0],
'sell_reason': [ExitType.ROI.value, ExitType.ROI.value],
'exit_reason': [ExitType.ROI.value, ExitType.ROI.value],
'initial_stop_loss_abs': [0.0940005, 0.09272236],
'initial_stop_loss_ratio': [-0.1, -0.1],
'stop_loss_abs': [0.0940005, 0.09272236],
@@ -807,7 +807,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -833,7 +833,7 @@ def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None
def test_backtest_trim_no_data_left(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -878,7 +878,7 @@ def test_processed(default_conf, mocker, testdatadir) -> None:
def test_backtest_dataprovider_analyzed_df(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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=100000)
@@ -1151,10 +1151,10 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
default_conf.update({
"use_sell_signal": True,
"sell_profit_only": False,
"sell_profit_offset": 0.0,
"ignore_roi_if_buy_signal": False,
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
})
patch_exchange(mocker)
backtestmock = MagicMock(return_value={
@@ -1178,7 +1178,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
text_table_bt_results=text_table_mock,
text_table_strategy=strattable_mock,
generate_pair_metrics=MagicMock(),
generate_sell_reason_stats=sell_reason_mock,
generate_exit_reason_stats=sell_reason_mock,
generate_strategy_comparison=strat_summary,
generate_daily_stats=MagicMock(),
)
@@ -1228,10 +1228,10 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
@pytest.mark.filterwarnings("ignore:deprecated")
def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdatadir, capsys):
default_conf.update({
"use_sell_signal": True,
"sell_profit_only": False,
"sell_profit_offset": 0.0,
"ignore_roi_if_buy_signal": False,
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
})
patch_exchange(mocker)
result1 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC'],
@@ -1249,7 +1249,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
'close_rate': [0.104969, 0.103541],
"is_short": [False, False],
'sell_reason': [ExitType.ROI, ExitType.ROI]
'exit_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
'profit_ratio': [0.03, 0.01, 0.1],
@@ -1267,7 +1267,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
'open_rate': [0.104445, 0.10302485, 0.122541],
'close_rate': [0.104969, 0.103541, 0.123541],
"is_short": [False, False, False],
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{
@@ -1346,10 +1346,10 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
default_conf_usdt.update({
"trading_mode": "futures",
"margin_mode": "isolated",
"use_sell_signal": True,
"sell_profit_only": False,
"sell_profit_offset": 0.0,
"ignore_roi_if_buy_signal": False,
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
"strategy": CURRENT_TEST_STRATEGY,
})
patch_exchange(mocker)
@@ -1367,7 +1367,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
'stake_amount': [0.01, 0.01],
'open_rate': [0.104445, 0.10302485],
'close_rate': [0.104969, 0.103541],
'sell_reason': [ExitType.ROI, ExitType.ROI]
'exit_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/USDT', 'XRP/USDT', 'XRP/USDT'],
'profit_ratio': [0.03, 0.01, 0.1],
@@ -1385,7 +1385,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
'stake_amount': [0.01, 0.01, 0.01],
'open_rate': [0.104445, 0.10302485, 0.122541],
'close_rate': [0.104969, 0.103541, 0.123541],
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{
@@ -1450,10 +1450,10 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
caplog, testdatadir, capsys):
# Tests detail-data loading
default_conf.update({
"use_sell_signal": True,
"sell_profit_only": False,
"sell_profit_offset": 0.0,
"ignore_roi_if_buy_signal": False,
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
})
patch_exchange(mocker)
result1 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC'],
@@ -1470,7 +1470,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
'stake_amount': [0.01, 0.01],
'open_rate': [0.104445, 0.10302485],
'close_rate': [0.104969, 0.103541],
'sell_reason': [ExitType.ROI, ExitType.ROI]
'exit_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
'profit_ratio': [0.03, 0.01, 0.1],
@@ -1488,7 +1488,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
'stake_amount': [0.01, 0.01, 0.01],
'open_rate': [0.104445, 0.10302485, 0.122541],
'close_rate': [0.104969, 0.103541, 0.123541],
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{
@@ -1557,10 +1557,10 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testdatadir, run_id,
start_delta, cache):
default_conf.update({
"use_sell_signal": True,
"sell_profit_only": False,
"sell_profit_offset": 0.0,
"ignore_roi_if_buy_signal": False,
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
})
patch_exchange(mocker)
backtestmock = MagicMock(return_value={

View File

@@ -14,7 +14,7 @@ from tests.conftest import patch_exchange
def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False
default_conf['use_exit_signal'] = False
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'))
@@ -60,7 +60,7 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
'trade_duration': [200, 40],
'profit_ratio': [0.0, 0.0],
'profit_abs': [0.0, 0.0],
'sell_reason': [ExitType.ROI.value, ExitType.ROI.value],
'exit_reason': [ExitType.ROI.value, ExitType.ROI.value],
'initial_stop_loss_abs': [0.0940005, 0.09272236],
'initial_stop_loss_ratio': [-0.1, -0.1],
'stop_loss_abs': [0.0940005, 0.09272236],

View File

@@ -357,8 +357,8 @@ def test_hyperopt_format_results(hyperopt):
"is_open": [False, False, False, True],
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_SELL]
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_EXIT]
}),
'config': hyperopt.config,
'locks': [],
@@ -428,8 +428,8 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
"is_open": [False, False, False, True],
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_SELL]
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_EXIT]
}),
'config': hyperopt_conf,
'locks': [],

View File

@@ -15,9 +15,8 @@ from freqtrade.edge import PairInfo
from freqtrade.enums import ExitType
from freqtrade.optimize.optimize_reports import (_get_resample_from_period, generate_backtest_stats,
generate_daily_stats, generate_edge_table,
generate_pair_metrics,
generate_exit_reason_stats, generate_pair_metrics,
generate_periodic_breakdown_stats,
generate_sell_reason_stats,
generate_strategy_comparison,
generate_trading_stats, show_sorted_pairlist,
store_backtest_stats, text_table_bt_results,
@@ -77,8 +76,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
"is_open": [False, False, False, True],
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_SELL]
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_EXIT]
}),
'config': default_conf,
'locks': [],
@@ -129,8 +128,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
"is_open": [False, False, False, True],
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [ExitType.ROI, ExitType.ROI,
ExitType.STOP_LOSS, ExitType.FORCE_SELL]
"exit_reason": [ExitType.ROI, ExitType.ROI,
ExitType.STOP_LOSS, ExitType.FORCE_EXIT]
}),
'config': default_conf,
'locks': [],
@@ -265,7 +264,7 @@ def test_generate_trading_stats(testdatadir):
assert res['losses'] == 0
def test_text_table_sell_reason():
def test_text_table_exit_reason():
results = pd.DataFrame(
{
@@ -276,7 +275,7 @@ def test_text_table_sell_reason():
'wins': [2, 0, 0],
'draws': [0, 0, 0],
'losses': [0, 0, 1],
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
}
)
@@ -291,9 +290,9 @@ def test_text_table_sell_reason():
' -0.2 | -5 |'
)
sell_reason_stats = generate_sell_reason_stats(max_open_trades=2,
exit_reason_stats = generate_exit_reason_stats(max_open_trades=2,
results=results)
assert text_table_exit_reason(sell_reason_stats=sell_reason_stats,
assert text_table_exit_reason(exit_reason_stats=exit_reason_stats,
stake_currency='BTC') == result_str
@@ -308,23 +307,23 @@ def test_generate_sell_reason_stats():
'wins': [2, 0, 0],
'draws': [0, 0, 0],
'losses': [0, 0, 1],
'sell_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value]
'exit_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value]
}
)
sell_reason_stats = generate_sell_reason_stats(max_open_trades=2,
exit_reason_stats = generate_exit_reason_stats(max_open_trades=2,
results=results)
roi_result = sell_reason_stats[0]
assert roi_result['sell_reason'] == 'roi'
roi_result = exit_reason_stats[0]
assert roi_result['exit_reason'] == 'roi'
assert roi_result['trades'] == 2
assert pytest.approx(roi_result['profit_mean']) == 0.15
assert roi_result['profit_mean_pct'] == round(roi_result['profit_mean'] * 100, 2)
assert pytest.approx(roi_result['profit_mean']) == 0.15
assert roi_result['profit_mean_pct'] == round(roi_result['profit_mean'] * 100, 2)
stop_result = sell_reason_stats[1]
stop_result = exit_reason_stats[1]
assert stop_result['sell_reason'] == 'stop_loss'
assert stop_result['exit_reason'] == 'stop_loss'
assert stop_result['trades'] == 1
assert pytest.approx(stop_result['profit_mean']) == -0.1
assert stop_result['profit_mean_pct'] == round(stop_result['profit_mean'] * 100, 2)

View File

@@ -11,7 +11,7 @@ from tests.conftest import get_patched_freqtradebot, log_has_re
def generate_mock_trade(pair: str, fee: float, is_open: bool,
sell_reason: str = ExitType.SELL_SIGNAL,
sell_reason: str = ExitType.EXIT_SIGNAL,
min_ago_open: int = None, min_ago_close: int = None,
profit_rate: float = 0.9
):
@@ -32,7 +32,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool,
trade.recalc_open_trade_value()
if not is_open:
trade.close(open_rate * profit_rate)
trade.sell_reason = sell_reason
trade.exit_reason = sell_reason
return trade

View File

@@ -66,7 +66,8 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'open_trade_value': 0.0010025,
'close_rate_requested': ANY,
'sell_reason': ANY,
'sell_order_status': ANY,
'exit_reason': ANY,
'exit_order_status': ANY,
'min_rate': ANY,
'max_rate': ANY,
'strategy': ANY,
@@ -148,7 +149,8 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'open_trade_value': ANY,
'close_rate_requested': ANY,
'sell_reason': ANY,
'sell_order_status': ANY,
'exit_reason': ANY,
'exit_order_status': ANY,
'min_rate': ANY,
'max_rate': ANY,
'strategy': ANY,
@@ -769,7 +771,7 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
assert freqtradebot.config['max_open_trades'] == 0
def test_rpc_forceexit(default_conf, ticker, fee, mocker) -> None:
def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
cancel_order_mock = MagicMock()
@@ -796,29 +798,29 @@ def test_rpc_forceexit(default_conf, ticker, fee, mocker) -> None:
freqtradebot.state = State.STOPPED
with pytest.raises(RPCException, match=r'.*trader is not running*'):
rpc._rpc_forceexit(None)
rpc._rpc_force_exit(None)
freqtradebot.state = State.RUNNING
with pytest.raises(RPCException, match=r'.*invalid argument*'):
rpc._rpc_forceexit(None)
rpc._rpc_force_exit(None)
msg = rpc._rpc_forceexit('all')
msg = rpc._rpc_force_exit('all')
assert msg == {'result': 'Created sell orders for all open trades.'}
freqtradebot.enter_positions()
msg = rpc._rpc_forceexit('all')
msg = rpc._rpc_force_exit('all')
assert msg == {'result': 'Created sell orders for all open trades.'}
freqtradebot.enter_positions()
msg = rpc._rpc_forceexit('2')
msg = rpc._rpc_force_exit('2')
assert msg == {'result': 'Created sell order for trade 2.'}
freqtradebot.state = State.STOPPED
with pytest.raises(RPCException, match=r'.*trader is not running*'):
rpc._rpc_forceexit(None)
rpc._rpc_force_exit(None)
with pytest.raises(RPCException, match=r'.*trader is not running*'):
rpc._rpc_forceexit('all')
rpc._rpc_force_exit('all')
freqtradebot.state = State.RUNNING
assert cancel_order_mock.call_count == 0
@@ -847,7 +849,7 @@ def test_rpc_forceexit(default_conf, ticker, fee, mocker) -> None:
)
# check that the trade is called, which is done by ensuring exchange.cancel_order is called
# and trade amount is updated
rpc._rpc_forceexit('3')
rpc._rpc_force_exit('3')
assert cancel_order_mock.call_count == 1
assert trade.amount == filled_amount
@@ -875,7 +877,7 @@ def test_rpc_forceexit(default_conf, ticker, fee, mocker) -> None:
}
)
# check that the trade is called, which is done by ensuring exchange.cancel_order is called
msg = rpc._rpc_forceexit('4')
msg = rpc._rpc_force_exit('4')
assert msg == {'result': 'Created sell order for trade 4.'}
assert cancel_order_mock.call_count == 2
assert trade.amount == amount
@@ -892,7 +894,7 @@ def test_rpc_forceexit(default_conf, ticker, fee, mocker) -> None:
'filled': 0.0
}
)
msg = rpc._rpc_forceexit('3')
msg = rpc._rpc_force_exit('3')
assert msg == {'result': 'Created sell order for trade 3.'}
# status quo, no exchange calls
assert cancel_order_mock.call_count == 3
@@ -1008,7 +1010,7 @@ def test_enter_tag_performance_handle_2(mocker, default_conf, markets, fee):
assert prec_satoshi(res[0]['profit_pct'], 0.5)
def test_sell_reason_performance_handle(default_conf, ticker, limit_buy_order, fee,
def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
@@ -1037,23 +1039,23 @@ def test_sell_reason_performance_handle(default_conf, ticker, limit_buy_order, f
trade.close_date = datetime.utcnow()
trade.is_open = False
res = rpc._rpc_sell_reason_performance(None)
res = rpc._rpc_exit_reason_performance(None)
assert len(res) == 1
assert res[0]['sell_reason'] == 'Other'
assert res[0]['exit_reason'] == 'Other'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
trade.sell_reason = "TEST1"
res = rpc._rpc_sell_reason_performance(None)
trade.exit_reason = "TEST1"
res = rpc._rpc_exit_reason_performance(None)
assert len(res) == 1
assert res[0]['sell_reason'] == 'TEST1'
assert res[0]['exit_reason'] == 'TEST1'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
def test_sell_reason_performance_handle_2(mocker, default_conf, markets, fee):
def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee):
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -1064,21 +1066,21 @@ def test_sell_reason_performance_handle_2(mocker, default_conf, markets, fee):
create_mock_trades(fee)
rpc = RPC(freqtradebot)
res = rpc._rpc_sell_reason_performance(None)
res = rpc._rpc_exit_reason_performance(None)
assert len(res) == 2
assert res[0]['sell_reason'] == 'sell_signal'
assert res[0]['exit_reason'] == 'sell_signal'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 0.5)
assert res[1]['sell_reason'] == 'roi'
assert res[1]['exit_reason'] == 'roi'
assert res[1]['count'] == 1
assert prec_satoshi(res[1]['profit_pct'], 1.0)
# Test for a specific pair
res = rpc._rpc_sell_reason_performance('ETC/BTC')
res = rpc._rpc_exit_reason_performance('ETC/BTC')
assert len(res) == 1
assert res[0]['count'] == 1
assert res[0]['sell_reason'] == 'sell_signal'
assert res[0]['exit_reason'] == 'sell_signal'
assert prec_satoshi(res[0]['profit_pct'], 0.5)
@@ -1119,7 +1121,7 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
assert prec_satoshi(res[0]['profit_pct'], 6.2)
trade.enter_tag = "TESTBUY"
trade.sell_reason = "TESTSELL"
trade.exit_reason = "TESTSELL"
res = rpc._rpc_mix_tag_performance(None)
assert len(res) == 1
@@ -1180,8 +1182,8 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
assert counts["current"] == 1
def test_rpc_forceentry(mocker, default_conf, ticker, fee, limit_buy_order_open) -> None:
default_conf['forcebuy_enable'] = True
def test_rpc_force_entry(mocker, default_conf, ticker, fee, limit_buy_order_open) -> None:
default_conf['force_entry_enable'] = True
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
buy_mm = MagicMock(return_value=limit_buy_order_open)
mocker.patch.multiple(
@@ -1219,7 +1221,7 @@ def test_rpc_forceentry(mocker, default_conf, ticker, fee, limit_buy_order_open)
pair = 'LTC/BTC'
trade = rpc._rpc_force_entry(pair, 0.0001, order_type='limit', stake_amount=0.05)
assert trade.stake_amount == 0.05
assert trade.buy_tag == 'forceentry'
assert trade.buy_tag == 'force_entry'
# Test not buying
pair = 'XRP/BTC'
@@ -1232,8 +1234,8 @@ def test_rpc_forceentry(mocker, default_conf, ticker, fee, limit_buy_order_open)
assert trade is None
def test_rpc_forceentry_stopped(mocker, default_conf) -> None:
default_conf['forcebuy_enable'] = True
def test_rpc_force_entry_stopped(mocker, default_conf) -> None:
default_conf['force_entry_enable'] = True
default_conf['initial_state'] = 'stopped'
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
@@ -1245,19 +1247,19 @@ def test_rpc_forceentry_stopped(mocker, default_conf) -> None:
rpc._rpc_force_entry(pair, None)
def test_rpc_forceentry_disabled(mocker, default_conf) -> None:
def test_rpc_force_entry_disabled(mocker, default_conf) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot)
rpc = RPC(freqtradebot)
pair = 'ETH/BTC'
with pytest.raises(RPCException, match=r'Forceentry not enabled.'):
with pytest.raises(RPCException, match=r'Force_entry not enabled.'):
rpc._rpc_force_entry(pair, None)
def test_rpc_forceentry_wrong_mode(mocker, default_conf) -> None:
default_conf['forcebuy_enable'] = True
def test_rpc_force_entry_wrong_mode(mocker, default_conf) -> None:
default_conf['force_entry_enable'] = True
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = get_patched_freqtradebot(mocker, default_conf)

View File

@@ -822,14 +822,14 @@ def test_api_stats(botclient, mocker, ticker, fee, markets, is_short):
rc = client_get(client, f"{BASE_URI}/stats")
assert_response(rc, 200)
assert 'durations' in rc.json()
assert 'sell_reasons' in rc.json()
assert 'exit_reasons' in rc.json()
create_mock_trades(fee, is_short=is_short)
rc = client_get(client, f"{BASE_URI}/stats")
assert_response(rc, 200)
assert 'durations' in rc.json()
assert 'sell_reasons' in rc.json()
assert 'exit_reasons' in rc.json()
assert 'wins' in rc.json()['durations']
assert 'losses' in rc.json()['durations']
@@ -962,7 +962,8 @@ def test_api_status(botclient, mocker, ticker, fee, markets, is_short,
'open_rate_requested': ANY,
'open_trade_value': open_trade_value,
'sell_reason': None,
'sell_order_status': None,
'exit_reason': None,
'exit_order_status': None,
'strategy': CURRENT_TEST_STRATEGY,
'buy_tag': None,
'enter_tag': None,
@@ -1076,16 +1077,16 @@ def test_api_whitelist(botclient):
'forcebuy',
'forceenter',
])
def test_api_forceentry(botclient, mocker, fee, endpoint):
def test_api_force_entry(botclient, mocker, fee, endpoint):
ftbot, client = botclient
rc = client_post(client, f"{BASE_URI}/{endpoint}",
data='{"pair": "ETH/BTC"}')
assert_response(rc, 502)
assert rc.json() == {"error": f"Error querying /api/v1/{endpoint}: Forceentry not enabled."}
assert rc.json() == {"error": f"Error querying /api/v1/{endpoint}: Force_entry not enabled."}
# enable forcebuy
ftbot.config['forcebuy_enable'] = True
ftbot.config['force_entry_enable'] = True
fbuy_mock = MagicMock(return_value=None)
mocker.patch("freqtrade.rpc.RPC._rpc_force_entry", fbuy_mock)
@@ -1162,7 +1163,8 @@ def test_api_forceentry(botclient, mocker, fee, endpoint):
'open_rate_requested': None,
'open_trade_value': 0.24605460,
'sell_reason': None,
'sell_order_status': None,
'exit_reason': None,
'exit_order_status': None,
'strategy': CURRENT_TEST_STRATEGY,
'buy_tag': None,
'enter_tag': None,

View File

@@ -95,9 +95,9 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], "
"['balance'], ['start'], ['stop'], "
"['forcesell', 'forceexit'], ['forcebuy', 'forcelong'], ['forceshort'], "
"['forcesell', 'forceexit', 'fx'], ['forcebuy', 'forcelong'], ['forceshort'], "
"['trades'], ['delete'], ['performance'], "
"['buys', 'entries'], ['sells'], ['mix_tags'], "
"['buys', 'entries'], ['sells', 'exits'], ['mix_tags'], "
"['stats'], ['daily'], ['weekly'], ['monthly'], "
"['count'], ['locks'], ['unlock', 'delete_locks'], "
"['reload_config', 'reload_conf'], ['show_config', 'show_conf'], "
@@ -199,7 +199,7 @@ def test_telegram_status(default_conf, update, mocker) -> None:
'profit_ratio': -0.0059,
'initial_stop_loss_abs': 1.098e-05,
'stop_loss_abs': 1.099e-05,
'sell_order_status': None,
'exit_order_status': None,
'initial_stop_loss_ratio': -0.0005,
'stoploss_current_dist': 1e-08,
'stoploss_current_dist_ratio': -0.0002,
@@ -837,7 +837,7 @@ def test_telegram_stats(default_conf, update, ticker, ticker_sell_up, fee,
telegram._stats(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'Sell Reason' in msg_mock.call_args_list[-1][0][0]
assert 'Exit Reason' in msg_mock.call_args_list[-1][0][0]
assert 'ROI' in msg_mock.call_args_list[-1][0][0]
assert 'Avg. Duration' in msg_mock.call_args_list[-1][0][0]
msg_mock.reset_mock()
@@ -1035,12 +1035,12 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forceexit(update=update, context=context)
telegram._force_exit(update=update, context=context)
assert msg_mock.call_count == 4
last_msg = msg_mock.call_args_list[-2][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
@@ -1059,7 +1059,8 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': ExitType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_EXIT.value,
'exit_reason': ExitType.FORCE_EXIT.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -1102,13 +1103,13 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forceexit(update=update, context=context)
telegram._force_exit(update=update, context=context)
assert msg_mock.call_count == 4
last_msg = msg_mock.call_args_list[-2][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
@@ -1127,7 +1128,8 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': ExitType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_EXIT.value,
'exit_reason': ExitType.FORCE_EXIT.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -1160,13 +1162,13 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
# /forcesell all
context = MagicMock()
context.args = ["all"]
telegram._forceexit(update=update, context=context)
telegram._force_exit(update=update, context=context)
# Called for each trade 2 times
assert msg_mock.call_count == 8
msg = msg_mock.call_args_list[0][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
@@ -1185,7 +1187,8 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': ExitType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_EXIT.value,
'exit_reason': ExitType.FORCE_EXIT.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -1204,7 +1207,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forceexit(update=update, context=context)
telegram._force_exit(update=update, context=context)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
@@ -1214,12 +1217,12 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
# /forcesell 123456
context = MagicMock()
context.args = ["123456"]
telegram._forceexit(update=update, context=context)
telegram._force_exit(update=update, context=context)
assert msg_mock.call_count == 1
assert 'invalid argument' in msg_mock.call_args_list[0][0][0]
def test_forceenter_handle(default_conf, update, mocker) -> None:
def test_force_enter_handle(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
fbuy_mock = MagicMock(return_value=None)
@@ -1231,7 +1234,7 @@ def test_forceenter_handle(default_conf, update, mocker) -> None:
# /forcelong ETH/BTC
context = MagicMock()
context.args = ["ETH/BTC"]
telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG)
telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@@ -1244,7 +1247,7 @@ def test_forceenter_handle(default_conf, update, mocker) -> None:
# /forcelong ETH/BTC 0.055
context = MagicMock()
context.args = ["ETH/BTC", "0.055"]
telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG)
telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@@ -1252,20 +1255,20 @@ def test_forceenter_handle(default_conf, update, mocker) -> None:
assert fbuy_mock.call_args_list[0][0][1] == 0.055
def test_forceenter_handle_exception(default_conf, update, mocker) -> None:
def test_force_enter_handle_exception(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
update.message.text = '/forcebuy ETH/Nonepair'
telegram._forceenter(update=update, context=MagicMock(), order_side=SignalDirection.LONG)
telegram._force_enter(update=update, context=MagicMock(), order_side=SignalDirection.LONG)
assert msg_mock.call_count == 1
assert msg_mock.call_args_list[0][0][0] == 'Forceentry not enabled.'
assert msg_mock.call_args_list[0][0][0] == 'Force_entry not enabled.'
def test_forceenter_no_pair(default_conf, update, mocker) -> None:
def test_force_enter_no_pair(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
fbuy_mock = MagicMock(return_value=None)
@@ -1277,7 +1280,7 @@ def test_forceenter_no_pair(default_conf, update, mocker) -> None:
context = MagicMock()
context.args = []
telegram._forceenter(update=update, context=context, order_side=SignalDirection.LONG)
telegram._force_enter(update=update, context=context, order_side=SignalDirection.LONG)
assert fbuy_mock.call_count == 0
assert msg_mock.call_count == 1
@@ -1289,7 +1292,7 @@ def test_forceenter_no_pair(default_conf, update, mocker) -> None:
update = MagicMock()
update.callback_query = MagicMock()
update.callback_query.data = 'XRP/USDT_||_long'
telegram._forceenter_inline(update, None)
telegram._force_enter_inline(update, None)
assert fbuy_mock.call_count == 1
@@ -1325,8 +1328,8 @@ def test_telegram_performance_handle(default_conf, update, ticker, fee,
assert '<code>ETH/BTC\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
def test_telegram_buy_tag_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
def test_telegram_entry_tag_performance_handle(
default_conf, update, ticker, fee, limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
@@ -1354,7 +1357,7 @@ def test_telegram_buy_tag_performance_handle(default_conf, update, ticker, fee,
context = MagicMock()
telegram._enter_tag_performance(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Buy Tag Performance' in msg_mock.call_args_list[0][0][0]
assert 'Entry Tag Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>TESTBUY\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
context.args = [trade.pair]
@@ -1370,7 +1373,7 @@ def test_telegram_buy_tag_performance_handle(default_conf, update, ticker, fee,
assert "Error" in msg_mock.call_args_list[0][0][0]
def test_telegram_sell_reason_performance_handle(default_conf, update, ticker, fee,
def test_telegram_exit_reason_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -1384,7 +1387,7 @@ def test_telegram_sell_reason_performance_handle(default_conf, update, ticker, f
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
trade.sell_reason = 'TESTSELL'
trade.exit_reason = 'TESTSELL'
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
@@ -1396,19 +1399,19 @@ def test_telegram_sell_reason_performance_handle(default_conf, update, ticker, f
trade.close_date = datetime.utcnow()
trade.is_open = False
context = MagicMock()
telegram._sell_reason_performance(update=update, context=context)
telegram._exit_reason_performance(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Sell Reason Performance' in msg_mock.call_args_list[0][0][0]
assert 'Exit Reason Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>TESTSELL\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
context.args = [trade.pair]
telegram._sell_reason_performance(update=update, context=context)
telegram._exit_reason_performance(update=update, context=context)
assert msg_mock.call_count == 2
msg_mock.reset_mock()
mocker.patch('freqtrade.rpc.rpc.RPC._rpc_sell_reason_performance',
mocker.patch('freqtrade.rpc.rpc.RPC._rpc_exit_reason_performance',
side_effect=RPCException('Error'))
telegram._sell_reason_performance(update=update, context=MagicMock())
telegram._exit_reason_performance(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert "Error" in msg_mock.call_args_list[0][0][0]
@@ -1430,7 +1433,7 @@ def test_telegram_mix_tag_performance_handle(default_conf, update, ticker, fee,
assert trade
trade.enter_tag = "TESTBUY"
trade.sell_reason = "TESTSELL"
trade.exit_reason = "TESTSELL"
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
@@ -1759,10 +1762,10 @@ def test_show_config_handle(default_conf, update, mocker) -> None:
@pytest.mark.parametrize('message_type,enter,enter_signal,leverage', [
(RPCMessageType.BUY, 'Long', 'long_signal_01', None),
(RPCMessageType.BUY, 'Long', 'long_signal_01', 1.0),
(RPCMessageType.BUY, 'Long', 'long_signal_01', 5.0),
(RPCMessageType.SHORT, 'Short', 'short_signal_01', 2.0)])
(RPCMessageType.ENTRY, 'Long', 'long_signal_01', 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:
@@ -1775,6 +1778,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
'leverage': leverage,
'limit': 1.099e-05,
'order_type': 'limit',
'direction': enter,
'stake_amount': 0.01465333,
'stake_amount_fiat': 0.0,
'stake_currency': 'BTC',
@@ -1815,8 +1819,8 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type,
@pytest.mark.parametrize('message_type,enter_signal', [
(RPCMessageType.BUY_CANCEL, 'long_signal_01'),
(RPCMessageType.SHORT_CANCEL, 'short_signal_01')])
(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:
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
@@ -1863,14 +1867,14 @@ def test_send_msg_protection_notification(default_conf, mocker, time_machine) ->
@pytest.mark.parametrize('message_type,entered,enter_signal,leverage', [
(RPCMessageType.BUY_FILL, 'Longed', 'long_signal_01', 1.0),
(RPCMessageType.BUY_FILL, 'Longed', 'long_signal_02', 2.0),
(RPCMessageType.SHORT_FILL, 'Shorted', 'short_signal_01', 2.0),
(RPCMessageType.ENTRY_FILL, 'Long', 'long_signal_01', 1.0),
(RPCMessageType.ENTRY_FILL, 'Long', 'long_signal_02', 2.0),
(RPCMessageType.ENTRY_FILL, 'Short', 'short_signal_01', 2.0),
])
def test_send_msg_buy_fill_notification(default_conf, mocker, message_type, entered,
enter_signal, leverage) -> None:
def test_send_msg_entry_fill_notification(default_conf, mocker, message_type, entered,
enter_signal, leverage) -> None:
default_conf['telegram']['notification_settings']['buy_fill'] = 'on'
default_conf['telegram']['notification_settings']['entry_fill'] = 'on'
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram.send_msg({
@@ -1881,6 +1885,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker, message_type, ente
'pair': 'ETH/BTC',
'leverage': leverage,
'stake_amount': 0.01465333,
'direction': entered,
# 'stake_amount_fiat': 0.0,
'stake_currency': 'BTC',
'fiat_currency': 'USD',
@@ -1890,7 +1895,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker, message_type, ente
})
leverage_text = f'*Leverage:* `{leverage}`\n' if leverage != 1.0 else ''
assert msg_mock.call_args[0][0] == (
f'\N{CHECK MARK} *Binance:* {entered} ETH/BTC (#1)\n'
f'\N{CHECK MARK} *Binance:* {entered}ed ETH/BTC (#1)\n'
f'*Enter Tag:* `{enter_signal}`\n'
'*Amount:* `1333.33333333`\n'
f"{leverage_text}"
@@ -1906,7 +1911,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
old_convamount = telegram._rpc._fiat_converter.convert_amount
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
telegram.send_msg({
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -1923,7 +1928,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'stake_currency': 'ETH',
'fiat_currency': 'USD',
'enter_tag': 'buy_signal1',
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-1),
'close_date': arrow.utcnow(),
})
@@ -1942,7 +1947,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
msg_mock.reset_mock()
telegram.send_msg({
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -1957,7 +1962,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'profit_ratio': -0.57405275,
'stake_currency': 'ETH',
'enter_tag': 'buy_signal1',
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(),
})
@@ -1984,7 +1989,7 @@ def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
old_convamount = telegram._rpc._fiat_converter.convert_amount
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
telegram.send_msg({
'type': RPCMessageType.SELL_CANCEL,
'type': RPCMessageType.EXIT_CANCEL,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -1996,7 +2001,7 @@ def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
msg_mock.reset_mock()
telegram.send_msg({
'type': RPCMessageType.SELL_CANCEL,
'type': RPCMessageType.EXIT_CANCEL,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -2016,11 +2021,11 @@ def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
def test_send_msg_sell_fill_notification(default_conf, mocker, direction,
enter_signal, leverage) -> None:
default_conf['telegram']['notification_settings']['sell_fill'] = 'on'
default_conf['telegram']['notification_settings']['exit_fill'] = 'on'
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram.send_msg({
'type': RPCMessageType.SELL_FILL,
'type': RPCMessageType.EXIT_FILL,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -2036,7 +2041,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction,
'profit_ratio': -0.57405275,
'stake_currency': 'ETH',
'enter_tag': enter_signal,
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(),
})
@@ -2093,9 +2098,9 @@ def test_send_msg_unknown_type(default_conf, mocker) -> None:
@pytest.mark.parametrize('message_type,enter,enter_signal,leverage', [
(RPCMessageType.BUY, 'Long', 'long_signal_01', None),
(RPCMessageType.BUY, 'Long', 'long_signal_01', 2.0),
(RPCMessageType.SHORT, 'Short', 'short_signal_01', 2.0)])
(RPCMessageType.ENTRY, 'Long', 'long_signal_01', None),
(RPCMessageType.ENTRY, 'Long', 'long_signal_01', 2.0),
(RPCMessageType.ENTRY, 'Short', 'short_signal_01', 2.0)])
def test_send_msg_buy_notification_no_fiat(
default_conf, mocker, message_type, enter, enter_signal, leverage) -> None:
del default_conf['fiat_display_currency']
@@ -2110,6 +2115,7 @@ def test_send_msg_buy_notification_no_fiat(
'leverage': leverage,
'limit': 1.099e-05,
'order_type': 'limit',
'direction': enter,
'stake_amount': 0.01465333,
'stake_amount_fiat': 0.0,
'stake_currency': 'BTC',
@@ -2143,7 +2149,7 @@ def test_send_msg_sell_notification_no_fiat(
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram.send_msg({
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'KEY/ETH',
@@ -2160,7 +2166,7 @@ def test_send_msg_sell_notification_no_fiat(
'stake_currency': 'ETH',
'fiat_currency': 'USD',
'enter_tag': enter_signal,
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3),
'close_date': arrow.utcnow(),
})
@@ -2182,13 +2188,13 @@ def test_send_msg_sell_notification_no_fiat(
@pytest.mark.parametrize('msg,expected', [
({'profit_percent': 20.1, 'sell_reason': 'roi'}, "\N{ROCKET}"),
({'profit_percent': 5.1, 'sell_reason': 'roi'}, "\N{ROCKET}"),
({'profit_percent': 2.56, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': 1.0, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': 0.0, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': -5.0, 'sell_reason': 'stop_loss'}, "\N{WARNING SIGN}"),
({'profit_percent': -2.0, 'sell_reason': 'sell_signal'}, "\N{CROSS MARK}"),
({'profit_percent': 20.1, 'exit_reason': 'roi'}, "\N{ROCKET}"),
({'profit_percent': 5.1, 'exit_reason': 'roi'}, "\N{ROCKET}"),
({'profit_percent': 2.56, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': 1.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': 0.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
({'profit_percent': -5.0, 'exit_reason': 'stop_loss'}, "\N{WARNING SIGN}"),
({'profit_percent': -2.0, 'exit_reason': 'sell_signal'}, "\N{CROSS MARK}"),
])
def test__sell_emoji(default_conf, mocker, msg, expected):
del default_conf['fiat_display_currency']

View File

@@ -15,38 +15,38 @@ def get_webhook_dict() -> dict:
return {
"enabled": True,
"url": "https://maker.ifttt.com/trigger/freqtrade_test/with/key/c764udvJ5jfSlswVRukZZ2/",
"webhookbuy": {
"webhookentry": {
"value1": "Buying {pair}",
"value2": "limit {limit:8f}",
"value3": "{stake_amount:8f} {stake_currency}",
"value4": "leverage {leverage:.1f}",
"value5": "direction {direction}"
},
"webhookbuycancel": {
"webhookentrycancel": {
"value1": "Cancelling Open Buy Order for {pair}",
"value2": "limit {limit:8f}",
"value3": "{stake_amount:8f} {stake_currency}",
"value4": "leverage {leverage:.1f}",
"value5": "direction {direction}"
},
"webhookbuyfill": {
"webhookentryfill": {
"value1": "Buy Order for {pair} filled",
"value2": "at {open_rate:8f}",
"value3": "{stake_amount:8f} {stake_currency}",
"value4": "leverage {leverage:.1f}",
"value5": "direction {direction}"
},
"webhooksell": {
"webhookexit": {
"value1": "Selling {pair}",
"value2": "limit {limit:8f}",
"value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"
},
"webhooksellcancel": {
"webhookexitcancel": {
"value1": "Cancelling Open Sell Order for {pair}",
"value2": "limit {limit:8f}",
"value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"
},
"webhooksellfill": {
"webhookexitfill": {
"value1": "Sell Order for {pair} filled",
"value2": "at {close_rate:8f}",
"value3": ""
@@ -74,7 +74,7 @@ def test_send_msg_webhook(default_conf, mocker):
msg_mock = MagicMock()
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
msg = {
'type': RPCMessageType.BUY,
'type': RPCMessageType.ENTRY,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 1.0,
@@ -88,20 +88,20 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuy"]["value1"].format(**msg))
default_conf["webhook"]["webhookentry"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuy"]["value2"].format(**msg))
default_conf["webhook"]["webhookentry"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuy"]["value3"].format(**msg))
default_conf["webhook"]["webhookentry"]["value3"].format(**msg))
assert (msg_mock.call_args[0][0]["value4"] ==
default_conf["webhook"]["webhookbuy"]["value4"].format(**msg))
default_conf["webhook"]["webhookentry"]["value4"].format(**msg))
assert (msg_mock.call_args[0][0]["value5"] ==
default_conf["webhook"]["webhookbuy"]["value5"].format(**msg))
default_conf["webhook"]["webhookentry"]["value5"].format(**msg))
# Test short
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SHORT,
'type': RPCMessageType.ENTRY,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 2.0,
@@ -115,20 +115,20 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuy"]["value1"].format(**msg))
default_conf["webhook"]["webhookentry"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuy"]["value2"].format(**msg))
default_conf["webhook"]["webhookentry"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuy"]["value3"].format(**msg))
default_conf["webhook"]["webhookentry"]["value3"].format(**msg))
assert (msg_mock.call_args[0][0]["value4"] ==
default_conf["webhook"]["webhookbuy"]["value4"].format(**msg))
default_conf["webhook"]["webhookentry"]["value4"].format(**msg))
assert (msg_mock.call_args[0][0]["value5"] ==
default_conf["webhook"]["webhookbuy"]["value5"].format(**msg))
default_conf["webhook"]["webhookentry"]["value5"].format(**msg))
# Test buy cancel
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.BUY_CANCEL,
'type': RPCMessageType.ENTRY_CANCEL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 1.0,
@@ -142,16 +142,16 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuycancel"]["value1"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuycancel"]["value2"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuycancel"]["value3"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value3"].format(**msg))
# Test short cancel
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SHORT_CANCEL,
'type': RPCMessageType.ENTRY_CANCEL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 2.0,
@@ -165,20 +165,20 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuycancel"]["value1"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuycancel"]["value2"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuycancel"]["value3"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value3"].format(**msg))
assert (msg_mock.call_args[0][0]["value4"] ==
default_conf["webhook"]["webhookbuycancel"]["value4"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value4"].format(**msg))
assert (msg_mock.call_args[0][0]["value5"] ==
default_conf["webhook"]["webhookbuycancel"]["value5"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value5"].format(**msg))
# Test buy fill
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.BUY_FILL,
'type': RPCMessageType.ENTRY_FILL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 1.0,
@@ -192,20 +192,20 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuyfill"]["value1"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuyfill"]["value2"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuyfill"]["value3"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value3"].format(**msg))
assert (msg_mock.call_args[0][0]["value4"] ==
default_conf["webhook"]["webhookbuycancel"]["value4"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value4"].format(**msg))
assert (msg_mock.call_args[0][0]["value5"] ==
default_conf["webhook"]["webhookbuycancel"]["value5"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value5"].format(**msg))
# Test short fill
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SHORT_FILL,
'type': RPCMessageType.ENTRY_FILL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'leverage': 2.0,
@@ -219,20 +219,20 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhookbuyfill"]["value1"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhookbuyfill"]["value2"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhookbuyfill"]["value3"].format(**msg))
default_conf["webhook"]["webhookentryfill"]["value3"].format(**msg))
assert (msg_mock.call_args[0][0]["value4"] ==
default_conf["webhook"]["webhookbuycancel"]["value4"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value4"].format(**msg))
assert (msg_mock.call_args[0][0]["value5"] ==
default_conf["webhook"]["webhookbuycancel"]["value5"].format(**msg))
default_conf["webhook"]["webhookentrycancel"]["value5"].format(**msg))
# Test sell
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'gain': "profit",
@@ -249,15 +249,15 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhooksell"]["value1"].format(**msg))
default_conf["webhook"]["webhookexit"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhooksell"]["value2"].format(**msg))
default_conf["webhook"]["webhookexit"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhooksell"]["value3"].format(**msg))
default_conf["webhook"]["webhookexit"]["value3"].format(**msg))
# Test sell cancel
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SELL_CANCEL,
'type': RPCMessageType.EXIT_CANCEL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'gain': "profit",
@@ -274,15 +274,15 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhooksellcancel"]["value1"].format(**msg))
default_conf["webhook"]["webhookexitcancel"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhooksellcancel"]["value2"].format(**msg))
default_conf["webhook"]["webhookexitcancel"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhooksellcancel"]["value3"].format(**msg))
default_conf["webhook"]["webhookexitcancel"]["value3"].format(**msg))
# Test Sell fill
msg_mock.reset_mock()
msg = {
'type': RPCMessageType.SELL_FILL,
'type': RPCMessageType.EXIT_FILL,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'gain': "profit",
@@ -299,11 +299,11 @@ def test_send_msg_webhook(default_conf, mocker):
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert (msg_mock.call_args[0][0]["value1"] ==
default_conf["webhook"]["webhooksellfill"]["value1"].format(**msg))
default_conf["webhook"]["webhookexitfill"]["value1"].format(**msg))
assert (msg_mock.call_args[0][0]["value2"] ==
default_conf["webhook"]["webhooksellfill"]["value2"].format(**msg))
default_conf["webhook"]["webhookexitfill"]["value2"].format(**msg))
assert (msg_mock.call_args[0][0]["value3"] ==
default_conf["webhook"]["webhooksellfill"]["value3"].format(**msg))
default_conf["webhook"]["webhookexitfill"]["value3"].format(**msg))
for msgtype in [RPCMessageType.STATUS,
RPCMessageType.WARNING,
@@ -327,20 +327,20 @@ def test_send_msg_webhook(default_conf, mocker):
def test_exception_send_msg(default_conf, mocker, caplog):
default_conf["webhook"] = get_webhook_dict()
del default_conf["webhook"]["webhookbuy"]
del default_conf["webhook"]["webhookentry"]
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
webhook.send_msg({'type': RPCMessageType.BUY})
assert log_has(f"Message type '{RPCMessageType.BUY}' not configured for webhooks",
webhook.send_msg({'type': RPCMessageType.ENTRY})
assert log_has(f"Message type '{RPCMessageType.ENTRY}' not configured for webhooks",
caplog)
default_conf["webhook"] = get_webhook_dict()
default_conf["webhook"]["webhookbuy"]["value1"] = "{DEADBEEF:8f}"
default_conf["webhook"]["webhookentry"]["value1"] = "{DEADBEEF:8f}"
msg_mock = MagicMock()
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
msg = {
'type': RPCMessageType.BUY,
'type': RPCMessageType.ENTRY,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'limit': 0.005,

View File

@@ -50,6 +50,8 @@ class StrategyTestV2(IStrategy):
'entry': 'gtc',
'exit': 'gtc',
}
# Test legacy use_sell_signal definition
use_sell_signal = False
# By default this strategy does not use Position Adjustments
position_adjustment_enable = False

View File

@@ -183,7 +183,7 @@ class StrategyTestV3(IStrategy):
current_profit: float, min_stake: float, max_stake: float, **kwargs):
if current_profit < -0.0075:
orders = trade.select_filled_orders(trade.enter_side)
orders = trade.select_filled_orders(trade.entry_side)
return round(orders[0].cost, 0)
return None

View File

@@ -503,15 +503,15 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
enter=False, exit_=False,
low=None, high=None)
assert res.exit_flag is True
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_reason == 'custom_sell'
assert res.exit_type == ExitType.CUSTOM_EXIT
assert res.exit_reason == 'custom_exit'
strategy.custom_exit = MagicMock(return_value='hello world')
res = strategy.should_exit(trade, 1, now,
enter=False, exit_=False,
low=None, high=None)
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_type == ExitType.CUSTOM_EXIT
assert res.exit_flag is True
assert res.exit_reason == 'hello world'
@@ -520,7 +520,7 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
res = strategy.should_exit(trade, 1, now,
enter=False, exit_=False,
low=None, high=None)
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_type == ExitType.CUSTOM_EXIT
assert res.exit_flag is True
assert res.exit_reason == 'h' * 64
assert log_has_re('Custom sell reason returned from custom_exit is too long.*', caplog)

View File

@@ -143,16 +143,6 @@ def test_strategy_can_short(caplog, default_conf):
assert isinstance(strat, IStrategy)
def test_strategy_implements_populate_entry(caplog, default_conf):
caplog.set_level(logging.INFO)
default_conf.update({
'strategy': "StrategyTestV2",
})
default_conf['trading_mode'] = 'futures'
with pytest.raises(OperationalException, match="`populate_entry_trend` must be implemented."):
StrategyResolver.load_strategy(default_conf)
def test_strategy_override_minimal_roi(caplog, default_conf):
caplog.set_level(logging.INFO)
default_conf.update({
@@ -310,50 +300,50 @@ def test_strategy_override_order_tif(caplog, default_conf):
StrategyResolver.load_strategy(default_conf)
def test_strategy_override_use_sell_signal(caplog, default_conf):
def test_strategy_override_use_exit_signal(caplog, default_conf):
caplog.set_level(logging.INFO)
default_conf.update({
'strategy': CURRENT_TEST_STRATEGY,
})
strategy = StrategyResolver.load_strategy(default_conf)
assert strategy.use_sell_signal
assert isinstance(strategy.use_sell_signal, bool)
assert strategy.use_exit_signal
assert isinstance(strategy.use_exit_signal, bool)
# must be inserted to configuration
assert 'use_sell_signal' in default_conf
assert default_conf['use_sell_signal']
assert 'use_exit_signal' in default_conf
assert default_conf['use_exit_signal']
default_conf.update({
'strategy': CURRENT_TEST_STRATEGY,
'use_sell_signal': False,
'use_exit_signal': False,
})
strategy = StrategyResolver.load_strategy(default_conf)
assert not strategy.use_sell_signal
assert isinstance(strategy.use_sell_signal, bool)
assert log_has("Override strategy 'use_sell_signal' with value in config file: False.", caplog)
assert not strategy.use_exit_signal
assert isinstance(strategy.use_exit_signal, bool)
assert log_has("Override strategy 'use_exit_signal' with value in config file: False.", caplog)
def test_strategy_override_use_sell_profit_only(caplog, default_conf):
def test_strategy_override_use_exit_profit_only(caplog, default_conf):
caplog.set_level(logging.INFO)
default_conf.update({
'strategy': CURRENT_TEST_STRATEGY,
})
strategy = StrategyResolver.load_strategy(default_conf)
assert not strategy.sell_profit_only
assert isinstance(strategy.sell_profit_only, bool)
assert not strategy.exit_profit_only
assert isinstance(strategy.exit_profit_only, bool)
# must be inserted to configuration
assert 'sell_profit_only' in default_conf
assert not default_conf['sell_profit_only']
assert 'exit_profit_only' in default_conf
assert not default_conf['exit_profit_only']
default_conf.update({
'strategy': CURRENT_TEST_STRATEGY,
'sell_profit_only': True,
'exit_profit_only': True,
})
strategy = StrategyResolver.load_strategy(default_conf)
assert strategy.sell_profit_only
assert isinstance(strategy.sell_profit_only, bool)
assert log_has("Override strategy 'sell_profit_only' with value in config file: True.", caplog)
assert strategy.exit_profit_only
assert isinstance(strategy.exit_profit_only, bool)
assert log_has("Override strategy 'exit_profit_only' with value in config file: True.", caplog)
@pytest.mark.filterwarnings("ignore:deprecated")
@@ -391,7 +381,22 @@ def test_deprecate_populate_indicators(result, default_conf):
@pytest.mark.filterwarnings("ignore:deprecated")
def test_missing_implements(default_conf):
def test_missing_implements(default_conf, caplog):
default_location = Path(__file__).parent / "strats"
default_conf.update({'strategy': 'StrategyTestV2',
'strategy_path': default_location})
StrategyResolver.load_strategy(default_conf)
log_has_re(r"DEPRECATED: .*use_sell_signal.*use_exit_signal.", caplog)
default_conf['trading_mode'] = 'futures'
with pytest.raises(OperationalException,
match=r"DEPRECATED: .*use_sell_signal.*use_exit_signal."):
StrategyResolver.load_strategy(default_conf)
default_conf['trading_mode'] = 'spot'
default_location = Path(__file__).parent / "strats/broken_strats"
default_conf.update({'strategy': 'TestStrategyNoImplements',
'strategy_path': default_location})

View File

@@ -160,7 +160,7 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
configsmock = MagicMock(side_effect=config_files)
mocker.patch(
'freqtrade.configuration.configuration.load_config_file',
'freqtrade.configuration.load_config.load_config_file',
configsmock
)
@@ -191,7 +191,7 @@ def test_from_config(default_conf, mocker, caplog) -> None:
mocker.patch('freqtrade.configuration.configuration.create_datadir', lambda c, x: x)
configsmock = MagicMock(side_effect=config_files)
mocker.patch('freqtrade.configuration.configuration.load_config_file', configsmock)
mocker.patch('freqtrade.configuration.load_config.load_config_file', configsmock)
validated_conf = Configuration.from_files(['test_conf.json', 'test2_conf.json'])
@@ -214,7 +214,7 @@ def test_print_config(default_conf, mocker, caplog) -> None:
configsmock = MagicMock(side_effect=config_files)
mocker.patch('freqtrade.configuration.configuration.create_datadir', lambda c, x: x)
mocker.patch('freqtrade.configuration.configuration.load_config_file', configsmock)
mocker.patch('freqtrade.configuration.configuration.load_from_files', configsmock)
validated_conf = Configuration.from_files(['test_conf.json'])
@@ -772,15 +772,15 @@ def test_set_logfile(default_conf, mocker, tmpdir):
def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None:
default_conf['forcebuy_enable'] = True
default_conf['force_entry_enable'] = True
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments(['trade']).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('forcebuy_enable')
assert log_has('`forcebuy` RPC message enabled.', caplog)
assert validated_conf.get('force_entry_enable')
assert log_has('`force_entry_enable` RPC message enabled.', caplog)
def test_validate_default_conf(default_conf) -> None:
@@ -868,15 +868,15 @@ def test_validate_tsl(default_conf):
def test_validate_edge2(edge_conf):
edge_conf.update({
"use_sell_signal": True,
"use_exit_signal": True,
})
# Passes test
validate_config_consistency(edge_conf)
edge_conf.update({
"use_sell_signal": False,
"use_exit_signal": False,
})
with pytest.raises(OperationalException, match="Edge requires `use_sell_signal` to be True, "
with pytest.raises(OperationalException, match="Edge requires `use_exit_signal` to be True, "
"otherwise no sells will happen."):
validate_config_consistency(edge_conf)
@@ -977,7 +977,7 @@ def test__validate_order_types(default_conf, caplog) -> None:
assert log_has_re(r"DEPRECATED: Using 'buy' and 'sell' for order_types is.*", caplog)
assert conf['order_types']['entry'] == 'limit'
assert conf['order_types']['exit'] == 'market'
assert conf['order_types']['forceentry'] == 'limit'
assert conf['order_types']['force_entry'] == 'limit'
assert 'buy' not in conf['order_types']
assert 'sell' not in conf['order_types']
assert 'forcebuy' not in conf['order_types']
@@ -1238,14 +1238,8 @@ def test_pairlist_resolving_fallback(mocker):
@pytest.mark.parametrize("setting", [
("ask_strategy", "use_sell_signal", True,
None, "use_sell_signal", False),
("ask_strategy", "sell_profit_only", True,
None, "sell_profit_only", False),
("ask_strategy", "sell_profit_offset", 0.1,
None, "sell_profit_offset", 0.01),
("ask_strategy", "ignore_roi_if_buy_signal", True,
None, "ignore_roi_if_buy_signal", False),
("webhook", "webhookbuy", 'testWEbhook',
"webhook", "webhookentry", 'testWEbhook'),
("ask_strategy", "ignore_buying_expired_candle_after", 5,
None, "ignore_buying_expired_candle_after", 6),
])

View File

@@ -25,7 +25,7 @@ from freqtrade.worker import Worker
from tests.conftest import (create_mock_trades, get_patched_freqtradebot, get_patched_worker,
log_has, log_has_re, patch_edge, patch_exchange, patch_get_signal,
patch_wallet, patch_whitelist)
from tests.conftest_trades import (MOCK_TRADE_COUNT, enter_side, exit_side, mock_order_1,
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)
@@ -236,6 +236,8 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
assert freqtrade.handle_trade(trade) is not ignore_strat_sl
if not ignore_strat_sl:
assert log_has_re('Exit for NEO/BTC detected. Reason: stop_loss.*', caplog)
assert trade.exit_reason == ExitType.STOP_LOSS.value
# Test compatibility ...
assert trade.sell_reason == ExitType.STOP_LOSS.value
@@ -301,7 +303,7 @@ def test_create_trade(default_conf_usdt, ticker_usdt, limit_order,
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(
limit_order[enter_side(is_short)], 'ADA/USDT', enter_side(is_short))
limit_order[entry_side(is_short)], 'ADA/USDT', entry_side(is_short))
trade.update_trade(oobj)
assert trade.open_rate == open_rate
@@ -339,7 +341,7 @@ def test_create_trade_minimal_amount(
) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
enter_mock = MagicMock(return_value=limit_order_open[enter_side(is_short)])
enter_mock = MagicMock(return_value=limit_order_open[entry_side(is_short)])
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_usdt,
@@ -535,8 +537,8 @@ def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_order, lim
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_usdt,
create_order=MagicMock(return_value=limit_order_open[enter_side(is_short)]),
fetch_order=MagicMock(return_value=limit_order[enter_side(is_short)]),
create_order=MagicMock(return_value=limit_order_open[entry_side(is_short)]),
fetch_order=MagicMock(return_value=limit_order[entry_side(is_short)]),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf_usdt)
@@ -749,8 +751,8 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
(10 - (2 / 1)) / (1 - (0.01 + 0.0006)) = 8.085708510208207
"""
# TODO: Split this test into multiple tests to improve readability
open_order = limit_order_open[enter_side(is_short)]
order = limit_order[enter_side(is_short)]
open_order = limit_order_open[entry_side(is_short)]
order = limit_order[entry_side(is_short)]
default_conf_usdt['trading_mode'] = trading_mode
default_conf_usdt['liquidation_buffer'] = liq_buffer
leverage = 1.0 if trading_mode == 'spot' else 5.0
@@ -973,7 +975,7 @@ def test_execute_entry_confirm_error(mocker, default_conf_usdt, fee, limit_order
'ask': 2.2,
'last': 1.9
}),
create_order=MagicMock(return_value=limit_order[enter_side(is_short)]),
create_order=MagicMock(return_value=limit_order[entry_side(is_short)]),
get_rate=MagicMock(return_value=0.11),
get_min_pair_stake_amount=MagicMock(return_value=1),
get_fee=fee,
@@ -984,11 +986,11 @@ def test_execute_entry_confirm_error(mocker, default_conf_usdt, fee, limit_order
freqtrade.strategy.confirm_trade_entry = MagicMock(side_effect=ValueError)
assert freqtrade.execute_entry(pair, stake_amount)
limit_order[enter_side(is_short)]['id'] = '222'
limit_order[entry_side(is_short)]['id'] = '222'
freqtrade.strategy.confirm_trade_entry = MagicMock(side_effect=Exception)
assert freqtrade.execute_entry(pair, stake_amount)
limit_order[enter_side(is_short)]['id'] = '2223'
limit_order[entry_side(is_short)]['id'] = '2223'
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
assert freqtrade.execute_entry(pair, stake_amount)
@@ -1008,7 +1010,7 @@ def test_execute_entry_min_leverage(mocker, default_conf_usdt, fee, limit_order,
'ask': 2.2,
'last': 1.9
}),
create_order=MagicMock(return_value=limit_order[enter_side(is_short)]),
create_order=MagicMock(return_value=limit_order[entry_side(is_short)]),
get_rate=MagicMock(return_value=0.11),
# Minimum stake-amount is ~5$
get_maintenance_ratio_and_amt=MagicMock(return_value=(0.0, 0.0)),
@@ -1030,7 +1032,7 @@ def test_execute_entry_min_leverage(mocker, default_conf_usdt, fee, limit_order,
def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_short) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
order = limit_order[enter_side(is_short)]
order = limit_order[entry_side(is_short)]
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True))
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
@@ -1060,7 +1062,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho
def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_short,
limit_order) -> None:
stoploss = MagicMock(return_value={'id': 13434334})
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -1208,14 +1210,14 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
assert freqtrade.handle_stoploss_on_exchange(trade) is False
assert trade.stoploss_order_id is None
assert trade.is_open is False
assert trade.sell_reason == str(ExitType.EMERGENCY_SELL)
assert trade.exit_reason == str(ExitType.EMERGENCY_EXIT)
@pytest.mark.parametrize("is_short", [False, True])
def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, is_short,
limit_order) -> None:
# Sixth case: stoploss order was cancelled but couldn't create new one
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -1258,7 +1260,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog,
def test_create_stoploss_order_invalid_order(
mocker, default_conf_usdt, caplog, fee, is_short, limit_order, limit_order_open
):
open_order = limit_order_open[enter_side(is_short)]
open_order = limit_order_open[entry_side(is_short)]
order = limit_order[exit_side(is_short)]
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -1291,7 +1293,7 @@ def test_create_stoploss_order_invalid_order(
caplog.clear()
freqtrade.create_stoploss_order(trade, 200)
assert trade.stoploss_order_id is None
assert trade.sell_reason == ExitType.EMERGENCY_SELL.value
assert trade.exit_reason == ExitType.EMERGENCY_EXIT.value
assert log_has("Unable to place a stoploss order on exchange. ", caplog)
assert log_has("Exiting the trade forcefully", caplog)
@@ -1303,7 +1305,7 @@ def test_create_stoploss_order_invalid_order(
# Rpc is sending first buy, then sell
assert rpc_mock.call_count == 2
assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == ExitType.EMERGENCY_SELL.value
assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == ExitType.EMERGENCY_EXIT.value
assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market'
@@ -1323,7 +1325,7 @@ def test_create_stoploss_order_insufficient_funds(
'last': 1.9
}),
create_order=MagicMock(side_effect=[
limit_order[enter_side(is_short)],
limit_order[entry_side(is_short)],
exit_order,
]),
get_fee=fee,
@@ -1362,7 +1364,7 @@ def test_handle_stoploss_on_exchange_trailing(
mocker, default_conf_usdt, fee, is_short, bid, ask, limit_order, stop_price, amt, hang_price
) -> None:
# When trailing stoploss is set
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
stoploss = MagicMock(return_value={'id': 13434334})
patch_RPCManager(mocker)
@@ -1483,7 +1485,7 @@ def test_handle_stoploss_on_exchange_trailing(
def test_handle_stoploss_on_exchange_trailing_error(
mocker, default_conf_usdt, fee, caplog, limit_order, is_short
) -> None:
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
# When trailing stoploss is set
stoploss = MagicMock(return_value={'id': 13434334})
@@ -1591,7 +1593,7 @@ def test_stoploss_on_exchange_price_rounding(
def test_handle_stoploss_on_exchange_custom_stop(
mocker, default_conf_usdt, fee, is_short, limit_order
) -> None:
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
# When trailing stoploss is set
stoploss = MagicMock(return_value={'id': 13434334})
@@ -1858,10 +1860,10 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True))
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
return_value=limit_order[enter_side(is_short)])
return_value=limit_order[entry_side(is_short)])
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
return_value=limit_order[enter_side(is_short)]['amount'])
return_value=limit_order[entry_side(is_short)]['amount'])
trade = MagicMock()
trade.is_short = is_short
@@ -1884,7 +1886,7 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog
@pytest.mark.parametrize("is_short", [False, True])
def test_exit_positions_exception(mocker, default_conf_usdt, limit_order, caplog, is_short) -> None:
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
order = limit_order[enter_side(is_short)]
order = limit_order[entry_side(is_short)]
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
trade = MagicMock()
@@ -1907,7 +1909,7 @@ def test_exit_positions_exception(mocker, default_conf_usdt, limit_order, caplog
@pytest.mark.parametrize("is_short", [False, True])
def test_update_trade_state(mocker, default_conf_usdt, limit_order, is_short, caplog) -> None:
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
order = limit_order[enter_side(is_short)]
order = limit_order[entry_side(is_short)]
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True))
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
@@ -1928,7 +1930,7 @@ def test_update_trade_state(mocker, default_conf_usdt, limit_order, is_short, ca
leverage=1,
)
trade.orders.append(Order(
ft_order_side=enter_side(is_short),
ft_order_side=entry_side(is_short),
price=0.01,
order_id=order_id,
@@ -1978,7 +1980,7 @@ def test_update_trade_state_withorderdict(
default_conf_usdt, trades_for_order, limit_order, fee, mocker, initial_amount,
has_rounding_fee, is_short, caplog
):
order = limit_order[enter_side(is_short)]
order = limit_order[entry_side(is_short)]
trades_for_order[0]['amount'] = initial_amount
order_id = "oid_123456"
order['id'] = order_id
@@ -2004,7 +2006,7 @@ def test_update_trade_state_withorderdict(
)
trade.orders.append(
Order(
ft_order_side=enter_side(is_short),
ft_order_side=entry_side(is_short),
ft_pair=trade.pair,
ft_is_open=True,
order_id=order_id,
@@ -2024,7 +2026,7 @@ def test_update_trade_state_withorderdict(
@pytest.mark.parametrize("is_short", [False, True])
def test_update_trade_state_exception(mocker, default_conf_usdt, is_short, limit_order,
caplog) -> None:
order = limit_order[enter_side(is_short)]
order = limit_order[entry_side(is_short)]
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
@@ -2105,7 +2107,7 @@ def test_handle_trade(
default_conf_usdt, limit_order_open, limit_order, fee, mocker, is_short, close_profit
) -> None:
open_order = limit_order_open[exit_side(is_short)]
enter_order = limit_order[enter_side(is_short)]
enter_order = limit_order[entry_side(is_short)]
exit_order = limit_order[exit_side(is_short)]
patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -2132,7 +2134,7 @@ def test_handle_trade(
assert trade
time.sleep(0.01) # Race condition fix
oobj = Order.parse_from_ccxt_object(enter_order, enter_order['symbol'], enter_side(is_short))
oobj = Order.parse_from_ccxt_object(enter_order, enter_order['symbol'], entry_side(is_short))
trade.update_trade(oobj)
assert trade.is_open is True
freqtrade.wallets.update()
@@ -2150,7 +2152,7 @@ def test_handle_trade(
assert trade.close_profit == close_profit
assert trade.calc_profit() == 5.685
assert trade.close_date is not None
assert trade.sell_reason == 'sell_signal1'
assert trade.exit_reason == 'sell_signal1'
@pytest.mark.parametrize("is_short", [False, True])
@@ -2233,7 +2235,7 @@ def test_handle_overlapping_signals(
def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_order_open, fee, mocker, caplog,
is_short) -> None:
open_order = limit_order_open[enter_side(is_short)]
open_order = limit_order_open[entry_side(is_short)]
caplog.set_level(logging.DEBUG)
@@ -2266,19 +2268,19 @@ def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_order_open, fee,
caplog.clear()
patch_get_signal(freqtrade)
assert freqtrade.handle_trade(trade)
assert log_has("ETH/USDT - Required profit reached. sell_type=ExitType.ROI",
assert log_has("ETH/USDT - Required profit reached. exit_type=ExitType.ROI",
caplog)
@pytest.mark.parametrize("is_short", [False, True])
def test_handle_trade_use_sell_signal(
def test_handle_trade_use_exit_signal(
default_conf_usdt, ticker_usdt, limit_order_open, fee, mocker, caplog, is_short
) -> None:
enter_open_order = limit_order_open[exit_side(is_short)]
exit_open_order = limit_order_open[enter_side(is_short)]
exit_open_order = limit_order_open[entry_side(is_short)]
# use_sell_signal is True buy default
# use_exit_signal is True buy default
caplog.set_level(logging.DEBUG)
patch_RPCManager(mocker)
mocker.patch.multiple(
@@ -2308,7 +2310,7 @@ def test_handle_trade_use_sell_signal(
else:
patch_get_signal(freqtrade, enter_long=False, exit_long=True)
assert freqtrade.handle_trade(trade)
assert log_has("ETH/USDT - Sell signal received. sell_type=ExitType.SELL_SIGNAL",
assert log_has("ETH/USDT - Sell signal received. exit_type=ExitType.EXIT_SIGNAL",
caplog)
@@ -2318,7 +2320,7 @@ def test_close_trade(
) -> None:
open_order = limit_order_open[exit_side(is_short)]
enter_order = limit_order[exit_side(is_short)]
exit_order = limit_order[enter_side(is_short)]
exit_order = limit_order[entry_side(is_short)]
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch.multiple(
@@ -2764,7 +2766,7 @@ def test_check_handle_timedout_partial_fee(
assert trades[0].amount == (limit_buy_order_old_partial['amount'] -
limit_buy_order_old_partial['remaining']) - 0.023
assert trades[0].open_order_id is None
assert trades[0].fee_updated(open_trade.enter_side)
assert trades[0].fee_updated(open_trade.entry_side)
assert pytest.approx(trades[0].fee_open) == 0.001
@@ -2851,8 +2853,8 @@ def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_tr
def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_short) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
l_order = limit_order[enter_side(is_short)]
cancel_buy_order = deepcopy(limit_order[enter_side(is_short)])
l_order = limit_order[entry_side(is_short)]
cancel_buy_order = deepcopy(limit_order[entry_side(is_short)])
cancel_buy_order['status'] = 'canceled'
del cancel_buy_order['filled']
@@ -2866,7 +2868,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
trade.pair = 'LTC/USDT'
trade.open_rate = 200
trade.is_short = False
trade.enter_side = "buy"
trade.entry_side = "buy"
l_order['filled'] = 0.0
l_order['status'] = 'open'
reason = CANCEL_REASON['TIMEOUT']
@@ -2894,7 +2896,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
assert log_has_re(r"Order .* for .* not cancelled.", caplog)
# min_pair_stake empty should not crash
mocker.patch('freqtrade.exchange.Exchange.get_min_pair_stake_amount', return_value=None)
assert not freqtrade.handle_cancel_enter(trade, limit_order[enter_side(is_short)], reason)
assert not freqtrade.handle_cancel_enter(trade, limit_order[entry_side(is_short)], reason)
@pytest.mark.parametrize("is_short", [False, True])
@@ -2913,11 +2915,11 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho
reason = CANCEL_REASON['TIMEOUT']
trade = MagicMock()
trade.pair = 'LTC/ETH'
trade.enter_side = "sell" if is_short else "buy"
trade.entry_side = "sell" if is_short else "buy"
assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason)
assert cancel_order_mock.call_count == 0
assert log_has_re(
f'{trade.enter_side.capitalize()} order fully cancelled. '
f'{trade.entry_side.capitalize()} order fully cancelled. '
r'Removing .* from database\.',
caplog
)
@@ -2935,7 +2937,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
cancelorder) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
l_order = limit_order[enter_side(is_short)]
l_order = limit_order[entry_side(is_short)]
cancel_order_mock = MagicMock(return_value=cancelorder)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -2947,9 +2949,9 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
trade = MagicMock()
trade.pair = 'LTC/USDT'
trade.enter_side = "buy"
trade.entry_side = "buy"
trade.open_rate = 200
trade.enter_side = "buy"
trade.entry_side = "buy"
l_order['filled'] = 0.0
l_order['status'] = 'open'
reason = CANCEL_REASON['TIMEOUT']
@@ -2985,7 +2987,7 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
fee_close=fee.return_value,
close_rate=0.555,
close_date=arrow.utcnow().datetime,
sell_reason="sell_reason_whatever",
exit_reason="sell_reason_whatever",
)
order = {'remaining': 1,
'amount': 1,
@@ -2995,7 +2997,7 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
assert cancel_order_mock.call_count == 1
assert send_msg_mock.call_count == 1
assert trade.close_rate is None
assert trade.sell_reason is None
assert trade.exit_reason is None
send_msg_mock.reset_mock()
@@ -3012,7 +3014,7 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
send_msg_mock.call_args_list[0][0][0]['reason'] = CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
# Message should not be iterated again
assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
assert trade.exit_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
assert send_msg_mock.call_count == 1
@@ -3089,7 +3091,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_
last_msg = rpc_mock.call_args_list[-1][0][0]
assert {
'trade_id': 1,
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'exchange': 'Binance',
'pair': 'ETH/USDT',
'gain': 'profit',
@@ -3107,6 +3109,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': ExitType.ROI.value,
'exit_reason': ExitType.ROI.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -3147,7 +3150,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd
assert rpc_mock.call_count == 2
last_msg = rpc_mock.call_args_list[-1][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/USDT',
@@ -3166,6 +3169,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -3217,7 +3221,7 @@ def test_execute_trade_exit_custom_exit_price(
freqtrade.execute_trade_exit(
trade=trade,
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
exit_check=ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL)
exit_check=ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)
)
# Sell price must be different to default bid price
@@ -3228,7 +3232,7 @@ def test_execute_trade_exit_custom_exit_price(
last_msg = rpc_mock.call_args_list[-1][0][0]
assert {
'trade_id': 1,
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'exchange': 'Binance',
'pair': 'ETH/USDT',
'direction': 'Short' if trade.is_short else 'Long',
@@ -3245,7 +3249,8 @@ def test_execute_trade_exit_custom_exit_price(
'profit_ratio': profit_ratio,
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': ExitType.SELL_SIGNAL.value,
'sell_reason': ExitType.EXIT_SIGNAL.value,
'exit_reason': ExitType.EXIT_SIGNAL.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -3294,7 +3299,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(
last_msg = rpc_mock.call_args_list[-1][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/USDT',
@@ -3313,6 +3318,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': ExitType.STOP_LOSS.value,
'exit_reason': ExitType.STOP_LOSS.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -3479,17 +3485,11 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
freqtrade.exit_positions(trades)
assert trade.stoploss_order_id is None
assert trade.is_open is False
assert trade.sell_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
assert rpc_mock.call_count == 3
if is_short:
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.SHORT
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.SHORT_FILL
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL
else:
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.BUY
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.BUY_FILL
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.ENTRY
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.ENTRY_FILL
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.EXIT
@pytest.mark.parametrize(
@@ -3557,7 +3557,7 @@ def test_execute_trade_exit_market_order(
assert rpc_mock.call_count == 3
last_msg = rpc_mock.call_args_list[-2][0][0]
assert {
'type': RPCMessageType.SELL,
'type': RPCMessageType.EXIT,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/USDT',
@@ -3576,6 +3576,7 @@ def test_execute_trade_exit_market_order(
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': ExitType.ROI.value,
'exit_reason': ExitType.ROI.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@@ -3621,27 +3622,27 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u
assert mock_insuf.call_count == 1
@pytest.mark.parametrize('profit_only,bid,ask,handle_first,handle_second,sell_type,is_short', [
@pytest.mark.parametrize('profit_only,bid,ask,handle_first,handle_second,exit_type,is_short', [
# Enable profit
(True, 2.18, 2.2, False, True, ExitType.SELL_SIGNAL.value, False),
(True, 2.18, 2.2, False, True, ExitType.SELL_SIGNAL.value, True),
(True, 2.18, 2.2, False, True, ExitType.EXIT_SIGNAL.value, False),
(True, 2.18, 2.2, False, True, ExitType.EXIT_SIGNAL.value, True),
# # Disable profit
(False, 3.19, 3.2, True, False, ExitType.SELL_SIGNAL.value, False),
(False, 3.19, 3.2, True, False, ExitType.SELL_SIGNAL.value, True),
(False, 3.19, 3.2, True, False, ExitType.EXIT_SIGNAL.value, False),
(False, 3.19, 3.2, True, False, ExitType.EXIT_SIGNAL.value, True),
# # Enable loss
# # * Shouldn't this be ExitType.STOP_LOSS.value
(True, 0.21, 0.22, False, False, None, False),
(True, 2.41, 2.42, False, False, None, True),
# Disable loss
(False, 0.10, 0.22, True, False, ExitType.SELL_SIGNAL.value, False),
(False, 0.10, 0.22, True, False, ExitType.SELL_SIGNAL.value, True),
(False, 0.10, 0.22, True, False, ExitType.EXIT_SIGNAL.value, False),
(False, 0.10, 0.22, True, False, ExitType.EXIT_SIGNAL.value, True),
])
def test_sell_profit_only(
def test_exit_profit_only(
default_conf_usdt, limit_order, limit_order_open, is_short,
fee, mocker, profit_only, bid, ask, handle_first, handle_second, sell_type) -> None:
fee, mocker, profit_only, bid, ask, handle_first, handle_second, exit_type) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
eside = enter_side(is_short)
eside = entry_side(is_short)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
@@ -3656,13 +3657,13 @@ def test_sell_profit_only(
get_fee=fee,
)
default_conf_usdt.update({
'use_sell_signal': True,
'sell_profit_only': profit_only,
'sell_profit_offset': 0.1,
'use_exit_signal': True,
'exit_profit_only': profit_only,
'exit_profit_offset': 0.1,
})
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
if sell_type == ExitType.SELL_SIGNAL.value:
if exit_type == ExitType.EXIT_SIGNAL.value:
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
else:
freqtrade.strategy.stop_loss_reached = MagicMock(return_value=ExitCheckTuple(
@@ -3678,7 +3679,7 @@ def test_sell_profit_only(
assert freqtrade.handle_trade(trade) is handle_first
if handle_second:
freqtrade.strategy.sell_profit_offset = 0.0
freqtrade.strategy.exit_profit_offset = 0.0
assert freqtrade.handle_trade(trade) is True
@@ -3798,11 +3799,11 @@ def test_locked_pairs(default_conf_usdt, ticker_usdt, fee,
@pytest.mark.parametrize("is_short", [False, True])
def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_order_open, is_short,
fee, mocker) -> None:
def test_ignore_roi_if_entry_signal(default_conf_usdt, limit_order, limit_order_open, is_short,
fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
eside = enter_side(is_short)
eside = entry_side(is_short)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
@@ -3816,7 +3817,7 @@ def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_order_op
]),
get_fee=fee,
)
default_conf_usdt['ignore_roi_if_buy_signal'] = True
default_conf_usdt['ignore_roi_if_entry_signal'] = True
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
@@ -3843,7 +3844,7 @@ def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_order_op
else:
patch_get_signal(freqtrade, enter_long=False, exit_long=False)
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == ExitType.ROI.value
assert trade.exit_reason == ExitType.ROI.value
@pytest.mark.parametrize("is_short,val1,val2", [
@@ -3862,7 +3863,7 @@ def test_trailing_stop_loss(default_conf_usdt, limit_order_open,
'last': 2.0
}),
create_order=MagicMock(side_effect=[
limit_order_open[enter_side(is_short)],
limit_order_open[entry_side(is_short)],
{'id': 1234553382},
]),
get_fee=fee,
@@ -3905,7 +3906,7 @@ def test_trailing_stop_loss(default_conf_usdt, limit_order_open,
f"stoploss is {(2.0 * val1 * stop_multi):6f}, "
f"initial stoploss was at {(2.0 * stop_multi):6f}, trade opened at 2.000000",
caplog)
assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value
assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value
@pytest.mark.parametrize('offset,trail_if_reached,second_sl,is_short', [
@@ -3920,10 +3921,10 @@ def test_trailing_stop_loss_positive(
default_conf_usdt, limit_order, limit_order_open,
offset, fee, caplog, mocker, trail_if_reached, second_sl, is_short
) -> None:
enter_price = limit_order[enter_side(is_short)]['price']
enter_price = limit_order[entry_side(is_short)]['price']
patch_RPCManager(mocker)
patch_exchange(mocker)
eside = enter_side(is_short)
eside = entry_side(is_short)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
@@ -4011,15 +4012,15 @@ def test_trailing_stop_loss_positive(
f"initial stoploss was at {'2.42' if is_short else '1.80'}0000, "
f"trade opened at {2.2 if is_short else 2.0}00000",
caplog)
assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value
assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value
@pytest.mark.parametrize("is_short", [False, True])
def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_order_open,
is_short, fee, mocker) -> None:
def test_disable_ignore_roi_if_entry_signal(default_conf_usdt, limit_order, limit_order_open,
is_short, fee, mocker) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
eside = enter_side(is_short)
eside = entry_side(is_short)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
@@ -4036,7 +4037,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_
_is_dry_limit_order_filled=MagicMock(return_value=False),
)
default_conf_usdt['exit_pricing'] = {
'ignore_roi_if_buy_signal': False
'ignore_roi_if_entry_signal': False
}
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
@@ -4057,7 +4058,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_
# Test if entry-signal is absent
patch_get_signal(freqtrade)
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == ExitType.ROI.value
assert trade.exit_reason == ExitType.ROI.value
def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog,
@@ -4423,7 +4424,7 @@ def test_order_book_depth_of_market(
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_usdt,
create_order=MagicMock(return_value=limit_order_open[enter_side(is_short)]),
create_order=MagicMock(return_value=limit_order_open[entry_side(is_short)]),
get_fee=fee,
)
@@ -4448,7 +4449,7 @@ def test_order_book_depth_of_market(
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(
limit_order_open[enter_side(is_short)], 'ADA/USDT', enter_side(is_short))
limit_order_open[entry_side(is_short)], 'ADA/USDT', entry_side(is_short))
trade.update_trade(oobj)
assert trade.open_rate == ticker_usdt.return_value[ticker_side]
@@ -4637,7 +4638,7 @@ def test_cancel_all_open_orders(mocker, default_conf_usdt, fee, limit_order, lim
side_effect=[
ExchangeError(),
limit_order[exit_side(is_short)],
limit_order_open[enter_side(is_short)],
limit_order_open[entry_side(is_short)],
limit_order_open[exit_side(is_short)],
]
)
@@ -4750,7 +4751,7 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf_usdt, f
for trade in trades:
if trade.is_open:
# Exclude Trade 4 - as the order is still open.
if trade.select_order(enter_side(is_short), False):
if trade.select_order(entry_side(is_short), False):
assert trade.fee_open_cost is not None
assert trade.fee_open_currency is not None
else:
@@ -5007,7 +5008,7 @@ def test_update_funding_fees(
# SETUP
time_machine.move_to("2021-09-01 00:00:00 +00:00")
open_order = limit_order_open[enter_side(is_short)]
open_order = limit_order_open[entry_side(is_short)]
open_exit_order = limit_order_open[exit_side(is_short)]
bid = 0.11
enter_rate_mock = MagicMock(return_value=bid)

View File

@@ -53,7 +53,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
# Sell 3rd trade (not called for the first trade)
should_sell_mock = MagicMock(side_effect=[
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL)]
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)]
)
cancel_order_mock = MagicMock()
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
@@ -115,15 +115,15 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
assert wallets_mock.call_count == 4
trade = trades[0]
assert trade.sell_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
assert not trade.is_open
trade = trades[1]
assert not trade.sell_reason
assert not trade.exit_reason
assert trade.is_open
trade = trades[2]
assert trade.sell_reason == ExitType.SELL_SIGNAL.value
assert trade.exit_reason == ExitType.EXIT_SIGNAL.value
assert not trade.is_open
@@ -139,7 +139,7 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati
one trade was sold at a loss.
"""
default_conf['max_open_trades'] = 5
default_conf['forcebuy_enable'] = True
default_conf['force_entry_enable'] = True
default_conf['stake_amount'] = 'unlimited'
default_conf['tradable_balance_ratio'] = balance_ratio
default_conf['dry_run_wallet'] = 1000
@@ -161,7 +161,7 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati
)
should_sell_mock = MagicMock(side_effect=[
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL),
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.NONE)]

View File

@@ -76,7 +76,7 @@ def test_init_dryrun_db(default_conf, tmpdir):
@pytest.mark.parametrize('is_short', [False, True])
@pytest.mark.usefixtures("init_persistence")
def test_enter_exit_side(fee, is_short):
enter_side, exit_side = ("sell", "buy") if is_short else ("buy", "sell")
entry_side, exit_side = ("sell", "buy") if is_short else ("buy", "sell")
trade = Trade(
id=2,
pair='ADA/USDT',
@@ -92,7 +92,7 @@ def test_enter_exit_side(fee, is_short):
leverage=2.0,
trading_mode=margin
)
assert trade.enter_side == enter_side
assert trade.entry_side == entry_side
assert trade.exit_side == exit_side
assert trade.trade_direction == 'short' if is_short else 'long'
@@ -456,7 +456,7 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
enter_order = limit_sell_order_usdt if is_short else limit_buy_order_usdt
exit_order = limit_buy_order_usdt if is_short else limit_sell_order_usdt
enter_side, exit_side = ("sell", "buy") if is_short else ("buy", "sell")
entry_side, exit_side = ("sell", "buy") if is_short else ("buy", "sell")
trade = Trade(
id=2,
@@ -479,13 +479,13 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
assert trade.close_date is None
trade.open_order_id = 'something'
oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', enter_side)
oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', entry_side)
trade.update_trade(oobj)
assert trade.open_order_id is None
assert trade.open_rate == open_rate
assert trade.close_profit is None
assert trade.close_date is None
assert log_has_re(f"LIMIT_{enter_side.upper()} has been fulfilled for "
assert log_has_re(f"LIMIT_{entry_side.upper()} has been fulfilled for "
r"Trade\(id=2, pair=ADA/USDT, amount=30.00000000, "
f"is_short={is_short}, leverage={lev}, open_rate={open_rate}0000000, "
r"open_since=.*\).",
@@ -1255,7 +1255,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
assert trade.min_rate is None
assert trade.stop_loss == 0.0
assert trade.initial_stop_loss == 0.0
assert trade.sell_reason is None
assert trade.exit_reason is None
assert trade.strategy is None
assert trade.timeframe == '5m'
assert trade.stoploss_order_id == 'stop_order_id222'
@@ -1590,7 +1590,8 @@ def test_to_json(fee):
'profit_pct': None,
'profit_abs': None,
'sell_reason': None,
'sell_order_status': None,
'exit_reason': None,
'exit_order_status': None,
'stop_loss_abs': None,
'stop_loss_ratio': None,
'stop_loss_pct': None,
@@ -1676,7 +1677,8 @@ def test_to_json(fee):
'open_rate_requested': None,
'open_trade_value': 12.33075,
'sell_reason': None,
'sell_order_status': None,
'exit_reason': None,
'exit_order_status': None,
'strategy': None,
'buy_tag': 'buys_signal_001',
'enter_tag': 'buys_signal_001',
@@ -2133,19 +2135,19 @@ def test_select_order(fee, is_short):
trades = Trade.get_trades().all()
# Open buy order, no sell order
order = trades[0].select_order(trades[0].enter_side, True)
order = trades[0].select_order(trades[0].entry_side, True)
assert order is None
order = trades[0].select_order(trades[0].enter_side, False)
order = trades[0].select_order(trades[0].entry_side, False)
assert order is not None
order = trades[0].select_order(trades[0].exit_side, None)
assert order is None
# closed buy order, and open sell order
order = trades[1].select_order(trades[1].enter_side, True)
order = trades[1].select_order(trades[1].entry_side, True)
assert order is None
order = trades[1].select_order(trades[1].enter_side, False)
order = trades[1].select_order(trades[1].entry_side, False)
assert order is not None
order = trades[1].select_order(trades[1].enter_side, None)
order = trades[1].select_order(trades[1].entry_side, None)
assert order is not None
order = trades[1].select_order(trades[1].exit_side, True)
assert order is None
@@ -2153,15 +2155,15 @@ def test_select_order(fee, is_short):
assert order is not None
# Has open buy order
order = trades[3].select_order(trades[3].enter_side, True)
order = trades[3].select_order(trades[3].entry_side, True)
assert order is not None
order = trades[3].select_order(trades[3].enter_side, False)
order = trades[3].select_order(trades[3].entry_side, False)
assert order is None
# Open sell order
order = trades[4].select_order(trades[4].enter_side, True)
order = trades[4].select_order(trades[4].entry_side, True)
assert order is None
order = trades[4].select_order(trades[4].enter_side, False)
order = trades[4].select_order(trades[4].entry_side, False)
assert order is not None
trades[4].orders[1].ft_order_side = trades[4].exit_side
@@ -2195,7 +2197,7 @@ def test_Trade_object_idem():
'get_open_trades_without_assigned_fees',
'get_open_order_trades',
'get_trades',
'get_sell_reason_performance',
'get_exit_reason_performance',
'get_enter_tag_performance',
'get_mix_tag_performance',
@@ -2384,7 +2386,7 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
o1_cost = o1_amount * o1_rate
o1_fee_cost = o1_cost * fee.return_value
o1_trade_val = o1_cost - o1_fee_cost if is_short else o1_cost + o1_fee_cost
enter_side = "sell" if is_short else "buy"
entry_side = "sell" if is_short else "buy"
exit_side = "buy" if is_short else "sell"
trade = Trade(
@@ -2400,16 +2402,16 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
is_short=is_short,
leverage=1.0,
)
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, enter_side)
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, entry_side)
# Check with 1 order
order1 = Order(
ft_order_side=enter_side,
ft_order_side=entry_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side=enter_side,
side=entry_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2430,13 +2432,13 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
assert trade.nr_of_successful_entries == 1
order2 = Order(
ft_order_side=enter_side,
ft_order_side=entry_side,
ft_pair=trade.pair,
ft_is_open=True,
status="open",
symbol=trade.pair,
order_type="market",
side=enter_side,
side=entry_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2458,13 +2460,13 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
# Let's try with some other orders
order3 = Order(
ft_order_side=enter_side,
ft_order_side=entry_side,
ft_pair=trade.pair,
ft_is_open=False,
status="cancelled",
symbol=trade.pair,
order_type="market",
side=enter_side,
side=entry_side,
price=1,
average=2,
filled=0,
@@ -2485,13 +2487,13 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
assert trade.nr_of_successful_entries == 1
order4 = Order(
ft_order_side=enter_side,
ft_order_side=entry_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side=enter_side,
side=entry_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2540,13 +2542,13 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
# Check with 1 order
order_noavg = Order(
ft_order_side=enter_side,
ft_order_side=entry_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side=enter_side,
side=entry_side,
price=o1_rate,
average=None,
filled=o1_amount,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long