Refactor optimize_report
we should not calculate non-daily statistics in the daily stats method
This commit is contained in:
parent
9994fce577
commit
545cba7fd8
@ -194,7 +194,37 @@ 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_trading_stats(results: DataFrame) -> Dict[str, Any]:
|
||||||
|
""" Generate overall trade statistics """
|
||||||
|
if len(results) == 0:
|
||||||
|
return {
|
||||||
|
'wins': 0,
|
||||||
|
'losses': 0,
|
||||||
|
'draws': 0,
|
||||||
|
'holding_avg': timedelta(),
|
||||||
|
'winner_holding_avg': timedelta(),
|
||||||
|
'loser_holding_avg': timedelta(),
|
||||||
|
}
|
||||||
|
|
||||||
|
winning_trades = results.loc[results['profit_ratio'] > 0]
|
||||||
|
draw_trades = results.loc[results['profit_ratio'] == 0]
|
||||||
|
losing_trades = results.loc[results['profit_ratio'] < 0]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'wins': len(winning_trades),
|
||||||
|
'losses': len(losing_trades),
|
||||||
|
'draws': len(draw_trades),
|
||||||
|
'holding_avg': (timedelta(minutes=round(results['trade_duration'].mean()))
|
||||||
|
if not results.empty else timedelta()),
|
||||||
|
'winner_holding_avg': (timedelta(minutes=round(winning_trades['trade_duration'].mean()))
|
||||||
|
if not winning_trades.empty else timedelta()),
|
||||||
|
'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean()))
|
||||||
|
if not losing_trades.empty else timedelta()),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
||||||
|
""" Generate daily statistics """
|
||||||
if len(results) == 0:
|
if len(results) == 0:
|
||||||
return {
|
return {
|
||||||
'backtest_best_day': 0,
|
'backtest_best_day': 0,
|
||||||
@ -204,8 +234,6 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
|||||||
'winning_days': 0,
|
'winning_days': 0,
|
||||||
'draw_days': 0,
|
'draw_days': 0,
|
||||||
'losing_days': 0,
|
'losing_days': 0,
|
||||||
'winner_holding_avg': timedelta(),
|
|
||||||
'loser_holding_avg': timedelta(),
|
|
||||||
}
|
}
|
||||||
daily_profit_rel = results.resample('1d', on='close_date')['profit_ratio'].sum()
|
daily_profit_rel = results.resample('1d', on='close_date')['profit_ratio'].sum()
|
||||||
daily_profit = results.resample('1d', on='close_date')['profit_abs'].sum().round(10)
|
daily_profit = results.resample('1d', on='close_date')['profit_abs'].sum().round(10)
|
||||||
@ -217,9 +245,6 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
|||||||
draw_days = sum(daily_profit == 0)
|
draw_days = sum(daily_profit == 0)
|
||||||
losing_days = sum(daily_profit < 0)
|
losing_days = sum(daily_profit < 0)
|
||||||
|
|
||||||
winning_trades = results.loc[results['profit_ratio'] > 0]
|
|
||||||
losing_trades = results.loc[results['profit_ratio'] < 0]
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'backtest_best_day': best_rel,
|
'backtest_best_day': best_rel,
|
||||||
'backtest_worst_day': worst_rel,
|
'backtest_worst_day': worst_rel,
|
||||||
@ -228,10 +253,6 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
|||||||
'winning_days': winning_days,
|
'winning_days': winning_days,
|
||||||
'draw_days': draw_days,
|
'draw_days': draw_days,
|
||||||
'losing_days': losing_days,
|
'losing_days': losing_days,
|
||||||
'winner_holding_avg': (timedelta(minutes=round(winning_trades['trade_duration'].mean()))
|
|
||||||
if not winning_trades.empty else timedelta()),
|
|
||||||
'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean()))
|
|
||||||
if not losing_trades.empty else timedelta()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -269,6 +290,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
results=results.loc[results['is_open']],
|
results=results.loc[results['is_open']],
|
||||||
skip_nan=True)
|
skip_nan=True)
|
||||||
daily_stats = generate_daily_stats(results)
|
daily_stats = generate_daily_stats(results)
|
||||||
|
trade_stats = generate_trading_stats(results)
|
||||||
best_pair = max([pair for pair in pair_results if pair['key'] != 'TOTAL'],
|
best_pair = max([pair for pair in pair_results if pair['key'] != 'TOTAL'],
|
||||||
key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None
|
key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None
|
||||||
worst_pair = min([pair for pair in pair_results if pair['key'] != 'TOTAL'],
|
worst_pair = min([pair for pair in pair_results if pair['key'] != 'TOTAL'],
|
||||||
@ -289,6 +311,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
'total_volume': float(results['stake_amount'].sum()),
|
'total_volume': float(results['stake_amount'].sum()),
|
||||||
'avg_stake_amount': results['stake_amount'].mean() if len(results) > 0 else 0,
|
'avg_stake_amount': results['stake_amount'].mean() if len(results) > 0 else 0,
|
||||||
'profit_mean': results['profit_ratio'].mean() if len(results) > 0 else 0,
|
'profit_mean': results['profit_ratio'].mean() if len(results) > 0 else 0,
|
||||||
|
'profit_median': results['profit_ratio'].median() if len(results) > 0 else 0,
|
||||||
'profit_total': results['profit_abs'].sum() / starting_balance,
|
'profit_total': results['profit_abs'].sum() / starting_balance,
|
||||||
'profit_total_abs': results['profit_abs'].sum(),
|
'profit_total_abs': results['profit_abs'].sum(),
|
||||||
'backtest_start': min_date.datetime,
|
'backtest_start': min_date.datetime,
|
||||||
@ -329,6 +352,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
'sell_profit_offset': config['ask_strategy']['sell_profit_offset'],
|
'sell_profit_offset': config['ask_strategy']['sell_profit_offset'],
|
||||||
'ignore_roi_if_buy_signal': config['ask_strategy']['ignore_roi_if_buy_signal'],
|
'ignore_roi_if_buy_signal': config['ask_strategy']['ignore_roi_if_buy_signal'],
|
||||||
**daily_stats,
|
**daily_stats,
|
||||||
|
**trade_stats
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -14,7 +14,7 @@ from freqtrade.edge import PairInfo
|
|||||||
from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_daily_stats,
|
from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_daily_stats,
|
||||||
generate_edge_table, generate_pair_metrics,
|
generate_edge_table, generate_pair_metrics,
|
||||||
generate_sell_reason_stats,
|
generate_sell_reason_stats,
|
||||||
generate_strategy_comparison, store_backtest_stats,
|
generate_strategy_comparison, generate_trading_stats, store_backtest_stats,
|
||||||
text_table_bt_results, text_table_sell_reason,
|
text_table_bt_results, text_table_sell_reason,
|
||||||
text_table_strategy)
|
text_table_strategy)
|
||||||
from freqtrade.resolvers.strategy_resolver import StrategyResolver
|
from freqtrade.resolvers.strategy_resolver import StrategyResolver
|
||||||
@ -226,8 +226,6 @@ def test_generate_daily_stats(testdatadir):
|
|||||||
assert res['winning_days'] == 14
|
assert res['winning_days'] == 14
|
||||||
assert res['draw_days'] == 4
|
assert res['draw_days'] == 4
|
||||||
assert res['losing_days'] == 3
|
assert res['losing_days'] == 3
|
||||||
assert res['winner_holding_avg'] == timedelta(seconds=1440)
|
|
||||||
assert res['loser_holding_avg'] == timedelta(days=1, seconds=21420)
|
|
||||||
|
|
||||||
# Select empty dataframe!
|
# Select empty dataframe!
|
||||||
res = generate_daily_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :])
|
res = generate_daily_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :])
|
||||||
@ -238,6 +236,23 @@ def test_generate_daily_stats(testdatadir):
|
|||||||
assert res['losing_days'] == 0
|
assert res['losing_days'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_trading_stats(testdatadir):
|
||||||
|
filename = testdatadir / "backtest-result_new.json"
|
||||||
|
bt_data = load_backtest_data(filename)
|
||||||
|
res = generate_trading_stats(bt_data)
|
||||||
|
assert isinstance(res, dict)
|
||||||
|
assert res['winner_holding_avg'] == timedelta(seconds=1440)
|
||||||
|
assert res['loser_holding_avg'] == timedelta(days=1, seconds=21420)
|
||||||
|
assert 'wins' in res
|
||||||
|
assert 'losses' in res
|
||||||
|
assert 'draws' in res
|
||||||
|
|
||||||
|
# Select empty dataframe!
|
||||||
|
res = generate_trading_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :])
|
||||||
|
assert res['wins'] == 0
|
||||||
|
assert res['losses'] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_text_table_sell_reason():
|
def test_text_table_sell_reason():
|
||||||
|
|
||||||
results = pd.DataFrame(
|
results = pd.DataFrame(
|
||||||
|
Loading…
Reference in New Issue
Block a user