Fixed test failures.

This commit is contained in:
theluxaz 2021-10-21 17:25:38 +03:00
parent 1267374c8a
commit 0e085298e9
6 changed files with 81 additions and 46 deletions

View File

@ -361,8 +361,12 @@ class Backtesting:
if sell.sell_flag: if sell.sell_flag:
trade.close_date = sell_candle_time trade.close_date = sell_candle_time
trade.sell_reason = sell.sell_reason trade.sell_reason = sell.sell_reason
if(sell_row[EXIT_TAG_IDX] is not None):
# Checks and adds an exit tag, after checking that the length of the
# sell_row has the length for an exit tag column
if(len(sell_row) > EXIT_TAG_IDX and sell_row[EXIT_TAG_IDX] is not None and len(sell_row[EXIT_TAG_IDX]) > 0):
trade.sell_reason = sell_row[EXIT_TAG_IDX] trade.sell_reason = sell_row[EXIT_TAG_IDX]
trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60) trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60)
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur) closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)

View File

@ -150,19 +150,22 @@ def generate_tag_metrics(tag_type: str,
tabular_data = [] tabular_data = []
for tag, count in results[tag_type].value_counts().iteritems(): if tag_type in results.columns:
result = results[results[tag_type] == tag] for tag, count in results[tag_type].value_counts().iteritems():
if skip_nan and result['profit_abs'].isnull().all(): result = results[results[tag_type] == tag]
continue if skip_nan and result['profit_abs'].isnull().all():
continue
tabular_data.append(_generate_tag_result_line(result, starting_balance, tag)) tabular_data.append(_generate_tag_result_line(result, starting_balance, tag))
# Sort by total profit %: # Sort by total profit %:
tabular_data = sorted(tabular_data, key=lambda k: k['profit_total_abs'], reverse=True) tabular_data = sorted(tabular_data, key=lambda k: k['profit_total_abs'], reverse=True)
# Append Total # Append Total
tabular_data.append(_generate_result_line(results, starting_balance, 'TOTAL')) tabular_data.append(_generate_result_line(results, starting_balance, 'TOTAL'))
return tabular_data return tabular_data
else:
return None
def _generate_tag_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict: def _generate_tag_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict:
@ -732,14 +735,15 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
print(' BACKTESTING REPORT '.center(len(table.splitlines()[0]), '=')) print(' BACKTESTING REPORT '.center(len(table.splitlines()[0]), '='))
print(table) print(table)
table = text_table_tags( if(results['results_per_buy_tag'] is not None):
"buy_tag", table = text_table_tags(
results['results_per_buy_tag'], "buy_tag",
stake_currency=stake_currency) results['results_per_buy_tag'],
stake_currency=stake_currency)
if isinstance(table, str) and len(table) > 0: if isinstance(table, str) and len(table) > 0:
print(' BUY TAG STATS '.center(len(table.splitlines()[0]), '=')) print(' BUY TAG STATS '.center(len(table.splitlines()[0]), '='))
print(table) print(table)
table = text_table_sell_reason(sell_reason_stats=results['sell_reason_summary'], table = text_table_sell_reason(sell_reason_stats=results['sell_reason_summary'],
stake_currency=stake_currency) stake_currency=stake_currency)

View File

@ -107,10 +107,9 @@ class Telegram(RPCHandler):
# this needs refactoring of the whole telegram module (same # this needs refactoring of the whole telegram module (same
# problem in _help()). # problem in _help()).
valid_keys: List[str] = [r'/start$', r'/stop$', r'/status$', r'/status table$', valid_keys: List[str] = [r'/start$', r'/stop$', r'/status$', r'/status table$',
r'/trades$', r'/performance$', r'/daily$', r'/daily \d+$', r'/trades$', r'/performance$', r'/buys', r'/sells', r'/mix_tags',
r'/profit$', r'/profit \d+', r'/daily$', r'/daily \d+$', r'/profit$', r'/profit \d+',
r'/stats$', r'/count$', r'/locks$', r'/balance$', r'/stats$', r'/count$', r'/locks$', r'/balance$',
r'/buys', r'/sells', r'/mix_tags',
r'/stopbuy$', r'/reload_config$', r'/show_config$', r'/stopbuy$', r'/reload_config$', r'/show_config$',
r'/logs$', r'/whitelist$', r'/blacklist$', r'/edge$', r'/logs$', r'/whitelist$', r'/blacklist$', r'/edge$',
r'/forcebuy$', r'/help$', r'/version$'] r'/forcebuy$', r'/help$', r'/version$']
@ -179,9 +178,9 @@ class Telegram(RPCHandler):
CallbackQueryHandler(self._profit, pattern='update_profit'), CallbackQueryHandler(self._profit, pattern='update_profit'),
CallbackQueryHandler(self._balance, pattern='update_balance'), CallbackQueryHandler(self._balance, pattern='update_balance'),
CallbackQueryHandler(self._performance, pattern='update_performance'), CallbackQueryHandler(self._performance, pattern='update_performance'),
CallbackQueryHandler(self._performance, pattern='update_buy_tag_performance'), CallbackQueryHandler(self._buy_tag_performance, pattern='update_buy_tag_performance'),
CallbackQueryHandler(self._performance, pattern='update_sell_reason_performance'), CallbackQueryHandler(self._sell_reason_performance, pattern='update_sell_reason_performance'),
CallbackQueryHandler(self._performance, pattern='update_mix_tag_performance'), CallbackQueryHandler(self._mix_tag_performance, pattern='update_mix_tag_performance'),
CallbackQueryHandler(self._count, pattern='update_count'), CallbackQueryHandler(self._count, pattern='update_count'),
CallbackQueryHandler(self._forcebuy_inline), CallbackQueryHandler(self._forcebuy_inline),
] ]

