Add improved vol calculation.
This commit is contained in:
@@ -133,11 +133,37 @@ def analyze_trends(df):
|
||||
return position_returns
|
||||
|
||||
|
||||
def calculate_volatility(df, short_window=30, medium_window=90, long_window=180):
|
||||
"""
|
||||
Calculate volatility using multiple timeframes and exponential weighting.
|
||||
Returns a more nuanced estimate of current market volatility.
|
||||
"""
|
||||
df = df.copy()
|
||||
|
||||
# Calculate log returns if not already present
|
||||
if "Log_Return" not in df.columns:
|
||||
df["Log_Price"] = np.log(df["Close"])
|
||||
df["Log_Return"] = df["Log_Price"].diff()
|
||||
|
||||
# Calculate exponentially weighted volatilities for different timeframes
|
||||
short_vol = df["Log_Return"].ewm(span=short_window).std().iloc[-1]
|
||||
medium_vol = df["Log_Return"].ewm(span=medium_window).std().iloc[-1]
|
||||
long_vol = df["Log_Return"].ewm(span=long_window).std().iloc[-1]
|
||||
|
||||
# Blend the estimates with more weight on recent data
|
||||
base_vol = 0.5 * short_vol + 0.3 * medium_vol + 0.2 * long_vol
|
||||
|
||||
# Scale up volatility to target ~68% coverage
|
||||
volatility_scale = 1.2
|
||||
return base_vol * volatility_scale
|
||||
|
||||
|
||||
def project_prices(
|
||||
df, days_forward=365, simulations=1000, confidence_levels=[0.95, 0.68]
|
||||
):
|
||||
"""
|
||||
Project future Bitcoin prices using Monte Carlo simulation.
|
||||
Now with enhanced volatility calculation.
|
||||
"""
|
||||
# Calculate log returns for volatility estimation
|
||||
df = df.copy()
|
||||
@@ -170,19 +196,23 @@ def project_prices(
|
||||
[cycle_trends.get(day, cycle_trends.mean()) for day in future_cycle_days]
|
||||
)
|
||||
|
||||
# Calculate volatility using recent data
|
||||
recent_volatility = df["Log_Return"].tail(90).std()
|
||||
# Calculate enhanced volatility
|
||||
volatility = calculate_volatility(df)
|
||||
|
||||
# Run Monte Carlo simulation
|
||||
np.random.seed(42) # For reproducibility
|
||||
# Run Monte Carlo simulation with enhanced volatility
|
||||
np.random.seed(42)
|
||||
simulated_paths = np.zeros((days_forward, simulations))
|
||||
|
||||
for sim in range(simulations):
|
||||
# Generate random returns using cycle-aware expected returns
|
||||
# Generate random returns with slight skew based on expected returns
|
||||
skew = np.sign(expected_returns) * 0.1 # Small skew in direction of trend
|
||||
returns = np.random.normal(
|
||||
loc=expected_returns, scale=recent_volatility, size=days_forward
|
||||
loc=expected_returns + skew * volatility,
|
||||
scale=volatility,
|
||||
size=days_forward,
|
||||
)
|
||||
# Since we're using log returns, we can simply sum them
|
||||
|
||||
# Calculate price path
|
||||
cumulative_returns = np.cumsum(returns)
|
||||
price_path = last_price * np.exp(cumulative_returns)
|
||||
simulated_paths[:, sim] = price_path
|
||||
|
||||
Reference in New Issue
Block a user