Manus AI
Fix: Plotting error in core/plot.py by correcting MACD Histogram column name from 'macdh_12_26_9' to 'macdhist_12_26_9'.
0c2f6bc
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import logging
import matplotlib.pyplot as plt
from plotly.subplots import make_subplots
import numpy as np
logging.basicConfig(level=logging.INFO)
def plot_indicators(df, ticker):
try:
fig = make_subplots(
rows=7, cols=1, shared_xaxes=True, vertical_spacing=0.03,
subplot_titles=(
'Price & Moving Averages', 'Volume', 'MACD & RSI',
'Stochastic & Williams %R', 'ADX & DI', 'ATR & CCI', 'Signal Strength'
),
row_heights=[0.4, 0.1, 0.15, 0.15, 0.15, 0.15, 0.15]
)
# Price and Moving Averages
fig.add_trace(
go.Candlestick(
x=df.index, open=df['Open'], high=df['High'], low=df['Low'], close=df['value'],
name='Price', increasing_line_color='#00CC96', decreasing_line_color='#EF553B'
), row=1, col=1
)
for ma in ['sma_10', 'sma_20', 'sma_50', 'ema_12', 'ema_26', 'ema_50']:
if ma in df:
fig.add_trace(
go.Scatter(x=df.index, y=df[ma], name=ma.upper(), line=dict(width=1.5)),
row=1, col=1
)
if 'bbu_20_2' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df['bbu_20_2'], name='BB Upper', line=dict(color='gray', dash='dot')),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df['bbm_20_2'], name='BB Middle', line=dict(color='gray')),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df["bbl_20_2"], name="BB Lower", line=dict(color="gray", dash="dot")),
row=1, col=1
)
# Position Size and Risk Annotation
if 'atr_14' in df:
atr = df['atr_14'].iloc[-1]
stop_distance = atr * 2
position_size = (10000 * 0.01) / stop_distance
fig.add_annotation(
text=f"Position Size: {position_size:.0f} shares (1% risk, ATR {atr:.2f})",
xref="paper", yref="paper", x=0.05, y=0.95, showarrow=False,
font=dict(color="black", size=12)
)
# Volume
fig.add_trace(
go.Bar(x=df.index, y=df["Volume"], name="Volume", marker_color="blue", opacity=0.5),
row=2, col=1
)
# MACD & RSI
if 'macd_12_26_9' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df['macd_12_26_9'], name='MACD', line=dict(color='blue')),
row=3, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df["macds_12_26_9"], name="MACD Signal", line=dict(color="orange")),
row=3, col=1
)
fig.add_trace(
go.Bar(x=df.index, y=df["macdhist_12_26_9"], name="MACD Hist", marker_color="gray"),
row=3, col=1
)
if 'rsi_14' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["rsi_14"], name="RSI 14", line=dict(color="purple")),
row=3, col=1
)
fig.add_hline(y=70, line_dash="dash", line_color="red", row=3, col=1)
fig.add_hline(y=30, line_dash="dash", line_color="green", row=3, col=1)
if 'rsi_21' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["rsi_21"], name="RSI 21", line=dict(color="magenta", dash="dash")),
row=3, col=1
)
if 'rsi_50' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["rsi_50"], name="RSI 50", line=dict(color="cyan", dash="dot")),
row=3, col=1
)
# Stochastic & Williams %R
if 'stochk_14_3_3' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["stochk_14_3_3"], name="Stoch %K", line=dict(color="blue")),
row=4, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df["stochd_14_3_3"], name="Stoch %D", line=dict(color="orange")),
row=4, col=1
)
fig.add_hline(y=80, line_dash="dash", line_color="red", row=4, col=1)
fig.add_hline(y=20, line_dash="dash", line_color="green", row=4, col=1)
if 'willr_14' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["willr_14"], name="Williams %R", line=dict(color="green")),
row=4, col=1
)
fig.add_hline(y=-20, line_dash="dash", line_color="red", row=4, col=1)
fig.add_hline(y=-80, line_dash="dash", line_color="green", row=4, col=1)
# ADX & DI
if 'adx_14' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df['adx_14'], name='ADX', line=dict(color='blue')),
row=5, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df.get('pdi_14'), name='+DI', line=dict(color='green')),
row=5, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df.get('mdi_14'), name='-DI', line=dict(color='red')),
row=5, col=1
)
fig.add_hline(y=25, line_dash="dash", line_color="black", row=5, col=1)
# ATR & CCI
if 'atr_14' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["atr_14"], name="ATR", line=dict(color="orange")),
row=6, col=1
)
if 'cci_20' in df:
fig.add_trace(
go.Scatter(x=df.index, y=df["cci_20"], name="CCI", line=dict(color="purple")),
row=6, col=1
)
fig.add_hline(y=100, line_dash="dash", line_color="red", row=6, col=1)
fig.add_hline(y=-100, line_dash="dash", line_color="green", row=6, col=1)
# Signal Strength Plot
if all(col in df for col in ['RSI_Signal', 'MACD_Signal', 'ADX_Signal', 'Sentiment_Signal', 'Model_Signal']):
signal_strength = (
df['RSI_Signal'].abs() +
df['MACD_Signal'].abs() +
df['ADX_Signal'].abs() +
df['Sentiment_Signal'].abs() +
df['Model_Signal'].abs()
)
fig.add_trace(
go.Scatter(
x=df.index, y=signal_strength, name='Signal Strength',
line=dict(color='teal'), fill='tozeroy'
), row=7, col=1
)
fig.add_hline(y=3, line_dash="dash", line_color="orange", row=7, col=1, annotation_text="Strong Signal Threshold")
fig.update_layout(
title=f"{ticker} Price and Technical Indicators",
template="plotly_white",
height=2400,
width=1400,
showlegend=True,
xaxis_rangeslider_visible=False,
margin=dict(l=50, r=50, t=100, b=50),
xaxis=dict(tickformat="%Y-%m-%d", minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white",
hovermode="x unified"
)
return fig
except Exception as e:
logging.error(f"Plot indicators error: {e}")
return None
def plot_future_forecast(df, result, indicators):
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(df.index, df["value"], label="Historical Value", color="blue", linewidth=2)
for ind in indicators:
if ind in df.columns:
ax.plot(df.index, df[ind], label=ind, linestyle='--')
if "latest_prediction" in result:
last_date = df.index[-1]
horizon = len(result["latest_prediction"])
future_dates = pd.date_range(start=last_date + pd.Timedelta(days=1), periods=horizon, freq='B')
ax.plot(future_dates, result["latest_prediction"], label="Forecast Value", color="orange", linestyle="--", linewidth=2)
for i, val in enumerate(result["latest_prediction"]):
ax.text(future_dates[i], val, f"{val:.2f}", color="orange")
ax.legend()
ax.set_title("Historical Data, Indicators, and Future Forecast")
ax.set_xlabel("Date")
ax.set_ylabel("Value")
ax.grid(True)
plt.tight_layout()
return fig
# Other plotting functions remain unchanged
def plot_forecast(result, df):
try:
actual = result.get("actual", [])
forecast = result.get("forecast", [])
if not actual or not forecast:
return None
dates = df.index[-len(actual):]
fig = go.Figure()
fig.add_trace(go.Scatter(x=dates, y=actual, name='Actual', line=dict(color='blue')))
fig.add_trace(go.Scatter(x=dates, y=forecast, name='Forecast', line=dict(color='orange')))
fig.update_layout(
title="Backtest: Actual vs Forecast",
template="plotly_white",
height=600,
xaxis_title="Date",
yaxis_title="Price",
xaxis=dict(tickformat="%Y-%m-%d", minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot forecast error: {e}")
return None
# ... (other plotting functions like plot_future_forecast, plot_metrics_r2, etc., remain as provided)
def plot_metrics_r2(result):
try:
metrics = result.get("metrics", {})
if not metrics:
return None
fig = go.Figure()
fig.add_trace(go.Bar(
x=['R²', 'MAPE'],
y=[metrics.get('R2', 0), metrics.get('MAPE', 0)],
marker_color=['#1E90FF', '#FF6347']
))
fig.update_layout(
title="R² and MAPE Metrics",
template="plotly_white",
height=600,
xaxis_title="Metric",
yaxis_title="Value",
xaxis=dict(minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot R2 error: {e}")
return None
def plot_metrics_errors(result):
try:
metrics = result.get("metrics", {})
if not metrics:
return None
fig = go.Figure()
fig.add_trace(go.Bar(
x=['RMSE', 'MAE'],
y=[metrics.get('RMSE', 0), metrics.get('MAE', 0)],
marker_color=['#32CD32', '#9370DB']
))
fig.update_layout(
title="Error Metrics",
template="plotly_white",
height=600,
xaxis_title="Metric",
yaxis_title="Value",
xaxis=dict(minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot metrics errors: {e}")
return None
def plot_metrics_precision_recall(result):
try:
metrics = result.get("metrics", {})
if not metrics:
return None
fig = go.Figure()
fig.add_trace(go.Bar(
x=['Precision', 'Recall'],
y=[metrics.get('Precision', 0), metrics.get('Recall', 0)],
marker_color=['#1E90FF', '#FF6347']
))
fig.update_layout(
title="Precision and Recall Metrics",
template="plotly_white",
height=600,
xaxis_title="Metric",
yaxis_title="Value",
xaxis=dict(minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot precision recall error: {e}")
return None
def plot_metrics_risk(result):
try:
metrics = result.get("metrics", {})
if not metrics:
return None
fig = go.Figure()
fig.add_trace(go.Bar(
x=['MASE', 'Sharpe', 'Volatility'],
y=[metrics.get('MASE', 0), metrics.get('Sharpe', 0), metrics.get('Volatility', 0)],
marker_color=['#32CD32', '#9370DB', '#FFD700']
))
fig.update_layout(
title="Risk Metrics",
template="plotly_white",
height=600,
xaxis_title="Metric",
yaxis_title="Value",
xaxis=dict(minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot risk metrics error: {e}")
return None
def plot_loss_curve(result):
try:
train_loss = result.get("train_loss", [])
val_loss = result.get("val_loss", [])
if not train_loss:
return None
epochs = list(range(1, len(train_loss) + 1))
fig = go.Figure()
fig.add_trace(go.Scatter(x=epochs, y=train_loss, mode='lines', name='Train Loss', line=dict(color='#00CC96')))
fig.add_trace(go.Scatter(x=epochs, y=val_loss, mode='lines', name='Validation Loss', line=dict(color='#EF553B')))
fig.update_layout(
title="Training and Validation Loss",
template="plotly_white",
height=600,
xaxis_title="Epoch",
yaxis_title="Loss",
xaxis=dict(minor=dict(ticks="inside", showgrid=True), gridcolor="lightgrey"),
yaxis=dict(gridcolor="lightgrey"),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot loss curve error: {e}")
return None
def plot_model_architecture(result):
try:
summary_text = result.get("model_summary", "No model summary available.")
if not summary_text or summary_text == "No model summary available.":
summary_text = "Model architecture summary could not be generated."
fig = go.Figure()
fig.add_annotation(
text=summary_text.replace('\n', '<br>'),
xref="paper",
yref="paper",
x=0,
y=1,
showarrow=False,
font=dict(size=14, family="Courier New", color="#1E90FF"),
align="left",
bgcolor="white",
bordercolor="black",
borderwidth=1,
width=600,
height=400
)
fig.update_layout(
title="Model Architecture",
template="plotly_white",
height=600,
showlegend=False,
xaxis=dict(visible=False),
yaxis=dict(visible=False),
plot_bgcolor="white",
paper_bgcolor="white"
)
return fig
except Exception as e:
logging.error(f"Plot model architecture error: {e}")
return None
def plot_signals(signals_df, ticker):
try:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=signals_df.index,
y=signals_df['Price'],
mode='lines',
name='Price'
))
buy_signals = signals_df[signals_df['Signal'] == 'Buy']
sell_signals = signals_df[signals_df['Signal'] == 'Sell']
fig.add_trace(go.Scatter(
x=buy_signals.index,
y=buy_signals['Price'],
mode='markers',
marker=dict(symbol='triangle-up', size=10, color='green'),
name='Buy Signal'
))
fig.add_trace(go.Scatter(
x=sell_signals.index,
y=sell_signals['Price'],
mode='markers',
marker=dict(symbol='triangle-down', size=10, color='red'),
name='Sell Signal'
))
fig.update_layout(
title=f'{ticker} Trading Signals',
xaxis_title='Date',
yaxis_title='Price',
template="plotly_white",
xaxis_rangeslider_visible=False
)
return fig
except Exception as e:
logging.error(f"Plot signals error: {e}")
return None
def plot_backtest(equity_df, trades_df, ticker):
try:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=equity_df.index,
y=equity_df['Equity'],
mode='lines',
name='Equity Curve'
))
buy_trades = trades_df[trades_df['Type'] == 'Buy']
sell_trades = trades_df[trades_df['Type'] == 'Sell']
exit_trades = trades_df[trades_df['Type'] == 'Exit']
fig.add_trace(go.Scatter(
x=buy_trades['Date'],
y=buy_trades['Price'],
mode='markers',
marker=dict(symbol='triangle-up', size=10, color='green'),
name='Buy Trades'
))
fig.add_trace(go.Scatter(
x=sell_trades['Date'],
y=sell_trades['Price'],
mode='markers',
marker=dict(symbol='triangle-down', size=10, color='red'),
name='Sell Trades'
))
fig.add_trace(go.Scatter(
x=exit_trades['Date'],
y=exit_trades['Price'],
mode='markers',
marker=dict(symbol='circle', size=8, color='blue'),
name='Exit Trades'
))
fig.update_layout(
title=f'{ticker} Backtest Equity Curve and Trades',
xaxis_title='Date',
yaxis_title='Equity / Price',
template="plotly_white",
xaxis_rangeslider_visible=False
)
return fig
except Exception as e:
logging.error(f"Plot backtest error: {e}")
return None