View File

@ -567,6 +567,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
195, # Low 195, # Low
201.5, # High 201.5, # High
'', # Buy Signal Name '', # Buy Signal Name
'', # Exit Signal Name
] ]
trade = backtesting._enter_trade(pair, row=row) trade = backtesting._enter_trade(pair, row=row)
@ -581,26 +582,27 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
195, # Low 195, # Low
210.5, # High 210.5, # High
'', # Buy Signal Name '', # Buy Signal Name
'', # Exit Signal Name
] ]
row_detail = pd.DataFrame( row_detail = pd.DataFrame(
[ [
[ [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0, tzinfo=timezone.utc), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0, tzinfo=timezone.utc),
1, 200, 199, 0, 197, 200.1, '', 1, 200, 199, 0, 197, 200.1, '', '',
], [ ], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=1, tzinfo=timezone.utc), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=1, tzinfo=timezone.utc),
0, 199, 199.5, 0, 199, 199.7, '', 0, 199, 199.5, 0, 199, 199.7, '', '',
], [ ], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=2, tzinfo=timezone.utc), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=2, tzinfo=timezone.utc),
0, 199.5, 200.5, 0, 199, 200.8, '', 0, 199.5, 200.5, 0, 199, 200.8, '', '',
], [ ], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=3, tzinfo=timezone.utc), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=3, tzinfo=timezone.utc),
0, 200.5, 210.5, 0, 193, 210.5, '', # ROI sell (?) 0, 200.5, 210.5, 0, 193, 210.5, '', '', # ROI sell (?)
], [ ], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=4, tzinfo=timezone.utc), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=4, tzinfo=timezone.utc),
0, 200, 199, 0, 193, 200.1, '', 0, 200, 199, 0, 193, 200.1, '', '',
], ],
], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag"] ], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag", "exit_tag"]
) )
# No data available. # No data available.
@ -614,7 +616,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
assert isinstance(trade, LocalTrade) assert isinstance(trade, LocalTrade)
# Assign empty ... no result. # Assign empty ... no result.
backtesting.detail_data[pair] = pd.DataFrame( backtesting.detail_data[pair] = pd.DataFrame(
[], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag"]) [], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag", "exit_tag"])
res = backtesting._get_sell_trade_entry(trade, row) res = backtesting._get_sell_trade_entry(trade, row)
assert res is None assert res is None
@ -678,7 +680,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
'min_rate': [0.10370188, 0.10300000000000001], 'min_rate': [0.10370188, 0.10300000000000001],
'max_rate': [0.10501, 0.1038888], 'max_rate': [0.10501, 0.1038888],
'is_open': [False, False], 'is_open': [False, False],
'buy_tag': [None, None], 'buy_tag': [None, None]
}) })
pd.testing.assert_frame_equal(results, expected) pd.testing.assert_frame_equal(results, expected)
data_pair = processed[pair] data_pair = processed[pair]

