File size: 4,329 Bytes
174e0f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
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