Update drawdown calculation to account drawdown
This commit is contained in:
parent
42579c0268
commit
7a2b50ce8b
@ -312,7 +312,7 @@ A backtesting result will look like that:
|
|||||||
| | |
|
| | |
|
||||||
| Min balance | 0.00945123 BTC |
|
| Min balance | 0.00945123 BTC |
|
||||||
| Max balance | 0.01846651 BTC |
|
| Max balance | 0.01846651 BTC |
|
||||||
| Drawdown | 50.63% |
|
| Drawdown (Account) | 13.33% |
|
||||||
| Drawdown | 0.0015 BTC |
|
| Drawdown | 0.0015 BTC |
|
||||||
| Drawdown high | 0.0013 BTC |
|
| Drawdown high | 0.0013 BTC |
|
||||||
| Drawdown low | -0.0002 BTC |
|
| Drawdown low | -0.0002 BTC |
|
||||||
@ -399,7 +399,7 @@ It contains some useful key metrics about performance of your strategy on backte
|
|||||||
| | |
|
| | |
|
||||||
| Min balance | 0.00945123 BTC |
|
| Min balance | 0.00945123 BTC |
|
||||||
| Max balance | 0.01846651 BTC |
|
| Max balance | 0.01846651 BTC |
|
||||||
| Drawdown | 50.63% |
|
| Drawdown (Account) | 13.33% |
|
||||||
| Drawdown | 0.0015 BTC |
|
| Drawdown | 0.0015 BTC |
|
||||||
| Drawdown high | 0.0013 BTC |
|
| Drawdown high | 0.0013 BTC |
|
||||||
| Drawdown low | -0.0002 BTC |
|
| Drawdown low | -0.0002 BTC |
|
||||||
@ -426,7 +426,8 @@ It contains some useful key metrics about performance of your strategy on backte
|
|||||||
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
||||||
- `Rejected Buy signals`: Buy signals that could not be acted upon due to max_open_trades being reached.
|
- `Rejected Buy signals`: Buy signals that could not be acted upon due to max_open_trades being reached.
|
||||||
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
||||||
- `Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced).
|
- `Drawdown (Account)`: Maximum Account Drawdown experienced. Calculated as $(Absolute Drawdown) / (DrawdownHigh + startingBalance)$.
|
||||||
|
- `Drawdown`: Maximum, absolute drawdown experienced. Difference between Drawdown High and Low.
|
||||||
- `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost.
|
- `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost.
|
||||||
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
|
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
|
||||||
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
|
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
|
||||||
|
@ -392,15 +392,17 @@ def calculate_underwater(trades: pd.DataFrame, *, date_col: str = 'close_date',
|
|||||||
|
|
||||||
|
|
||||||
def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date',
|
def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date',
|
||||||
value_col: str = 'profit_ratio'
|
value_col: str = 'profit_abs', starting_balance: float = 0
|
||||||
) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float]:
|
) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float, float]:
|
||||||
"""
|
"""
|
||||||
Calculate max drawdown and the corresponding close dates
|
Calculate max drawdown and the corresponding close dates
|
||||||
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
||||||
:param date_col: Column in DataFrame to use for dates (defaults to 'close_date')
|
:param date_col: Column in DataFrame to use for dates (defaults to 'close_date')
|
||||||
:param value_col: Column in DataFrame to use for values (defaults to 'profit_ratio')
|
:param value_col: Column in DataFrame to use for values (defaults to 'profit_abs')
|
||||||
:return: Tuple (float, highdate, lowdate, highvalue, lowvalue) with absolute max drawdown,
|
:param starting_balance: Portfolio starting balance - properly calculate relative drawdown.
|
||||||
high and low time and high and low value.
|
:return: Tuple (float, highdate, lowdate, highvalue, lowvalue, relative_drawdown)
|
||||||
|
with absolute max drawdown, high and low time and high and low value,
|
||||||
|
and the relative account drawdown
|
||||||
:raise: ValueError if trade-dataframe was found empty.
|
:raise: ValueError if trade-dataframe was found empty.
|
||||||
"""
|
"""
|
||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
@ -416,7 +418,17 @@ def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date'
|
|||||||
high_val = max_drawdown_df.loc[max_drawdown_df.iloc[:idxmin]
|
high_val = max_drawdown_df.loc[max_drawdown_df.iloc[:idxmin]
|
||||||
['high_value'].idxmax(), 'cumulative']
|
['high_value'].idxmax(), 'cumulative']
|
||||||
low_val = max_drawdown_df.loc[idxmin, 'cumulative']
|
low_val = max_drawdown_df.loc[idxmin, 'cumulative']
|
||||||
return abs(min(max_drawdown_df['drawdown'])), high_date, low_date, high_val, low_val
|
|
||||||
|
max_drawdown_rel = (high_val - low_val) / (high_val + starting_balance)
|
||||||
|
|
||||||
|
return (
|
||||||
|
abs(min(max_drawdown_df['drawdown'])),
|
||||||
|
high_date,
|
||||||
|
low_date,
|
||||||
|
high_val,
|
||||||
|
low_val,
|
||||||
|
max_drawdown_rel
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> Tuple[float, float]:
|
def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> Tuple[float, float]:
|
||||||
|
@ -462,12 +462,11 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
max_drawdown, _, _, _, _ = calculate_max_drawdown(
|
(drawdown_abs, drawdown_start, drawdown_end, high_val, low_val,
|
||||||
results, value_col='profit_ratio')
|
max_drawdown) = calculate_max_drawdown(
|
||||||
drawdown_abs, drawdown_start, drawdown_end, high_val, low_val = calculate_max_drawdown(
|
results, value_col='profit_abs', starting_balance=starting_balance)
|
||||||
results, value_col='profit_abs')
|
|
||||||
strat_stats.update({
|
strat_stats.update({
|
||||||
'max_drawdown': max_drawdown,
|
'max_drawdown_account': max_drawdown,
|
||||||
'max_drawdown_abs': drawdown_abs,
|
'max_drawdown_abs': drawdown_abs,
|
||||||
'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT),
|
'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT),
|
||||||
'drawdown_start_ts': drawdown_start.timestamp() * 1000,
|
'drawdown_start_ts': drawdown_start.timestamp() * 1000,
|
||||||
@ -486,7 +485,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
strat_stats.update({
|
strat_stats.update({
|
||||||
'max_drawdown': 0.0,
|
'max_drawdown_account': 0.0,
|
||||||
'max_drawdown_abs': 0.0,
|
'max_drawdown_abs': 0.0,
|
||||||
'max_drawdown_low': 0.0,
|
'max_drawdown_low': 0.0,
|
||||||
'max_drawdown_high': 0.0,
|
'max_drawdown_high': 0.0,
|
||||||
@ -716,7 +715,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
('Max balance', round_coin_value(strat_results['csum_max'],
|
('Max balance', round_coin_value(strat_results['csum_max'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
|
|
||||||
('Drawdown', f"{strat_results['max_drawdown']:.2%}"),
|
('Drawdown (Account)', f"{strat_results['max_drawdown_account']:.2%}"),
|
||||||
('Drawdown', round_coin_value(strat_results['max_drawdown_abs'],
|
('Drawdown', round_coin_value(strat_results['max_drawdown_abs'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Drawdown high', round_coin_value(strat_results['max_drawdown_high'],
|
('Drawdown high', round_coin_value(strat_results['max_drawdown_high'],
|
||||||
|
@ -161,7 +161,7 @@ def add_max_drawdown(fig, row, trades: pd.DataFrame, df_comb: pd.DataFrame,
|
|||||||
Add scatter points indicating max drawdown
|
Add scatter points indicating max drawdown
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
max_drawdown, highdate, lowdate, _, _ = calculate_max_drawdown(trades)
|
_, highdate, lowdate, _, _, max_drawdown = calculate_max_drawdown(trades)
|
||||||
|
|
||||||
drawdown = go.Scatter(
|
drawdown = go.Scatter(
|
||||||
x=[highdate, lowdate],
|
x=[highdate, lowdate],
|
||||||
|
Loading…
Reference in New Issue
Block a user