Update metrics.py

This commit is contained in:
Stefano Ariestasia 2022-11-28 08:56:49 +09:00
parent 320535a227
commit f410b1b14d

View File

@ -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