| |
| """ |
| Gradio App for StoxChai NSE Stock Prediction Models |
| This will be deployed on Hugging Face Spaces for interactive testing |
| """ |
|
|
| import gradio as gr |
| import numpy as np |
| import pandas as pd |
| import joblib |
| import os |
| from typing import Dict, List, Tuple |
| import warnings |
| warnings.filterwarnings('ignore') |
|
|
| |
| models = {} |
| feature_scaler = None |
| feature_names = [ |
| 'OpnPric', 'HghPric', 'LwPric', 'LastPric', 'PrvsClsgPric', |
| 'Price_Range', 'Price_Change', 'Price_Change_Pct', 'Volume_Price_Ratio', |
| 'SMA_5', 'SMA_20', 'Price_Momentum', 'Volume_MA', 'Volume_Ratio', |
| 'TtlTradgVol', 'TtlTrfVal' |
| ] |
|
|
| def load_models(): |
| """Load all trained models and scaler""" |
| global models, feature_scaler |
| |
| try: |
| |
| scaler_path = 'feature_scaler.joblib' |
| if os.path.exists(scaler_path): |
| feature_scaler = joblib.load(scaler_path) |
| print("β
Feature scaler loaded") |
| |
| |
| model_files = { |
| 'RandomForest': 'randomforest_model.joblib', |
| 'GradientBoosting': 'gradientboosting_model.joblib', |
| 'LinearRegression': 'linearregression_model.joblib', |
| 'Ridge': 'ridge_model.joblib', |
| 'Lasso': 'lasso_model.joblib', |
| 'SVR': 'svr_model.joblib', |
| 'XGBoost': 'xgboost_model.joblib', |
| 'LightGBM': 'lightgbm_model.joblib' |
| } |
| |
| for model_name, filename in model_files.items(): |
| if os.path.exists(filename): |
| models[model_name] = joblib.load(filename) |
| print(f"β
{model_name} model loaded") |
| |
| print(f"π― Successfully loaded {len(models)} models") |
| return True |
| |
| except Exception as e: |
| print(f"β Error loading models: {e}") |
| return False |
|
|
| def predict_stock_price(features: List[float], model_name: str = "RandomForest") -> Tuple[str, Dict]: |
| """Make prediction using the specified model""" |
| try: |
| if not models or feature_scaler is None: |
| return "β Models not loaded. Please check the model files.", {} |
| |
| if model_name not in models: |
| return f"β Model '{model_name}' not found.", {} |
| |
| |
| features = np.array(features, dtype=float) |
| |
| |
| if len(features) != 16: |
| return f"β Expected 16 features, got {len(features)}", {} |
| |
| |
| sequence = np.tile(features, (5, 1)) |
| flattened_features = sequence.reshape(1, -1) |
| |
| |
| scaled_features = feature_scaler.transform(flattened_features) |
| |
| |
| model = models[model_name] |
| prediction = model.predict(scaled_features)[0] |
| |
| |
| all_predictions = {} |
| for name, model_obj in models.items(): |
| try: |
| pred = model_obj.predict(scaled_features)[0] |
| all_predictions[name] = pred |
| except: |
| all_predictions[name] = None |
| |
| |
| successful_predictions = [p for p in all_predictions.values() if p is not None] |
| if successful_predictions: |
| all_predictions['Ensemble'] = np.mean(successful_predictions) |
| |
| return f"β
{model_name} Prediction: βΉ{prediction:.2f}", all_predictions |
| |
| except Exception as e: |
| return f"β Prediction error: {e}", {} |
|
|
| def create_sample_data(): |
| """Create sample data for demonstration""" |
| sample_features = [ |
| 100.0, |
| 105.0, |
| 98.0, |
| 102.0, |
| 100.0, |
| 7.0, |
| 2.0, |
| 2.0, |
| 1.5, |
| 101.0, |
| 100.5, |
| 0.01, |
| 1000.0, |
| 1.2, |
| 1200.0, |
| 120000.0 |
| ] |
| return sample_features |
|
|
| def format_predictions(predictions: Dict) -> str: |
| """Format predictions for display""" |
| if not predictions: |
| return "No predictions available" |
| |
| result = "π All Model Predictions:\n\n" |
| for model, pred in predictions.items(): |
| if pred is not None: |
| result += f"β’ {model:15s}: βΉ{pred:8.2f}\n" |
| else: |
| result += f"β’ {model:15s}: β Error\n" |
| |
| return result |
|
|
| |
| def create_interface(): |
| """Create the Gradio interface""" |
| |
| |
| if not load_models(): |
| gr.Warning("β οΈ Failed to load models. Please check the model files.") |
| |
| with gr.Blocks( |
| title="StoxChai NSE Stock Price Predictor", |
| theme=gr.themes.Soft(), |
| css=""" |
| .gradio-container { |
| max-width: 1200px !important; |
| } |
| .feature-input { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| padding: 20px; |
| border-radius: 15px; |
| margin: 10px 0; |
| } |
| .prediction-output { |
| background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
| padding: 20px; |
| border-radius: 15px; |
| margin: 10px 0; |
| } |
| """ |
| ) as app: |
| |
| gr.Markdown(""" |
| # π― StoxChai NSE Stock Price Predictor |
| |
| ## Overview |
| This app allows you to test our trained machine learning models for predicting Indian stock prices using NSE bhavcopy data. |
| |
| **Models Available**: RandomForest, GradientBoosting, LinearRegression, Ridge, Lasso, SVR, XGBoost, LightGBM |
| |
| **Data Source**: NSE Bhavcopy (Jan 1 - Aug 20, 2025) covering 3,257 Indian equity stocks |
| """) |
| |
| with gr.Row(): |
| with gr.Column(scale=2): |
| gr.Markdown("### π Input Features") |
| gr.Markdown(""" |
| Enter the 16 features in order: |
| 1. **OpnPric** - Opening Price |
| 2. **HghPric** - High Price |
| 3. **LwPric** - Low Price |
| 4. **LastPric** - Last Price |
| 5. **PrvsClsgPric** - Previous Close |
| 6. **Price_Range** - High - Low |
| 7. **Price_Change** - Current - Previous Close |
| 8. **Price_Change_Pct** - Price Change % |
| 9. **Volume_Price_Ratio** - Trading Value / Volume |
| 10. **SMA_5** - 5-day Moving Average |
| 11. **SMA_20** - 20-day Moving Average |
| 12. **Price_Momentum** - Current / SMA_5 - 1 |
| 13. **Volume_MA** - 5-day Volume Average |
| 14. **Volume_Ratio** - Current Volume / Volume_MA |
| 15. **TtlTradgVol** - Total Trading Volume |
| 16. **TtlTrfVal** - Total Trading Value |
| """) |
| |
| |
| feature_inputs = [] |
| for i, name in enumerate(feature_names): |
| with gr.Row(): |
| gr.Markdown(f"**{name}:**") |
| input_field = gr.Number( |
| value=create_sample_data()[i], |
| label=f"{i+1}. {name}", |
| precision=2, |
| scale=1 |
| ) |
| feature_inputs.append(input_field) |
| |
| |
| model_dropdown = gr.Dropdown( |
| choices=list(models.keys()) if models else ["RandomForest"], |
| value="RandomForest" if models else None, |
| label="Select Model", |
| info="Choose which model to use for prediction" |
| ) |
| |
| |
| with gr.Row(): |
| predict_btn = gr.Button("π Make Prediction", variant="primary", size="lg") |
| sample_btn = gr.Button("π Load Sample Data", variant="secondary") |
| clear_btn = gr.Button("ποΈ Clear All", variant="secondary") |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### π― Prediction Results") |
| |
| |
| prediction_output = gr.Textbox( |
| label="Prediction Result", |
| placeholder="Click 'Make Prediction' to see results...", |
| lines=3, |
| max_lines=5 |
| ) |
| |
| |
| all_predictions_output = gr.Textbox( |
| label="All Model Predictions", |
| placeholder="All model predictions will appear here...", |
| lines=15, |
| max_lines=20 |
| ) |
| |
| |
| gr.Markdown("### π Model Information") |
| model_info = gr.Markdown(f""" |
| **Models Loaded**: {len(models)}/8 |
| |
| **Features**: 16 technical indicators |
| |
| **Training Data**: 464,548 samples |
| |
| **Coverage**: 3,257 Indian stocks |
| |
| **Period**: Jan 1 - Aug 20, 2025 |
| """) |
| |
| |
| def predict_handler(): |
| features = [float(input_field.value) for input_field in feature_inputs] |
| result, predictions = predict_stock_price(features, model_dropdown.value) |
| return result, format_predictions(predictions) |
| |
| def sample_handler(): |
| sample_data = create_sample_data() |
| return sample_data |
| |
| def clear_handler(): |
| return [0.0] * 16 |
| |
| predict_btn.click( |
| fn=predict_handler, |
| outputs=[prediction_output, all_predictions_output] |
| ) |
| |
| sample_btn.click( |
| fn=sample_handler, |
| outputs=feature_inputs |
| ) |
| |
| clear_btn.click( |
| fn=clear_handler, |
| outputs=feature_inputs |
| ) |
| |
| |
| gr.Markdown(""" |
| --- |
| |
| **Disclaimer**: These predictions are for educational and research purposes only. |
| Do not use them as investment advice. Stock markets are inherently unpredictable. |
| |
| **Model Details**: All models were trained on NSE bhavcopy data from 2025 and use |
| 16 technical features with 5-day lookback sequences. |
| """) |
| |
| return app |
|
|
| |
| if __name__ == "__main__": |
| app = create_interface() |
| app.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False, |
| show_error=True |
| ) |
|
|