View File

@ -33,6 +33,7 @@ class DummyCls(Telegram):
""" """
Dummy class for testing the Telegram @authorized_only decorator Dummy class for testing the Telegram @authorized_only decorator
""" """
def __init__(self, rpc: RPC, config) -> None: def __init__(self, rpc: RPC, config) -> None:
super().__init__(rpc, config) super().__init__(rpc, config)
self.state = {'called': False} self.state = {'called': False}
@ -92,7 +93,8 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], " message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], "
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], ['trades'], " "['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'], " "['unlock', 'delete_locks'], ['reload_config', 'reload_conf'], "
"['show_config', 'show_conf'], ['stopbuy'], " "['show_config', 'show_conf'], ['stopbuy'], "
"['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']" "['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']"
@ -713,6 +715,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
'profit_ratio': 0.0629778, 'profit_ratio': 0.0629778,
'stake_currency': 'BTC', 'stake_currency': 'BTC',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value, 'sell_reason': SellType.FORCE_SELL.value,
'open_date': ANY, 'open_date': ANY,
'close_date': ANY, 'close_date': ANY,
@ -776,6 +779,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
'profit_ratio': -0.05482878, 'profit_ratio': -0.05482878,
'stake_currency': 'BTC', 'stake_currency': 'BTC',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value, 'sell_reason': SellType.FORCE_SELL.value,
'open_date': ANY, 'open_date': ANY,
'close_date': ANY, 'close_date': ANY,
@ -829,6 +833,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
'profit_ratio': -0.00408133, 'profit_ratio': -0.00408133,
'stake_currency': 'BTC', 'stake_currency': 'BTC',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value, 'sell_reason': SellType.FORCE_SELL.value,
'open_date': ANY, 'open_date': ANY,
'close_date': ANY, 'close_date': ANY,
@ -997,9 +1002,9 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
msg = ('<pre> current max total stake\n--------- ----- -------------\n' msg = ('<pre> current max total stake\n--------- ----- -------------\n'
' 1 {} {}</pre>').format( ' 1 {} {}</pre>').format(
default_conf['max_open_trades'], default_conf['max_open_trades'],
default_conf['stake_amount'] default_conf['stake_amount']
) )
assert msg in msg_mock.call_args_list[0][0][0] assert msg in msg_mock.call_args_list[0][0][0]
@ -1382,6 +1387,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'profit_ratio': -0.57405275, 'profit_ratio': -0.57405275,
'stake_currency': 'ETH', 'stake_currency': 'ETH',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value, 'sell_reason': SellType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-1), 'open_date': arrow.utcnow().shift(hours=-1),
'close_date': arrow.utcnow(), 'close_date': arrow.utcnow(),
@ -1389,6 +1395,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
assert msg_mock.call_args[0][0] \ assert msg_mock.call_args[0][0] \
== ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
'*Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n' '*Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
'*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `1:00:00 (60.0 min)`\n' '*Duration:* `1:00:00 (60.0 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
@ -1412,6 +1419,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'profit_amount': -0.05746268, 'profit_amount': -0.05746268,
'profit_ratio': -0.57405275, 'profit_ratio': -0.57405275,
'stake_currency': 'ETH', 'stake_currency': 'ETH',
'buy_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value, 'sell_reason': SellType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(), 'close_date': arrow.utcnow(),
@ -1419,6 +1427,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
assert msg_mock.call_args[0][0] \ assert msg_mock.call_args[0][0] \
== ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
'*Profit:* `-57.41%`\n' '*Profit:* `-57.41%`\n'
'*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n' '*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
@ -1483,6 +1492,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None:
'profit_ratio': -0.57405275, 'profit_ratio': -0.57405275,
'stake_currency': 'ETH', 'stake_currency': 'ETH',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value, 'sell_reason': SellType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-1), 'open_date': arrow.utcnow().shift(hours=-1),
'close_date': arrow.utcnow(), 'close_date': arrow.utcnow(),
@ -1574,12 +1584,14 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
'profit_ratio': -0.57405275, 'profit_ratio': -0.57405275,
'stake_currency': 'ETH', 'stake_currency': 'ETH',
'fiat_currency': 'USD', 'fiat_currency': 'USD',
'buy_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value, 'sell_reason': SellType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3), 'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3),
'close_date': arrow.utcnow(), 'close_date': arrow.utcnow(),
}) })
assert msg_mock.call_args[0][0] == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' assert msg_mock.call_args[0][0] == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n'
'*Profit:* `-57.41%`\n' '*Profit:* `-57.41%`\n'
'*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `2:35:03 (155.1 min)`\n' '*Duration:* `2:35:03 (155.1 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'

