Merge branch 'feat/short' into funding-fee-dry-run

This commit is contained in:
Sam Germain
2021-11-06 22:46:00 -06:00
73 changed files with 1653 additions and 394 deletions

View File

@@ -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

View File

@@ -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 ...
"""

View File

@@ -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,
)

View File

@@ -47,6 +47,11 @@ EXCHANGES = {
'hasQuoteVolume': True,
'timeframe': '5m',
},
'okex': {
'pair': 'BTC/USDT',
'hasQuoteVolume': True,
'timeframe': '5m',
},
}

View File

@@ -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

View File

@@ -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]],

View File

@@ -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]

View File

@@ -209,7 +209,8 @@ def test_export_params(tmpdir):
assert filename.is_file()
content = rapidjson.load(filename.open('r'))
with filename.open('r') as f:
content = rapidjson.load(f)
assert content['strategy_name'] == CURRENT_TEST_STRATEGY
assert 'params' in content
assert "buy" in content["params"]

View File

@@ -85,6 +85,8 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) ->
"SharpeHyperOptLoss",
"SharpeHyperOptLossDaily",
"MaxDrawDownHyperOptLoss",
"CalmarHyperOptLoss",
])
def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunction) -> None:
results_over = hyperopt_results.copy()
@@ -96,11 +98,32 @@ def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunct
default_conf.update({'hyperopt_loss': lossfunction})
hl = HyperOptLossResolver.load_hyperoptloss(default_conf)
correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results),
datetime(2019, 1, 1), datetime(2019, 5, 1))
over = hl.hyperopt_loss_function(results_over, len(results_over),
datetime(2019, 1, 1), datetime(2019, 5, 1))
under = hl.hyperopt_loss_function(results_under, len(results_under),
datetime(2019, 1, 1), datetime(2019, 5, 1))
correct = hl.hyperopt_loss_function(
hyperopt_results,
trade_count=len(hyperopt_results),
min_date=datetime(2019, 1, 1),
max_date=datetime(2019, 5, 1),
config=default_conf,
processed=None,
backtest_stats={'profit_total': hyperopt_results['profit_abs'].sum()}
)
over = hl.hyperopt_loss_function(
results_over,
trade_count=len(results_over),
min_date=datetime(2019, 1, 1),
max_date=datetime(2019, 5, 1),
config=default_conf,
processed=None,
backtest_stats={'profit_total': results_over['profit_abs'].sum()}
)
under = hl.hyperopt_loss_function(
results_under,
trade_count=len(results_under),
min_date=datetime(2019, 1, 1),
max_date=datetime(2019, 5, 1),
config=default_conf,
processed=None,
backtest_stats={'profit_total': results_under['profit_abs'].sum()}
)
assert over < correct
assert under > correct

View File

@@ -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

View File

@@ -116,3 +116,28 @@ def test_PairLocks_getlongestlock(use_db):
PairLocks.reset_locks()
PairLocks.use_db = True
@pytest.mark.parametrize('use_db', (False, True))
@pytest.mark.usefixtures("init_persistence")
def test_PairLocks_reason(use_db):
PairLocks.timeframe = '5m'
PairLocks.use_db = use_db
# No lock should be present
if use_db:
assert len(PairLock.query.all()) == 0
assert PairLocks.use_db == use_db
PairLocks.lock_pair('XRP/USDT', arrow.utcnow().shift(minutes=4).datetime, 'TestLock1')
PairLocks.lock_pair('ETH/USDT', arrow.utcnow().shift(minutes=4).datetime, 'TestLock2')
assert PairLocks.is_pair_locked('XRP/USDT')
assert PairLocks.is_pair_locked('ETH/USDT')
PairLocks.unlock_reason('TestLock1')
assert not PairLocks.is_pair_locked('XRP/USDT')
assert PairLocks.is_pair_locked('ETH/USDT')
PairLocks.reset_locks()
PairLocks.use_db = True

View File

@@ -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())

View File

@@ -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', [

View File

@@ -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'

View File

@@ -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):
@@ -633,6 +636,13 @@ def test_is_pair_locked(default_conf):
strategy.unlock_pair(pair)
assert not strategy.is_pair_locked(pair)
# Lock with reason
reason = "TestLockR"
strategy.lock_pair(pair, arrow.now(timezone.utc).shift(minutes=4).datetime, reason)
assert strategy.is_pair_locked(pair)
strategy.unlock_reason(reason)
assert not strategy.is_pair_locked(pair)
pair = 'BTC/USDT'
# Lock until 14:30
lock_time = datetime(2020, 5, 1, 14, 30, 0, tzinfo=timezone.utc)
@@ -704,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

View File

@@ -62,8 +62,8 @@ def test_load_strategy(default_conf, result):
def test_load_strategy_base64(result, caplog, default_conf):
with (Path(__file__).parents[2] / 'freqtrade/templates/sample_strategy.py').open("rb") as file:
encoded_string = urlsafe_b64encode(file.read()).decode("utf-8")
filepath = Path(__file__).parents[2] / 'freqtrade/templates/sample_strategy.py'
encoded_string = urlsafe_b64encode(filepath.read_bytes()).decode("utf-8")
default_conf.update({'strategy': 'SampleStrategy:{}'.format(encoded_string)})
strategy = StrategyResolver.load_strategy(default_conf)

View File

@@ -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)

View File

@@ -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,

View File

@@ -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