Implement trend smoothing.
This commit is contained in:
@@ -105,7 +105,7 @@ def get_nice_price_points(min_price, max_price):
|
|||||||
|
|
||||||
def analyze_trends(df):
|
def analyze_trends(df):
|
||||||
"""
|
"""
|
||||||
Analyze Bitcoin price trends using log returns.
|
Analyze Bitcoin price trends using log returns with simple moving average smoothing.
|
||||||
"""
|
"""
|
||||||
df = df.copy()
|
df = df.copy()
|
||||||
|
|
||||||
@@ -123,14 +123,18 @@ def analyze_trends(df):
|
|||||||
# Group by position in cycle
|
# Group by position in cycle
|
||||||
position_returns = df.groupby("Cycle_Days")["Log_Return"].mean()
|
position_returns = df.groupby("Cycle_Days")["Log_Return"].mean()
|
||||||
|
|
||||||
# Smooth the returns using Savitzky-Golay filter
|
# Simple moving average smoothing
|
||||||
window = 91 # About 3 months
|
window = 60
|
||||||
if len(position_returns) > window:
|
smoothed_returns = position_returns.rolling(
|
||||||
position_returns = pd.Series(
|
window=window,
|
||||||
savgol_filter(position_returns, window, 3), index=position_returns.index
|
center=True, # Center the window for better trend capture
|
||||||
)
|
min_periods=int(window / 2), # Allow partial windows to reduce edge effects
|
||||||
|
).mean()
|
||||||
|
|
||||||
return position_returns
|
# Fill any NaN values at the edges
|
||||||
|
smoothed_returns = smoothed_returns.fillna(method="bfill").fillna(method="ffill")
|
||||||
|
|
||||||
|
return smoothed_returns
|
||||||
|
|
||||||
|
|
||||||
def calculate_volatility(df, short_window=30, medium_window=90, long_window=180):
|
def calculate_volatility(df, short_window=30, medium_window=90, long_window=180):
|
||||||
@@ -163,14 +167,14 @@ def project_prices(
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Project future Bitcoin prices using Monte Carlo simulation.
|
Project future Bitcoin prices using Monte Carlo simulation.
|
||||||
Now with enhanced volatility calculation.
|
Uses enhanced trend smoothing for better predictions.
|
||||||
"""
|
"""
|
||||||
# Calculate log returns for volatility estimation
|
# Calculate log returns for volatility estimation
|
||||||
df = df.copy()
|
df = df.copy()
|
||||||
df["Log_Price"] = np.log(df["Close"])
|
df["Log_Price"] = np.log(df["Close"])
|
||||||
df["Log_Return"] = df["Log_Price"].diff()
|
df["Log_Return"] = df["Log_Price"].diff()
|
||||||
|
|
||||||
# Get cycle-based trends
|
# Get smoothed trends
|
||||||
cycle_trends = analyze_trends(df)
|
cycle_trends = analyze_trends(df)
|
||||||
|
|
||||||
# Get current position in halving cycle
|
# Get current position in halving cycle
|
||||||
@@ -188,24 +192,33 @@ def project_prices(
|
|||||||
start=last_date + timedelta(days=1), periods=days_forward, freq="D"
|
start=last_date + timedelta(days=1), periods=days_forward, freq="D"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate expected returns for future dates based on cycle position
|
# Calculate expected returns with enhanced cycle boundary handling
|
||||||
future_cycle_days = [
|
future_cycle_days = [
|
||||||
(current_cycle_days + i) % (4 * 365) for i in range(days_forward)
|
(current_cycle_days + i) % (4 * 365) for i in range(days_forward)
|
||||||
]
|
]
|
||||||
expected_returns = np.array(
|
expected_returns = []
|
||||||
[cycle_trends.get(day, cycle_trends.mean()) for day in future_cycle_days]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Calculate enhanced volatility
|
for day in future_cycle_days:
|
||||||
|
# Get base trend value
|
||||||
|
base_trend = cycle_trends.get(day, cycle_trends.mean())
|
||||||
|
|
||||||
|
# Add slight mean reversion for extreme values
|
||||||
|
if abs(base_trend) > 2 * cycle_trends.std():
|
||||||
|
base_trend *= 0.8 # Dampen extreme trends
|
||||||
|
|
||||||
|
expected_returns.append(base_trend)
|
||||||
|
|
||||||
|
expected_returns = np.array(expected_returns)
|
||||||
|
|
||||||
|
# Calculate volatility
|
||||||
volatility = calculate_volatility(df)
|
volatility = calculate_volatility(df)
|
||||||
|
|
||||||
# Run Monte Carlo simulation with enhanced volatility
|
# Run Monte Carlo simulation
|
||||||
np.random.seed(42)
|
np.random.seed(42)
|
||||||
simulated_paths = np.zeros((days_forward, simulations))
|
simulated_paths = np.zeros((days_forward, simulations))
|
||||||
|
|
||||||
for sim in range(simulations):
|
for sim in range(simulations):
|
||||||
# Generate random returns with slight skew based on expected returns
|
skew = np.sign(expected_returns) * 0.087 # Small skew in direction of trend
|
||||||
skew = np.sign(expected_returns) * 0.1 # Small skew in direction of trend
|
|
||||||
returns = np.random.normal(
|
returns = np.random.normal(
|
||||||
loc=expected_returns + skew * volatility,
|
loc=expected_returns + skew * volatility,
|
||||||
scale=volatility,
|
scale=volatility,
|
||||||
|
|||||||
Reference in New Issue
Block a user