week4: ai stock trading

This commit is contained in:
Omar Marie
2025-07-21 20:49:24 +03:00
parent 59f4a5be27
commit c3d0a8e8b7
10 changed files with 3043 additions and 221 deletions

View File

@@ -0,0 +1,483 @@
"""
Charting Module
This module provides comprehensive charting and visualization capabilities
for stock analysis with interactive dashboards using Plotly.
"""
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import streamlit as st
from typing import Dict, List, Optional, Tuple
import warnings
warnings.filterwarnings('ignore')
class StockChartGenerator:
"""Enhanced stock chart generator with interactive dashboards"""
def __init__(self):
self.color_scheme = {
'primary': '#1f77b4',
'secondary': '#ff7f0e',
'success': '#2ca02c',
'danger': '#d62728',
'warning': '#ff7f0e',
'info': '#17a2b8',
'background': '#f8f9fa'
}
def create_price_chart(self, data: pd.DataFrame, symbol: str, analysis: Dict = None) -> go.Figure:
"""
Create comprehensive price chart with technical indicators
Args:
data: Stock price data
symbol: Stock symbol
analysis: Technical analysis results
Returns:
Plotly figure object
"""
if data.empty:
return self._create_empty_chart("No data available")
# Create subplots
fig = make_subplots(
rows=3, cols=1,
shared_xaxes=True,
vertical_spacing=0.05,
subplot_titles=(f'{symbol} Price Chart', 'Volume', 'Technical Indicators'),
row_heights=[0.6, 0.2, 0.2]
)
# Main price chart (candlestick)
fig.add_trace(
go.Candlestick(
x=data.index,
open=data['Open'],
high=data['High'],
low=data['Low'],
close=data['Close'],
name='Price',
increasing_line_color=self.color_scheme['success'],
decreasing_line_color=self.color_scheme['danger']
),
row=1, col=1
)
# Add moving averages if available
if 'SMA_20' in data.columns:
fig.add_trace(
go.Scatter(
x=data.index,
y=data['SMA_20'],
mode='lines',
name='SMA 20',
line=dict(color=self.color_scheme['primary'], width=1)
),
row=1, col=1
)
if 'SMA_50' in data.columns:
fig.add_trace(
go.Scatter(
x=data.index,
y=data['SMA_50'],
mode='lines',
name='SMA 50',
line=dict(color=self.color_scheme['secondary'], width=1)
),
row=1, col=1
)
# Volume chart
colors = ['red' if close < open else 'green' for close, open in zip(data['Close'], data['Open'])]
fig.add_trace(
go.Bar(
x=data.index,
y=data['Volume'],
name='Volume',
marker_color=colors,
opacity=0.7
),
row=2, col=1
)
# Technical indicators (RSI if available in analysis)
if analysis and 'rsi' in analysis:
# Create RSI line (simplified - would need full RSI calculation for time series)
rsi_value = analysis['rsi']
rsi_line = [rsi_value] * len(data)
fig.add_trace(
go.Scatter(
x=data.index,
y=rsi_line,
mode='lines',
name=f'RSI ({rsi_value:.1f})',
line=dict(color=self.color_scheme['info'], width=2)
),
row=3, col=1
)
# Add RSI reference lines
fig.add_hline(y=70, line_dash="dash", line_color="red", opacity=0.5, row=3, col=1)
fig.add_hline(y=30, line_dash="dash", line_color="green", opacity=0.5, row=3, col=1)
# Update layout
fig.update_layout(
title=f'{symbol} Stock Analysis Dashboard',
xaxis_title='Date',
yaxis_title='Price ($)',
template='plotly_white',
height=800,
showlegend=True,
hovermode='x unified'
)
# Remove rangeslider for cleaner look
fig.update_layout(xaxis_rangeslider_visible=False)
return fig
def create_performance_chart(self, data: pd.DataFrame, symbol: str, analysis: Dict) -> go.Figure:
"""
Create performance analysis chart
Args:
data: Stock price data
symbol: Stock symbol
analysis: Analysis results with performance metrics
Returns:
Plotly figure object
"""
if data.empty:
return self._create_empty_chart("No data available for performance analysis")
# Calculate cumulative returns
daily_returns = data['Close'].pct_change().fillna(0)
cumulative_returns = (1 + daily_returns).cumprod() - 1
fig = go.Figure()
# Cumulative returns line
fig.add_trace(
go.Scatter(
x=data.index,
y=cumulative_returns * 100,
mode='lines',
name='Cumulative Returns (%)',
line=dict(color=self.color_scheme['primary'], width=2),
fill='tonexty',
fillcolor='rgba(31, 119, 180, 0.1)'
)
)
# Add benchmark line (0% return)
fig.add_hline(y=0, line_dash="dash", line_color="gray", opacity=0.5)
# Add performance annotations
if analysis:
total_return = analysis.get('total_return_pct', 0)
fig.add_annotation(
x=data.index[-1],
y=total_return,
text=f"Total Return: {total_return:.1f}%",
showarrow=True,
arrowhead=2,
arrowcolor=self.color_scheme['primary'],
bgcolor="white",
bordercolor=self.color_scheme['primary']
)
fig.update_layout(
title=f'{symbol} Performance Analysis',
xaxis_title='Date',
yaxis_title='Cumulative Returns (%)',
template='plotly_white',
height=500,
hovermode='x'
)
return fig
def create_risk_analysis_chart(self, analysis: Dict, symbol: str) -> go.Figure:
"""
Create risk analysis visualization
Args:
analysis: Analysis results with risk metrics
symbol: Stock symbol
Returns:
Plotly figure object
"""
if not analysis or 'error' in analysis:
return self._create_empty_chart("No risk data available")
# Prepare risk metrics
risk_metrics = {
'Volatility (Annual)': analysis.get('volatility_annualized', 0),
'Max Drawdown': abs(analysis.get('max_drawdown', 0)),
'VaR 95%': abs(analysis.get('var_95', 0)),
'VaR 99%': abs(analysis.get('var_99', 0))
}
# Create radar chart for risk metrics
categories = list(risk_metrics.keys())
values = list(risk_metrics.values())
fig = go.Figure()
fig.add_trace(go.Scatterpolar(
r=values,
theta=categories,
fill='toself',
name=f'{symbol} Risk Profile',
line_color=self.color_scheme['danger'],
fillcolor='rgba(214, 39, 40, 0.1)'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, max(values) * 1.2] if values else [0, 100]
)
),
title=f'{symbol} Risk Analysis Chart',
template='plotly_white',
height=500
)
return fig
def create_comparison_chart(self, data_dict: Dict[str, pd.DataFrame], symbols: List[str]) -> go.Figure:
"""
Create comparison chart for multiple stocks
Args:
data_dict: Dictionary of stock data {symbol: dataframe}
symbols: List of stock symbols to compare
Returns:
Plotly figure object
"""
fig = go.Figure()
colors = [self.color_scheme['primary'], self.color_scheme['secondary'],
self.color_scheme['success'], self.color_scheme['danger']]
for i, symbol in enumerate(symbols):
if symbol in data_dict and not data_dict[symbol].empty:
data = data_dict[symbol]
# Normalize prices to start at 100 for comparison
normalized_prices = (data['Close'] / data['Close'].iloc[0]) * 100
fig.add_trace(
go.Scatter(
x=data.index,
y=normalized_prices,
mode='lines',
name=symbol,
line=dict(color=colors[i % len(colors)], width=2)
)
)
fig.update_layout(
title='Stock Price Comparison (Normalized to 100)',
xaxis_title='Date',
yaxis_title='Normalized Price',
template='plotly_white',
height=600,
hovermode='x unified'
)
return fig
def create_sector_analysis_chart(self, sector_data: Dict) -> go.Figure:
"""
Create sector analysis visualization
Args:
sector_data: Dictionary with sector analysis data
Returns:
Plotly figure object
"""
# This would typically show sector performance, P/E ratios, etc.
# For now, create a placeholder
fig = go.Figure()
fig.add_annotation(
x=0.5, y=0.5,
text="Sector Analysis<br>Coming Soon",
showarrow=False,
font=dict(size=20),
xref="paper", yref="paper"
)
fig.update_layout(
title='Sector Analysis Dashboard',
template='plotly_white',
height=400,
showticklabels=False
)
return fig
def create_trading_signals_chart(self, data: pd.DataFrame, analysis: Dict, trading_decision: Dict, symbol: str) -> go.Figure:
"""
Create trading signals visualization
Args:
data: Stock price data
analysis: Technical analysis results
trading_decision: Trading recommendation
symbol: Stock symbol
Returns:
Plotly figure object
"""
if data.empty:
return self._create_empty_chart("No data available for trading signals")
fig = go.Figure()
# Price line
fig.add_trace(
go.Scatter(
x=data.index,
y=data['Close'],
mode='lines',
name='Price',
line=dict(color=self.color_scheme['primary'], width=2)
)
)
# Add trading signal
recommendation = trading_decision.get('recommendation', 'HOLD')
current_price = data['Close'].iloc[-1]
signal_color = {
'BUY': self.color_scheme['success'],
'SELL': self.color_scheme['danger'],
'HOLD': self.color_scheme['warning']
}.get(recommendation, self.color_scheme['info'])
fig.add_trace(
go.Scatter(
x=[data.index[-1]],
y=[current_price],
mode='markers',
name=f'{recommendation} Signal',
marker=dict(
color=signal_color,
size=15,
symbol='triangle-up' if recommendation == 'BUY' else
'triangle-down' if recommendation == 'SELL' else 'circle'
)
)
)
# Add price target if available
price_target = trading_decision.get('price_target')
if price_target:
fig.add_hline(
y=price_target,
line_dash="dash",
line_color=self.color_scheme['success'],
annotation_text=f"Target: ${price_target:.2f}"
)
# Add stop loss if available
stop_loss = trading_decision.get('stop_loss')
if stop_loss:
fig.add_hline(
y=stop_loss,
line_dash="dash",
line_color=self.color_scheme['danger'],
annotation_text=f"Stop Loss: ${stop_loss:.2f}"
)
fig.update_layout(
title=f'{symbol} Trading Signals',
xaxis_title='Date',
yaxis_title='Price ($)',
template='plotly_white',
height=500,
hovermode='x'
)
return fig
def create_dashboard_summary(self, symbol: str, analysis: Dict, trading_decision: Dict, sharia_compliance: Dict) -> Dict:
"""
Create summary metrics for dashboard display
Args:
symbol: Stock symbol
analysis: Technical analysis results
trading_decision: Trading recommendation
sharia_compliance: Sharia compliance results
Returns:
Dictionary with summary metrics
"""
summary = {
'symbol': symbol,
'current_price': analysis.get('current_price', 0),
'total_return': analysis.get('total_return_pct', 0),
'volatility': analysis.get('volatility_annualized', 0),
'trading_recommendation': trading_decision.get('recommendation', 'HOLD'),
'trading_confidence': trading_decision.get('confidence', 0) * 100,
'sharia_ruling': sharia_compliance.get('ruling', 'UNCERTAIN'),
'sharia_confidence': sharia_compliance.get('confidence', 0) * 100,
'risk_level': trading_decision.get('risk_level', 'medium'),
'trend_direction': analysis.get('trend_direction', 'unknown'),
'rsi': analysis.get('rsi', 50),
'max_drawdown': analysis.get('max_drawdown', 0)
}
return summary
def _create_empty_chart(self, message: str) -> go.Figure:
"""Create an empty chart with a message"""
fig = go.Figure()
fig.add_annotation(
x=0.5, y=0.5,
text=message,
showarrow=False,
font=dict(size=16),
xref="paper", yref="paper"
)
fig.update_layout(
template='plotly_white',
height=400,
showticklabels=False
)
return fig
# Global instance for easy import
chart_generator = StockChartGenerator()
# Convenience functions
def create_price_chart(data: pd.DataFrame, symbol: str, analysis: Dict = None) -> go.Figure:
"""Convenience function to create price chart"""
return chart_generator.create_price_chart(data, symbol, analysis)
def create_performance_chart(data: pd.DataFrame, symbol: str, analysis: Dict) -> go.Figure:
"""Convenience function to create performance chart"""
return chart_generator.create_performance_chart(data, symbol, analysis)
def create_trading_signals_chart(data: pd.DataFrame, analysis: Dict, trading_decision: Dict, symbol: str) -> go.Figure:
"""Convenience function to create trading signals chart"""
return chart_generator.create_trading_signals_chart(data, analysis, trading_decision, symbol)