mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-14 03:41:14 +00:00
Add day of week to backtest breakdowns
This commit is contained in:
@@ -268,7 +268,8 @@
|
|||||||
"day",
|
"day",
|
||||||
"week",
|
"week",
|
||||||
"month",
|
"month",
|
||||||
"year"
|
"year",
|
||||||
|
"weekday"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--backtest-filename PATH]
|
[--backtest-filename PATH]
|
||||||
[--backtest-directory PATH]
|
[--backtest-directory PATH]
|
||||||
[--show-pair-list]
|
[--show-pair-list]
|
||||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -18,9 +18,9 @@ options:
|
|||||||
Directory to use for backtest results. Example:
|
Directory to use for backtest results. Example:
|
||||||
`--export-directory=user_data/backtest_results/`.
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--show-pair-list Show backtesting pairlist sorted by profit.
|
--show-pair-list Show backtesting pairlist sorted by profit.
|
||||||
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
|
||||||
Show backtesting breakdown per [day, week, month,
|
Show backtesting breakdown per [day, week, month,
|
||||||
year].
|
year, weekday].
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--export {none,trades,signals}]
|
[--export {none,trades,signals}]
|
||||||
[--backtest-filename PATH]
|
[--backtest-filename PATH]
|
||||||
[--backtest-directory PATH]
|
[--backtest-directory PATH]
|
||||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
|
||||||
[--cache {none,day,week,month}]
|
[--cache {none,day,week,month}]
|
||||||
[--freqai-backtest-live-models] [--notes TEXT]
|
[--freqai-backtest-live-models] [--notes TEXT]
|
||||||
|
|
||||||
@@ -77,9 +77,9 @@ options:
|
|||||||
--backtest-directory PATH, --export-directory PATH
|
--backtest-directory PATH, --export-directory PATH
|
||||||
Directory to use for backtest results. Example:
|
Directory to use for backtest results. Example:
|
||||||
`--export-directory=user_data/backtest_results/`.
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
|
||||||
Show backtesting breakdown per [day, week, month,
|
Show backtesting breakdown per [day, week, month,
|
||||||
year].
|
year, weekday].
|
||||||
--cache {none,day,week,month}
|
--cache {none,day,week,month}
|
||||||
Load a cached backtest result no older than specified
|
Load a cached backtest result no older than specified
|
||||||
age (default: day).
|
age (default: day).
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ usage: freqtrade hyperopt-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--profitable] [-n INT] [--print-json]
|
[--profitable] [-n INT] [--print-json]
|
||||||
[--hyperopt-filename FILENAME] [--no-header]
|
[--hyperopt-filename FILENAME] [--no-header]
|
||||||
[--disable-param-export]
|
[--disable-param-export]
|
||||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -18,9 +18,9 @@ options:
|
|||||||
--no-header Do not print epoch details header.
|
--no-header Do not print epoch details header.
|
||||||
--disable-param-export
|
--disable-param-export
|
||||||
Disable automatic hyperopt parameter export.
|
Disable automatic hyperopt parameter export.
|
||||||
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
|
||||||
Show backtesting breakdown per [day, week, month,
|
Show backtesting breakdown per [day, week, month,
|
||||||
year].
|
year, weekday].
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
),
|
),
|
||||||
"backtest_breakdown": Arg(
|
"backtest_breakdown": Arg(
|
||||||
"--breakdown",
|
"--breakdown",
|
||||||
help="Show backtesting breakdown per [day, week, month, year].",
|
help="Show backtesting breakdown per [day, week, month, year, weekday].",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
choices=constants.BACKTEST_BREAKDOWNS,
|
choices=constants.BACKTEST_BREAKDOWNS,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ AVAILABLE_PAIRLISTS = [
|
|||||||
"VolatilityFilter",
|
"VolatilityFilter",
|
||||||
]
|
]
|
||||||
AVAILABLE_DATAHANDLERS = ["json", "jsongz", "feather", "parquet"]
|
AVAILABLE_DATAHANDLERS = ["json", "jsongz", "feather", "parquet"]
|
||||||
BACKTEST_BREAKDOWNS = ["day", "week", "month", "year"]
|
BACKTEST_BREAKDOWNS = ["day", "week", "month", "year", "weekday"]
|
||||||
BACKTEST_CACHE_AGE = ["none", "day", "week", "month"]
|
BACKTEST_CACHE_AGE = ["none", "day", "week", "month"]
|
||||||
BACKTEST_CACHE_DEFAULT = "day"
|
BACKTEST_CACHE_DEFAULT = "day"
|
||||||
DRY_RUN_WALLET = 1000
|
DRY_RUN_WALLET = 1000
|
||||||
|
|||||||
@@ -132,8 +132,13 @@ def text_table_periodic_breakdown(
|
|||||||
:param days_breakdown_stats: Days breakdown metrics
|
:param days_breakdown_stats: Days breakdown metrics
|
||||||
:param stake_currency: Stakecurrency used
|
:param stake_currency: Stakecurrency used
|
||||||
"""
|
"""
|
||||||
|
if period == "weekday":
|
||||||
|
first_column = "Week day"
|
||||||
|
else:
|
||||||
|
first_column = period.capitalize()
|
||||||
|
|
||||||
headers = [
|
headers = [
|
||||||
period.capitalize(),
|
first_column,
|
||||||
"Trades",
|
"Trades",
|
||||||
f"Tot Profit {stake_currency}",
|
f"Tot Profit {stake_currency}",
|
||||||
"Profit Factor",
|
"Profit Factor",
|
||||||
|
|||||||
@@ -256,40 +256,66 @@ def _get_resample_from_period(period: str) -> str:
|
|||||||
return "1ME"
|
return "1ME"
|
||||||
if period == "year":
|
if period == "year":
|
||||||
return "1YE"
|
return "1YE"
|
||||||
|
if period == "weekday":
|
||||||
|
# Required to pass the test
|
||||||
|
return "weekday"
|
||||||
raise ValueError(f"Period {period} is not supported.")
|
raise ValueError(f"Period {period} is not supported.")
|
||||||
|
|
||||||
|
|
||||||
|
def _calculate_stats_for_period(data: DataFrame) -> dict[str, Any]:
|
||||||
|
profit_abs = data["profit_abs"].sum().round(10)
|
||||||
|
wins = sum(data["profit_abs"] > 0)
|
||||||
|
draws = sum(data["profit_abs"] == 0)
|
||||||
|
losses = sum(data["profit_abs"] < 0)
|
||||||
|
trades = wins + draws + losses
|
||||||
|
winning_profit = data.loc[data["profit_abs"] > 0, "profit_abs"].sum()
|
||||||
|
losing_profit = data.loc[data["profit_abs"] < 0, "profit_abs"].sum()
|
||||||
|
profit_factor = winning_profit / abs(losing_profit) if losing_profit else 0.0
|
||||||
|
|
||||||
|
return {
|
||||||
|
"profit_abs": profit_abs,
|
||||||
|
"wins": wins,
|
||||||
|
"draws": draws,
|
||||||
|
"losses": losses,
|
||||||
|
"trades": trades,
|
||||||
|
"profit_factor": round(profit_factor, 8),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_periodic_breakdown_stats(
|
def generate_periodic_breakdown_stats(
|
||||||
trade_list: list | DataFrame, period: str
|
trade_list: list | DataFrame, period: str
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
results = trade_list if not isinstance(trade_list, list) else DataFrame.from_records(trade_list)
|
results = trade_list if not isinstance(trade_list, list) else DataFrame.from_records(trade_list)
|
||||||
if len(results) == 0:
|
if len(results) == 0:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
results["close_date"] = to_datetime(results["close_date"], utc=True)
|
results["close_date"] = to_datetime(results["close_date"], utc=True)
|
||||||
resample_period = _get_resample_from_period(period)
|
|
||||||
resampled = results.resample(resample_period, on="close_date")
|
if period == "weekday":
|
||||||
stats = []
|
day_names = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||||
for name, day in resampled:
|
results["weekday"] = results["close_date"].dt.dayofweek
|
||||||
profit_abs = day["profit_abs"].sum().round(10)
|
|
||||||
wins = sum(day["profit_abs"] > 0)
|
stats = []
|
||||||
draws = sum(day["profit_abs"] == 0)
|
for day_num in range(7):
|
||||||
losses = sum(day["profit_abs"] < 0)
|
day_data = results[results["weekday"] == day_num]
|
||||||
trades = wins + draws + losses
|
if len(day_data) > 0:
|
||||||
winning_profit = day.loc[day["profit_abs"] > 0, "profit_abs"].sum()
|
period_stats = _calculate_stats_for_period(day_data)
|
||||||
losing_profit = day.loc[day["profit_abs"] < 0, "profit_abs"].sum()
|
stats.append({"date": day_names[day_num], "date_ts": day_num, **period_stats})
|
||||||
profit_factor = winning_profit / abs(losing_profit) if losing_profit else 0.0
|
else:
|
||||||
stats.append(
|
resample_period = _get_resample_from_period(period)
|
||||||
{
|
resampled = results.resample(resample_period, on="close_date")
|
||||||
"date": name.strftime("%d/%m/%Y"),
|
|
||||||
"date_ts": int(name.to_pydatetime().timestamp() * 1000),
|
stats = []
|
||||||
"profit_abs": profit_abs,
|
for name, period_data in resampled:
|
||||||
"wins": wins,
|
period_stats = _calculate_stats_for_period(period_data)
|
||||||
"draws": draws,
|
stats.append(
|
||||||
"losses": losses,
|
{
|
||||||
"trades": trades,
|
"date": name.strftime("%d/%m/%Y"),
|
||||||
"profit_factor": round(profit_factor, 8),
|
"date_ts": int(name.to_pydatetime().timestamp() * 1000),
|
||||||
}
|
**period_stats,
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user