Spaces:
Sleeping
Sleeping
Download app.py from pareshmishra/StockSignalAI: direct link, hf CLI and curl.
- Browser
- Download file 21 kB
-
https://huggingface.co/spaces/pareshmishra/StockSignalAI/resolve/main/app.py
- Command line
-
hf download hf://spaces/pareshmishra/StockSignalAI/app.py
-
curl -L -o app.py https://huggingface.co/spaces/pareshmishra/StockSignalAI/resolve/main/app.py
21 kB
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import yfinance as yf | |
| import pickle | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| import os | |
| from datetime import datetime, timedelta | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Import custom modules | |
| from data_processor import DataProcessor | |
| from technical_indicators import TechnicalIndicators | |
| from model_trainer import ModelTrainer | |
| from database import DatabaseManager | |
| # Configure page | |
| st.set_page_config( | |
| page_title="AI Stock Trading Signals", | |
| page_icon="π", | |
| layout="wide" | |
| ) | |
| # Initialize session state | |
| if 'model_trained' not in st.session_state: | |
| st.session_state.model_trained = False | |
| if 'model' not in st.session_state: | |
| st.session_state.model = None | |
| if 'feature_columns' not in st.session_state: | |
| st.session_state.feature_columns = None | |
| if 'db_manager' not in st.session_state: | |
| st.session_state.db_manager = DatabaseManager() | |
| def load_or_train_model(stock_symbol): | |
| """Load existing model or train new one""" | |
| model_file = f"model_{stock_symbol.replace('.', '_')}.pkl" | |
| if os.path.exists(model_file) and st.session_state.model is None: | |
| try: | |
| with open(model_file, 'rb') as f: | |
| model_data = pickle.load(f) | |
| st.session_state.model = model_data['model'] | |
| st.session_state.feature_columns = model_data['feature_columns'] | |
| st.session_state.model_trained = True | |
| return True | |
| except Exception as e: | |
| st.error(f"Error loading model: {str(e)}") | |
| return False | |
| return st.session_state.model_trained | |
| def train_new_model(stock_symbol): | |
| """Train a new model for the selected stock""" | |
| with st.spinner("Training AI model... This may take a few minutes."): | |
| try: | |
| # Initialize components | |
| data_processor = DataProcessor() | |
| tech_indicators = TechnicalIndicators() | |
| model_trainer = ModelTrainer() | |
| # Download and process data | |
| data = data_processor.download_stock_data(stock_symbol, period="1y") | |
| if data is None or len(data) < 100: | |
| st.error("Insufficient data for training. Please try another stock.") | |
| return False | |
| # Save stock data to database | |
| st.session_state.db_manager.save_stock_data(stock_symbol, data) | |
| # Calculate technical indicators | |
| data_with_indicators = tech_indicators.calculate_all_indicators(data) | |
| # Save technical indicators to database | |
| st.session_state.db_manager.save_technical_indicators(stock_symbol, data_with_indicators) | |
| # Prepare features and labels | |
| features, labels = data_processor.prepare_features_and_labels(data_with_indicators) | |
| if len(features) == 0: | |
| st.error("No valid features could be generated for training.") | |
| return False | |
| # Train model | |
| model, feature_columns, metrics = model_trainer.train_model(features, labels) | |
| # Save model performance to database | |
| st.session_state.db_manager.save_model_metrics( | |
| stock_symbol, | |
| "RandomForest", | |
| metrics['accuracy'], | |
| metrics['precision'], | |
| metrics['recall'], | |
| len(feature_columns), | |
| len(features) | |
| ) | |
| # Save model | |
| model_file = f"model_{stock_symbol.replace('.', '_')}.pkl" | |
| with open(model_file, 'wb') as f: | |
| pickle.dump({ | |
| 'model': model, | |
| 'feature_columns': feature_columns, | |
| 'metrics': metrics | |
| }, f) | |
| # Update session state | |
| st.session_state.model = model | |
| st.session_state.feature_columns = feature_columns | |
| st.session_state.model_trained = True | |
| # Display training metrics | |
| st.success("Model trained successfully!") | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.metric("Accuracy", f"{metrics['accuracy']:.3f}") | |
| with col2: | |
| st.metric("Precision", f"{metrics['precision']:.3f}") | |
| with col3: | |
| st.metric("Recall", f"{metrics['recall']:.3f}") | |
| return True | |
| except Exception as e: | |
| st.error(f"Error training model: {str(e)}") | |
| return False | |
| def get_live_price(stock_symbol): | |
| """Get live stock price""" | |
| try: | |
| # Try to get live price using nsepython | |
| try: | |
| from nsepython import nsefetch | |
| # Extract stock name without .NS suffix | |
| stock_name = stock_symbol.replace('.NS', '') | |
| url = f"https://www.nseindia.com/api/quote-equity?symbol={stock_name}" | |
| live_data = nsefetch(url) | |
| if live_data and 'priceInfo' in live_data and 'lastPrice' in live_data['priceInfo']: | |
| return float(live_data['priceInfo']['lastPrice']) | |
| except: | |
| pass | |
| # Fallback to yfinance | |
| ticker = yf.Ticker(stock_symbol) | |
| data = ticker.history(period="1d", interval="1m") | |
| if not data.empty: | |
| return float(data['Close'].iloc[-1]) | |
| return None | |
| except Exception as e: | |
| st.warning(f"Could not fetch live price: {str(e)}") | |
| return None | |
| def predict_signal(stock_symbol): | |
| """Predict trading signal for the stock""" | |
| try: | |
| # Initialize components | |
| data_processor = DataProcessor() | |
| tech_indicators = TechnicalIndicators() | |
| # Get recent data for prediction | |
| data = data_processor.download_stock_data(stock_symbol, period="3mo") | |
| if data is None or len(data) < 50: | |
| return None, "Insufficient data for prediction" | |
| # Calculate technical indicators | |
| data_with_indicators = tech_indicators.calculate_all_indicators(data) | |
| # Get latest features | |
| latest_features = data_processor.get_latest_features(data_with_indicators, st.session_state.feature_columns) | |
| if latest_features is None: | |
| return None, "Could not extract features from latest data" | |
| # Make prediction | |
| prediction = st.session_state.model.predict([latest_features])[0] | |
| prediction_proba = st.session_state.model.predict_proba([latest_features])[0] | |
| # Convert prediction to signal | |
| signal_map = {-1: "SELL", 0: "HOLD", 1: "BUY"} | |
| signal = signal_map.get(prediction, "HOLD") | |
| confidence = max(prediction_proba) | |
| # Get current live price for saving to database | |
| live_price = get_live_price(stock_symbol) | |
| # Save trading signal to database | |
| if live_price and hasattr(st.session_state, 'db_manager') and st.session_state.db_manager: | |
| try: | |
| st.session_state.db_manager.save_trading_signal( | |
| stock_symbol, signal, confidence, live_price, model_version="v1.0" | |
| ) | |
| except Exception as e: | |
| print(f"Error saving trading signal: {str(e)}") | |
| return { | |
| 'signal': signal, | |
| 'confidence': confidence, | |
| 'prediction': prediction, | |
| 'probabilities': prediction_proba | |
| }, None | |
| except Exception as e: | |
| return None, f"Error making prediction: {str(e)}" | |
| def create_price_chart(stock_symbol): | |
| """Create interactive price chart with technical indicators""" | |
| try: | |
| # Initialize components | |
| data_processor = DataProcessor() | |
| tech_indicators = TechnicalIndicators() | |
| # Get data for last 30 days | |
| data = data_processor.download_stock_data(stock_symbol, period="2mo") | |
| if data is None: | |
| return None | |
| # Calculate technical indicators | |
| data_with_indicators = tech_indicators.calculate_all_indicators(data) | |
| # Get last 30 days | |
| data_chart = data_with_indicators.tail(30).copy() | |
| # Create subplots | |
| fig = make_subplots( | |
| rows=4, cols=1, | |
| # shared_xaxis=True, | |
| shared_xaxes=True, | |
| vertical_spacing=0.03, | |
| subplot_titles=('Price & Bollinger Bands', 'RSI', 'MACD', 'Volume'), | |
| row_heights=[0.5, 0.2, 0.2, 0.1] | |
| ) | |
| # Price and Bollinger Bands | |
| fig.add_trace( | |
| go.Candlestick( | |
| x=data_chart.index, | |
| open=data_chart['Open'], | |
| high=data_chart['High'], | |
| low=data_chart['Low'], | |
| close=data_chart['Close'], | |
| name='Price' | |
| ), row=1, col=1 | |
| ) | |
| # Bollinger Bands | |
| if 'BB_upper' in data_chart.columns: | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['BB_upper'], | |
| name='BB Upper', line=dict(color='red', width=1)), row=1, col=1 | |
| ) | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['BB_middle'], | |
| name='BB Middle', line=dict(color='blue', width=1)), row=1, col=1 | |
| ) | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['BB_lower'], | |
| name='BB Lower', line=dict(color='red', width=1)), row=1, col=1 | |
| ) | |
| # EMA | |
| if 'EMA_20' in data_chart.columns: | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['EMA_20'], | |
| name='EMA 20', line=dict(color='orange', width=2)), row=1, col=1 | |
| ) | |
| # RSI | |
| if 'RSI' in data_chart.columns: | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['RSI'], | |
| name='RSI', line=dict(color='purple')), row=2, col=1 | |
| ) | |
| # RSI overbought/oversold lines | |
| fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1) | |
| fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1) | |
| # MACD | |
| if 'MACD' in data_chart.columns: | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['MACD'], | |
| name='MACD', line=dict(color='blue')), row=3, col=1 | |
| ) | |
| if 'MACD_signal' in data_chart.columns: | |
| fig.add_trace( | |
| go.Scatter(x=data_chart.index, y=data_chart['MACD_signal'], | |
| name='MACD Signal', line=dict(color='red')), row=3, col=1 | |
| ) | |
| # Volume | |
| fig.add_trace( | |
| go.Bar(x=data_chart.index, y=data_chart['Volume'], | |
| name='Volume', marker_color='lightblue'), row=4, col=1 | |
| ) | |
| # Update layout | |
| fig.update_layout( | |
| title=f"{stock_symbol} - Price Chart with Technical Indicators", | |
| xaxis_rangeslider_visible=False, | |
| height=800, | |
| showlegend=True | |
| ) | |
| # Update y-axis labels | |
| fig.update_yaxes(title_text="Price (βΉ)", row=1, col=1) | |
| fig.update_yaxes(title_text="RSI", row=2, col=1) | |
| fig.update_yaxes(title_text="MACD", row=3, col=1) | |
| fig.update_yaxes(title_text="Volume", row=4, col=1) | |
| return fig | |
| except Exception as e: | |
| st.error(f"Error creating chart: {str(e)}") | |
| return None | |
| def main(): | |
| st.title("π AI-Powered Stock Trading Signals") | |
| st.markdown("### NSE Stock Analysis with Machine Learning") | |
| # Initialize database manager early | |
| if 'db_manager' not in st.session_state: | |
| try: | |
| from database import DatabaseManager | |
| st.session_state.db_manager = DatabaseManager() | |
| st.success("Database initialized successfully") | |
| except Exception as e: | |
| st.error(f"Database initialization failed: {str(e)}") | |
| st.session_state.db_manager = None | |
| # Sidebar for stock selection | |
| st.sidebar.header("Stock Selection") | |
| # Expanded NSE stock options | |
| stock_options = { | |
| "Reliance Industries": "RELIANCE.NS", | |
| "Tata Consultancy Services": "TCS.NS", | |
| "Infosys": "INFY.NS", | |
| "HDFC Bank": "HDFCBANK.NS", | |
| "ICICI Bank": "ICICIBANK.NS", | |
| "State Bank of India": "SBIN.NS", | |
| "ITC Limited": "ITC.NS", | |
| "Hindustan Unilever": "HINDUNILVR.NS", | |
| "Larsen & Toubro": "LT.NS", | |
| "Axis Bank": "AXISBANK.NS", | |
| "Kotak Mahindra Bank": "KOTAKBANK.NS", | |
| "Wipro": "WIPRO.NS", | |
| "Tech Mahindra": "TECHM.NS", | |
| "Bharti Airtel": "BHARTIARTL.NS", | |
| "Asian Paints": "ASIANPAINT.NS", | |
| "Maruti Suzuki": "MARUTI.NS", | |
| "Bajaj Finance": "BAJFINANCE.NS", | |
| "NTPC": "NTPC.NS", | |
| "Power Grid Corp": "POWERGRID.NS", | |
| "Tata Steel": "TATASTEEL.NS" | |
| } | |
| # Option to enter custom stock symbol | |
| st.sidebar.subheader("Or Enter Custom Stock") | |
| custom_stock = st.sidebar.text_input( | |
| "Enter NSE stock symbol (e.g., ADANIPORTS.NS):", | |
| placeholder="SYMBOL.NS" | |
| ) | |
| # Determine selected stock | |
| if custom_stock and custom_stock.strip(): | |
| if not custom_stock.endswith('.NS'): | |
| custom_stock += '.NS' | |
| selected_stock = custom_stock.upper() | |
| selected_stock_name = f"Custom: {selected_stock}" | |
| else: | |
| selected_stock_name = st.sidebar.selectbox( | |
| "Choose a stock:", | |
| list(stock_options.keys()) | |
| ) | |
| selected_stock = stock_options[selected_stock_name] | |
| # Model training section | |
| st.sidebar.header("Model Management") | |
| # Check if model exists | |
| model_exists = load_or_train_model(selected_stock) | |
| if not model_exists: | |
| st.sidebar.warning("No trained model found for this stock.") | |
| if st.sidebar.button("Train New Model"): | |
| train_new_model(selected_stock) | |
| else: | |
| st.sidebar.success("Model loaded successfully!") | |
| if st.sidebar.button("Retrain Model"): | |
| st.session_state.model = None | |
| st.session_state.model_trained = False | |
| train_new_model(selected_stock) | |
| # Main content | |
| if st.session_state.model_trained and st.session_state.model is not None: | |
| # Live price section | |
| st.header("π Live Market Data") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("π Get Live Price", type="primary"): | |
| live_price = get_live_price(selected_stock) | |
| if live_price: | |
| st.metric("Live Price (LTP)", f"βΉ{live_price:.2f}") | |
| else: | |
| st.warning("Could not fetch live price") | |
| # Prediction section | |
| st.header("π€ AI Trading Signal") | |
| if st.button("π― Get Trading Signal", type="primary"): | |
| prediction_result, error = predict_signal(selected_stock) | |
| if prediction_result: | |
| signal = prediction_result['signal'] | |
| confidence = prediction_result['confidence'] | |
| # Display signal with color coding | |
| if signal == "BUY": | |
| st.success(f"π’ **{signal}** Signal") | |
| elif signal == "SELL": | |
| st.error(f"π΄ **{signal}** Signal") | |
| else: | |
| st.info(f"π‘ **{signal}** Signal") | |
| # Display confidence and probabilities | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.metric("Confidence", f"{confidence:.1%}") | |
| with col2: | |
| prob_df = pd.DataFrame({ | |
| 'Signal': ['SELL', 'HOLD', 'BUY'], | |
| 'Probability': prediction_result['probabilities'] | |
| }) | |
| st.dataframe(prob_df, hide_index=True) | |
| else: | |
| st.error(f"Prediction failed: {error}") | |
| # Chart section | |
| st.header("π Technical Analysis Chart") | |
| if st.button("π Generate Chart"): | |
| chart = create_price_chart(selected_stock) | |
| if chart: | |
| st.plotly_chart(chart, use_container_width=True) | |
| # Additional information | |
| st.header("βΉοΈ Model Information") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.info("**Features Used:**\n- RSI, EMA, MACD\n- Bollinger Bands\n- SMA, Stochastic\n- Williams %R, ATR") | |
| with col2: | |
| st.info("**Signal Criteria:**\n- BUY: Expected 2%+ gain\n- SELL: Expected 2%+ loss\n- HOLD: Neutral expectation") | |
| else: | |
| st.info("π Please train a model first using the sidebar to get started with AI-powered trading signals.") | |
| # Show sample data while waiting | |
| st.header("π Sample Stock Data") | |
| try: | |
| data_processor = DataProcessor() | |
| #sample_data = data_processor.download_stock_data(selected_stock, period="1mo") | |
| sample_data = data_processor.download_stock_data(selected_stock, period="1y") # 1 year | |
| # or | |
| # sample_data = data_processor.download_stock_data(selected_stock, period="2y") # 2 years | |
| # or | |
| # sample_data = data_processor.download_stock_data(selected_stock, period="max") # full available history | |
| if sample_data is not None: | |
| st.dataframe(sample_data.tail(10)) | |
| except: | |
| st.warning("Could not load sample data") | |
| # Database Information Section | |
| st.sidebar.header("π Database Status") | |
| # Database Console Link | |
| st.sidebar.markdown("---") | |
| st.sidebar.markdown("### ποΈ Database Console") | |
| st.sidebar.markdown("Access the SQLite database console:") | |
| st.sidebar.markdown("**[Open Database Console](http://localhost:5001)**") | |
| st.sidebar.markdown("*View tables, run SQL queries, analyze trading data*") | |
| st.sidebar.markdown("*Database file: `stock_trading.db`*") | |
| st.sidebar.markdown("---") | |
| try: | |
| if hasattr(st.session_state, 'db_manager') and st.session_state.db_manager: | |
| db_stats = st.session_state.db_manager.get_database_stats() | |
| if db_stats: | |
| st.sidebar.metric("Stock Records", db_stats.get('total_stock_records', 0)) | |
| st.sidebar.metric("Trading Signals", db_stats.get('total_signals', 0)) | |
| st.sidebar.metric("Active Models", db_stats.get('active_models', 0)) | |
| st.sidebar.metric("Symbols Tracked", db_stats.get('symbols_tracked', 0)) | |
| else: | |
| st.sidebar.info("Database ready - no data yet") | |
| else: | |
| st.sidebar.info("Database initializing...") | |
| except Exception as e: | |
| st.sidebar.warning("Database tables will be created when first used") | |
| # Trading History Section | |
| if st.session_state.model_trained and hasattr(st.session_state, 'db_manager') and st.session_state.db_manager: | |
| st.header("π Trading History") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("View Signal History"): | |
| try: | |
| signal_history = st.session_state.db_manager.get_trading_signals_history(selected_stock) | |
| if not signal_history.empty: | |
| st.dataframe(signal_history.head(10)) | |
| else: | |
| st.info("No trading signals found in database") | |
| except Exception as e: | |
| st.error(f"Error loading signal history: {str(e)}") | |
| with col2: | |
| if st.button("Model Performance"): | |
| try: | |
| model_perf = st.session_state.db_manager.get_model_performance(selected_stock) | |
| if model_perf: | |
| st.json(model_perf) | |
| else: | |
| st.info("No model performance data found") | |
| except Exception as e: | |
| st.error(f"Error loading model performance: {str(e)}") | |
| # Database Console Access | |
| st.markdown("---") | |
| st.info("π‘ **Tip**: Use the Database Console in the sidebar to view all stored data, run SQL queries, and analyze trading patterns across all stocks.") | |
| if __name__ == "__main__": | |
| main() | |