View File

@ -38,20 +38,27 @@ def test_returns_latest_signal(mocker, default_conf, ohlcv_history):
mocked_history['buy'] = 0 mocked_history['buy'] = 0
mocked_history.loc[1, 'sell'] = 1 mocked_history.loc[1, 'sell'] = 1
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True, None) assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True, None, None)
mocked_history.loc[1, 'sell'] = 0 mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 1 mocked_history.loc[1, 'buy'] = 1
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, None) assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, None, None)
mocked_history.loc[1, 'sell'] = 0 mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 0 mocked_history.loc[1, 'buy'] = 0
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False, None) assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False, None, None)
mocked_history.loc[1, 'sell'] = 0 mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 1 mocked_history.loc[1, 'buy'] = 1
mocked_history.loc[1, 'buy_tag'] = 'buy_signal_01' mocked_history.loc[1, 'buy_tag'] = 'buy_signal_01'
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, 'buy_signal_01') assert _STRATEGY.get_signal(
'ETH/BTC',
'5m',
mocked_history) == (
True,
False,
'buy_signal_01',
None)
def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history): def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
@ -68,17 +75,24 @@ def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
def test_get_signal_empty(default_conf, mocker, caplog): def test_get_signal_empty(default_conf, mocker, caplog):
assert (False, False, None) == _STRATEGY.get_signal( assert (False, False, None, None) == _STRATEGY.get_signal(
'foo', default_conf['timeframe'], DataFrame() 'foo', default_conf['timeframe'], DataFrame()
) )
assert log_has('Empty candle (OHLCV) data for pair foo', caplog) assert log_has('Empty candle (OHLCV) data for pair foo', caplog)
caplog.clear() caplog.clear()
assert (False, False, None) == _STRATEGY.get_signal('bar', default_conf['timeframe'], None) assert (
False,
False,
None,
None) == _STRATEGY.get_signal(
'bar',
default_conf['timeframe'],
None)
assert log_has('Empty candle (OHLCV) data for pair bar', caplog) assert log_has('Empty candle (OHLCV) data for pair bar', caplog)
caplog.clear() caplog.clear()
assert (False, False, None) == _STRATEGY.get_signal( assert (False, False, None, None) == _STRATEGY.get_signal(
'baz', 'baz',
default_conf['timeframe'], default_conf['timeframe'],
DataFrame([]) DataFrame([])
@ -118,7 +132,7 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history):
caplog.set_level(logging.INFO) caplog.set_level(logging.INFO)
mocker.patch.object(_STRATEGY, 'assert_df') mocker.patch.object(_STRATEGY, 'assert_df')
assert (False, False, None) == _STRATEGY.get_signal( assert (False, False, None, None) == _STRATEGY.get_signal(
'xyz', 'xyz',
default_conf['timeframe'], default_conf['timeframe'],
mocked_history mocked_history
@ -140,7 +154,7 @@ def test_get_signal_no_sell_column(default_conf, mocker, caplog, ohlcv_history):
caplog.set_level(logging.INFO) caplog.set_level(logging.INFO)
mocker.patch.object(_STRATEGY, 'assert_df') mocker.patch.object(_STRATEGY, 'assert_df')
assert (True, False, None) == _STRATEGY.get_signal( assert (True, False, None, None) == _STRATEGY.get_signal(
'xyz', 'xyz',
default_conf['timeframe'], default_conf['timeframe'],
mocked_history mocked_history
@ -646,7 +660,7 @@ def test_strategy_safe_wrapper(value):
ret = strategy_safe_wrapper(working_method, message='DeadBeef')(value) ret = strategy_safe_wrapper(working_method, message='DeadBeef')(value)
assert type(ret) == type(value) assert isinstance(ret, type(value))
assert ret == value assert ret == value