Update metrics.py
This commit is contained in:
parent
320535a227
commit
f410b1b14d
@ -1,9 +1,9 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Dict, Tuple
|
from typing import Dict, Tuple
|
||||||
|
from datetime import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import math
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -190,3 +190,128 @@ def calculate_cagr(days_passed: int, starting_balance: float, final_balance: flo
|
|||||||
:return: CAGR
|
:return: CAGR
|
||||||
"""
|
"""
|
||||||
return (final_balance / starting_balance) ** (1 / (days_passed / 365)) - 1
|
return (final_balance / starting_balance) ** (1 / (days_passed / 365)) - 1
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_expectancy(trades: pd.DataFrame) -> float:
|
||||||
|
"""
|
||||||
|
Calculate expectancy
|
||||||
|
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
||||||
|
:return: expectancy
|
||||||
|
"""
|
||||||
|
if len(trades) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
expectancy = 1
|
||||||
|
|
||||||
|
profit_sum = trades.loc[trades['profit_abs'] > 0, 'profit_abs'].sum()
|
||||||
|
loss_sum = abs(trades.loc[trades['profit_abs'] < 0, 'profit_abs'].sum())
|
||||||
|
nb_win_trades = len(trades.loc[trades['profit_abs'] > 0])
|
||||||
|
nb_loss_trades = len(trades.loc[trades['profit_abs'] < 0])
|
||||||
|
|
||||||
|
if (nb_win_trades > 0) and (nb_loss_trades > 0):
|
||||||
|
average_win = profit_sum / nb_win_trades
|
||||||
|
average_loss = loss_sum / nb_loss_trades
|
||||||
|
risk_reward_ratio = average_win / average_loss
|
||||||
|
winrate = nb_win_trades / len(trades)
|
||||||
|
expectancy = ((1 + risk_reward_ratio) * winrate) - 1
|
||||||
|
elif nb_win_trades == 0:
|
||||||
|
expectancy = 0
|
||||||
|
|
||||||
|
return expectancy
|
||||||
|
|
||||||
|
def calculate_sortino(trades: pd.DataFrame,
|
||||||
|
min_date: datetime, max_date: datetime) -> float:
|
||||||
|
"""
|
||||||
|
Calculate sortino
|
||||||
|
:param trades: DataFrame containing trades (requires columns profit_ratio)
|
||||||
|
:return: sortino
|
||||||
|
"""
|
||||||
|
if (len(trades) == 0) or (min_date == None) or (max_date == None) or (min_date == max_date):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
total_profit = trades["profit_ratio"]
|
||||||
|
days_period = (max_date - min_date).days
|
||||||
|
|
||||||
|
if days_period == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# adding slippage of 0.1% per trade
|
||||||
|
# total_profit = total_profit - 0.0005
|
||||||
|
expected_returns_mean = total_profit.sum() / days_period
|
||||||
|
|
||||||
|
trades['downside_returns'] = 0
|
||||||
|
trades.loc[total_profit < 0, 'downside_returns'] = trades['profit_ratio']
|
||||||
|
down_stdev = np.std(trades['downside_returns'])
|
||||||
|
|
||||||
|
if down_stdev != 0:
|
||||||
|
sortino_ratio = expected_returns_mean / down_stdev * np.sqrt(365)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sortino ratio to be clear that this is NOT optimal.
|
||||||
|
sortino_ratio = -100
|
||||||
|
|
||||||
|
# print(expected_returns_mean, down_stdev, sortino_ratio)
|
||||||
|
return sortino_ratio
|
||||||
|
|
||||||
|
def calculate_sharpe(trades: pd.DataFrame,
|
||||||
|
min_date: datetime, max_date: datetime) -> float:
|
||||||
|
"""
|
||||||
|
Calculate sharpe
|
||||||
|
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
||||||
|
:return: sharpe
|
||||||
|
"""
|
||||||
|
if (len(trades) == 0) or (min_date == None) or (max_date == None) or (min_date == max_date):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
total_profit = trades["profit_ratio"]
|
||||||
|
days_period = (max_date - min_date).days
|
||||||
|
|
||||||
|
if days_period == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# adding slippage of 0.1% per trade
|
||||||
|
# total_profit = total_profit - 0.0005
|
||||||
|
expected_returns_mean = total_profit.sum() / days_period
|
||||||
|
up_stdev = np.std(total_profit)
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * np.sqrt(365)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -100
|
||||||
|
|
||||||
|
# print(expected_returns_mean, up_stdev, sharp_ratio)
|
||||||
|
return sharp_ratio
|
||||||
|
|
||||||
|
def calculate_calmar(trades: pd.DataFrame,
|
||||||
|
min_date: datetime, max_date: datetime) -> float:
|
||||||
|
"""
|
||||||
|
Calculate calmar
|
||||||
|
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
||||||
|
:return: calmar
|
||||||
|
"""
|
||||||
|
if (len(trades) == 0) or (min_date == None) or (max_date == None) or (min_date == max_date):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
total_profit = trades["profit_ratio"]
|
||||||
|
days_period = (max_date - min_date).days
|
||||||
|
|
||||||
|
# adding slippage of 0.1% per trade
|
||||||
|
# total_profit = total_profit - 0.0005
|
||||||
|
expected_returns_mean = total_profit.sum() / days_period * 100
|
||||||
|
|
||||||
|
# calculate max drawdown
|
||||||
|
try:
|
||||||
|
_, _, _, _, _, max_drawdown = calculate_max_drawdown(
|
||||||
|
trades, value_col="profit_abs"
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
max_drawdown = 0
|
||||||
|
|
||||||
|
if max_drawdown != 0:
|
||||||
|
calmar_ratio = expected_returns_mean / max_drawdown * math.sqrt(365)
|
||||||
|
else:
|
||||||
|
# Define high (negative) calmar ratio to be clear that this is NOT optimal.
|
||||||
|
calmar_ratio = -100
|
||||||
|
|
||||||
|
# print(expected_returns_mean, max_drawdown, calmar_ratio)
|
||||||
|
return calmar_ratio
|
||||||
|
Loading…
Reference in New Issue
Block a user