Merge branch 'develop' into feat/short
This commit is contained in:
@@ -8,12 +8,12 @@ from zipfile import ZipFile
|
||||
import arrow
|
||||
import pytest
|
||||
|
||||
from freqtrade.commands import (start_convert_data, start_convert_trades, start_create_userdir,
|
||||
start_download_data, start_hyperopt_list, start_hyperopt_show,
|
||||
start_install_ui, start_list_data, start_list_exchanges,
|
||||
start_list_markets, start_list_strategies, start_list_timeframes,
|
||||
start_new_strategy, start_show_trades, start_test_pairlist,
|
||||
start_trading, start_webserver)
|
||||
from freqtrade.commands import (start_backtesting_show, start_convert_data, start_convert_trades,
|
||||
start_create_userdir, start_download_data, start_hyperopt_list,
|
||||
start_hyperopt_show, start_install_ui, start_list_data,
|
||||
start_list_exchanges, start_list_markets, start_list_strategies,
|
||||
start_list_timeframes, start_new_strategy, start_show_trades,
|
||||
start_test_pairlist, start_trading, start_webserver)
|
||||
from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui,
|
||||
get_ui_download_url, read_ui_version)
|
||||
from freqtrade.configuration import setup_utils_configuration
|
||||
@@ -1390,3 +1390,19 @@ def test_show_trades(mocker, fee, capsys, caplog):
|
||||
|
||||
with pytest.raises(OperationalException, match=r"--db-url is required for this command."):
|
||||
start_show_trades(pargs)
|
||||
|
||||
|
||||
def test_backtesting_show(mocker, testdatadir, capsys):
|
||||
sbr = mocker.patch('freqtrade.optimize.optimize_reports.show_backtest_results')
|
||||
args = [
|
||||
"backtesting-show",
|
||||
"--export-filename",
|
||||
f"{testdatadir / 'backtest-result_new.json'}",
|
||||
"--show-pair-list"
|
||||
]
|
||||
pargs = get_args(args)
|
||||
pargs['config'] = None
|
||||
start_backtesting_show(pargs)
|
||||
assert sbr.call_count == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert "Pairs for Strategy" in out
|
||||
|
@@ -215,7 +215,8 @@ def patch_get_signal(
|
||||
exit_long=False,
|
||||
enter_short=False,
|
||||
exit_short=False,
|
||||
enter_tag: Optional[str] = None
|
||||
enter_tag: Optional[str] = None,
|
||||
exit_tag: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
:param mocker: mocker to patch IStrategy class
|
||||
@@ -237,9 +238,9 @@ def patch_get_signal(
|
||||
|
||||
def patched_get_exit_signal(pair, timeframe, dataframe, is_short):
|
||||
if is_short:
|
||||
return enter_short, exit_short
|
||||
return enter_short, exit_short, exit_tag
|
||||
else:
|
||||
return enter_long, exit_long
|
||||
return enter_long, exit_long, exit_tag
|
||||
|
||||
# returns (enter, exit)
|
||||
freqtrade.strategy.get_exit_signal = patched_get_exit_signal
|
||||
@@ -247,7 +248,7 @@ def patch_get_signal(
|
||||
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
|
||||
|
||||
|
||||
def create_mock_trades(fee, is_short: bool, use_db: bool = True):
|
||||
def create_mock_trades(fee, is_short: bool = False, use_db: bool = True):
|
||||
"""
|
||||
Create some fake trades ...
|
||||
"""
|
||||
|
@@ -102,6 +102,7 @@ def mock_trade_2(fee, is_short: bool):
|
||||
open_order_id=f'dry_run_sell_{direc(is_short)}_12345',
|
||||
strategy='StrategyTestV3',
|
||||
timeframe=5,
|
||||
buy_tag='TEST1',
|
||||
sell_reason='sell_signal',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
|
||||
@@ -257,6 +258,7 @@ def mock_trade_5(fee, is_short: bool):
|
||||
open_rate=0.123,
|
||||
exchange='binance',
|
||||
strategy='SampleStrategy',
|
||||
buy_tag='TEST1',
|
||||
stoploss_order_id=f'prod_stoploss_{direc(is_short)}_3455',
|
||||
timeframe=5,
|
||||
is_short=is_short
|
||||
@@ -312,6 +314,7 @@ def mock_trade_6(fee, is_short: bool):
|
||||
open_rate=0.15,
|
||||
exchange='binance',
|
||||
strategy='SampleStrategy',
|
||||
buy_tag='TEST2',
|
||||
open_order_id=f"prod_sell_{direc(is_short)}_6",
|
||||
timeframe=5,
|
||||
)
|
||||
|
@@ -47,6 +47,11 @@ EXCHANGES = {
|
||||
'hasQuoteVolume': True,
|
||||
'timeframe': '5m',
|
||||
},
|
||||
'okex': {
|
||||
'pair': 'BTC/USDT',
|
||||
'hasQuoteVolume': True,
|
||||
'timeframe': '5m',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@@ -58,4 +58,12 @@ def _build_backtest_dataframe(data):
|
||||
frame[column] = frame[column].astype('float64')
|
||||
if 'enter_tag' not in columns:
|
||||
frame['enter_tag'] = None
|
||||
if 'exit_tag' not in columns:
|
||||
frame['exit_tag'] = None
|
||||
|
||||
# Ensure all candles make kindof sense
|
||||
assert all(frame['low'] <= frame['close'])
|
||||
assert all(frame['low'] <= frame['open'])
|
||||
assert all(frame['high'] >= frame['close'])
|
||||
assert all(frame['high'] >= frame['open'])
|
||||
return frame
|
||||
|
@@ -17,10 +17,10 @@ tc0 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4986, 4600, 6172, 0, 0], # exit with stoploss hit
|
||||
[3, 5010, 5000, 4980, 5010, 6172, 0, 1],
|
||||
[4, 5010, 4987, 4977, 4995, 6172, 0, 0],
|
||||
[5, 4995, 4995, 4995, 4950, 6172, 0, 0]],
|
||||
[2, 4987, 5012, 4986, 4986, 6172, 0, 0], # exit with stoploss hit
|
||||
[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=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
|
||||
)
|
||||
@@ -32,9 +32,9 @@ tc1 = BTContainer(data=[
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4600, 4600, 6172, 0, 0], # exit with stoploss hit
|
||||
[3, 4975, 5000, 4980, 4977, 6172, 0, 0],
|
||||
[4, 4977, 4987, 4977, 4995, 6172, 0, 0],
|
||||
[5, 4995, 4995, 4995, 4950, 6172, 0, 0]],
|
||||
[3, 4975, 5000, 4975, 4977, 6172, 0, 0],
|
||||
[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=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
|
||||
)
|
||||
@@ -69,7 +69,7 @@ tc3 = BTContainer(data=[
|
||||
[3, 4975, 5000, 4950, 4962, 6172, 1, 0],
|
||||
[4, 4975, 5000, 4950, 4962, 6172, 0, 0], # enter trade 2 (signal on last candle)
|
||||
[5, 4962, 4987, 4000, 4000, 6172, 0, 0], # exit with stoploss hit
|
||||
[6, 4950, 4975, 4975, 4950, 6172, 0, 0]],
|
||||
[6, 4950, 4975, 4950, 4950, 6172, 0, 0]],
|
||||
stop_loss=-0.02, roi={"0": 1}, profit_perc=-0.04,
|
||||
trades=[BTrade(sell_reason=SellType.STOP_LOSS, open_tick=1, close_tick=2),
|
||||
BTrade(sell_reason=SellType.STOP_LOSS, open_tick=4, close_tick=5)]
|
||||
@@ -99,7 +99,7 @@ tc5 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4980, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[3, 4975, 6000, 4975, 6000, 6172, 0, 0], # ROI
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
@@ -113,7 +113,7 @@ tc6 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5300, 4850, 5050, 6172, 0, 0], # Exit with stoploss
|
||||
[3, 4975, 5000, 4950, 4962, 6172, 0, 0],
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
|
||||
@@ -127,7 +127,7 @@ tc7 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
||||
[3, 4975, 5000, 4950, 4962, 6172, 0, 0],
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=2)]
|
||||
@@ -167,7 +167,7 @@ tc9 = BTContainer(data=[
|
||||
tc10 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 5100, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -183,7 +183,7 @@ tc10 = BTContainer(data=[
|
||||
tc11 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 5100, 5100, 6172, 0, 0],
|
||||
[3, 5000, 5150, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -199,7 +199,7 @@ tc11 = BTContainer(data=[
|
||||
tc12 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 4650, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -216,8 +216,8 @@ tc13 = BTContainer(data=[
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 4850, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4850, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4850, 4750, 6172, 0, 0]],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=1)]
|
||||
)
|
||||
@@ -229,7 +229,7 @@ tc14 = BTContainer(data=[
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5100, 4600, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 4850, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4850, 4750, 6172, 0, 0],
|
||||
[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=SellType.STOP_LOSS, open_tick=1, close_tick=1)]
|
||||
@@ -243,7 +243,7 @@ tc15 = BTContainer(data=[
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5100, 4900, 5100, 6172, 1, 0],
|
||||
[2, 5100, 5251, 4650, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4850, 4750, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=1),
|
||||
@@ -259,7 +259,7 @@ tc16 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
||||
[3, 4975, 5000, 4940, 4962, 6172, 0, 0], # ForceSell on ROI (roi=-1)
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
@@ -275,7 +275,7 @@ tc17 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
||||
[3, 4980, 5000, 4940, 4962, 6172, 0, 0], # ForceSell on ROI (roi=-1)
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
@@ -291,7 +291,7 @@ tc18 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
|
||||
[3, 5200, 5220, 4940, 4962, 6172, 0, 0], # Sell on ROI (sells on open)
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
@@ -306,8 +306,8 @@ tc19 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
|
||||
[3, 5000, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[5, 4550, 4975, 4925, 4950, 6172, 0, 0]],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
)
|
||||
@@ -321,8 +321,8 @@ tc20 = BTContainer(data=[
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
|
||||
[3, 5200, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
|
||||
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
|
||||
[5, 4550, 4975, 4925, 4950, 6172, 0, 0]],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
)
|
||||
@@ -334,7 +334,7 @@ tc20 = BTContainer(data=[
|
||||
tc21 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 4650, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -350,7 +350,7 @@ tc21 = BTContainer(data=[
|
||||
tc22 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 5100, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -369,7 +369,7 @@ tc22 = BTContainer(data=[
|
||||
tc23 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 5100, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5251, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -386,10 +386,10 @@ tc24 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4986, 4600, 6172, 0, 0],
|
||||
[3, 5010, 5000, 4855, 5010, 6172, 0, 1], # Triggers stoploss + sellsignal
|
||||
[4, 5010, 4987, 4977, 4995, 6172, 0, 0],
|
||||
[5, 4995, 4995, 4995, 4950, 6172, 0, 0]],
|
||||
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
|
||||
[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=SellType.STOP_LOSS, open_tick=1, close_tick=3)]
|
||||
)
|
||||
@@ -401,10 +401,10 @@ tc25 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4986, 4600, 6172, 0, 0],
|
||||
[3, 5010, 5000, 4986, 5010, 6172, 0, 1],
|
||||
[4, 5010, 4987, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
|
||||
[5, 4995, 4995, 4995, 4950, 6172, 0, 0]],
|
||||
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
|
||||
[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=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
|
||||
)
|
||||
@@ -416,10 +416,10 @@ tc26 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4986, 4600, 6172, 0, 0],
|
||||
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
|
||||
[3, 5010, 5251, 4986, 5010, 6172, 0, 1], # Triggers ROI, sell-signal
|
||||
[4, 5010, 4987, 4855, 4995, 6172, 0, 0],
|
||||
[5, 4995, 4995, 4995, 4950, 6172, 0, 0]],
|
||||
[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=SellType.ROI, open_tick=1, close_tick=3)]
|
||||
)
|
||||
@@ -432,10 +432,10 @@ tc27 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4987, 5012, 4986, 4600, 6172, 0, 0],
|
||||
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
|
||||
[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, 4995, 4950, 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=SellType.ROI, open_tick=1, close_tick=4)]
|
||||
)
|
||||
@@ -447,7 +447,7 @@ tc27 = BTContainer(data=[
|
||||
tc28 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 4950, 5100, 6172, 0, 0],
|
||||
[1, 5000, 5100, 4950, 5100, 6172, 0, 0],
|
||||
[2, 5100, 5251, 5100, 5100, 6172, 0, 0],
|
||||
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -463,7 +463,7 @@ tc28 = BTContainer(data=[
|
||||
tc29 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5050, 5000, 4900, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[1, 5000, 5050, 5000, 5000, 6172, 0, 0], # enter trade (signal on last candle)
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Triggers trailing-stoploss
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -477,7 +477,7 @@ tc29 = BTContainer(data=[
|
||||
tc30 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5500, 5000, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
|
||||
[1, 5000, 5500, 4900, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0],
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -491,7 +491,7 @@ tc30 = BTContainer(data=[
|
||||
tc31 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5500, 5000, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
|
||||
[1, 5000, 5500, 4900, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0],
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -506,7 +506,7 @@ tc31 = BTContainer(data=[
|
||||
tc32 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
|
||||
[1, 5000, 5500, 5000, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
|
||||
[1, 5000, 5500, 4951, 5000, 6172, 0, 0], # enter trade and stop
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0],
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||
@@ -521,7 +521,7 @@ tc32 = BTContainer(data=[
|
||||
tc33 = BTContainer(data=[
|
||||
# D O H L C V EL XL ES Xs BT
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0, 0, 0, 'buy_signal_01'],
|
||||
[1, 5000, 5500, 5000, 4900, 6172, 0, 0, 0, 0, None], # enter trade and stop
|
||||
[1, 5000, 5500, 4951, 5000, 6172, 0, 0, 0, 0, None], # enter trade and stop
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0, 0, 0, None],
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 0, None],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0, None]],
|
||||
|
@@ -579,6 +579,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
||||
0, # exit_hsort
|
||||
'', # Long Signal Name
|
||||
'', # Short Signal Name
|
||||
'', # Exit Signal Name
|
||||
]
|
||||
|
||||
trade = backtesting._enter_trade(pair, row=row, direction='long')
|
||||
@@ -596,27 +597,29 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
||||
0, # exit_short
|
||||
'', # long Signal Name
|
||||
'', # Short Signal Name
|
||||
'', # Exit Signal Name
|
||||
|
||||
]
|
||||
row_detail = pd.DataFrame(
|
||||
[
|
||||
[
|
||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0, tzinfo=timezone.utc),
|
||||
200, 200.1, 197, 199, 1, 0, 0, 0, '', '',
|
||||
200, 200.1, 197, 199, 1, 0, 0, 0, '', '', '',
|
||||
], [
|
||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=1, tzinfo=timezone.utc),
|
||||
199, 199.7, 199, 199.5, 0, 0, 0, 0, '', ''
|
||||
199, 199.7, 199, 199.5, 0, 0, 0, 0, '', '', '',
|
||||
], [
|
||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=2, tzinfo=timezone.utc),
|
||||
199.5, 200.8, 199, 200.9, 0, 0, 0, 0, '', ''
|
||||
199.5, 200.8, 199, 200.9, 0, 0, 0, 0, '', '', '',
|
||||
], [
|
||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=3, tzinfo=timezone.utc),
|
||||
200.5, 210.5, 193, 210.5, 0, 0, 0, 0, '', '' # ROI sell (?)
|
||||
200.5, 210.5, 193, 210.5, 0, 0, 0, 0, '', '', '', # ROI sell (?)
|
||||
], [
|
||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=4, tzinfo=timezone.utc),
|
||||
200, 200.1, 193, 199, 0, 0, 0, 0, '', ''
|
||||
200, 200.1, 193, 199, 0, 0, 0, 0, '', '', '',
|
||||
],
|
||||
], columns=['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long',
|
||||
'enter_short', 'exit_short', 'long_tag', 'short_tag']
|
||||
'enter_short', 'exit_short', 'long_tag', 'short_tag', 'exit_tag']
|
||||
)
|
||||
|
||||
# No data available.
|
||||
@@ -631,7 +634,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
||||
# Assign empty ... no result.
|
||||
backtesting.detail_data[pair] = pd.DataFrame(
|
||||
[], columns=['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long',
|
||||
'enter_short', 'exit_short', 'long_tag', 'short_tag'])
|
||||
'enter_short', 'exit_short', 'long_tag', 'short_tag', 'exit_tag'])
|
||||
|
||||
res = backtesting._get_sell_trade_entry(trade, row)
|
||||
assert res is None
|
||||
@@ -695,7 +698,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
|
||||
'min_rate': [0.10370188, 0.10300000000000001],
|
||||
'max_rate': [0.10501, 0.1038888],
|
||||
'is_open': [False, False],
|
||||
'buy_tag': [None, None],
|
||||
'buy_tag': [None, None]
|
||||
})
|
||||
pd.testing.assert_frame_equal(results, expected)
|
||||
data_pair = processed[pair]
|
||||
|
@@ -10,7 +10,8 @@ from arrow import Arrow
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN
|
||||
from freqtrade.data import history
|
||||
from freqtrade.data.btanalysis import get_latest_backtest_filename, load_backtest_data
|
||||
from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backtest_data,
|
||||
load_backtest_stats)
|
||||
from freqtrade.edge import PairInfo
|
||||
from freqtrade.enums import SellType
|
||||
from freqtrade.optimize.optimize_reports import (_get_resample_from_period, generate_backtest_stats,
|
||||
@@ -19,9 +20,9 @@ from freqtrade.optimize.optimize_reports import (_get_resample_from_period, gene
|
||||
generate_periodic_breakdown_stats,
|
||||
generate_sell_reason_stats,
|
||||
generate_strategy_comparison,
|
||||
generate_trading_stats, store_backtest_stats,
|
||||
text_table_bt_results, text_table_sell_reason,
|
||||
text_table_strategy)
|
||||
generate_trading_stats, show_sorted_pairlist,
|
||||
store_backtest_stats, text_table_bt_results,
|
||||
text_table_sell_reason, text_table_strategy)
|
||||
from freqtrade.resolvers.strategy_resolver import StrategyResolver
|
||||
from tests.conftest import CURRENT_TEST_STRATEGY
|
||||
from tests.data.test_history import _backup_file, _clean_test_file
|
||||
@@ -408,3 +409,16 @@ def test__get_resample_from_period():
|
||||
assert _get_resample_from_period('month') == '1M'
|
||||
with pytest.raises(ValueError, match=r"Period noooo is not supported."):
|
||||
_get_resample_from_period('noooo')
|
||||
|
||||
|
||||
def test_show_sorted_pairlist(testdatadir, default_conf, capsys):
|
||||
filename = testdatadir / "backtest-result_new.json"
|
||||
bt_data = load_backtest_stats(filename)
|
||||
default_conf['backtest_show_pair_list'] = True
|
||||
|
||||
show_sorted_pairlist(default_conf, bt_data)
|
||||
|
||||
out, err = capsys.readouterr()
|
||||
assert 'Pairs for Strategy StrategyTestV2: \n[' in out
|
||||
assert 'TOTAL' not in out
|
||||
assert '"ETH/BTC", // ' in out
|
||||
|
@@ -839,8 +839,226 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
assert len(res) == 1
|
||||
assert res[0]['pair'] == 'ETH/BTC'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 6.2)
|
||||
|
||||
|
||||
def test_buy_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
limit_sell_order, mocker) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
res = rpc._rpc_buy_tag_performance(None)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['buy_tag'] == 'Other'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 6.2)
|
||||
|
||||
trade.buy_tag = "TEST_TAG"
|
||||
res = rpc._rpc_buy_tag_performance(None)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['buy_tag'] == 'TEST_TAG'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 6.2)
|
||||
|
||||
|
||||
def test_buy_tag_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
create_mock_trades(fee)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
res = rpc._rpc_buy_tag_performance(None)
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0]['buy_tag'] == 'TEST1'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
assert res[1]['buy_tag'] == 'Other'
|
||||
assert res[1]['count'] == 1
|
||||
assert prec_satoshi(res[1]['profit_pct'], 1.0)
|
||||
|
||||
# Test for a specific pair
|
||||
res = rpc._rpc_buy_tag_performance('ETC/BTC')
|
||||
assert len(res) == 1
|
||||
assert res[0]['count'] == 1
|
||||
assert res[0]['buy_tag'] == 'TEST1'
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
|
||||
|
||||
def test_sell_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(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
res = rpc._rpc_sell_reason_performance(None)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['sell_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)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['sell_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):
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
create_mock_trades(fee)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
res = rpc._rpc_sell_reason_performance(None)
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0]['sell_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]['count'] == 1
|
||||
assert prec_satoshi(res[1]['profit_pct'], 1.0)
|
||||
|
||||
# Test for a specific pair
|
||||
res = rpc._rpc_sell_reason_performance('ETC/BTC')
|
||||
assert len(res) == 1
|
||||
assert res[0]['count'] == 1
|
||||
assert res[0]['sell_reason'] == 'sell_signal'
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
|
||||
|
||||
def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
limit_sell_order, mocker) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
res = rpc._rpc_mix_tag_performance(None)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['mix_tag'] == 'Other Other'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit'], 6.2)
|
||||
|
||||
trade.buy_tag = "TESTBUY"
|
||||
trade.sell_reason = "TESTSELL"
|
||||
res = rpc._rpc_mix_tag_performance(None)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['mix_tag'] == 'TESTBUY TESTSELL'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit'], 6.2)
|
||||
|
||||
|
||||
def test_mix_tag_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
create_mock_trades(fee)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
res = rpc._rpc_mix_tag_performance(None)
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0]['mix_tag'] == 'TEST1 sell_signal'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit'], 0.5)
|
||||
assert res[1]['mix_tag'] == 'Other roi'
|
||||
assert res[1]['count'] == 1
|
||||
assert prec_satoshi(res[1]['profit'], 1.0)
|
||||
|
||||
# Test for a specific pair
|
||||
res = rpc._rpc_mix_tag_performance('ETC/BTC')
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['count'] == 1
|
||||
assert res[0]['mix_tag'] == 'TEST1 sell_signal'
|
||||
assert prec_satoshi(res[0]['profit'], 0.5)
|
||||
|
||||
|
||||
def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
|
@@ -820,8 +820,10 @@ def test_api_performance(botclient, fee):
|
||||
rc = client_get(client, f"{BASE_URI}/performance")
|
||||
assert_response(rc)
|
||||
assert len(rc.json()) == 2
|
||||
assert rc.json() == [{'count': 1, 'pair': 'LTC/ETH', 'profit': 7.61, 'profit_abs': 0.01872279},
|
||||
{'count': 1, 'pair': 'XRP/ETH', 'profit': -5.57, 'profit_abs': -0.1150375}]
|
||||
assert rc.json() == [{'count': 1, 'pair': 'LTC/ETH', 'profit': 7.61, 'profit_pct': 7.61,
|
||||
'profit_ratio': 0.07609203, 'profit_abs': 0.01872279},
|
||||
{'count': 1, 'pair': 'XRP/ETH', 'profit': -5.57, 'profit_pct': -5.57,
|
||||
'profit_ratio': -0.05570419, 'profit_abs': -0.1150375}]
|
||||
|
||||
|
||||
# TODO-lev: @pytest.mark.parametrize('is_short,side', [
|
||||
|
@@ -93,7 +93,8 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
|
||||
|
||||
message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], "
|
||||
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], ['trades'], "
|
||||
"['delete'], ['performance'], ['stats'], ['daily'], ['count'], ['locks'], "
|
||||
"['delete'], ['performance'], ['buys'], ['sells'], ['mix_tags'], "
|
||||
"['stats'], ['daily'], ['count'], ['locks'], "
|
||||
"['unlock', 'delete_locks'], ['reload_config', 'reload_conf'], "
|
||||
"['show_config', 'show_conf'], ['stopbuy'], "
|
||||
"['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']"
|
||||
@@ -715,6 +716,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
||||
'profit_ratio': 0.0629778,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': ANY,
|
||||
'sell_reason': SellType.FORCE_SELL.value,
|
||||
'open_date': ANY,
|
||||
'close_date': ANY,
|
||||
@@ -778,6 +780,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
|
||||
'profit_ratio': -0.05482878,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': ANY,
|
||||
'sell_reason': SellType.FORCE_SELL.value,
|
||||
'open_date': ANY,
|
||||
'close_date': ANY,
|
||||
@@ -831,6 +834,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
'profit_ratio': -0.00408133,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': ANY,
|
||||
'sell_reason': SellType.FORCE_SELL.value,
|
||||
'open_date': ANY,
|
||||
'close_date': ANY,
|
||||
@@ -976,6 +980,102 @@ def test_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_buy_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,
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
trade.buy_tag = "TESTBUY"
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
telegram._buy_tag_performance(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'Buy 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]
|
||||
|
||||
|
||||
def test_sell_reason_performance_handle(default_conf, update, ticker, fee,
|
||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
trade.sell_reason = 'TESTSELL'
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
telegram._sell_reason_performance(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'Sell 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]
|
||||
|
||||
|
||||
def test_mix_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,
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
trade.buy_tag = "TESTBUY"
|
||||
trade.sell_reason = "TESTSELL"
|
||||
|
||||
# Simulate fulfilled LIMIT_SELL order for trade
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
telegram._mix_tag_performance(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'Mix Tag Performance' in msg_mock.call_args_list[0][0][0]
|
||||
assert ('<code>TESTBUY TESTSELL\t0.00006217 BTC (6.20%) (1)</code>'
|
||||
in msg_mock.call_args_list[0][0][0])
|
||||
|
||||
|
||||
def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
@@ -1386,6 +1486,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': 'buy_signal1',
|
||||
'sell_reason': SellType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(hours=-1),
|
||||
'close_date': arrow.utcnow(),
|
||||
@@ -1393,6 +1494,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
|
||||
'*Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
|
||||
'*Buy Tag:* `buy_signal1`\n'
|
||||
'*Sell Reason:* `stop_loss`\n'
|
||||
'*Duration:* `1:00:00 (60.0 min)`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
@@ -1416,6 +1518,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'buy_tag': 'buy_signal1',
|
||||
'sell_reason': SellType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
@@ -1423,6 +1526,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
|
||||
'*Profit:* `-57.41%`\n'
|
||||
'*Buy Tag:* `buy_signal1`\n'
|
||||
'*Sell Reason:* `stop_loss`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
@@ -1487,6 +1591,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None:
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': 'buy_signal1',
|
||||
'sell_reason': SellType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(hours=-1),
|
||||
'close_date': arrow.utcnow(),
|
||||
@@ -1578,12 +1683,14 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'buy_tag': 'buy_signal1',
|
||||
'sell_reason': SellType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
|
||||
'*Profit:* `-57.41%`\n'
|
||||
'*Buy Tag:* `buy_signal1`\n'
|
||||
'*Sell Reason:* `stop_loss`\n'
|
||||
'*Duration:* `2:35:03 (155.1 min)`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
|
@@ -42,29 +42,29 @@ def test_returns_latest_signal(ohlcv_history):
|
||||
mocked_history.loc[1, 'exit_long'] = 1
|
||||
|
||||
assert _STRATEGY.get_entry_signal('ETH/BTC', '5m', mocked_history) == (None, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, True)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, True, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False, None)
|
||||
mocked_history.loc[1, 'exit_long'] = 0
|
||||
mocked_history.loc[1, 'enter_long'] = 1
|
||||
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (SignalDirection.LONG, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (True, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (True, False, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False, None)
|
||||
mocked_history.loc[1, 'exit_long'] = 0
|
||||
mocked_history.loc[1, 'enter_long'] = 0
|
||||
|
||||
assert _STRATEGY.get_entry_signal('ETH/BTC', '5m', mocked_history) == (None, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False, None)
|
||||
mocked_history.loc[1, 'exit_long'] = 0
|
||||
mocked_history.loc[1, 'enter_long'] = 1
|
||||
mocked_history.loc[1, 'enter_tag'] = 'buy_signal_01'
|
||||
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (SignalDirection.LONG, 'buy_signal_01')
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (True, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (True, False, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False, None)
|
||||
|
||||
mocked_history.loc[1, 'exit_long'] = 0
|
||||
mocked_history.loc[1, 'enter_long'] = 0
|
||||
@@ -74,15 +74,18 @@ def test_returns_latest_signal(ohlcv_history):
|
||||
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (SignalDirection.SHORT, 'sell_signal_01')
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False, None)
|
||||
|
||||
mocked_history.loc[1, 'enter_short'] = 0
|
||||
mocked_history.loc[1, 'exit_short'] = 1
|
||||
mocked_history.loc[1, 'exit_tag'] = 'sell_signal_02'
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (None, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, True)
|
||||
assert _STRATEGY.get_exit_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (False, False, 'sell_signal_02')
|
||||
assert _STRATEGY.get_exit_signal(
|
||||
'ETH/BTC', '5m', mocked_history, True) == (False, True, 'sell_signal_02')
|
||||
|
||||
|
||||
def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
|
||||
@@ -711,7 +714,7 @@ def test_strategy_safe_wrapper(value):
|
||||
|
||||
ret = strategy_safe_wrapper(working_method, message='DeadBeef')(value)
|
||||
|
||||
assert type(ret) == type(value)
|
||||
assert isinstance(ret, type(value))
|
||||
assert ret == value
|
||||
|
||||
|
||||
|
@@ -1360,6 +1360,7 @@ def test_flat_vars_to_nested_dict(caplog):
|
||||
'FREQTRADE__ASK_STRATEGY__PRICE_SIDE': 'bid',
|
||||
'FREQTRADE__ASK_STRATEGY__cccc': '500',
|
||||
'FREQTRADE__STAKE_AMOUNT': '200.05',
|
||||
'FREQTRADE__TELEGRAM__CHAT_ID': '2151',
|
||||
'NOT_RELEVANT': '200.0', # Will be ignored
|
||||
}
|
||||
expected = {
|
||||
@@ -1374,6 +1375,9 @@ def test_flat_vars_to_nested_dict(caplog):
|
||||
},
|
||||
'some_setting': True,
|
||||
'some_false_setting': False,
|
||||
},
|
||||
'telegram': {
|
||||
'chat_id': '2151'
|
||||
}
|
||||
}
|
||||
res = flat_vars_to_nested_dict(test_args, ENV_VAR_PREFIX)
|
||||
|
@@ -236,7 +236,7 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
|
||||
# stoploss shoud be hit
|
||||
assert freqtrade.handle_trade(trade) is not ignore_strat_sl
|
||||
if not ignore_strat_sl:
|
||||
assert log_has('Exit for NEO/BTC detected. Reason: stop_loss', caplog)
|
||||
assert log_has_re('Exit for NEO/BTC detected. Reason: stop_loss.*', caplog)
|
||||
assert trade.sell_reason == SellType.STOP_LOSS.value
|
||||
|
||||
|
||||
@@ -458,7 +458,6 @@ def test_create_trade_no_signal(default_conf_usdt, fee, mocker) -> None:
|
||||
)
|
||||
default_conf_usdt['stake_amount'] = 10
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
# patch_get_signal(freqtrade, enter_long=False)
|
||||
patch_get_signal(freqtrade, enter_long=False, exit_long=False)
|
||||
|
||||
Trade.query = MagicMock()
|
||||
@@ -1800,6 +1799,15 @@ def test_update_trade_state(
|
||||
freqtrade.update_trade_state(trade, '123')
|
||||
|
||||
assert log_has_re('Found open order for.*', caplog)
|
||||
limit_buy_order_usdt_new = deepcopy(limit_order)
|
||||
limit_buy_order_usdt_new['filled'] = 0.0
|
||||
limit_buy_order_usdt_new['status'] = 'canceled'
|
||||
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', side_effect=ValueError)
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt_new)
|
||||
res = freqtrade.update_trade_state(trade, '123')
|
||||
# Cancelled empty
|
||||
assert res is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@@ -1956,7 +1964,8 @@ def test_handle_trade(
|
||||
assert trade.is_open is True
|
||||
freqtrade.wallets.update()
|
||||
|
||||
patch_get_signal(freqtrade, enter_long=False, exit_short=is_short, exit_long=not is_short)
|
||||
patch_get_signal(freqtrade, enter_long=False, exit_short=is_short,
|
||||
exit_long=not is_short, exit_tag='sell_signal1')
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.open_order_id == exit_order['id']
|
||||
|
||||
@@ -1967,6 +1976,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'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@@ -2851,6 +2861,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_
|
||||
'limit': 2.0 if is_short else 2.2,
|
||||
'amount': amt,
|
||||
'order_type': 'limit',
|
||||
'buy_tag': None,
|
||||
'open_rate': open_rate,
|
||||
'current_rate': 2.01 if is_short else 2.3,
|
||||
'profit_amount': 0.29554455 if is_short else 5.685,
|
||||
@@ -2906,6 +2917,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd
|
||||
'limit': 2.2 if is_short else 2.01,
|
||||
'amount': 29.70297029 if is_short else 30.0,
|
||||
'order_type': 'limit',
|
||||
'buy_tag': None,
|
||||
'open_rate': 2.02 if is_short else 2.0,
|
||||
'current_rate': 2.2 if is_short else 2.0,
|
||||
'profit_amount': -5.65990099 if is_short else -0.00075,
|
||||
@@ -2980,6 +2992,7 @@ def test_execute_trade_exit_custom_exit_price(
|
||||
'limit': limit,
|
||||
'amount': amount,
|
||||
'order_type': 'limit',
|
||||
'buy_tag': None,
|
||||
'open_rate': open_rate,
|
||||
'current_rate': current_rate,
|
||||
'profit_amount': profit_amount,
|
||||
@@ -3043,6 +3056,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(
|
||||
'limit': 2.02 if is_short else 1.98,
|
||||
'amount': 29.70297029 if is_short else 30.0,
|
||||
'order_type': 'limit',
|
||||
'buy_tag': None,
|
||||
'open_rate': 2.02 if is_short else 2.0,
|
||||
'current_rate': 2.2 if is_short else 2.0,
|
||||
'profit_amount': -0.3 if is_short else -0.8985,
|
||||
@@ -3295,6 +3309,7 @@ def test_execute_trade_exit_market_order(
|
||||
'limit': limit,
|
||||
'amount': round(amount, 9),
|
||||
'order_type': 'market',
|
||||
'buy_tag': None,
|
||||
'open_rate': open_rate,
|
||||
'current_rate': current_rate,
|
||||
'profit_amount': profit_amount,
|
||||
|
@@ -2108,6 +2108,10 @@ def test_Trade_object_idem():
|
||||
'get_open_trades_without_assigned_fees',
|
||||
'get_open_order_trades',
|
||||
'get_trades',
|
||||
'get_sell_reason_performance',
|
||||
'get_buy_tag_performance',
|
||||
'get_mix_tag_performance',
|
||||
|
||||
)
|
||||
|
||||
# Parent (LocalTrade) should have the same attributes
|
||||
|
Reference in New Issue
Block a user