Support day/week/month breakdowns
This commit is contained in:
parent
7197f4ce77
commit
fa028c2134
@ -23,7 +23,7 @@ ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", "dataformat_ohlcv",
|
|||||||
|
|
||||||
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
|
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
|
||||||
"enable_protections", "dry_run_wallet", "timeframe_detail",
|
"enable_protections", "dry_run_wallet", "timeframe_detail",
|
||||||
"strategy_list", "export", "exportfilename", "show_days"]
|
"strategy_list", "export", "exportfilename", "backtest_breakdown"]
|
||||||
|
|
||||||
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
|
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
|
||||||
"position_stacking", "use_max_market_positions",
|
"position_stacking", "use_max_market_positions",
|
||||||
@ -89,7 +89,7 @@ ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable",
|
|||||||
|
|
||||||
ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index",
|
ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index",
|
||||||
"print_json", "hyperoptexportfilename", "hyperopt_show_no_header",
|
"print_json", "hyperoptexportfilename", "hyperopt_show_no_header",
|
||||||
"disableparamexport", "show_days"]
|
"disableparamexport", "backtest_breakdown"]
|
||||||
|
|
||||||
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
|
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
|
||||||
"list-markets", "list-pairs", "list-strategies", "list-data",
|
"list-markets", "list-pairs", "list-strategies", "list-data",
|
||||||
|
@ -193,11 +193,11 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
type=float,
|
type=float,
|
||||||
metavar='FLOAT',
|
metavar='FLOAT',
|
||||||
),
|
),
|
||||||
"show_days": Arg(
|
"backtest_breakdown": Arg(
|
||||||
'--show-days',
|
'--breakdown',
|
||||||
help='Print days breakdown for backtest results',
|
help='Show backtesting breakdown per [day, week, month].',
|
||||||
action='store_true',
|
nargs='+',
|
||||||
default=False,
|
choices=constants.BACKTEST_BREAKDOWNS
|
||||||
),
|
),
|
||||||
# Edge
|
# Edge
|
||||||
"stoploss_range": Arg(
|
"stoploss_range": Arg(
|
||||||
|
@ -96,7 +96,7 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
|||||||
if 'strategy_name' in metrics:
|
if 'strategy_name' in metrics:
|
||||||
strategy_name = metrics['strategy_name']
|
strategy_name = metrics['strategy_name']
|
||||||
show_backtest_result(strategy_name, metrics,
|
show_backtest_result(strategy_name, metrics,
|
||||||
metrics['stake_currency'], config.get('show_days', False))
|
metrics['stake_currency'], config.get('backtest_breakdown', []))
|
||||||
|
|
||||||
HyperoptTools.try_export_params(config, strategy_name, val)
|
HyperoptTools.try_export_params(config, strategy_name, val)
|
||||||
|
|
||||||
|
@ -269,8 +269,8 @@ class Configuration:
|
|||||||
self._args_to_config(config, argname='export',
|
self._args_to_config(config, argname='export',
|
||||||
logstring='Parameter --export detected: {} ...')
|
logstring='Parameter --export detected: {} ...')
|
||||||
|
|
||||||
self._args_to_config(config, argname='show_days',
|
self._args_to_config(config, argname='backtest_breakdown',
|
||||||
logstring='Parameter --show-days detected ...')
|
logstring='Parameter --breakdown detected ...')
|
||||||
|
|
||||||
self._args_to_config(config, argname='disableparamexport',
|
self._args_to_config(config, argname='disableparamexport',
|
||||||
logstring='Parameter --disableparamexport detected: {} ...')
|
logstring='Parameter --disableparamexport detected: {} ...')
|
||||||
|
@ -32,6 +32,7 @@ AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
|
|||||||
'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter']
|
'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter']
|
||||||
AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard']
|
AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard']
|
||||||
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
|
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
|
||||||
|
BACKTEST_BREAKDOWNS = ['day', 'week', 'month']
|
||||||
DRY_RUN_WALLET = 1000
|
DRY_RUN_WALLET = 1000
|
||||||
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'
|
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||||
MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons
|
MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons
|
||||||
@ -146,6 +147,10 @@ CONF_SCHEMA = {
|
|||||||
'sell_profit_offset': {'type': 'number'},
|
'sell_profit_offset': {'type': 'number'},
|
||||||
'ignore_roi_if_buy_signal': {'type': 'boolean'},
|
'ignore_roi_if_buy_signal': {'type': 'boolean'},
|
||||||
'ignore_buying_expired_candle_after': {'type': 'number'},
|
'ignore_buying_expired_candle_after': {'type': 'number'},
|
||||||
|
'backtest_breakdown': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS}
|
||||||
|
},
|
||||||
'bot_name': {'type': 'string'},
|
'bot_name': {'type': 'string'},
|
||||||
'unfilledtimeout': {
|
'unfilledtimeout': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
|
@ -213,17 +213,28 @@ def generate_edge_table(results: dict) -> str:
|
|||||||
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") # type: ignore
|
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def generate_days_breakdown_stats(trade_list: List, starting_balance: int) -> List[Dict[str, Any]]:
|
def _get_resample_from_period(period: str) -> str:
|
||||||
|
if period == 'day':
|
||||||
|
return '1d'
|
||||||
|
if period == 'week':
|
||||||
|
return '1w'
|
||||||
|
if period == 'month':
|
||||||
|
return '1m'
|
||||||
|
raise ValueError(f"Period {period} is not supported.")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_periodic_breakdown_stats(trade_list: List, period: str) -> List[Dict[str, Any]]:
|
||||||
results = DataFrame.from_records(trade_list)
|
results = DataFrame.from_records(trade_list)
|
||||||
results['close_date'] = to_datetime(results['close_date'], utc=True)
|
results['close_date'] = to_datetime(results['close_date'], utc=True)
|
||||||
days = results.resample('1d', on='close_date')
|
resample = _get_resample_from_period(period)
|
||||||
days_stats = []
|
period = results.resample(resample, on='close_date')
|
||||||
for name, day in days:
|
stats = []
|
||||||
|
for name, day in period:
|
||||||
profit_abs = day['profit_abs'].sum().round(10)
|
profit_abs = day['profit_abs'].sum().round(10)
|
||||||
wins = sum(day['profit_abs'] > 0)
|
wins = sum(day['profit_abs'] > 0)
|
||||||
draws = sum(day['profit_abs'] == 0)
|
draws = sum(day['profit_abs'] == 0)
|
||||||
loses = sum(day['profit_abs'] < 0)
|
loses = sum(day['profit_abs'] < 0)
|
||||||
days_stats.append(
|
stats.append(
|
||||||
{
|
{
|
||||||
'date': name.strftime('%d/%m/%Y'),
|
'date': name.strftime('%d/%m/%Y'),
|
||||||
'profit_abs': profit_abs,
|
'profit_abs': profit_abs,
|
||||||
@ -232,7 +243,7 @@ def generate_days_breakdown_stats(trade_list: List, starting_balance: int) -> Li
|
|||||||
'loses': loses
|
'loses': loses
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return days_stats
|
return stats
|
||||||
|
|
||||||
|
|
||||||
def generate_trading_stats(results: DataFrame) -> Dict[str, Any]:
|
def generate_trading_stats(results: DataFrame) -> Dict[str, Any]:
|
||||||
@ -529,8 +540,8 @@ def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren
|
|||||||
return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
|
return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
|
||||||
|
|
||||||
|
|
||||||
def text_table_days_breakdown(days_breakdown_stats: List[Dict[str, Any]],
|
def text_table_periodic_breakdown(days_breakdown_stats: List[Dict[str, Any]],
|
||||||
stake_currency: str) -> str:
|
stake_currency: str, period: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate small table with Backtest results by days
|
Generate small table with Backtest results by days
|
||||||
:param days_breakdown_stats: Days breakdown metrics
|
:param days_breakdown_stats: Days breakdown metrics
|
||||||
@ -538,7 +549,7 @@ def text_table_days_breakdown(days_breakdown_stats: List[Dict[str, Any]],
|
|||||||
:return: pretty printed table with tabulate as string
|
:return: pretty printed table with tabulate as string
|
||||||
"""
|
"""
|
||||||
headers = [
|
headers = [
|
||||||
'Day',
|
period.capitalize(),
|
||||||
f'Tot Profit {stake_currency}',
|
f'Tot Profit {stake_currency}',
|
||||||
'Wins',
|
'Wins',
|
||||||
'Draws',
|
'Draws',
|
||||||
@ -663,7 +674,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency: str,
|
def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency: str,
|
||||||
show_days=False):
|
backtest_breakdown=[]):
|
||||||
"""
|
"""
|
||||||
Print results for one strategy
|
Print results for one strategy
|
||||||
"""
|
"""
|
||||||
@ -685,13 +696,13 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
|
|||||||
print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '='))
|
print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
|
|
||||||
if show_days:
|
for period in backtest_breakdown:
|
||||||
days_breakdown_stats = generate_days_breakdown_stats(
|
days_breakdown_stats = generate_periodic_breakdown_stats(
|
||||||
trade_list=results['trades'], starting_balance=results['starting_balance'])
|
trade_list=results['trades'], period=period)
|
||||||
table = text_table_days_breakdown(days_breakdown_stats=days_breakdown_stats,
|
table = text_table_periodic_breakdown(days_breakdown_stats=days_breakdown_stats,
|
||||||
stake_currency=stake_currency)
|
stake_currency=stake_currency, period=period)
|
||||||
if isinstance(table, str) and len(table) > 0:
|
if isinstance(table, str) and len(table) > 0:
|
||||||
print(' DAYS BREAKDOWN '.center(len(table.splitlines()[0]), '='))
|
print(f' {period.upper()} BREAKDOWN '.center(len(table.splitlines()[0]), '='))
|
||||||
print(table)
|
print(table)
|
||||||
|
|
||||||
table = text_table_add_metrics(results)
|
table = text_table_add_metrics(results)
|
||||||
@ -708,7 +719,9 @@ def show_backtest_results(config: Dict, backtest_stats: Dict):
|
|||||||
stake_currency = config['stake_currency']
|
stake_currency = config['stake_currency']
|
||||||
|
|
||||||
for strategy, results in backtest_stats['strategy'].items():
|
for strategy, results in backtest_stats['strategy'].items():
|
||||||
show_backtest_result(strategy, results, stake_currency, config.get('show_days', False))
|
show_backtest_result(
|
||||||
|
strategy, results, stake_currency,
|
||||||
|
config.get('backtest_breakdown', []))
|
||||||
|
|
||||||
if len(backtest_stats['strategy']) > 1:
|
if len(backtest_stats['strategy']) > 1:
|
||||||
# Print Strategy summary table
|
# Print Strategy summary table
|
||||||
|
Loading…
Reference in New Issue
Block a user