""" 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}
" f"Daily Volume: {row['volume']:.2f}
" f"Cumulative Volume: {row['cumulative_volume']:.2f}
" f"Day-over-Day Change: {row['day_over_day_pct']:.1f}%
" 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}
7-Day SMA: %{y:.1f}%', 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