ETF_Suite_Portal/services/nav_erosion_service/service.py

90 lines
3.6 KiB
Python

from typing import Dict, Tuple
class NavErosionService:
def _calculate_nav_risk(self, etf_data: Dict, etf_type: ETFType) -> Tuple[float, Dict]:
"""Calculate NAV risk components with ETF-type specific adjustments"""
components = {}
# Base risk calculation with ETF-type specific thresholds
if etf_data.get('max_drawdown') is not None:
if etf_type == ETFType.INCOME:
# Income ETFs typically have lower drawdowns
if etf_data['max_drawdown'] > 0.25:
components['drawdown'] = 7
elif etf_data['max_drawdown'] > 0.15:
components['drawdown'] = 5
elif etf_data['max_drawdown'] > 0.10:
components['drawdown'] = 3
else:
components['drawdown'] = 2
elif etf_type == ETFType.GROWTH:
# Growth ETFs typically have higher drawdowns
if etf_data['max_drawdown'] > 0.35:
components['drawdown'] = 7
elif etf_data['max_drawdown'] > 0.25:
components['drawdown'] = 5
elif etf_data['max_drawdown'] > 0.15:
components['drawdown'] = 3
else:
components['drawdown'] = 2
else: # BALANCED
# Balanced ETFs have moderate drawdowns
if etf_data['max_drawdown'] > 0.30:
components['drawdown'] = 7
elif etf_data['max_drawdown'] > 0.20:
components['drawdown'] = 5
elif etf_data['max_drawdown'] > 0.12:
components['drawdown'] = 3
else:
components['drawdown'] = 2
else:
components['drawdown'] = 4 # Default medium risk if no data
# Rest of the method remains unchanged
if etf_data.get('volatility') is not None:
if etf_data['volatility'] > 0.40:
components['volatility'] = 7
elif etf_data['volatility'] > 0.25:
components['volatility'] = 5
elif etf_data['volatility'] > 0.15:
components['volatility'] = 3
else:
components['volatility'] = 2
else:
components['volatility'] = 4
if etf_data.get('sharpe_ratio') is not None:
if etf_data['sharpe_ratio'] >= 2.0:
components['sharpe'] = 1
elif etf_data['sharpe_ratio'] >= 1.5:
components['sharpe'] = 2
elif etf_data['sharpe_ratio'] >= 1.0:
components['sharpe'] = 3
elif etf_data['sharpe_ratio'] >= 0.5:
components['sharpe'] = 4
else:
components['sharpe'] = 5
else:
components['sharpe'] = 4
if etf_data.get('sortino_ratio') is not None:
if etf_data['sortino_ratio'] >= 2.0:
components['sortino'] = 1
elif etf_data['sortino_ratio'] >= 1.5:
components['sortino'] = 2
elif etf_data['sortino_ratio'] >= 1.0:
components['sortino'] = 3
elif etf_data['sortino_ratio'] >= 0.5:
components['sortino'] = 4
else:
components['sortino'] = 5
else:
components['sortino'] = 4
# Calculate weighted NAV risk
nav_risk = sum(
components[component] * weight
for component, weight in self.NAV_COMPONENT_WEIGHTS.items()
)
return nav_risk, components