Fix create_plots() output.

This commit is contained in:
sam
2024-11-15 14:08:16 -08:00
parent b024a38040
commit 4975e1647d
+61 -124
View File
@@ -512,7 +512,7 @@ def analyze_bitcoin_prices(csv_path):
def create_plots(df, start=None, end=None, project_days=365):
"""
Create plots including historical data and future projections.
Create enhanced plots including market maturity visualization.
"""
# Filter data based on date range
mask = pd.Series(True, index=df.index)
@@ -530,20 +530,20 @@ def create_plots(df, start=None, end=None, project_days=365):
maturity_score = calculate_market_maturity_score(plot_df)
plot_df["Market_Maturity"] = maturity_score
# Generate projections with market maturity adjustments
# Generate projections
projections = project_prices(plot_df, days_forward=project_days)
# Set up the style
plt.style.use("seaborn-v0_8")
# Create figure with additional subplot for maturity
fig = plt.figure(figsize=(15, 18)) # Made taller to accommodate new subplot
# Create figure with adjusted size for additional subplot
fig = plt.figure(figsize=(15, 20)) # Increased height to accommodate new subplot
# Date range for titles
hist_date_range = f" ({plot_df['Date'].min().strftime('%Y-%m-%d')} to {plot_df['Date'].max().strftime('%Y-%m-%d')})"
# 1. Price history and projections (log scale)
ax1 = plt.subplot(5, 1, 1) # Changed to 5,1 grid
ax1 = plt.subplot(5, 1, 1)
# Plot historical prices
ax1.semilogy(plot_df["Date"], plot_df["Close"], "b-", label="Historical Price")
@@ -582,48 +582,54 @@ def create_plots(df, start=None, end=None, project_days=365):
# Customize y-axis
ax1.yaxis.set_major_formatter(plt.FuncFormatter(format_price))
# Set custom y-axis ticks at meaningful price points
min_price = min(plot_df["Low"].min(), projections["Lower_95"].min())
max_price = max(plot_df["High"].max(), projections["Upper_95"].max())
price_points = get_nice_price_points(min_price, max_price)
ax1.set_yticks(price_points)
# Adjust y-axis label properties
ax1.tick_params(axis="y", labelsize=8) # Smaller font size
# Add some padding to prevent label cutoff
ax1.tick_params(axis="y", labelsize=8)
ax1.margins(y=0.02)
# Adjust label padding to prevent overlap
ax1.yaxis.set_tick_params(pad=1)
# Add grid lines with adjusted opacity
ax1.grid(True, which="major", linestyle="-", alpha=0.5)
ax1.grid(True, which="minor", linestyle=":", alpha=0.2)
ax1.set_title("Bitcoin Price History and Projections (Log Scale)" + hist_date_range)
# Make legend font size smaller too for consistency
ax1.legend(fontsize=8)
# 2. Rolling volatility
ax2 = plt.subplot(4, 1, 2)
# 2. Market Maturity Score
ax2 = plt.subplot(5, 1, 2)
ax2.plot(
plot_df["Date"],
plot_df["Market_Maturity"],
color="purple",
label="Market Maturity Score",
)
ax2.set_title("Market Maturity Score" + hist_date_range)
ax2.set_ylim(0, 1)
ax2.grid(True, alpha=0.3)
ax2.legend()
# Add futures launch annotation
futures_date = pd.Timestamp("2017-12-10")
if futures_date >= plot_df["Date"].min() and futures_date <= plot_df["Date"].max():
ax2.axvline(futures_date, color="red", linestyle="--", alpha=0.5)
ax2.text(
futures_date, 0.95, "Futures\nLaunch", rotation=90, va="top", ha="right"
)
# 3. Rolling volatility
ax3 = plt.subplot(5, 1, 3)
ax3.plot(
plot_df["Date"],
plot_df["Rolling_Volatility_30d"],
"r-",
label="30-Day Rolling Volatility",
)
ax2.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
ax2.set_xlabel("Date")
ax2.set_ylabel("Volatility")
ax2.grid(True)
ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
ax2.legend()
ax3.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
ax3.set_ylabel("Volatility")
ax3.grid(True)
ax3.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
ax3.legend()
# 3. Returns distribution
ax3 = plt.subplot(4, 1, 3)
# 4. Returns distribution
ax4 = plt.subplot(5, 1, 4)
returns_mean = plot_df["Daily_Return"].mean()
returns_std = plot_df["Daily_Return"].std()
filtered_returns = plot_df["Daily_Return"][
@@ -631,30 +637,28 @@ def create_plots(df, start=None, end=None, project_days=365):
& (plot_df["Daily_Return"] < returns_mean + 5 * returns_std)
]
sns.histplot(filtered_returns, bins=100, ax=ax3)
ax3.set_title(
sns.histplot(filtered_returns, bins=100, ax=ax4)
ax4.set_title(
"Distribution of Daily Returns (Excluding Extreme Outliers)" + hist_date_range
)
ax3.set_xlabel("Daily Return")
ax3.set_ylabel("Count")
ax3.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: "{:.0%}".format(x)))
ax4.set_xlabel("Daily Return")
ax4.set_ylabel("Count")
ax4.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: "{:.0%}".format(x)))
# Add a vertical line for mean return
ax3.axvline(filtered_returns.mean(), color="r", linestyle="dashed", linewidth=1)
ax3.text(
# Add mean line
ax4.axvline(filtered_returns.mean(), color="r", linestyle="dashed", linewidth=1)
ax4.text(
filtered_returns.mean(),
ax3.get_ylim()[1],
ax4.get_ylim()[1],
"Mean",
rotation=90,
va="top",
ha="right",
)
# 4. Projection ranges
ax4 = plt.subplot(4, 1, 4)
# Calculate and plot price ranges at different future points
timepoints = np.array(range(30, 365, 30))
# 5. Projection ranges
ax5 = plt.subplot(5, 1, 5)
timepoints = np.array(range(30, project_days, 30))
timepoints = timepoints[timepoints <= project_days]
ranges = []
@@ -662,7 +666,7 @@ def create_plots(df, start=None, end=None, project_days=365):
positions = []
for t in timepoints:
idx = t - 1 # Convert to 0-based index
idx = t - 1
ranges.extend(
[
projections["Lower_95"].iloc[idx],
@@ -675,93 +679,26 @@ def create_plots(df, start=None, end=None, project_days=365):
labels.extend(["95% Lower", "68% Lower", "Median", "68% Upper", "95% Upper"])
positions.extend([t] * 5)
# Plot ranges (removed violin plot)
ax4.scatter(positions, ranges, alpha=0.6)
ax5.scatter(positions, ranges, alpha=0.6)
# Add lines connecting the ranges
for t in timepoints:
idx = positions.index(t)
ax4.plot([t] * 5, ranges[idx : idx + 5], "k-", alpha=0.3)
ax5.plot([t] * 5, ranges[idx : idx + 5], "k-", alpha=0.3)
# Set log scale first
ax4.set_yscale("log")
# Get the current order of magnitude for setting appropriate ticks
ax5.set_yscale("log")
min_price = min(ranges)
max_price = max(ranges)
# Create price points at regular intervals on log scale
log_min = np.floor(np.log10(min_price))
log_max = np.ceil(np.log10(max_price))
price_points = []
for exp in range(int(log_min), int(log_max + 1)):
for mult in [1, 2, 5]:
point = mult * 10**exp
if min_price <= point <= max_price:
price_points.append(point)
ax4.set_yticks(price_points)
def price_formatter(x, p):
if x >= 1e6:
return f"${x/1e6:.1f}M"
if x >= 1e3:
return f"${x/1e3:.0f}K"
return f"${x:.0f}"
# Apply formatter to major ticks
ax4.yaxis.set_major_formatter(plt.FuncFormatter(price_formatter))
# Customize the plot
ax4.set_title("Projected Price Ranges at Future Timepoints")
ax4.set_xlabel("Days Forward")
ax4.set_ylabel("Price (USD)")
ax4.grid(True, alpha=0.3)
# Set x-axis to show only our timepoints
ax4.set_xticks(timepoints)
# 2. Market Maturity Score (New)
ax2 = plt.subplot(5, 1, 2)
ax2.plot(
plot_df["Date"],
plot_df["Market_Maturity"],
color="purple",
label="Market Maturity Score",
)
ax2.set_title("Market Maturity Score" + hist_date_range)
ax2.set_xlabel("Date")
ax2.set_ylabel("Maturity Score (0-1)")
ax2.grid(True)
ax2.legend()
# Add annotations for key events
futures_date = pd.Timestamp("2017-12-10")
if futures_date >= plot_df["Date"].min() and futures_date <= plot_df["Date"].max():
ax2.axvline(futures_date, color="red", linestyle="--", alpha=0.5)
ax2.text(
futures_date,
ax2.get_ylim()[1],
"Futures\nLaunch",
rotation=90,
va="top",
ha="right",
)
# 3. Rolling volatility (now third subplot)
ax3 = plt.subplot(5, 1, 3)
# [Previous volatility plotting code...]
# 4. Returns distribution (now fourth subplot)
ax4 = plt.subplot(5, 1, 4)
# [Previous distribution plotting code...]
# 5. Projection ranges (now fifth subplot)
ax5 = plt.subplot(5, 1, 5)
# [Previous projection ranges plotting code...]
price_points = get_nice_price_points(min_price, max_price)
ax5.set_yticks(price_points)
ax5.yaxis.set_major_formatter(plt.FuncFormatter(format_price))
ax5.set_title("Projected Price Ranges at Future Timepoints")
ax5.set_xlabel("Days Forward")
ax5.set_ylabel("Price (USD)")
ax5.grid(True, alpha=0.3)
ax5.set_xticks(timepoints)
# Adjust layout
plt.tight_layout()
plt.tight_layout(h_pad=1.0) # Increased spacing between subplots
# Save the plot
start_str = start if start else plot_df["Date"].min().strftime("%Y-%m-%d")