Actually use long-term vol in adaptive calculation.

This commit is contained in:
sam
2024-11-16 21:56:39 -08:00
parent 50f3f76830
commit 3158d7479d
+18 -6
View File
@@ -163,6 +163,9 @@ def calculate_adaptive_volatility(
""" """
Calculate volatility with adaptive window sizes based on market conditions. Calculate volatility with adaptive window sizes based on market conditions.
Returns a single volatility value for the most recent period. Returns a single volatility value for the most recent period.
Incorporates long-term volatility as a stability baseline and additional
reference point for regime detection.
""" """
df = df.copy() df = df.copy()
df["Log_Return"] = np.log(df["Close"]).diff() df["Log_Return"] = np.log(df["Close"]).diff()
@@ -190,10 +193,17 @@ def calculate_adaptive_volatility(
# Calculate regime indicators for recent period # Calculate regime indicators for recent period
medium_vol_mean = medium_vol.rolling(min(90, len(recent_df))).mean() medium_vol_mean = medium_vol.rolling(min(90, len(recent_df))).mean()
long_vol_mean = long_vol.rolling(min(180, len(recent_df))).mean()
if medium_vol_mean.iloc[-1] == 0: if medium_vol_mean.iloc[-1] == 0:
vol_regime = pd.Series([1.0] * len(recent_df)) vol_regime = pd.Series([1.0] * len(recent_df))
else: else:
vol_regime = short_vol / medium_vol_mean # Compare short-term to both medium and long-term volatility
medium_regime = short_vol / medium_vol_mean
long_regime = short_vol / long_vol_mean
# Use the more conservative (higher) regime indicator
vol_regime = pd.concat([medium_regime, long_regime], axis=1).max(axis=1)
vol_regime = vol_regime.clip(vol_clip_min, vol_clip_max) vol_regime = vol_regime.clip(vol_clip_min, vol_clip_max)
@@ -219,24 +229,26 @@ def calculate_adaptive_volatility(
]: ]:
return df["Log_Return"].std() return df["Log_Return"].std()
# Calculate regime-based weights # Calculate regime-based weights, now incorporating long-term volatility
high_vol_weight = (latest_regime - vol_clip_min) / (vol_clip_max - vol_clip_min) high_vol_weight = (latest_regime - vol_clip_min) / (vol_clip_max - vol_clip_min)
base_weights = np.array([0.2, 0.5, 0.3]) base_weights = np.array([0.2, 0.5, 0.3]) # Short, medium, long weights
stress_weights = np.array([0.4, 0.4, 0.2]) stress_weights = np.array(
[0.4, 0.4, 0.2]
) # More weight on short-term during stress
# Interpolate between base and stress weights # Interpolate between base and stress weights
weights = ( weights = (
base_weights * (1 - high_vol_weight) + stress_weights * high_vol_weight base_weights * (1 - high_vol_weight) + stress_weights * high_vol_weight
) )
# Calculate final volatility # Calculate final volatility using all three timeframes
final_vol = ( final_vol = (
final_short * weights[0] final_short * weights[0]
+ final_medium * weights[1] + final_medium * weights[1]
+ final_long * weights[2] + final_long * weights[2]
) )
# Add uncertainty adjustment # Add uncertainty adjustment based on regime changes
regime_change = abs(vol_regime.diff()).fillna(0) regime_change = abs(vol_regime.diff()).fillna(0)
regime_change_mean = regime_change.rolling(5, min_periods=1).mean().iloc[-1] regime_change_mean = regime_change.rolling(5, min_periods=1).mean().iloc[-1]
if regime_change_mean == 0: if regime_change_mean == 0: