Spaces:
Running
Running
""" | |
Volume chart implementations. | |
""" | |
import plotly.graph_objects as go | |
import pandas as pd | |
import logging | |
from datetime import datetime | |
from typing import Dict, Any, Optional, Tuple | |
from ..config.constants import Y_AXIS_RANGES, FILE_PATHS | |
from .base_chart import BaseChart | |
logger = logging.getLogger(__name__) | |
class VolumeChart(BaseChart): | |
"""Chart for Volume visualizations.""" | |
def create_chart(self, df: pd.DataFrame, **kwargs) -> go.Figure: | |
"""Create Cumulative Volume bar chart.""" | |
if df.empty: | |
return self._create_empty_chart("No volume data available") | |
# Calculate daily volume changes using the new method | |
daily_data = self.data_processor.calculate_daily_volume_changes(df) | |
if daily_data.empty: | |
return self._create_empty_chart("No daily volume data available") | |
# Create figure | |
fig = self._create_base_figure() | |
# Get time range | |
min_time = daily_data['date'].min() | |
max_time = daily_data['date'].max() | |
# Determine bar colors based on daily volume (all bars will be blue for cumulative volume) | |
bar_colors = ['blue'] * len(daily_data) | |
# Create custom hover text for bars | |
bar_hover_text = [] | |
for _, row in daily_data.iterrows(): | |
date_str = row['date'].strftime('%Y-%m-%d') | |
bar_hover_text.append( | |
f"Date: {date_str}<br>" | |
f"Daily Volume: {row['volume']:.2f}<br>" | |
f"Cumulative Volume: {row['cumulative_volume']:.2f}<br>" | |
f"Day-over-Day Change: {row['day_over_day_pct']:.1f}%<br>" | |
f"7-Day SMA: {row['sma_7d']:.1f}%" | |
) | |
# Add cumulative volume bar chart | |
fig.add_trace( | |
go.Bar( | |
x=daily_data['date'], | |
y=daily_data['cumulative_volume'], | |
marker=dict( | |
color=bar_colors, | |
line=dict(width=1, color='black'), | |
opacity=0.7 | |
), | |
name='Daily Volume Change', | |
hovertext=bar_hover_text, | |
hoverinfo='text', | |
customdata=daily_data[['volume', 'day_over_day_pct']].values | |
) | |
) | |
# Add 7-Day SMA line | |
fig.add_trace( | |
go.Scatter( | |
x=daily_data['date'], | |
y=daily_data['sma_7d'], | |
mode='lines', | |
line=dict(color='red', width=3), | |
name='7-Day SMA', | |
hovertemplate='Date: %{x}<br>7-Day SMA: %{y:.1f}%<extra></extra>', | |
yaxis='y2' | |
) | |
) | |
# Update layout and axes | |
self._update_layout( | |
fig, | |
title="Daily Volume Change (%) with 7-Day SMA", | |
y_axis_title="Cumulative Volume" | |
) | |
# Update axes | |
self._update_axes( | |
fig, | |
x_range=[min_time, max_time], | |
y_auto=True | |
) | |
# Update primary y-axis to show volume format | |
fig.update_yaxes(tickformat=".2f") | |
# Add secondary y-axis for SMA | |
fig.update_layout( | |
yaxis2=dict( | |
title="Percentage Change (%)", | |
overlaying='y', | |
side='right', | |
tickformat=".1f" | |
) | |
) | |
# Save chart | |
self._save_chart( | |
fig, | |
FILE_PATHS['volume_graph_html'], | |
FILE_PATHS['volume_graph_png'] | |
) | |
return fig | |
def generate_volume_visualizations(data_processor=None) -> Tuple[go.Figure, Optional[str]]: | |
"""Generate Volume visualizations.""" | |
from ..data.data_processor import DataProcessor | |
if data_processor is None: | |
data_processor = DataProcessor() | |
# Fetch data | |
apr_df, _ = data_processor.fetch_apr_data_from_db() | |
# Filter for records with volume data | |
volume_df = apr_df[apr_df['volume'].notna()].copy() | |
# Create chart | |
volume_chart = VolumeChart(data_processor) | |
fig, csv_path = volume_chart.generate_visualization( | |
volume_df, | |
csv_filename=FILE_PATHS['volume_csv'] | |
) | |
return fig, csv_path | |