Update metrics.py
This commit is contained in:
parent
320535a227
commit
f410b1b14d
@ -1,9 +1,9 @@
|
||||
import logging
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from datetime import datetime
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
import math
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -190,3 +190,128 @@ def calculate_cagr(days_passed: int, starting_balance: float, final_balance: flo
|
||||
:return: CAGR
|
||||
"""
|
||||
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