Implement trend smoothing.

This commit is contained in:
sam
2024-11-15 01:59:19 -08:00
parent 36eda3eb3e
commit f9b8af828a
+31 -18
View File
@@ -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,