#!/usr/bin/env python3 """ Hugging Face Spaces - BIST DP-LSTM Trading Dashboard Gradio 5.44.0 Compatible Version - Fixed for HF Spaces deployment """ import gradio as gr 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 from datetime import datetime, timedelta import json from typing import Dict, List, Tuple, Optional import os # BIST 30 symbols for demo BIST_30_SYMBOLS = [ "AKBNK", "ARCELIK", "ASELS", "BIMAS", "EKGYO", "EREGL", "FROTO", "GARAN", "HALKB", "ISCTR", "KCHOL", "KOZAL", "KOZAA", "KRDMD", "MGROS", "OYAKC", "PETKM", "PGSUS", "SAHOL", "SASA", "SISE", "SKBNK", "TAVHL", "TCELL", "THYAO", "TOASO", "TUPRS", "VAKBN", "VESTL", "YKBNK" ] def generate_mock_signals(symbol: str, days: int = 30) -> pd.DataFrame: """Generate mock trading signals for demo""" dates = pd.date_range(end=datetime.now(), periods=days, freq='D') # Mock price data with realistic movement np.random.seed(hash(symbol) % 2**32) # Reproducible for same symbol base_price = np.random.uniform(20, 80) prices = [base_price] for i in range(1, days): change = np.random.normal(0, 0.02) # 2% daily volatility new_price = max(prices[-1] * (1 + change), 1.0) # Ensure positive price prices.append(new_price) # Generate signals signals = [] confidences = [] expected_returns = [] for i in range(days): signal_prob = np.random.random() if signal_prob > 0.7: signal = "BUY" confidence = np.random.uniform(0.65, 0.95) expected_return = np.random.uniform(0.01, 0.05) elif signal_prob < 0.3: signal = "SELL" confidence = np.random.uniform(0.65, 0.95) expected_return = np.random.uniform(-0.05, -0.01) else: signal = "HOLD" confidence = np.random.uniform(0.4, 0.65) expected_return = np.random.uniform(-0.01, 0.01) signals.append(signal) confidences.append(confidence) expected_returns.append(expected_return) return pd.DataFrame({ 'date': dates, 'symbol': symbol, 'price': prices, 'signal': signals, 'confidence': confidences, 'expected_return': expected_returns, 'volume': np.random.uniform(100000, 1000000, days), 'sentiment_score': np.random.uniform(-1, 1, days) }) def create_price_chart(df: pd.DataFrame) -> go.Figure: """Create interactive price chart with signals""" fig = make_subplots( rows=2, cols=1, subplot_titles=('Price & Trading Signals', 'Volume'), vertical_spacing=0.15, row_heights=[0.7, 0.3] ) # Price line fig.add_trace( go.Scatter( x=df['date'], y=df['price'], mode='lines', name='Price', line=dict(color='blue', width=2) ), row=1, col=1 ) # Buy signals buy_signals = df[df['signal'] == 'BUY'] if not buy_signals.empty: fig.add_trace( go.Scatter( x=buy_signals['date'], y=buy_signals['price'], mode='markers', name='BUY', marker=dict(color='green', size=12, symbol='triangle-up'), text=[f'Conf: {c:.1%}' for c in buy_signals['confidence']], hovertemplate='BUY Signal
Date: %{x}
Price: %{y:.2f}
%{text}' ), row=1, col=1 ) # Sell signals sell_signals = df[df['signal'] == 'SELL'] if not sell_signals.empty: fig.add_trace( go.Scatter( x=sell_signals['date'], y=sell_signals['price'], mode='markers', name='SELL', marker=dict(color='red', size=12, symbol='triangle-down'), text=[f'Conf: {c:.1%}' for c in sell_signals['confidence']], hovertemplate='SELL Signal
Date: %{x}
Price: %{y:.2f}
%{text}' ), row=1, col=1 ) # Volume bars fig.add_trace( go.Bar( x=df['date'], y=df['volume'], name='Volume', marker_color='lightblue', opacity=0.7 ), row=2, col=1 ) fig.update_layout( title=f"{df['symbol'].iloc[0]} - BIST Trading Analysis", height=600, showlegend=True, template="plotly_white" ) fig.update_xaxes(title_text="Date", row=2, col=1) fig.update_yaxes(title_text="Price (TL)", row=1, col=1) fig.update_yaxes(title_text="Volume", row=2, col=1) return fig def create_metrics_display(df: pd.DataFrame) -> str: """Create formatted metrics text""" total_signals = len(df[df['signal'] != 'HOLD']) buy_signals = len(df[df['signal'] == 'BUY']) sell_signals = len(df[df['signal'] == 'SELL']) avg_confidence = df[df['signal'] != 'HOLD']['confidence'].mean() * 100 if total_signals > 0 else 0 # Mock performance calculation total_return = (df['price'].iloc[-1] / df['price'].iloc[0] - 1) * 100 win_rate = np.random.uniform(60, 75) sharpe_ratio = np.random.uniform(1.2, 2.5) max_drawdown = np.random.uniform(5, 15) return f""" ## 📊 Performance Metrics **Trading Activity:** - Total Signals: {total_signals} - Buy Signals: {buy_signals} - Sell Signals: {sell_signals} - Average Confidence: {avg_confidence:.1f}% **Performance:** - Total Return: {total_return:.2f}% - Win Rate: {win_rate:.1f}% - Sharpe Ratio: {sharpe_ratio:.2f} - Max Drawdown: {max_drawdown:.1f}% """ def create_signal_display(df: pd.DataFrame) -> str: """Create latest signal display""" latest = df.iloc[-1] sentiment = 'Positive' if latest['sentiment_score'] > 0.1 else 'Negative' if latest['sentiment_score'] < -0.1 else 'Neutral' return f""" ## 🎯 Latest Signal **Symbol:** {latest['symbol']} **Date:** {latest['date'].strftime('%Y-%m-%d')} **Signal:** {latest['signal']} **Confidence:** {latest['confidence']:.1%} **Expected Return:** {latest['expected_return']:.2%} **Current Price:** {latest['price']:.2f} TL **Sentiment:** {sentiment} """ def analyze_stock(symbol: str, days: int) -> Tuple[go.Figure, str, str]: """Main analysis function - returns chart and text displays""" # Generate mock data df = generate_mock_signals(symbol, days) # Create chart chart = create_price_chart(df) # Create text displays metrics_text = create_metrics_display(df) signal_text = create_signal_display(df) return chart, metrics_text, signal_text # Create Gradio Interface - Gradio 5.x Compatible def create_interface(): with gr.Blocks( title="BIST DP-LSTM Trading Dashboard", theme=gr.themes.Default() ) as demo: gr.Markdown(""" # 🚀 BIST DP-LSTM Trading System Advanced stock trading signals for BIST (Borsa Istanbul) using: - **Differential Privacy LSTM** models - **Turkish Financial Sentiment Analysis** - **Technical Indicators** (131+ features) - **Real-time Risk Management** ⚠️ **Demo Mode:** This interface shows simulated data for demonstration purposes. """) with gr.Row(): with gr.Column(scale=1): symbol_dropdown = gr.Dropdown( choices=BIST_30_SYMBOLS, value="AKBNK", label="📈 Select BIST Stock", info="Choose from BIST 30 index stocks" ) days_slider = gr.Slider( minimum=7, maximum=90, value=30, step=1, label="📅 Analysis Period (Days)", info="Number of days to analyze" ) analyze_btn = gr.Button( "🔍 Analyze Stock", variant="primary", size="lg" ) with gr.Row(): with gr.Column(): metrics_display = gr.Markdown("### 📊 Select a stock to see metrics...") with gr.Column(): signal_display = gr.Markdown("### 🎯 Select a stock to see latest signal...") with gr.Row(): price_chart = gr.Plot(label="📊 Price Chart & Trading Signals") # Event handlers analyze_btn.click( fn=analyze_stock, inputs=[symbol_dropdown, days_slider], outputs=[price_chart, metrics_display, signal_display] ) gr.Markdown(""" --- ## 🔗 Links - **GitHub Repository:** [RSMCTN/BIST_AI001](https://github.com/RSMCTN/BIST_AI001) - **Production API:** [Railway Deployment](https://bistai001-production.up.railway.app) - **Research Paper:** *Differential Privacy LSTM for Turkish Stock Market Prediction* ## 🛠️ System Architecture - **Data Sources:** MatriksIQ API, Turkish Financial News - **Models:** DP-LSTM + TFT + Simple Transformer Ensemble - **Privacy:** Adaptive Differential Privacy (Opacus) - **Deployment:** Railway + Docker + FastAPI + HF Spaces - **Monitoring:** Prometheus + Grafana ## ⚖️ Disclaimer This system is for research and educational purposes only. Past performance does not guarantee future results. Always consult with financial advisors before making investment decisions. """) return demo # Create and launch the demo demo = create_interface() if __name__ == "__main__": demo.launch()