VisualTradingAI / src /visualizers /chart_renderer.py
OmidSakaki's picture
Create src/visualizers/chart_renderer.py
1437e6d verified
raw
history blame
7.68 kB
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
class ChartRenderer:
def __init__(self):
pass
def render_price_chart(self, prices, actions=None, current_step=0):
"""Render price chart with actions"""
fig = go.Figure()
if not prices:
# Return empty figure if no data
fig.update_layout(
title="Price Chart - No Data Available",
xaxis_title="Time Step",
yaxis_title="Price",
height=300,
template="plotly_white"
)
return fig
# Add price line
fig.add_trace(go.Scatter(
x=list(range(len(prices))),
y=prices,
mode='lines',
name='Price',
line=dict(color='blue', width=2)
))
# Add action markers if provided
if actions and len(actions) == len(prices):
buy_indices = [i for i, action in enumerate(actions) if action == 1]
sell_indices = [i for i, action in enumerate(actions) if action == 2]
close_indices = [i for i, action in enumerate(actions) if action == 3]
if buy_indices:
fig.add_trace(go.Scatter(
x=buy_indices,
y=[prices[i] for i in buy_indices],
mode='markers',
name='Buy',
marker=dict(color='green', size=10, symbol='triangle-up',
line=dict(width=2, color='darkgreen'))
))
if sell_indices:
fig.add_trace(go.Scatter(
x=sell_indices,
y=[prices[i] for i in sell_indices],
mode='markers',
name='Sell',
marker=dict(color='red', size=10, symbol='triangle-down',
line=dict(width=2, color='darkred'))
))
if close_indices:
fig.add_trace(go.Scatter(
x=close_indices,
y=[prices[i] for i in close_indices],
mode='markers',
name='Close',
marker=dict(color='orange', size=8, symbol='x',
line=dict(width=2, color='darkorange'))
))
fig.update_layout(
title=f"Price Chart (Step: {current_step})",
xaxis_title="Time Step",
yaxis_title="Price",
height=300,
showlegend=True,
template="plotly_white"
)
return fig
def create_performance_chart(self, net_worth_history, reward_history, initial_balance):
"""Create portfolio performance chart"""
fig = make_subplots(
rows=2, cols=1,
subplot_titles=['Portfolio Value Over Time', 'Step Rewards'],
vertical_spacing=0.15
)
if not net_worth_history:
fig.update_layout(title="No Data Available", height=400)
return fig
# Portfolio value
fig.add_trace(go.Scatter(
x=list(range(len(net_worth_history))),
y=net_worth_history,
mode='lines+markers',
name='Net Worth',
line=dict(color='green', width=3),
marker=dict(size=4)
), row=1, col=1)
# Add initial balance reference line
fig.add_hline(y=initial_balance, line_dash="dash",
line_color="red", annotation_text="Initial Balance",
row=1, col=1)
# Rewards as bar chart
if reward_history:
fig.add_trace(go.Bar(
x=list(range(len(reward_history))),
y=reward_history,
name='Reward',
marker_color=['green' if r >= 0 else 'red' for r in reward_history],
opacity=0.7
), row=2, col=1)
fig.update_layout(height=500, showlegend=False, template="plotly_white")
fig.update_yaxes(title_text="Value ($)", row=1, col=1)
fig.update_yaxes(title_text="Reward", row=2, col=1)
fig.update_xaxes(title_text="Step", row=2, col=1)
return fig
def create_action_distribution(self, actions):
"""Create action distribution pie chart"""
fig = go.Figure()
if not actions:
fig.update_layout(title="No Actions Available", height=300)
return fig
action_names = ['Hold', 'Buy', 'Sell', 'Close']
action_counts = [actions.count(i) for i in range(4)]
colors = ['blue', 'green', 'red', 'orange']
fig = go.Figure(data=[go.Pie(
labels=action_names,
values=action_counts,
hole=.4,
marker_colors=colors,
textinfo='label+percent+value',
hoverinfo='label+percent+value'
)])
fig.update_layout(
title="Action Distribution",
height=350,
annotations=[dict(text='Actions', x=0.5, y=0.5, font_size=16, showarrow=False)],
template="plotly_white"
)
return fig
def create_training_progress(self, training_history):
"""Create training progress visualization"""
if not training_history:
fig = go.Figure()
fig.update_layout(title="No Training Data Available", height=500)
return fig
episodes = [h['episode'] for h in training_history]
rewards = [h['reward'] for h in training_history]
net_worths = [h['net_worth'] for h in training_history]
losses = [h.get('loss', 0) for h in training_history]
fig = make_subplots(
rows=2, cols=2,
subplot_titles=['Episode Rewards', 'Portfolio Value',
'Training Loss', 'Moving Average Reward (5)'],
specs=[[{}, {}], [{}, {}]]
)
# Rewards
fig.add_trace(go.Scatter(
x=episodes, y=rewards, mode='lines+markers',
name='Reward', line=dict(color='blue', width=2),
marker=dict(size=4)
), row=1, col=1)
# Portfolio value
fig.add_trace(go.Scatter(
x=episodes, y=net_worths, mode='lines+markers',
name='Net Worth', line=dict(color='green', width=2),
marker=dict(size=4)
), row=1, col=2)
# Loss
if any(loss > 0 for loss in losses):
fig.add_trace(go.Scatter(
x=episodes, y=losses, mode='lines+markers',
name='Loss', line=dict(color='red', width=2),
marker=dict(size=4)
), row=2, col=1)
# Moving average reward
if len(rewards) > 5:
ma_rewards = []
for i in range(len(rewards)):
start_idx = max(0, i - 4)
ma = np.mean(rewards[start_idx:i+1])
ma_rewards.append(ma)
fig.add_trace(go.Scatter(
x=episodes, y=ma_rewards, mode='lines',
name='MA Reward (5)', line=dict(color='orange', width=3, dash='dash')
), row=2, col=2)
fig.update_layout(
height=600,
showlegend=True,
title_text="Training Progress Over Episodes",
template="plotly_white"
)
return fig