Fix create_plots() output.
This commit is contained in:
@@ -512,7 +512,7 @@ def analyze_bitcoin_prices(csv_path):
|
|||||||
|
|
||||||
def create_plots(df, start=None, end=None, project_days=365):
|
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
|
# Filter data based on date range
|
||||||
mask = pd.Series(True, index=df.index)
|
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)
|
maturity_score = calculate_market_maturity_score(plot_df)
|
||||||
plot_df["Market_Maturity"] = maturity_score
|
plot_df["Market_Maturity"] = maturity_score
|
||||||
|
|
||||||
# Generate projections with market maturity adjustments
|
# Generate projections
|
||||||
projections = project_prices(plot_df, days_forward=project_days)
|
projections = project_prices(plot_df, days_forward=project_days)
|
||||||
|
|
||||||
# Set up the style
|
# Set up the style
|
||||||
plt.style.use("seaborn-v0_8")
|
plt.style.use("seaborn-v0_8")
|
||||||
|
|
||||||
# Create figure with additional subplot for maturity
|
# Create figure with adjusted size for additional subplot
|
||||||
fig = plt.figure(figsize=(15, 18)) # Made taller to accommodate new subplot
|
fig = plt.figure(figsize=(15, 20)) # Increased height to accommodate new subplot
|
||||||
|
|
||||||
# Date range for titles
|
# 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')})"
|
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)
|
# 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
|
# Plot historical prices
|
||||||
ax1.semilogy(plot_df["Date"], plot_df["Close"], "b-", label="Historical Price")
|
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
|
# Customize y-axis
|
||||||
ax1.yaxis.set_major_formatter(plt.FuncFormatter(format_price))
|
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())
|
min_price = min(plot_df["Low"].min(), projections["Lower_95"].min())
|
||||||
max_price = max(plot_df["High"].max(), projections["Upper_95"].max())
|
max_price = max(plot_df["High"].max(), projections["Upper_95"].max())
|
||||||
|
|
||||||
price_points = get_nice_price_points(min_price, max_price)
|
price_points = get_nice_price_points(min_price, max_price)
|
||||||
ax1.set_yticks(price_points)
|
ax1.set_yticks(price_points)
|
||||||
|
ax1.tick_params(axis="y", labelsize=8)
|
||||||
# Adjust y-axis label properties
|
|
||||||
ax1.tick_params(axis="y", labelsize=8) # Smaller font size
|
|
||||||
|
|
||||||
# Add some padding to prevent label cutoff
|
|
||||||
ax1.margins(y=0.02)
|
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="major", linestyle="-", alpha=0.5)
|
||||||
ax1.grid(True, which="minor", linestyle=":", alpha=0.2)
|
ax1.grid(True, which="minor", linestyle=":", alpha=0.2)
|
||||||
|
|
||||||
ax1.set_title("Bitcoin Price History and Projections (Log Scale)" + hist_date_range)
|
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)
|
ax1.legend(fontsize=8)
|
||||||
|
|
||||||
# 2. Rolling volatility
|
# 2. Market Maturity Score
|
||||||
ax2 = plt.subplot(4, 1, 2)
|
ax2 = plt.subplot(5, 1, 2)
|
||||||
ax2.plot(
|
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["Date"],
|
||||||
plot_df["Rolling_Volatility_30d"],
|
plot_df["Rolling_Volatility_30d"],
|
||||||
"r-",
|
"r-",
|
||||||
label="30-Day Rolling Volatility",
|
label="30-Day Rolling Volatility",
|
||||||
)
|
)
|
||||||
ax2.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
|
ax3.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
|
||||||
ax2.set_xlabel("Date")
|
ax3.set_ylabel("Volatility")
|
||||||
ax2.set_ylabel("Volatility")
|
ax3.grid(True)
|
||||||
ax2.grid(True)
|
ax3.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
|
||||||
ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
|
ax3.legend()
|
||||||
ax2.legend()
|
|
||||||
|
|
||||||
# 3. Returns distribution
|
# 4. Returns distribution
|
||||||
ax3 = plt.subplot(4, 1, 3)
|
ax4 = plt.subplot(5, 1, 4)
|
||||||
returns_mean = plot_df["Daily_Return"].mean()
|
returns_mean = plot_df["Daily_Return"].mean()
|
||||||
returns_std = plot_df["Daily_Return"].std()
|
returns_std = plot_df["Daily_Return"].std()
|
||||||
filtered_returns = plot_df["Daily_Return"][
|
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)
|
& (plot_df["Daily_Return"] < returns_mean + 5 * returns_std)
|
||||||
]
|
]
|
||||||
|
|
||||||
sns.histplot(filtered_returns, bins=100, ax=ax3)
|
sns.histplot(filtered_returns, bins=100, ax=ax4)
|
||||||
ax3.set_title(
|
ax4.set_title(
|
||||||
"Distribution of Daily Returns (Excluding Extreme Outliers)" + hist_date_range
|
"Distribution of Daily Returns (Excluding Extreme Outliers)" + hist_date_range
|
||||||
)
|
)
|
||||||
ax3.set_xlabel("Daily Return")
|
ax4.set_xlabel("Daily Return")
|
||||||
ax3.set_ylabel("Count")
|
ax4.set_ylabel("Count")
|
||||||
ax3.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: "{:.0%}".format(x)))
|
ax4.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: "{:.0%}".format(x)))
|
||||||
|
|
||||||
# Add a vertical line for mean return
|
# Add mean line
|
||||||
ax3.axvline(filtered_returns.mean(), color="r", linestyle="dashed", linewidth=1)
|
ax4.axvline(filtered_returns.mean(), color="r", linestyle="dashed", linewidth=1)
|
||||||
ax3.text(
|
ax4.text(
|
||||||
filtered_returns.mean(),
|
filtered_returns.mean(),
|
||||||
ax3.get_ylim()[1],
|
ax4.get_ylim()[1],
|
||||||
"Mean",
|
"Mean",
|
||||||
rotation=90,
|
rotation=90,
|
||||||
va="top",
|
va="top",
|
||||||
ha="right",
|
ha="right",
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Projection ranges
|
# 5. Projection ranges
|
||||||
ax4 = plt.subplot(4, 1, 4)
|
ax5 = plt.subplot(5, 1, 5)
|
||||||
|
timepoints = np.array(range(30, project_days, 30))
|
||||||
# Calculate and plot price ranges at different future points
|
|
||||||
timepoints = np.array(range(30, 365, 30))
|
|
||||||
timepoints = timepoints[timepoints <= project_days]
|
timepoints = timepoints[timepoints <= project_days]
|
||||||
|
|
||||||
ranges = []
|
ranges = []
|
||||||
@@ -662,7 +666,7 @@ def create_plots(df, start=None, end=None, project_days=365):
|
|||||||
positions = []
|
positions = []
|
||||||
|
|
||||||
for t in timepoints:
|
for t in timepoints:
|
||||||
idx = t - 1 # Convert to 0-based index
|
idx = t - 1
|
||||||
ranges.extend(
|
ranges.extend(
|
||||||
[
|
[
|
||||||
projections["Lower_95"].iloc[idx],
|
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"])
|
labels.extend(["95% Lower", "68% Lower", "Median", "68% Upper", "95% Upper"])
|
||||||
positions.extend([t] * 5)
|
positions.extend([t] * 5)
|
||||||
|
|
||||||
# Plot ranges (removed violin plot)
|
ax5.scatter(positions, ranges, alpha=0.6)
|
||||||
ax4.scatter(positions, ranges, alpha=0.6)
|
|
||||||
|
|
||||||
# Add lines connecting the ranges
|
|
||||||
for t in timepoints:
|
for t in timepoints:
|
||||||
idx = positions.index(t)
|
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
|
ax5.set_yscale("log")
|
||||||
ax4.set_yscale("log")
|
|
||||||
|
|
||||||
# Get the current order of magnitude for setting appropriate ticks
|
|
||||||
min_price = min(ranges)
|
min_price = min(ranges)
|
||||||
max_price = max(ranges)
|
max_price = max(ranges)
|
||||||
|
price_points = get_nice_price_points(min_price, max_price)
|
||||||
# Create price points at regular intervals on log scale
|
ax5.set_yticks(price_points)
|
||||||
log_min = np.floor(np.log10(min_price))
|
ax5.yaxis.set_major_formatter(plt.FuncFormatter(format_price))
|
||||||
log_max = np.ceil(np.log10(max_price))
|
ax5.set_title("Projected Price Ranges at Future Timepoints")
|
||||||
price_points = []
|
ax5.set_xlabel("Days Forward")
|
||||||
for exp in range(int(log_min), int(log_max + 1)):
|
ax5.set_ylabel("Price (USD)")
|
||||||
for mult in [1, 2, 5]:
|
ax5.grid(True, alpha=0.3)
|
||||||
point = mult * 10**exp
|
ax5.set_xticks(timepoints)
|
||||||
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...]
|
|
||||||
|
|
||||||
# Adjust layout
|
# Adjust layout
|
||||||
plt.tight_layout()
|
plt.tight_layout(h_pad=1.0) # Increased spacing between subplots
|
||||||
|
|
||||||
# Save the plot
|
# Save the plot
|
||||||
start_str = start if start else plot_df["Date"].min().strftime("%Y-%m-%d")
|
start_str = start if start else plot_df["Date"].min().strftime("%Y-%m-%d")
|
||||||
|
|||||||
Reference in New Issue
Block a user