pareshmishra commited on
Commit
a9237fb
·
verified ·
1 Parent(s): c441970

added new files

Browse files

files to run the AI analyser

Files changed (17) hide show
  1. .gitattributes +1 -0
  2. AIStockAnalyser.pdf +0 -0
  3. LICENSE +201 -0
  4. ReadMe.md +112 -0
  5. app.py +534 -0
  6. data_processor.py +127 -0
  7. database.py +266 -0
  8. database_console.py +344 -0
  9. db_console.py +290 -0
  10. model_trainer.py +187 -0
  11. pyproject.toml +18 -0
  12. requirements.txt +10 -0
  13. run_app.sh +3 -0
  14. simple_app.py +219 -0
  15. stock_trading.db +3 -0
  16. technical_indicators.py +225 -0
  17. uv.lock +0 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ stock_trading.db filter=lfs diff=lfs merge=lfs -text
AIStockAnalyser.pdf ADDED
Binary file (61.5 kB). View file
 
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
ReadMe.md ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 📈 StockSignalAI
2
+
3
+ AI-powered stock analysis and signal generation tool using Streamlit.
4
+
5
+ ---
6
+
7
+ ## 🚀 Features
8
+
9
+ - Live stock data via Yahoo Finance
10
+ - Technical indicators (e.g., RSI, MACD, EMA)
11
+ - ML-based trading signal generator
12
+ - Model training and evaluation
13
+ - Interactive UI with Streamlit
14
+ - SQLite-based data storage
15
+
16
+ ---
17
+
18
+ ## ⚙️ Setup Instructions
19
+
20
+ ### 1. Clone the Repository
21
+
22
+ ```bash
23
+ git clone https://github.com/yourusername/StockSignalAI.git
24
+ cd StockSignalAI
25
+
26
+
27
+ ## 2. Create Virtual Environment (optional but recommended)
28
+
29
+ python3 -m venv venv
30
+ source venv/bin/activate # For macOS/Linux
31
+ venv\Scripts\activate # For Windows
32
+ 3. Install Dependencies
33
+
34
+ pip install -r requirements.txt
35
+ If you don’t have a requirements.txt, you can create one:
36
+
37
+ txt
38
+ Copy
39
+ Edit
40
+ yfinance
41
+ pandas
42
+ numpy
43
+ matplotlib
44
+ scikit-learn
45
+ streamlit
46
+ ta
47
+ Save the above as requirements.txt, then run:
48
+
49
+
50
+ pip install -r requirements.txt
51
+ 🖥️ Run the App
52
+ Use Streamlit, not Python directly:
53
+
54
+
55
+ streamlit run app.py
56
+ 💡 If Port 8501 is Busy
57
+
58
+ streamlit run app.py --server.port 8888
59
+ 🧠 Notes
60
+ Session State Initialization
61
+ Before using any Streamlit session state variables (like model), initialize them at the start of the app:
62
+
63
+
64
+ if "model" not in st.session_state:
65
+ st.session_state.model = None
66
+ Add similar blocks for other keys like data, stock_symbol, etc.
67
+
68
+ 🗃️ Database Tables Used
69
+ Your app uses the following tables:
70
+
71
+ stock_data
72
+
73
+ technical_indicators
74
+
75
+ trading_signals
76
+
77
+ model_metrics
78
+
79
+ Ensure your SQLite DB or ORM setup creates them before use.
80
+
81
+ 🔧 Project Structure (Example)
82
+
83
+ StockSignalAI/
84
+ ├── app.py
85
+ ├── requirements.txt
86
+ ├── data/
87
+ │ └── stocks.db
88
+ ├── models/
89
+ │ └── trained_models.pkl
90
+ └── README.md
91
+ 📌
92
+
93
+ TODO / Future Enhancements
94
+ Add backtesting module
95
+
96
+ Save models per stock - this is done
97
+
98
+ Upload and analyze user CSV data
99
+
100
+ Add performance metrics dashboard
101
+
102
+ Email/SMS alerts on new signals
103
+
104
+ 🙌 Acknowledgments
105
+ yfinance
106
+
107
+ ta-lib
108
+
109
+ Streamlit
110
+
111
+ scikit-learn
112
+
app.py ADDED
@@ -0,0 +1,534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import yfinance as yf
5
+ import pickle
6
+ import plotly.graph_objects as go
7
+ from plotly.subplots import make_subplots
8
+ import os
9
+ from datetime import datetime, timedelta
10
+ import warnings
11
+ warnings.filterwarnings('ignore')
12
+
13
+ # Import custom modules
14
+ from data_processor import DataProcessor
15
+ from technical_indicators import TechnicalIndicators
16
+ from model_trainer import ModelTrainer
17
+ from database import DatabaseManager
18
+
19
+ # Configure page
20
+ st.set_page_config(
21
+ page_title="AI Stock Trading Signals",
22
+ page_icon="📈",
23
+ layout="wide"
24
+ )
25
+
26
+ # Initialize session state
27
+ if 'model_trained' not in st.session_state:
28
+ st.session_state.model_trained = False
29
+ if 'model' not in st.session_state:
30
+ st.session_state.model = None
31
+ if 'feature_columns' not in st.session_state:
32
+ st.session_state.feature_columns = None
33
+ if 'db_manager' not in st.session_state:
34
+ st.session_state.db_manager = DatabaseManager()
35
+
36
+ def load_or_train_model(stock_symbol):
37
+ """Load existing model or train new one"""
38
+ model_file = f"model_{stock_symbol.replace('.', '_')}.pkl"
39
+
40
+ if os.path.exists(model_file) and st.session_state.model is None:
41
+ try:
42
+ with open(model_file, 'rb') as f:
43
+ model_data = pickle.load(f)
44
+ st.session_state.model = model_data['model']
45
+ st.session_state.feature_columns = model_data['feature_columns']
46
+ st.session_state.model_trained = True
47
+ return True
48
+ except Exception as e:
49
+ st.error(f"Error loading model: {str(e)}")
50
+ return False
51
+
52
+ return st.session_state.model_trained
53
+
54
+ def train_new_model(stock_symbol):
55
+ """Train a new model for the selected stock"""
56
+ with st.spinner("Training AI model... This may take a few minutes."):
57
+ try:
58
+ # Initialize components
59
+ data_processor = DataProcessor()
60
+ tech_indicators = TechnicalIndicators()
61
+ model_trainer = ModelTrainer()
62
+
63
+ # Download and process data
64
+ data = data_processor.download_stock_data(stock_symbol, period="1y")
65
+ if data is None or len(data) < 100:
66
+ st.error("Insufficient data for training. Please try another stock.")
67
+ return False
68
+
69
+ # Save stock data to database
70
+ st.session_state.db_manager.save_stock_data(stock_symbol, data)
71
+
72
+ # Calculate technical indicators
73
+ data_with_indicators = tech_indicators.calculate_all_indicators(data)
74
+
75
+ # Save technical indicators to database
76
+ st.session_state.db_manager.save_technical_indicators(stock_symbol, data_with_indicators)
77
+
78
+ # Prepare features and labels
79
+ features, labels = data_processor.prepare_features_and_labels(data_with_indicators)
80
+
81
+ if len(features) == 0:
82
+ st.error("No valid features could be generated for training.")
83
+ return False
84
+
85
+ # Train model
86
+ model, feature_columns, metrics = model_trainer.train_model(features, labels)
87
+
88
+ # Save model performance to database
89
+ st.session_state.db_manager.save_model_metrics(
90
+ stock_symbol,
91
+ "RandomForest",
92
+ metrics['accuracy'],
93
+ metrics['precision'],
94
+ metrics['recall'],
95
+ len(feature_columns),
96
+ len(features)
97
+ )
98
+
99
+ # Save model
100
+ model_file = f"model_{stock_symbol.replace('.', '_')}.pkl"
101
+ with open(model_file, 'wb') as f:
102
+ pickle.dump({
103
+ 'model': model,
104
+ 'feature_columns': feature_columns,
105
+ 'metrics': metrics
106
+ }, f)
107
+
108
+ # Update session state
109
+ st.session_state.model = model
110
+ st.session_state.feature_columns = feature_columns
111
+ st.session_state.model_trained = True
112
+
113
+ # Display training metrics
114
+ st.success("Model trained successfully!")
115
+ col1, col2, col3 = st.columns(3)
116
+ with col1:
117
+ st.metric("Accuracy", f"{metrics['accuracy']:.3f}")
118
+ with col2:
119
+ st.metric("Precision", f"{metrics['precision']:.3f}")
120
+ with col3:
121
+ st.metric("Recall", f"{metrics['recall']:.3f}")
122
+
123
+ return True
124
+
125
+ except Exception as e:
126
+ st.error(f"Error training model: {str(e)}")
127
+ return False
128
+
129
+ def get_live_price(stock_symbol):
130
+ """Get live stock price"""
131
+ try:
132
+ # Try to get live price using nsepython
133
+ try:
134
+ from nsepython import nsefetch
135
+ # Extract stock name without .NS suffix
136
+ stock_name = stock_symbol.replace('.NS', '')
137
+ url = f"https://www.nseindia.com/api/quote-equity?symbol={stock_name}"
138
+ live_data = nsefetch(url)
139
+ if live_data and 'priceInfo' in live_data and 'lastPrice' in live_data['priceInfo']:
140
+ return float(live_data['priceInfo']['lastPrice'])
141
+ except:
142
+ pass
143
+
144
+ # Fallback to yfinance
145
+ ticker = yf.Ticker(stock_symbol)
146
+ data = ticker.history(period="1d", interval="1m")
147
+ if not data.empty:
148
+ return float(data['Close'].iloc[-1])
149
+
150
+ return None
151
+ except Exception as e:
152
+ st.warning(f"Could not fetch live price: {str(e)}")
153
+ return None
154
+
155
+ def predict_signal(stock_symbol):
156
+ """Predict trading signal for the stock"""
157
+ try:
158
+ # Initialize components
159
+ data_processor = DataProcessor()
160
+ tech_indicators = TechnicalIndicators()
161
+
162
+ # Get recent data for prediction
163
+ data = data_processor.download_stock_data(stock_symbol, period="3mo")
164
+ if data is None or len(data) < 50:
165
+ return None, "Insufficient data for prediction"
166
+
167
+ # Calculate technical indicators
168
+ data_with_indicators = tech_indicators.calculate_all_indicators(data)
169
+
170
+ # Get latest features
171
+ latest_features = data_processor.get_latest_features(data_with_indicators, st.session_state.feature_columns)
172
+
173
+ if latest_features is None:
174
+ return None, "Could not extract features from latest data"
175
+
176
+ # Make prediction
177
+ prediction = st.session_state.model.predict([latest_features])[0]
178
+ prediction_proba = st.session_state.model.predict_proba([latest_features])[0]
179
+
180
+ # Convert prediction to signal
181
+ signal_map = {-1: "SELL", 0: "HOLD", 1: "BUY"}
182
+ signal = signal_map.get(prediction, "HOLD")
183
+ confidence = max(prediction_proba)
184
+
185
+ # Get current live price for saving to database
186
+ live_price = get_live_price(stock_symbol)
187
+
188
+ # Save trading signal to database
189
+ if live_price and hasattr(st.session_state, 'db_manager') and st.session_state.db_manager:
190
+ try:
191
+ st.session_state.db_manager.save_trading_signal(
192
+ stock_symbol, signal, confidence, live_price, model_version="v1.0"
193
+ )
194
+ except Exception as e:
195
+ print(f"Error saving trading signal: {str(e)}")
196
+
197
+ return {
198
+ 'signal': signal,
199
+ 'confidence': confidence,
200
+ 'prediction': prediction,
201
+ 'probabilities': prediction_proba
202
+ }, None
203
+
204
+ except Exception as e:
205
+ return None, f"Error making prediction: {str(e)}"
206
+
207
+ def create_price_chart(stock_symbol):
208
+ """Create interactive price chart with technical indicators"""
209
+ try:
210
+ # Initialize components
211
+ data_processor = DataProcessor()
212
+ tech_indicators = TechnicalIndicators()
213
+
214
+ # Get data for last 30 days
215
+ data = data_processor.download_stock_data(stock_symbol, period="2mo")
216
+ if data is None:
217
+ return None
218
+
219
+ # Calculate technical indicators
220
+ data_with_indicators = tech_indicators.calculate_all_indicators(data)
221
+
222
+ # Get last 30 days
223
+ data_chart = data_with_indicators.tail(30).copy()
224
+
225
+ # Create subplots
226
+ fig = make_subplots(
227
+ rows=4, cols=1,
228
+ # shared_xaxis=True,
229
+ shared_xaxes=True,
230
+ vertical_spacing=0.03,
231
+ subplot_titles=('Price & Bollinger Bands', 'RSI', 'MACD', 'Volume'),
232
+ row_heights=[0.5, 0.2, 0.2, 0.1]
233
+ )
234
+
235
+ # Price and Bollinger Bands
236
+ fig.add_trace(
237
+ go.Candlestick(
238
+ x=data_chart.index,
239
+ open=data_chart['Open'],
240
+ high=data_chart['High'],
241
+ low=data_chart['Low'],
242
+ close=data_chart['Close'],
243
+ name='Price'
244
+ ), row=1, col=1
245
+ )
246
+
247
+ # Bollinger Bands
248
+ if 'BB_upper' in data_chart.columns:
249
+ fig.add_trace(
250
+ go.Scatter(x=data_chart.index, y=data_chart['BB_upper'],
251
+ name='BB Upper', line=dict(color='red', width=1)), row=1, col=1
252
+ )
253
+ fig.add_trace(
254
+ go.Scatter(x=data_chart.index, y=data_chart['BB_middle'],
255
+ name='BB Middle', line=dict(color='blue', width=1)), row=1, col=1
256
+ )
257
+ fig.add_trace(
258
+ go.Scatter(x=data_chart.index, y=data_chart['BB_lower'],
259
+ name='BB Lower', line=dict(color='red', width=1)), row=1, col=1
260
+ )
261
+
262
+ # EMA
263
+ if 'EMA_20' in data_chart.columns:
264
+ fig.add_trace(
265
+ go.Scatter(x=data_chart.index, y=data_chart['EMA_20'],
266
+ name='EMA 20', line=dict(color='orange', width=2)), row=1, col=1
267
+ )
268
+
269
+ # RSI
270
+ if 'RSI' in data_chart.columns:
271
+ fig.add_trace(
272
+ go.Scatter(x=data_chart.index, y=data_chart['RSI'],
273
+ name='RSI', line=dict(color='purple')), row=2, col=1
274
+ )
275
+ # RSI overbought/oversold lines
276
+ fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
277
+ fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
278
+
279
+ # MACD
280
+ if 'MACD' in data_chart.columns:
281
+ fig.add_trace(
282
+ go.Scatter(x=data_chart.index, y=data_chart['MACD'],
283
+ name='MACD', line=dict(color='blue')), row=3, col=1
284
+ )
285
+ if 'MACD_signal' in data_chart.columns:
286
+ fig.add_trace(
287
+ go.Scatter(x=data_chart.index, y=data_chart['MACD_signal'],
288
+ name='MACD Signal', line=dict(color='red')), row=3, col=1
289
+ )
290
+
291
+ # Volume
292
+ fig.add_trace(
293
+ go.Bar(x=data_chart.index, y=data_chart['Volume'],
294
+ name='Volume', marker_color='lightblue'), row=4, col=1
295
+ )
296
+
297
+ # Update layout
298
+ fig.update_layout(
299
+ title=f"{stock_symbol} - Price Chart with Technical Indicators",
300
+ xaxis_rangeslider_visible=False,
301
+ height=800,
302
+ showlegend=True
303
+ )
304
+
305
+ # Update y-axis labels
306
+ fig.update_yaxes(title_text="Price (₹)", row=1, col=1)
307
+ fig.update_yaxes(title_text="RSI", row=2, col=1)
308
+ fig.update_yaxes(title_text="MACD", row=3, col=1)
309
+ fig.update_yaxes(title_text="Volume", row=4, col=1)
310
+
311
+ return fig
312
+
313
+ except Exception as e:
314
+ st.error(f"Error creating chart: {str(e)}")
315
+ return None
316
+
317
+ def main():
318
+ st.title("📈 AI-Powered Stock Trading Signals")
319
+ st.markdown("### NSE Stock Analysis with Machine Learning")
320
+
321
+ # Initialize database manager early
322
+ if 'db_manager' not in st.session_state:
323
+ try:
324
+ from database import DatabaseManager
325
+ st.session_state.db_manager = DatabaseManager()
326
+ st.success("Database initialized successfully")
327
+ except Exception as e:
328
+ st.error(f"Database initialization failed: {str(e)}")
329
+ st.session_state.db_manager = None
330
+
331
+ # Sidebar for stock selection
332
+ st.sidebar.header("Stock Selection")
333
+
334
+ # Expanded NSE stock options
335
+ stock_options = {
336
+ "Reliance Industries": "RELIANCE.NS",
337
+ "Tata Consultancy Services": "TCS.NS",
338
+ "Infosys": "INFY.NS",
339
+ "HDFC Bank": "HDFCBANK.NS",
340
+ "ICICI Bank": "ICICIBANK.NS",
341
+ "State Bank of India": "SBIN.NS",
342
+ "ITC Limited": "ITC.NS",
343
+ "Hindustan Unilever": "HINDUNILVR.NS",
344
+ "Larsen & Toubro": "LT.NS",
345
+ "Axis Bank": "AXISBANK.NS",
346
+ "Kotak Mahindra Bank": "KOTAKBANK.NS",
347
+ "Wipro": "WIPRO.NS",
348
+ "Tech Mahindra": "TECHM.NS",
349
+ "Bharti Airtel": "BHARTIARTL.NS",
350
+ "Asian Paints": "ASIANPAINT.NS",
351
+ "Maruti Suzuki": "MARUTI.NS",
352
+ "Bajaj Finance": "BAJFINANCE.NS",
353
+ "NTPC": "NTPC.NS",
354
+ "Power Grid Corp": "POWERGRID.NS",
355
+ "Tata Steel": "TATASTEEL.NS"
356
+ }
357
+
358
+ # Option to enter custom stock symbol
359
+ st.sidebar.subheader("Or Enter Custom Stock")
360
+ custom_stock = st.sidebar.text_input(
361
+ "Enter NSE stock symbol (e.g., ADANIPORTS.NS):",
362
+ placeholder="SYMBOL.NS"
363
+ )
364
+
365
+ # Determine selected stock
366
+ if custom_stock and custom_stock.strip():
367
+ if not custom_stock.endswith('.NS'):
368
+ custom_stock += '.NS'
369
+ selected_stock = custom_stock.upper()
370
+ selected_stock_name = f"Custom: {selected_stock}"
371
+ else:
372
+ selected_stock_name = st.sidebar.selectbox(
373
+ "Choose a stock:",
374
+ list(stock_options.keys())
375
+ )
376
+ selected_stock = stock_options[selected_stock_name]
377
+
378
+ # Model training section
379
+ st.sidebar.header("Model Management")
380
+
381
+ # Check if model exists
382
+ model_exists = load_or_train_model(selected_stock)
383
+
384
+ if not model_exists:
385
+ st.sidebar.warning("No trained model found for this stock.")
386
+ if st.sidebar.button("Train New Model"):
387
+ train_new_model(selected_stock)
388
+ else:
389
+ st.sidebar.success("Model loaded successfully!")
390
+ if st.sidebar.button("Retrain Model"):
391
+ st.session_state.model = None
392
+ st.session_state.model_trained = False
393
+ train_new_model(selected_stock)
394
+
395
+ # Main content
396
+ if st.session_state.model_trained and st.session_state.model is not None:
397
+
398
+ # Live price section
399
+ st.header("📊 Live Market Data")
400
+ col1, col2 = st.columns(2)
401
+
402
+ with col1:
403
+ if st.button("🔄 Get Live Price", type="primary"):
404
+ live_price = get_live_price(selected_stock)
405
+ if live_price:
406
+ st.metric("Live Price (LTP)", f"₹{live_price:.2f}")
407
+ else:
408
+ st.warning("Could not fetch live price")
409
+
410
+ # Prediction section
411
+ st.header("🤖 AI Trading Signal")
412
+
413
+ if st.button("🎯 Get Trading Signal", type="primary"):
414
+ prediction_result, error = predict_signal(selected_stock)
415
+
416
+ if prediction_result:
417
+ signal = prediction_result['signal']
418
+ confidence = prediction_result['confidence']
419
+
420
+ # Display signal with color coding
421
+ if signal == "BUY":
422
+ st.success(f"🟢 **{signal}** Signal")
423
+ elif signal == "SELL":
424
+ st.error(f"🔴 **{signal}** Signal")
425
+ else:
426
+ st.info(f"🟡 **{signal}** Signal")
427
+
428
+ # Display confidence and probabilities
429
+ col1, col2 = st.columns(2)
430
+ with col1:
431
+ st.metric("Confidence", f"{confidence:.1%}")
432
+
433
+ with col2:
434
+ prob_df = pd.DataFrame({
435
+ 'Signal': ['SELL', 'HOLD', 'BUY'],
436
+ 'Probability': prediction_result['probabilities']
437
+ })
438
+ st.dataframe(prob_df, hide_index=True)
439
+
440
+ else:
441
+ st.error(f"Prediction failed: {error}")
442
+
443
+ # Chart section
444
+ st.header("📈 Technical Analysis Chart")
445
+
446
+ if st.button("📊 Generate Chart"):
447
+ chart = create_price_chart(selected_stock)
448
+ if chart:
449
+ st.plotly_chart(chart, use_container_width=True)
450
+
451
+ # Additional information
452
+ st.header("ℹ️ Model Information")
453
+
454
+ col1, col2 = st.columns(2)
455
+ with col1:
456
+ st.info("**Features Used:**\n- RSI, EMA, MACD\n- Bollinger Bands\n- SMA, Stochastic\n- Williams %R, ATR")
457
+
458
+ with col2:
459
+ st.info("**Signal Criteria:**\n- BUY: Expected 2%+ gain\n- SELL: Expected 2%+ loss\n- HOLD: Neutral expectation")
460
+
461
+ else:
462
+ st.info("👆 Please train a model first using the sidebar to get started with AI-powered trading signals.")
463
+
464
+ # Show sample data while waiting
465
+ st.header("📊 Sample Stock Data")
466
+ try:
467
+ data_processor = DataProcessor()
468
+ sample_data = data_processor.download_stock_data(selected_stock, period="1mo")
469
+ if sample_data is not None:
470
+ st.dataframe(sample_data.tail(10))
471
+ except:
472
+ st.warning("Could not load sample data")
473
+
474
+ # Database Information Section
475
+ st.sidebar.header("📊 Database Status")
476
+
477
+ # Database Console Link
478
+ st.sidebar.markdown("---")
479
+ st.sidebar.markdown("### 🗄️ Database Console")
480
+ st.sidebar.markdown("Access the SQLite database console:")
481
+ st.sidebar.markdown("**[Open Database Console](http://localhost:5001)**")
482
+ st.sidebar.markdown("*View tables, run SQL queries, analyze trading data*")
483
+ st.sidebar.markdown("*Database file: `stock_trading.db`*")
484
+ st.sidebar.markdown("---")
485
+
486
+ try:
487
+ if hasattr(st.session_state, 'db_manager') and st.session_state.db_manager:
488
+ db_stats = st.session_state.db_manager.get_database_stats()
489
+ if db_stats:
490
+ st.sidebar.metric("Stock Records", db_stats.get('total_stock_records', 0))
491
+ st.sidebar.metric("Trading Signals", db_stats.get('total_signals', 0))
492
+ st.sidebar.metric("Active Models", db_stats.get('active_models', 0))
493
+ st.sidebar.metric("Symbols Tracked", db_stats.get('symbols_tracked', 0))
494
+ else:
495
+ st.sidebar.info("Database ready - no data yet")
496
+ else:
497
+ st.sidebar.info("Database initializing...")
498
+ except Exception as e:
499
+ st.sidebar.warning("Database tables will be created when first used")
500
+
501
+ # Trading History Section
502
+ if st.session_state.model_trained and hasattr(st.session_state, 'db_manager') and st.session_state.db_manager:
503
+ st.header("📈 Trading History")
504
+
505
+ col1, col2 = st.columns(2)
506
+
507
+ with col1:
508
+ if st.button("View Signal History"):
509
+ try:
510
+ signal_history = st.session_state.db_manager.get_trading_signals_history(selected_stock)
511
+ if not signal_history.empty:
512
+ st.dataframe(signal_history.head(10))
513
+ else:
514
+ st.info("No trading signals found in database")
515
+ except Exception as e:
516
+ st.error(f"Error loading signal history: {str(e)}")
517
+
518
+ with col2:
519
+ if st.button("Model Performance"):
520
+ try:
521
+ model_perf = st.session_state.db_manager.get_model_performance(selected_stock)
522
+ if model_perf:
523
+ st.json(model_perf)
524
+ else:
525
+ st.info("No model performance data found")
526
+ except Exception as e:
527
+ st.error(f"Error loading model performance: {str(e)}")
528
+
529
+ # Database Console Access
530
+ st.markdown("---")
531
+ 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.")
532
+
533
+ if __name__ == "__main__":
534
+ main()
data_processor.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import yfinance as yf
4
+ from datetime import datetime, timedelta
5
+ import warnings
6
+ warnings.filterwarnings('ignore')
7
+
8
+ class DataProcessor:
9
+ def __init__(self):
10
+ pass
11
+
12
+ def download_stock_data(self, symbol, period="3mo", interval="1d"):
13
+ """Download stock data using yfinance"""
14
+ try:
15
+ ticker = yf.Ticker(symbol)
16
+ data = ticker.history(period=period, interval=interval)
17
+
18
+ if data.empty:
19
+ return None
20
+
21
+ # Clean column names
22
+ data.columns = [col.title() for col in data.columns]
23
+
24
+ # Remove timezone info for consistency
25
+ if data.index.tz is not None:
26
+ data.index = data.index.tz_localize(None)
27
+
28
+ return data
29
+
30
+ except Exception as e:
31
+ print(f"Error downloading data for {symbol}: {str(e)}")
32
+ return None
33
+
34
+ def prepare_features_and_labels(self, data, future_days=3, threshold=0.02):
35
+ """Prepare features and labels for machine learning"""
36
+ try:
37
+ # Calculate future returns for labeling
38
+ data = data.copy()
39
+ data['Future_Return'] = data['Close'].pct_change(periods=future_days).shift(-future_days)
40
+
41
+ # Create labels based on future returns
42
+ # 1 = BUY (expected gain > threshold)
43
+ # -1 = SELL (expected loss > threshold)
44
+ # 0 = HOLD (neutral)
45
+ conditions = [
46
+ data['Future_Return'] > threshold,
47
+ data['Future_Return'] < -threshold
48
+ ]
49
+ choices = [1, -1]
50
+ data['Label'] = np.select(conditions, choices, default=0)
51
+
52
+ # Select feature columns (all technical indicators)
53
+ feature_columns = [col for col in data.columns if col not in
54
+ ['Open', 'High', 'Low', 'Close', 'Volume', 'Future_Return', 'Label']]
55
+
56
+ # Remove rows with NaN values
57
+ clean_data = data.dropna()
58
+
59
+ if len(clean_data) == 0:
60
+ return pd.DataFrame(), pd.Series()
61
+
62
+ # Prepare features and labels
63
+ features = clean_data[feature_columns]
64
+ labels = clean_data['Label']
65
+
66
+ return features, labels
67
+
68
+ except Exception as e:
69
+ print(f"Error preparing features and labels: {str(e)}")
70
+ return pd.DataFrame(), pd.Series()
71
+
72
+ def get_latest_features(self, data, feature_columns):
73
+ """Extract latest features for prediction"""
74
+ try:
75
+ if data.empty or not feature_columns:
76
+ return None
77
+
78
+ # Get the latest row with all required features
79
+ latest_data = data[feature_columns].dropna()
80
+
81
+ if latest_data.empty:
82
+ return None
83
+
84
+ # Return the latest row as a list
85
+ return latest_data.iloc[-1].values.tolist()
86
+
87
+ except Exception as e:
88
+ print(f"Error extracting latest features: {str(e)}")
89
+ return None
90
+
91
+ def calculate_returns(self, data, periods=[1, 3, 5]):
92
+ """Calculate returns for different periods"""
93
+ try:
94
+ returns_data = data.copy()
95
+
96
+ for period in periods:
97
+ returns_data[f'Return_{period}d'] = data['Close'].pct_change(periods=period)
98
+
99
+ return returns_data
100
+
101
+ except Exception as e:
102
+ print(f"Error calculating returns: {str(e)}")
103
+ return data
104
+
105
+ def add_price_features(self, data):
106
+ """Add additional price-based features"""
107
+ try:
108
+ enhanced_data = data.copy()
109
+
110
+ # Price position within daily range
111
+ enhanced_data['Price_Position'] = (data['Close'] - data['Low']) / (data['High'] - data['Low'])
112
+ enhanced_data['Price_Position'].fillna(0.5, inplace=True)
113
+
114
+ # Gap from previous close
115
+ enhanced_data['Gap'] = (data['Open'] - data['Close'].shift(1)) / data['Close'].shift(1)
116
+
117
+ # Intraday return
118
+ enhanced_data['Intraday_Return'] = (data['Close'] - data['Open']) / data['Open']
119
+
120
+ # High-Low spread
121
+ enhanced_data['HL_Spread'] = (data['High'] - data['Low']) / data['Close']
122
+
123
+ return enhanced_data
124
+
125
+ except Exception as e:
126
+ print(f"Error adding price features: {str(e)}")
127
+ return data
database.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlalchemy as sa
2
+ from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Text, Boolean, text
3
+ from sqlalchemy.ext.declarative import declarative_base
4
+ from sqlalchemy.orm import sessionmaker
5
+ from datetime import datetime
6
+ import json
7
+ import pandas as pd
8
+
9
+ Base = declarative_base()
10
+
11
+ class StockData(Base):
12
+ __tablename__ = 'stock_data'
13
+
14
+ id = Column(Integer, primary_key=True)
15
+ symbol = Column(String(20), nullable=False)
16
+ date = Column(DateTime, nullable=False)
17
+ open_price = Column(Float)
18
+ high_price = Column(Float)
19
+ low_price = Column(Float)
20
+ close_price = Column(Float)
21
+ volume = Column(Integer)
22
+ created_at = Column(DateTime, default=datetime.now)
23
+
24
+ class TechnicalIndicators(Base):
25
+ __tablename__ = 'technical_indicators'
26
+
27
+ id = Column(Integer, primary_key=True)
28
+ symbol = Column(String(20), nullable=False)
29
+ date = Column(DateTime, nullable=False)
30
+ rsi = Column(Float)
31
+ macd = Column(Float)
32
+ macd_signal = Column(Float)
33
+ bb_upper = Column(Float)
34
+ bb_middle = Column(Float)
35
+ bb_lower = Column(Float)
36
+ ema_20 = Column(Float)
37
+ sma_20 = Column(Float)
38
+ sma_50 = Column(Float)
39
+ stoch_k = Column(Float)
40
+ williams_r = Column(Float)
41
+ atr = Column(Float)
42
+ created_at = Column(DateTime, default=datetime.now)
43
+
44
+ class TradingSignals(Base):
45
+ __tablename__ = 'trading_signals'
46
+
47
+ id = Column(Integer, primary_key=True)
48
+ symbol = Column(String(20), nullable=False)
49
+ signal_date = Column(DateTime, nullable=False)
50
+ signal = Column(String(10)) # BUY, SELL, HOLD
51
+ confidence = Column(Float)
52
+ live_price = Column(Float)
53
+ predicted_return = Column(Float)
54
+ model_version = Column(String(50))
55
+ created_at = Column(DateTime, default=datetime.now)
56
+
57
+ class ModelMetrics(Base):
58
+ __tablename__ = 'model_metrics'
59
+
60
+ id = Column(Integer, primary_key=True)
61
+ symbol = Column(String(20), nullable=False)
62
+ model_type = Column(String(50))
63
+ accuracy = Column(Float)
64
+ precision_score = Column(Float)
65
+ recall_score = Column(Float)
66
+ training_date = Column(DateTime, default=datetime.now)
67
+ feature_count = Column(Integer)
68
+ training_samples = Column(Integer)
69
+ is_active = Column(Boolean, default=True)
70
+
71
+ class DatabaseManager:
72
+ def __init__(self):
73
+ # SQLite persistent database for better data retention
74
+ self.engine = create_engine('sqlite:///stock_trading.db', echo=False)
75
+ try:
76
+ # Create all tables
77
+ Base.metadata.create_all(self.engine)
78
+ Session = sessionmaker(bind=self.engine)
79
+ self.session = Session()
80
+
81
+ # Verify tables were created
82
+ with self.engine.connect() as conn:
83
+ result = conn.execute(text("SELECT name FROM sqlite_master WHERE type='table'"))
84
+ tables = [row[0] for row in result]
85
+ print(f"Database tables available: {tables}")
86
+
87
+ except Exception as e:
88
+ print(f"Database initialization error: {str(e)}")
89
+ raise e
90
+
91
+ def save_stock_data(self, symbol, data_df):
92
+ """Save stock OHLCV data to database"""
93
+ try:
94
+ for index, row in data_df.iterrows():
95
+ stock_record = StockData(
96
+ symbol=symbol,
97
+ date=index,
98
+ open_price=float(row['Open']),
99
+ high_price=float(row['High']),
100
+ low_price=float(row['Low']),
101
+ close_price=float(row['Close']),
102
+ volume=int(row['Volume'])
103
+ )
104
+ self.session.merge(stock_record)
105
+ self.session.commit()
106
+ return True
107
+ except Exception as e:
108
+ self.session.rollback()
109
+ print(f"Error saving stock data: {str(e)}")
110
+ return False
111
+
112
+ def save_technical_indicators(self, symbol, indicators_df):
113
+ """Save technical indicators to database"""
114
+ try:
115
+ for index, row in indicators_df.iterrows():
116
+ indicator_record = TechnicalIndicators(
117
+ symbol=symbol,
118
+ date=index,
119
+ rsi=float(row.get('RSI', 0)) if pd.notna(row.get('RSI', 0)) else None,
120
+ macd=float(row.get('MACD', 0)) if pd.notna(row.get('MACD', 0)) else None,
121
+ macd_signal=float(row.get('MACD_signal', 0)) if pd.notna(row.get('MACD_signal', 0)) else None,
122
+ bb_upper=float(row.get('BB_upper', 0)) if pd.notna(row.get('BB_upper', 0)) else None,
123
+ bb_middle=float(row.get('BB_middle', 0)) if pd.notna(row.get('BB_middle', 0)) else None,
124
+ bb_lower=float(row.get('BB_lower', 0)) if pd.notna(row.get('BB_lower', 0)) else None,
125
+ ema_20=float(row.get('EMA_20', 0)) if pd.notna(row.get('EMA_20', 0)) else None,
126
+ sma_20=float(row.get('SMA_20', 0)) if pd.notna(row.get('SMA_20', 0)) else None,
127
+ sma_50=float(row.get('SMA_50', 0)) if pd.notna(row.get('SMA_50', 0)) else None,
128
+ stoch_k=float(row.get('Stoch_K', 0)) if pd.notna(row.get('Stoch_K', 0)) else None,
129
+ williams_r=float(row.get('Williams_R', 0)) if pd.notna(row.get('Williams_R', 0)) else None,
130
+ atr=float(row.get('ATR', 0)) if pd.notna(row.get('ATR', 0)) else None
131
+ )
132
+ self.session.merge(indicator_record)
133
+ self.session.commit()
134
+ return True
135
+ except Exception as e:
136
+ self.session.rollback()
137
+ print(f"Error saving technical indicators: {str(e)}")
138
+ return False
139
+
140
+ def save_trading_signal(self, symbol, signal, confidence, live_price, predicted_return=None, model_version="v1.0"):
141
+ """Save trading signal to database"""
142
+ try:
143
+ signal_record = TradingSignals(
144
+ symbol=symbol,
145
+ signal_date=datetime.now(),
146
+ signal=signal,
147
+ confidence=confidence,
148
+ live_price=live_price,
149
+ predicted_return=predicted_return,
150
+ model_version=model_version
151
+ )
152
+ self.session.add(signal_record)
153
+ self.session.commit()
154
+ return True
155
+ except Exception as e:
156
+ self.session.rollback()
157
+ print(f"Error saving trading signal: {str(e)}")
158
+ return False
159
+
160
+ def save_model_metrics(self, symbol, model_type, accuracy, precision, recall, feature_count, training_samples):
161
+ """Save model performance metrics to database"""
162
+ try:
163
+ # Deactivate old models for this symbol
164
+ old_models = self.session.query(ModelMetrics).filter_by(symbol=symbol, is_active=True).all()
165
+ for model in old_models:
166
+ model.is_active = False
167
+
168
+ # Add new model metrics
169
+ metrics_record = ModelMetrics(
170
+ symbol=symbol,
171
+ model_type=model_type,
172
+ accuracy=accuracy,
173
+ precision_score=precision,
174
+ recall_score=recall,
175
+ feature_count=feature_count,
176
+ training_samples=training_samples,
177
+ is_active=True
178
+ )
179
+ self.session.add(metrics_record)
180
+ self.session.commit()
181
+ return True
182
+ except Exception as e:
183
+ self.session.rollback()
184
+ print(f"Error saving model metrics: {str(e)}")
185
+ return False
186
+
187
+ def get_latest_stock_data(self, symbol, limit=100):
188
+ """Get latest stock data from database"""
189
+ try:
190
+ records = self.session.query(StockData).filter_by(symbol=symbol)\
191
+ .order_by(StockData.date.desc()).limit(limit).all()
192
+
193
+ data = []
194
+ for record in records:
195
+ data.append({
196
+ 'Date': record.date,
197
+ 'Open': record.open_price,
198
+ 'High': record.high_price,
199
+ 'Low': record.low_price,
200
+ 'Close': record.close_price,
201
+ 'Volume': record.volume
202
+ })
203
+
204
+ return pd.DataFrame(data).set_index('Date').sort_index()
205
+ except Exception as e:
206
+ print(f"Error getting stock data: {str(e)}")
207
+ return pd.DataFrame()
208
+
209
+ def get_trading_signals_history(self, symbol, limit=50):
210
+ """Get trading signals history for a symbol"""
211
+ try:
212
+ records = self.session.query(TradingSignals).filter_by(symbol=symbol)\
213
+ .order_by(TradingSignals.signal_date.desc()).limit(limit).all()
214
+
215
+ signals = []
216
+ for record in records:
217
+ signals.append({
218
+ 'Date': record.signal_date,
219
+ 'Signal': record.signal,
220
+ 'Confidence': record.confidence,
221
+ 'Live Price': record.live_price,
222
+ 'Model Version': record.model_version
223
+ })
224
+
225
+ return pd.DataFrame(signals)
226
+ except Exception as e:
227
+ print(f"Error getting trading signals: {str(e)}")
228
+ return pd.DataFrame()
229
+
230
+ def get_model_performance(self, symbol):
231
+ """Get current model performance metrics"""
232
+ try:
233
+ record = self.session.query(ModelMetrics).filter_by(symbol=symbol, is_active=True).first()
234
+ if record:
235
+ return {
236
+ 'model_type': record.model_type,
237
+ 'accuracy': record.accuracy,
238
+ 'precision': record.precision_score,
239
+ 'recall': record.recall_score,
240
+ 'training_date': record.training_date,
241
+ 'feature_count': record.feature_count,
242
+ 'training_samples': record.training_samples
243
+ }
244
+ return None
245
+ except Exception as e:
246
+ print(f"Error getting model performance: {str(e)}")
247
+ return None
248
+
249
+ def get_database_stats(self):
250
+ """Get database statistics"""
251
+ try:
252
+ stats = {
253
+ 'total_stock_records': self.session.query(StockData).count(),
254
+ 'total_indicators': self.session.query(TechnicalIndicators).count(),
255
+ 'total_signals': self.session.query(TradingSignals).count(),
256
+ 'active_models': self.session.query(ModelMetrics).filter_by(is_active=True).count(),
257
+ 'symbols_tracked': len(self.session.query(StockData.symbol).distinct().all())
258
+ }
259
+ return stats
260
+ except Exception as e:
261
+ print(f"Error getting database stats: {str(e)}")
262
+ return {}
263
+
264
+ def close(self):
265
+ """Close database connection"""
266
+ self.session.close()
database_console.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ from database import DatabaseManager
4
+ from sqlalchemy import text
5
+ import plotly.express as px
6
+ import plotly.graph_objects as go
7
+ from datetime import datetime, timedelta
8
+
9
+ def database_console():
10
+ """Database console interface for viewing and managing stock data"""
11
+ st.title("📊 Database Console - Stock Trading Data")
12
+ st.markdown("### SQLite Database Management")
13
+
14
+ # Show database file location
15
+ st.info("Database file: stock_trading.db (persistent storage)")
16
+
17
+ # Initialize database
18
+ try:
19
+ if 'console_db' not in st.session_state:
20
+ from database import DatabaseManager
21
+ st.session_state.console_db = DatabaseManager()
22
+ db = st.session_state.console_db
23
+ st.success("Database connection established")
24
+
25
+ # Show database file size if it exists
26
+ import os
27
+ if os.path.exists('stock_trading.db'):
28
+ size = os.path.getsize('stock_trading.db')
29
+ st.metric("Database Size", f"{size / 1024:.1f} KB")
30
+
31
+ except Exception as e:
32
+ st.error(f"Database connection failed: {str(e)}")
33
+ return
34
+
35
+ # Sidebar navigation
36
+ st.sidebar.header("Database Navigation")
37
+ section = st.sidebar.selectbox(
38
+ "Select Section:",
39
+ ["Overview", "Stock Data", "Technical Indicators", "Trading Signals", "Model Metrics", "SQL Query"]
40
+ )
41
+
42
+ if section == "Overview":
43
+ show_database_overview(db)
44
+ elif section == "Stock Data":
45
+ show_stock_data(db)
46
+ elif section == "Technical Indicators":
47
+ show_technical_indicators(db)
48
+ elif section == "Trading Signals":
49
+ show_trading_signals(db)
50
+ elif section == "Model Metrics":
51
+ show_model_metrics(db)
52
+ elif section == "SQL Query":
53
+ show_sql_interface(db)
54
+
55
+ def show_database_overview(db):
56
+ """Show database overview and statistics"""
57
+ st.header("Database Overview")
58
+
59
+ col1, col2, col3, col4 = st.columns(4)
60
+
61
+ try:
62
+ # Get table counts
63
+ stock_count = db.session.execute(text("SELECT COUNT(*) FROM stock_data")).scalar()
64
+ indicator_count = db.session.execute(text("SELECT COUNT(*) FROM technical_indicators")).scalar()
65
+ signal_count = db.session.execute(text("SELECT COUNT(*) FROM trading_signals")).scalar()
66
+ model_count = db.session.execute(text("SELECT COUNT(*) FROM model_metrics")).scalar()
67
+
68
+ with col1:
69
+ st.metric("Stock Records", stock_count)
70
+ with col2:
71
+ st.metric("Technical Indicators", indicator_count)
72
+ with col3:
73
+ st.metric("Trading Signals", signal_count)
74
+ with col4:
75
+ st.metric("Model Records", model_count)
76
+
77
+ except Exception as e:
78
+ st.warning(f"Error getting counts: {str(e)}")
79
+ # Initialize tables if they don't exist
80
+ if st.button("Initialize Database Tables"):
81
+ initialize_database_tables(db)
82
+
83
+ # Recent activity
84
+ st.subheader("Recent Activity")
85
+ try:
86
+ recent_signals = pd.read_sql("""
87
+ SELECT symbol, signal, confidence, live_price, created_at
88
+ FROM trading_signals
89
+ ORDER BY created_at DESC
90
+ LIMIT 10
91
+ """, db.engine)
92
+
93
+ if not recent_signals.empty:
94
+ st.dataframe(recent_signals)
95
+ else:
96
+ st.info("No recent trading signals found")
97
+
98
+ except Exception as e:
99
+ st.info("No trading signals table found yet")
100
+
101
+ def show_stock_data(db):
102
+ """Show stock OHLCV data"""
103
+ st.header("Stock Data (OHLCV)")
104
+
105
+ # Stock selection
106
+ symbol = st.selectbox(
107
+ "Select Stock Symbol:",
108
+ ["RELIANCE.NS", "TCS.NS", "INFY.NS", "HDFCBANK.NS", "ICICIBANK.NS"]
109
+ )
110
+
111
+ try:
112
+ # Get stock data
113
+ query = """
114
+ SELECT * FROM stock_data
115
+ WHERE symbol = :symbol
116
+ ORDER BY date DESC
117
+ LIMIT 100
118
+ """
119
+ stock_data = pd.read_sql(query, db.engine, params={"symbol": symbol})
120
+
121
+ if not stock_data.empty:
122
+ st.dataframe(stock_data)
123
+
124
+ # Create price chart
125
+ fig = go.Figure()
126
+ fig.add_trace(go.Candlestick(
127
+ x=stock_data['date'],
128
+ open=stock_data['open_price'],
129
+ high=stock_data['high_price'],
130
+ low=stock_data['low_price'],
131
+ close=stock_data['close_price'],
132
+ name=symbol
133
+ ))
134
+ fig.update_layout(title=f"{symbol} - Price Chart", xaxis_title="Date", yaxis_title="Price (₹)")
135
+ st.plotly_chart(fig, use_container_width=True)
136
+
137
+ else:
138
+ st.info(f"No stock data found for {symbol}")
139
+ if st.button(f"Load {symbol} Data"):
140
+ load_sample_data(db, symbol)
141
+
142
+ except Exception as e:
143
+ st.error(f"Error loading stock data: {str(e)}")
144
+
145
+ def show_technical_indicators(db):
146
+ """Show technical indicators data"""
147
+ st.header("Technical Indicators")
148
+
149
+ symbol = st.selectbox(
150
+ "Select Stock:",
151
+ ["RELIANCE.NS", "TCS.NS", "INFY.NS", "HDFCBANK.NS", "ICICIBANK.NS"],
152
+ key="tech_symbol"
153
+ )
154
+
155
+ try:
156
+ query = """
157
+ SELECT * FROM technical_indicators
158
+ WHERE symbol = :symbol
159
+ ORDER BY date DESC
160
+ LIMIT 50
161
+ """
162
+ tech_data = pd.read_sql(query, db.engine, params={"symbol": symbol})
163
+
164
+ if not tech_data.empty:
165
+ st.dataframe(tech_data)
166
+
167
+ # Create indicators chart
168
+ col1, col2 = st.columns(2)
169
+
170
+ with col1:
171
+ if 'rsi' in tech_data.columns:
172
+ fig_rsi = px.line(tech_data, x='date', y='rsi', title='RSI')
173
+ st.plotly_chart(fig_rsi, use_container_width=True)
174
+
175
+ with col2:
176
+ if 'macd' in tech_data.columns:
177
+ fig_macd = px.line(tech_data, x='date', y='macd', title='MACD')
178
+ st.plotly_chart(fig_macd, use_container_width=True)
179
+
180
+ else:
181
+ st.info(f"No technical indicators found for {symbol}")
182
+
183
+ except Exception as e:
184
+ st.error(f"Error loading technical indicators: {str(e)}")
185
+
186
+ def show_trading_signals(db):
187
+ """Show trading signals"""
188
+ st.header("Trading Signals")
189
+
190
+ try:
191
+ # Get all signals
192
+ signals_data = pd.read_sql("""
193
+ SELECT * FROM trading_signals
194
+ ORDER BY signal_date DESC
195
+ LIMIT 100
196
+ """, db.engine)
197
+
198
+ if not signals_data.empty:
199
+ st.dataframe(signals_data)
200
+
201
+ # Signal distribution
202
+ col1, col2 = st.columns(2)
203
+
204
+ with col1:
205
+ signal_counts = signals_data['signal'].value_counts()
206
+ fig_pie = px.pie(values=signal_counts.values, names=signal_counts.index,
207
+ title="Signal Distribution")
208
+ st.plotly_chart(fig_pie, use_container_width=True)
209
+
210
+ with col2:
211
+ fig_conf = px.histogram(signals_data, x='confidence', title="Confidence Distribution")
212
+ st.plotly_chart(fig_conf, use_container_width=True)
213
+
214
+ else:
215
+ st.info("No trading signals found")
216
+
217
+ except Exception as e:
218
+ st.error(f"Error loading trading signals: {str(e)}")
219
+
220
+ def show_model_metrics(db):
221
+ """Show model performance metrics"""
222
+ st.header("Model Performance Metrics")
223
+
224
+ try:
225
+ metrics_data = pd.read_sql("""
226
+ SELECT * FROM model_metrics
227
+ ORDER BY training_date DESC
228
+ """, db.engine)
229
+
230
+ if not metrics_data.empty:
231
+ st.dataframe(metrics_data)
232
+
233
+ # Performance charts
234
+ col1, col2 = st.columns(2)
235
+
236
+ with col1:
237
+ fig_acc = px.bar(metrics_data, x='symbol', y='accuracy',
238
+ title="Model Accuracy by Symbol")
239
+ st.plotly_chart(fig_acc, use_container_width=True)
240
+
241
+ with col2:
242
+ fig_prec = px.bar(metrics_data, x='symbol', y='precision_score',
243
+ title="Model Precision by Symbol")
244
+ st.plotly_chart(fig_prec, use_container_width=True)
245
+
246
+ else:
247
+ st.info("No model metrics found")
248
+
249
+ except Exception as e:
250
+ st.error(f"Error loading model metrics: {str(e)}")
251
+
252
+ def show_sql_interface(db):
253
+ """SQL query interface"""
254
+ st.header("SQL Query Interface")
255
+
256
+ # Predefined queries
257
+ st.subheader("Quick Queries")
258
+ col1, col2, col3 = st.columns(3)
259
+
260
+ with col1:
261
+ if st.button("Show All Tables"):
262
+ try:
263
+ tables = db.engine.execute(text("SELECT name FROM sqlite_master WHERE type='table'")).fetchall()
264
+ st.write("Tables:", [table[0] for table in tables])
265
+ except Exception as e:
266
+ st.error(f"Error: {str(e)}")
267
+
268
+ with col2:
269
+ if st.button("Latest Signals"):
270
+ try:
271
+ result = pd.read_sql("SELECT * FROM trading_signals ORDER BY created_at DESC LIMIT 5", db.engine)
272
+ st.dataframe(result)
273
+ except Exception as e:
274
+ st.error(f"Error: {str(e)}")
275
+
276
+ with col3:
277
+ if st.button("Stock Summary"):
278
+ try:
279
+ result = pd.read_sql("""
280
+ SELECT symbol, COUNT(*) as records,
281
+ MIN(date) as first_date, MAX(date) as last_date
282
+ FROM stock_data
283
+ GROUP BY symbol
284
+ """, db.engine)
285
+ st.dataframe(result)
286
+ except Exception as e:
287
+ st.error(f"Error: {str(e)}")
288
+
289
+ # Custom SQL query
290
+ st.subheader("Custom SQL Query")
291
+ sql_query = st.text_area(
292
+ "Enter SQL Query:",
293
+ value="SELECT * FROM trading_signals LIMIT 10;",
294
+ height=100
295
+ )
296
+
297
+ if st.button("Execute Query"):
298
+ try:
299
+ if sql_query.strip():
300
+ result = pd.read_sql(sql_query, db.engine)
301
+ st.dataframe(result)
302
+ st.success(f"Query executed successfully. {len(result)} rows returned.")
303
+ except Exception as e:
304
+ st.error(f"Query error: {str(e)}")
305
+
306
+ def initialize_database_tables(db):
307
+ """Initialize database tables with sample data"""
308
+ try:
309
+ from database import Base
310
+ Base.metadata.create_all(db.engine)
311
+ st.success("Database tables initialized successfully")
312
+ st.rerun()
313
+ except Exception as e:
314
+ st.error(f"Error initializing tables: {str(e)}")
315
+
316
+ def load_sample_data(db, symbol):
317
+ """Load sample data for testing"""
318
+ try:
319
+ import yfinance as yf
320
+ from technical_indicators import TechnicalIndicators
321
+
322
+ # Download stock data
323
+ ticker = yf.Ticker(symbol)
324
+ data = ticker.history(period="1mo")
325
+
326
+ if not data.empty:
327
+ # Save stock data
328
+ db.save_stock_data(symbol, data)
329
+
330
+ # Calculate and save technical indicators
331
+ tech = TechnicalIndicators()
332
+ data_with_indicators = tech.calculate_all_indicators(data)
333
+ db.save_technical_indicators(symbol, data_with_indicators)
334
+
335
+ st.success(f"Sample data loaded for {symbol}")
336
+ st.rerun()
337
+ else:
338
+ st.error(f"Could not fetch data for {symbol}")
339
+
340
+ except Exception as e:
341
+ st.error(f"Error loading sample data: {str(e)}")
342
+
343
+ if __name__ == "__main__":
344
+ database_console()
db_console.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import sqlite3
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ import os
7
+
8
+ def main():
9
+ st.set_page_config(page_title="Stock Trading Database Console", layout="wide")
10
+
11
+ st.title("📊 Stock Trading Database Console")
12
+ st.markdown("### SQLite Database Management & Analytics")
13
+
14
+ # Database file info
15
+ db_file = "stock_trading.db"
16
+ if os.path.exists(db_file):
17
+ size = os.path.getsize(db_file)
18
+ st.success(f"Database: {db_file} ({size/1024:.1f} KB)")
19
+ else:
20
+ st.warning(f"Database file {db_file} not found. Data will be created when you use the main app.")
21
+ return
22
+
23
+ # Connect to database
24
+ try:
25
+ conn = sqlite3.connect(db_file)
26
+ st.success("Database connection established")
27
+ except Exception as e:
28
+ st.error(f"Database connection failed: {str(e)}")
29
+ return
30
+
31
+ # Sidebar navigation
32
+ st.sidebar.header("Database Navigation")
33
+ section = st.sidebar.selectbox(
34
+ "Select Section:",
35
+ ["Overview", "Tables", "Stock Data", "Trading Signals", "Model Metrics", "SQL Query"]
36
+ )
37
+
38
+ if section == "Overview":
39
+ show_overview(conn)
40
+ elif section == "Tables":
41
+ show_tables(conn)
42
+ elif section == "Stock Data":
43
+ show_stock_data(conn)
44
+ elif section == "Trading Signals":
45
+ show_trading_signals(conn)
46
+ elif section == "Model Metrics":
47
+ show_model_metrics(conn)
48
+ elif section == "SQL Query":
49
+ show_sql_interface(conn)
50
+
51
+ conn.close()
52
+
53
+ def show_overview(conn):
54
+ """Show database overview"""
55
+ st.header("Database Overview")
56
+
57
+ # Get table information
58
+ tables_query = "SELECT name FROM sqlite_master WHERE type='table'"
59
+ tables = pd.read_sql(tables_query, conn)
60
+
61
+ if not tables.empty:
62
+ st.subheader("Available Tables")
63
+ st.dataframe(tables)
64
+
65
+ # Table statistics
66
+ col1, col2, col3, col4 = st.columns(4)
67
+
68
+ try:
69
+ stock_count = pd.read_sql("SELECT COUNT(*) as count FROM stock_data", conn).iloc[0]['count']
70
+ with col1:
71
+ st.metric("Stock Records", stock_count)
72
+ except:
73
+ with col1:
74
+ st.metric("Stock Records", 0)
75
+
76
+ try:
77
+ signals_count = pd.read_sql("SELECT COUNT(*) as count FROM trading_signals", conn).iloc[0]['count']
78
+ with col2:
79
+ st.metric("Trading Signals", signals_count)
80
+ except:
81
+ with col2:
82
+ st.metric("Trading Signals", 0)
83
+
84
+ try:
85
+ indicators_count = pd.read_sql("SELECT COUNT(*) as count FROM technical_indicators", conn).iloc[0]['count']
86
+ with col3:
87
+ st.metric("Technical Indicators", indicators_count)
88
+ except:
89
+ with col3:
90
+ st.metric("Technical Indicators", 0)
91
+
92
+ try:
93
+ models_count = pd.read_sql("SELECT COUNT(*) as count FROM model_metrics", conn).iloc[0]['count']
94
+ with col4:
95
+ st.metric("Model Metrics", models_count)
96
+ except:
97
+ with col4:
98
+ st.metric("Model Metrics", 0)
99
+ else:
100
+ st.info("No tables found. Use the main app to generate data.")
101
+
102
+ def show_tables(conn):
103
+ """Show table schemas"""
104
+ st.header("Table Schemas")
105
+
106
+ # Get all tables
107
+ tables_query = "SELECT name FROM sqlite_master WHERE type='table'"
108
+ tables = pd.read_sql(tables_query, conn)
109
+
110
+ for table_name in tables['name']:
111
+ st.subheader(f"Table: {table_name}")
112
+
113
+ # Get table schema
114
+ schema_query = f"PRAGMA table_info({table_name})"
115
+ schema = pd.read_sql(schema_query, conn)
116
+ st.dataframe(schema)
117
+
118
+ # Get sample data
119
+ try:
120
+ sample_query = f"SELECT * FROM {table_name} LIMIT 3"
121
+ sample = pd.read_sql(sample_query, conn)
122
+ if not sample.empty:
123
+ st.write("Sample Data:")
124
+ st.dataframe(sample)
125
+ except:
126
+ st.write("No sample data available")
127
+
128
+ st.markdown("---")
129
+
130
+ def show_stock_data(conn):
131
+ """Show stock OHLCV data"""
132
+ st.header("Stock Data Analysis")
133
+
134
+ try:
135
+ # Get unique symbols
136
+ symbols_query = "SELECT DISTINCT symbol FROM stock_data ORDER BY symbol"
137
+ symbols = pd.read_sql(symbols_query, conn)
138
+
139
+ if not symbols.empty:
140
+ selected_symbol = st.selectbox("Select Stock Symbol:", symbols['symbol'].tolist())
141
+
142
+ # Get data for selected symbol
143
+ data_query = f"""
144
+ SELECT * FROM stock_data
145
+ WHERE symbol = '{selected_symbol}'
146
+ ORDER BY date DESC
147
+ LIMIT 100
148
+ """
149
+ stock_data = pd.read_sql(data_query, conn)
150
+
151
+ if not stock_data.empty:
152
+ st.dataframe(stock_data)
153
+
154
+ # Create candlestick chart
155
+ fig = go.Figure(data=go.Candlestick(
156
+ x=stock_data['date'],
157
+ open=stock_data['open_price'],
158
+ high=stock_data['high_price'],
159
+ low=stock_data['low_price'],
160
+ close=stock_data['close_price']
161
+ ))
162
+ fig.update_layout(title=f"{selected_symbol} - Candlestick Chart")
163
+ st.plotly_chart(fig, use_container_width=True)
164
+
165
+ # Volume chart
166
+ fig_vol = px.bar(stock_data, x='date', y='volume', title=f"{selected_symbol} - Volume")
167
+ st.plotly_chart(fig_vol, use_container_width=True)
168
+ else:
169
+ st.info(f"No data found for {selected_symbol}")
170
+ else:
171
+ st.info("No stock data available. Train a model in the main app to generate data.")
172
+ except Exception as e:
173
+ st.error(f"Error loading stock data: {str(e)}")
174
+
175
+ def show_trading_signals(conn):
176
+ """Show trading signals"""
177
+ st.header("Trading Signals Analysis")
178
+
179
+ try:
180
+ signals_query = "SELECT * FROM trading_signals ORDER BY signal_date DESC LIMIT 100"
181
+ signals = pd.read_sql(signals_query, conn)
182
+
183
+ if not signals.empty:
184
+ st.dataframe(signals)
185
+
186
+ # Signal distribution
187
+ col1, col2 = st.columns(2)
188
+
189
+ with col1:
190
+ signal_counts = signals['signal'].value_counts()
191
+ fig_pie = px.pie(values=signal_counts.values, names=signal_counts.index,
192
+ title="Signal Distribution")
193
+ st.plotly_chart(fig_pie, use_container_width=True)
194
+
195
+ with col2:
196
+ fig_conf = px.histogram(signals, x='confidence', title="Confidence Distribution")
197
+ st.plotly_chart(fig_conf, use_container_width=True)
198
+
199
+ # Signals by symbol
200
+ if 'symbol' in signals.columns:
201
+ symbol_signals = signals.groupby('symbol')['signal'].count().reset_index()
202
+ fig_bar = px.bar(symbol_signals, x='symbol', y='signal', title="Signals by Symbol")
203
+ st.plotly_chart(fig_bar, use_container_width=True)
204
+ else:
205
+ st.info("No trading signals found. Generate signals in the main app.")
206
+ except Exception as e:
207
+ st.error(f"Error loading trading signals: {str(e)}")
208
+
209
+ def show_model_metrics(conn):
210
+ """Show model performance metrics"""
211
+ st.header("Model Performance Metrics")
212
+
213
+ try:
214
+ metrics_query = "SELECT * FROM model_metrics ORDER BY training_date DESC"
215
+ metrics = pd.read_sql(metrics_query, conn)
216
+
217
+ if not metrics.empty:
218
+ st.dataframe(metrics)
219
+
220
+ # Performance charts
221
+ col1, col2 = st.columns(2)
222
+
223
+ with col1:
224
+ fig_acc = px.bar(metrics, x='symbol', y='accuracy', title="Model Accuracy")
225
+ st.plotly_chart(fig_acc, use_container_width=True)
226
+
227
+ with col2:
228
+ fig_prec = px.bar(metrics, x='symbol', y='precision_score', title="Model Precision")
229
+ st.plotly_chart(fig_prec, use_container_width=True)
230
+ else:
231
+ st.info("No model metrics found. Train models in the main app.")
232
+ except Exception as e:
233
+ st.error(f"Error loading model metrics: {str(e)}")
234
+
235
+ def show_sql_interface(conn):
236
+ """SQL query interface"""
237
+ st.header("SQL Query Interface")
238
+
239
+ # Quick queries
240
+ st.subheader("Quick Queries")
241
+ col1, col2, col3 = st.columns(3)
242
+
243
+ with col1:
244
+ if st.button("Show All Tables"):
245
+ query = "SELECT name FROM sqlite_master WHERE type='table'"
246
+ result = pd.read_sql(query, conn)
247
+ st.dataframe(result)
248
+
249
+ with col2:
250
+ if st.button("Latest Signals"):
251
+ try:
252
+ query = "SELECT * FROM trading_signals ORDER BY created_at DESC LIMIT 10"
253
+ result = pd.read_sql(query, conn)
254
+ st.dataframe(result)
255
+ except Exception as e:
256
+ st.error(f"Error: {str(e)}")
257
+
258
+ with col3:
259
+ if st.button("Stock Summary"):
260
+ try:
261
+ query = """
262
+ SELECT symbol, COUNT(*) as records,
263
+ MIN(date) as first_date, MAX(date) as last_date
264
+ FROM stock_data
265
+ GROUP BY symbol
266
+ """
267
+ result = pd.read_sql(query, conn)
268
+ st.dataframe(result)
269
+ except Exception as e:
270
+ st.error(f"Error: {str(e)}")
271
+
272
+ # Custom SQL
273
+ st.subheader("Custom SQL Query")
274
+ sql_query = st.text_area(
275
+ "Enter SQL Query:",
276
+ value="SELECT * FROM sqlite_master WHERE type='table';",
277
+ height=100
278
+ )
279
+
280
+ if st.button("Execute Query"):
281
+ try:
282
+ if sql_query.strip():
283
+ result = pd.read_sql(sql_query, conn)
284
+ st.dataframe(result)
285
+ st.success(f"Query executed successfully. {len(result)} rows returned.")
286
+ except Exception as e:
287
+ st.error(f"Query error: {str(e)}")
288
+
289
+ if __name__ == "__main__":
290
+ main()
model_trainer.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ from sklearn.ensemble import RandomForestClassifier
4
+ from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
5
+ from sklearn.metrics import classification_report, confusion_matrix, accuracy_score, precision_score, recall_score
6
+ from sklearn.preprocessing import StandardScaler
7
+ import xgboost as xgb
8
+ import warnings
9
+ warnings.filterwarnings('ignore')
10
+
11
+ class ModelTrainer:
12
+ def __init__(self):
13
+ self.scaler = StandardScaler()
14
+
15
+ def train_model(self, features, labels, model_type='random_forest'):
16
+ """Train machine learning model for trading signals"""
17
+ try:
18
+ if len(features) == 0 or len(labels) == 0:
19
+ raise ValueError("No data available for training")
20
+
21
+ # Handle infinite and NaN values
22
+ features = features.replace([np.inf, -np.inf], np.nan)
23
+ features = features.fillna(features.mean())
24
+
25
+ # Split data
26
+ X_train, X_test, y_train, y_test = train_test_split(
27
+ features, labels, test_size=0.2, random_state=42, stratify=labels
28
+ )
29
+
30
+ # Scale features
31
+ X_train_scaled = self.scaler.fit_transform(X_train)
32
+ X_test_scaled = self.scaler.transform(X_test)
33
+
34
+ # Train model
35
+ if model_type == 'random_forest':
36
+ model = self.train_random_forest(X_train_scaled, y_train)
37
+ elif model_type == 'xgboost':
38
+ model = self.train_xgboost(X_train_scaled, y_train)
39
+ else:
40
+ raise ValueError(f"Unsupported model type: {model_type}")
41
+
42
+ # Evaluate model
43
+ metrics = self.evaluate_model(model, X_test_scaled, y_test)
44
+
45
+ # Feature importance
46
+ feature_importance = self.get_feature_importance(model, features.columns)
47
+
48
+ # Create final model pipeline that includes scaling
49
+ final_model = ModelPipeline(self.scaler, model)
50
+
51
+ return final_model, features.columns.tolist(), metrics
52
+
53
+ except Exception as e:
54
+ print(f"Error training model: {str(e)}")
55
+ raise e
56
+
57
+ def train_random_forest(self, X_train, y_train):
58
+ """Train Random Forest model with hyperparameter tuning"""
59
+ try:
60
+ # Define parameter grid for tuning
61
+ param_grid = {
62
+ 'n_estimators': [100, 200],
63
+ 'max_depth': [10, 15, None],
64
+ 'min_samples_split': [2, 5],
65
+ 'min_samples_leaf': [1, 2]
66
+ }
67
+
68
+ # Create base model
69
+ rf = RandomForestClassifier(random_state=42, class_weight='balanced')
70
+
71
+ # Grid search with cross-validation
72
+ grid_search = GridSearchCV(
73
+ rf, param_grid, cv=5, scoring='accuracy', n_jobs=-1
74
+ )
75
+
76
+ grid_search.fit(X_train, y_train)
77
+
78
+ return grid_search.best_estimator_
79
+
80
+ except Exception as e:
81
+ print(f"Error training Random Forest: {str(e)}")
82
+ # Fallback to basic model
83
+ return RandomForestClassifier(
84
+ n_estimators=100, random_state=42, class_weight='balanced'
85
+ ).fit(X_train, y_train)
86
+
87
+ def train_xgboost(self, X_train, y_train):
88
+ """Train XGBoost model"""
89
+ try:
90
+ # Convert labels to ensure compatibility
91
+ label_mapping = {-1: 0, 0: 1, 1: 2}
92
+ y_train_mapped = np.array([label_mapping[label] for label in y_train])
93
+
94
+ model = xgb.XGBClassifier(
95
+ n_estimators=100,
96
+ max_depth=6,
97
+ learning_rate=0.1,
98
+ random_state=42,
99
+ eval_metric='mlogloss'
100
+ )
101
+
102
+ model.fit(X_train, y_train_mapped)
103
+
104
+ # Wrap model to handle label mapping
105
+ return XGBoostWrapper(model, label_mapping)
106
+
107
+ except Exception as e:
108
+ print(f"Error training XGBoost: {str(e)}")
109
+ raise e
110
+
111
+ def evaluate_model(self, model, X_test, y_test):
112
+ """Evaluate model performance"""
113
+ try:
114
+ y_pred = model.predict(X_test)
115
+
116
+ # Calculate metrics
117
+ accuracy = accuracy_score(y_test, y_pred)
118
+ precision = precision_score(y_test, y_pred, average='weighted', zero_division=0)
119
+ recall = recall_score(y_test, y_pred, average='weighted', zero_division=0)
120
+
121
+ metrics = {
122
+ 'accuracy': accuracy,
123
+ 'precision': precision,
124
+ 'recall': recall,
125
+ 'classification_report': classification_report(y_test, y_pred, zero_division=0),
126
+ 'confusion_matrix': confusion_matrix(y_test, y_pred).tolist()
127
+ }
128
+
129
+ return metrics
130
+
131
+ except Exception as e:
132
+ print(f"Error evaluating model: {str(e)}")
133
+ return {'accuracy': 0.0, 'precision': 0.0, 'recall': 0.0}
134
+
135
+ def get_feature_importance(self, model, feature_names):
136
+ """Get feature importance from trained model"""
137
+ try:
138
+ if hasattr(model, 'feature_importances_'):
139
+ importance = model.feature_importances_
140
+ elif hasattr(model, 'model') and hasattr(model.model, 'feature_importances_'):
141
+ importance = model.model.feature_importances_
142
+ else:
143
+ return {}
144
+
145
+ feature_importance = dict(zip(feature_names, importance))
146
+
147
+ # Sort by importance
148
+ sorted_importance = dict(sorted(feature_importance.items(),
149
+ key=lambda x: x[1], reverse=True))
150
+
151
+ return sorted_importance
152
+
153
+ except Exception as e:
154
+ print(f"Error getting feature importance: {str(e)}")
155
+ return {}
156
+
157
+ class ModelPipeline:
158
+ """Pipeline that combines scaling and model prediction"""
159
+ def __init__(self, scaler, model):
160
+ self.scaler = scaler
161
+ self.model = model
162
+
163
+ def predict(self, X):
164
+ """Make predictions with scaling"""
165
+ X_scaled = self.scaler.transform(X)
166
+ return self.model.predict(X_scaled)
167
+
168
+ def predict_proba(self, X):
169
+ """Make probability predictions with scaling"""
170
+ X_scaled = self.scaler.transform(X)
171
+ return self.model.predict_proba(X_scaled)
172
+
173
+ class XGBoostWrapper:
174
+ """Wrapper for XGBoost to handle label mapping"""
175
+ def __init__(self, model, label_mapping):
176
+ self.model = model
177
+ self.label_mapping = label_mapping
178
+ self.reverse_mapping = {v: k for k, v in label_mapping.items()}
179
+
180
+ def predict(self, X):
181
+ """Predict with label remapping"""
182
+ pred_mapped = self.model.predict(X)
183
+ return np.array([self.reverse_mapping[pred] for pred in pred_mapped])
184
+
185
+ def predict_proba(self, X):
186
+ """Predict probabilities"""
187
+ return self.model.predict_proba(X)
pyproject.toml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "repl-nix-workspace"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "h2>=4.2.0",
8
+ "nsepython>=2.97",
9
+ "numpy>=2.3.0",
10
+ "pandas>=2.3.0",
11
+ "plotly>=6.1.2",
12
+ "scikit-learn>=1.7.0",
13
+ "sqlalchemy>=2.0.41",
14
+ "streamlit>=1.46.0",
15
+ "ta>=0.11.0",
16
+ "xgboost>=3.0.2",
17
+ "yfinance>=0.2.63",
18
+ ]
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit>=1.30.0
2
+ pandas>=2.0.0
3
+ numpy>=1.23.0
4
+ yfinance>=0.2.36
5
+ plotly>=5.18.0
6
+ scikit-learn>=1.2.0
7
+ ta>=0.11.0
8
+ sqlalchemy>=2.0.0
9
+ joblib>=1.2.0
10
+ matplotlib>=3.7.0 # If you're plotting manually outside of plotly
run_app.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #!/bin/bash
2
+ export LD_LIBRARY_PATH="/nix/store/055bzdrski1dwqa4km1gxpcjhpn73mng-gcc-10.3.0-lib/lib:/nix/store/026hln0aq1hyshaxsdvhg0kmcm6yf45r-zlib-1.2.13/lib:$LD_LIBRARY_PATH"
3
+ streamlit run app.py --server.port 5005
simple_app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import yfinance as yf
3
+ import plotly.graph_objects as go
4
+ from datetime import datetime, timedelta
5
+ import warnings
6
+ warnings.filterwarnings('ignore')
7
+
8
+ # Configure page
9
+ st.set_page_config(
10
+ page_title="AI Stock Trading Signals",
11
+ page_icon="📈",
12
+ layout="wide"
13
+ )
14
+
15
+ def get_stock_data(symbol, period="3mo"):
16
+ """Get stock data using yfinance"""
17
+ try:
18
+ ticker = yf.Ticker(symbol)
19
+ data = ticker.history(period=period)
20
+ return data
21
+ except Exception as e:
22
+ st.error(f"Error fetching data: {str(e)}")
23
+ return None
24
+
25
+ def get_live_price(stock_symbol):
26
+ """Get live stock price"""
27
+ try:
28
+ # Try nsepython first
29
+ try:
30
+ import nsepython as nse
31
+ stock_name = stock_symbol.replace('.NS', '')
32
+ live_data = nse.equity_quote(stock_name)
33
+ if live_data and 'lastPrice' in live_data:
34
+ return float(live_data['lastPrice'])
35
+ except:
36
+ pass
37
+
38
+ # Fallback to yfinance
39
+ ticker = yf.Ticker(stock_symbol)
40
+ data = ticker.history(period="1d", interval="1m")
41
+ if not data.empty:
42
+ return float(data['Close'].iloc[-1])
43
+
44
+ return None
45
+ except Exception as e:
46
+ st.warning(f"Could not fetch live price: {str(e)}")
47
+ return None
48
+
49
+ def create_simple_chart(stock_symbol):
50
+ """Create simple price chart"""
51
+ try:
52
+ data = get_stock_data(stock_symbol, period="1mo")
53
+ if data is None or data.empty:
54
+ return None
55
+
56
+ # Get last 30 days
57
+ data = data.tail(30)
58
+
59
+ fig = go.Figure()
60
+
61
+ # Add candlestick chart
62
+ fig.add_trace(go.Candlestick(
63
+ x=data.index,
64
+ open=data['Open'],
65
+ high=data['High'],
66
+ low=data['Low'],
67
+ close=data['Close'],
68
+ name='Price'
69
+ ))
70
+
71
+ # Add simple moving averages
72
+ sma_20 = data['Close'].rolling(window=20).mean()
73
+ sma_50 = data['Close'].rolling(window=50).mean()
74
+
75
+ fig.add_trace(go.Scatter(
76
+ x=data.index,
77
+ y=sma_20,
78
+ name='SMA 20',
79
+ line=dict(color='orange', width=2)
80
+ ))
81
+
82
+ fig.add_trace(go.Scatter(
83
+ x=data.index,
84
+ y=sma_50,
85
+ name='SMA 50',
86
+ line=dict(color='blue', width=2)
87
+ ))
88
+
89
+ fig.update_layout(
90
+ title=f"{stock_symbol} - Price Chart",
91
+ xaxis_rangeslider_visible=False,
92
+ height=600,
93
+ yaxis_title="Price (₹)"
94
+ )
95
+
96
+ return fig
97
+
98
+ except Exception as e:
99
+ st.error(f"Error creating chart: {str(e)}")
100
+ return None
101
+
102
+ def simple_trading_signal(stock_symbol):
103
+ """Generate simple trading signal based on moving averages"""
104
+ try:
105
+ data = get_stock_data(stock_symbol, period="3mo")
106
+ if data is None or data.empty:
107
+ return None, "No data available"
108
+
109
+ # Calculate simple moving averages
110
+ current_price = data['Close'].iloc[-1]
111
+ sma_20 = data['Close'].rolling(window=20).mean().iloc[-1]
112
+ sma_50 = data['Close'].rolling(window=50).mean().iloc[-1]
113
+
114
+ # Simple signal logic
115
+ if current_price > sma_20 and sma_20 > sma_50:
116
+ signal = "BUY"
117
+ confidence = 0.75
118
+ elif current_price < sma_20 and sma_20 < sma_50:
119
+ signal = "SELL"
120
+ confidence = 0.75
121
+ else:
122
+ signal = "HOLD"
123
+ confidence = 0.60
124
+
125
+ return {
126
+ 'signal': signal,
127
+ 'confidence': confidence,
128
+ 'current_price': current_price,
129
+ 'sma_20': sma_20,
130
+ 'sma_50': sma_50
131
+ }, None
132
+
133
+ except Exception as e:
134
+ return None, f"Error generating signal: {str(e)}"
135
+
136
+ def main():
137
+ st.title("📈 Stock Trading Signals App")
138
+ st.markdown("### NSE Stock Analysis (Simplified Version)")
139
+
140
+ # Sidebar for stock selection
141
+ st.sidebar.header("Stock Selection")
142
+
143
+ # Stock options
144
+ stock_options = {
145
+ "Reliance Industries": "RELIANCE.NS",
146
+ "Tata Consultancy Services": "TCS.NS",
147
+ "Infosys": "INFY.NS"
148
+ }
149
+
150
+ selected_stock_name = st.sidebar.selectbox(
151
+ "Choose a stock:",
152
+ list(stock_options.keys())
153
+ )
154
+
155
+ selected_stock = stock_options[selected_stock_name]
156
+
157
+ # Main content
158
+ st.header("📊 Live Market Data")
159
+
160
+ col1, col2 = st.columns(2)
161
+
162
+ with col1:
163
+ if st.button("🔄 Get Live Price", type="primary"):
164
+ live_price = get_live_price(selected_stock)
165
+ if live_price:
166
+ st.metric("Live Price (LTP)", f"₹{live_price:.2f}")
167
+ else:
168
+ st.warning("Could not fetch live price")
169
+
170
+ # Trading signal section
171
+ st.header("🎯 Trading Signal")
172
+
173
+ if st.button("📈 Get Signal", type="primary"):
174
+ signal_result, error = simple_trading_signal(selected_stock)
175
+
176
+ if signal_result:
177
+ signal = signal_result['signal']
178
+ confidence = signal_result['confidence']
179
+
180
+ # Display signal with color coding
181
+ if signal == "BUY":
182
+ st.success(f"🟢 **{signal}** Signal")
183
+ elif signal == "SELL":
184
+ st.error(f"🔴 **{signal}** Signal")
185
+ else:
186
+ st.info(f"🟡 **{signal}** Signal")
187
+
188
+ # Display metrics
189
+ col1, col2, col3 = st.columns(3)
190
+ with col1:
191
+ st.metric("Confidence", f"{confidence:.1%}")
192
+ with col2:
193
+ st.metric("Current Price", f"₹{signal_result['current_price']:.2f}")
194
+ with col3:
195
+ st.metric("SMA 20", f"₹{signal_result['sma_20']:.2f}")
196
+
197
+ else:
198
+ st.error(f"Signal generation failed: {error}")
199
+
200
+ # Chart section
201
+ st.header("📈 Price Chart")
202
+
203
+ if st.button("📊 Show Chart"):
204
+ chart = create_simple_chart(selected_stock)
205
+ if chart:
206
+ st.plotly_chart(chart, use_container_width=True)
207
+
208
+ # Information section
209
+ st.header("ℹ️ About This App")
210
+
211
+ col1, col2 = st.columns(2)
212
+ with col1:
213
+ st.info("**Signal Logic:**\n- BUY: Price > SMA20 > SMA50\n- SELL: Price < SMA20 < SMA50\n- HOLD: Mixed signals")
214
+
215
+ with col2:
216
+ st.info("**Data Source:**\n- Yahoo Finance (yfinance)\n- NSE Python for live prices\n- 3 months historical data")
217
+
218
+ if __name__ == "__main__":
219
+ main()
stock_trading.db ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c8187e8a6b515678267a307482a177aac4ce710bcf83f5eb26d5afd5f4a1743b
3
+ size 794624
technical_indicators.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import ta
4
+ from ta.utils import dropna
5
+ import warnings
6
+ warnings.filterwarnings('ignore')
7
+
8
+ class TechnicalIndicators:
9
+ def __init__(self):
10
+ pass
11
+
12
+ def calculate_all_indicators(self, data):
13
+ """Calculate comprehensive set of technical indicators"""
14
+ try:
15
+ df = data.copy()
16
+
17
+ # Ensure we have required columns
18
+ if not all(col in df.columns for col in ['Open', 'High', 'Low', 'Close', 'Volume']):
19
+ print("Missing required OHLCV columns")
20
+ return df
21
+
22
+ # Clean data and ensure sufficient data points
23
+ df = df.dropna()
24
+
25
+ if len(df) < 30: # Reduced minimum for testing
26
+ print(f"Insufficient data: {len(df)} rows, need at least 30")
27
+ return df
28
+
29
+ print(f"Calculating indicators for {len(df)} data points...")
30
+
31
+ # Basic Moving Averages
32
+ df = self.add_moving_averages(df)
33
+
34
+ # RSI
35
+ df = self.add_rsi(df)
36
+
37
+ # MACD
38
+ df = self.add_macd(df)
39
+
40
+ # Bollinger Bands
41
+ df = self.add_bollinger_bands(df)
42
+
43
+ # Stochastic Oscillator
44
+ df = self.add_stochastic(df)
45
+
46
+ # Williams %R
47
+ df = self.add_williams_r(df)
48
+
49
+ # Average True Range (ATR)
50
+ df = self.add_atr(df)
51
+
52
+ # Additional indicators
53
+ df = self.add_additional_indicators(df)
54
+
55
+ # Volume indicators
56
+ df = self.add_volume_indicators(df)
57
+
58
+ # Count new indicators added
59
+ original_cols = ['Open', 'High', 'Low', 'Close', 'Volume', 'Dividends', 'Stock Splits']
60
+ new_indicators = [col for col in df.columns if col not in original_cols]
61
+ print(f"Successfully calculated {len(new_indicators)} technical indicators")
62
+
63
+ return df
64
+
65
+ except Exception as e:
66
+ print(f"Error calculating technical indicators: {str(e)}")
67
+ return data
68
+
69
+ def add_moving_averages(self, df):
70
+ """Add various moving averages"""
71
+ try:
72
+ # Simple Moving Averages using pandas rolling
73
+ df['SMA_10'] = df['Close'].rolling(window=10).mean()
74
+ df['SMA_20'] = df['Close'].rolling(window=20).mean()
75
+ df['SMA_50'] = df['Close'].rolling(window=50).mean()
76
+
77
+ # Exponential Moving Averages using pandas ewm
78
+ df['EMA_12'] = df['Close'].ewm(span=12).mean()
79
+ df['EMA_20'] = df['Close'].ewm(span=20).mean()
80
+ df['EMA_26'] = df['Close'].ewm(span=26).mean()
81
+
82
+ return df
83
+ except Exception as e:
84
+ print(f"Error adding moving averages: {str(e)}")
85
+ return df
86
+
87
+ def add_rsi(self, df, window=14):
88
+ """Add Relative Strength Index"""
89
+ try:
90
+ # Calculate RSI manually
91
+ delta = df['Close'].diff()
92
+ gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
93
+ loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
94
+ rs = gain / loss
95
+ df['RSI'] = 100 - (100 / (1 + rs))
96
+ return df
97
+ except Exception as e:
98
+ print(f"Error adding RSI: {str(e)}")
99
+ return df
100
+
101
+ def add_macd(self, df):
102
+ """Add MACD indicators"""
103
+ try:
104
+ # Calculate MACD manually
105
+ ema_12 = df['Close'].ewm(span=12).mean()
106
+ ema_26 = df['Close'].ewm(span=26).mean()
107
+ df['MACD'] = ema_12 - ema_26
108
+ df['MACD_signal'] = df['MACD'].ewm(span=9).mean()
109
+ df['MACD_histogram'] = df['MACD'] - df['MACD_signal']
110
+ return df
111
+ except Exception as e:
112
+ print(f"Error adding MACD: {str(e)}")
113
+ return df
114
+
115
+ def add_bollinger_bands(self, df, window=20, std=2):
116
+ """Add Bollinger Bands"""
117
+ try:
118
+ # Calculate Bollinger Bands manually
119
+ df['BB_middle'] = df['Close'].rolling(window=window).mean()
120
+ bb_std = df['Close'].rolling(window=window).std()
121
+ df['BB_upper'] = df['BB_middle'] + (bb_std * std)
122
+ df['BB_lower'] = df['BB_middle'] - (bb_std * std)
123
+ df['BB_width'] = (df['BB_upper'] - df['BB_lower']) / df['BB_middle']
124
+ df['BB_position'] = (df['Close'] - df['BB_lower']) / (df['BB_upper'] - df['BB_lower'])
125
+ return df
126
+ except Exception as e:
127
+ print(f"Error adding Bollinger Bands: {str(e)}")
128
+ return df
129
+
130
+ def add_stochastic(self, df, k_window=14, d_window=3):
131
+ """Add Stochastic Oscillator"""
132
+ try:
133
+ stoch = ta.momentum.StochasticOscillator(df['High'], df['Low'], df['Close'],
134
+ window=k_window, smooth_window=d_window)
135
+ df['Stoch_K'] = stoch.stoch()
136
+ df['Stoch_D'] = stoch.stoch_signal()
137
+ return df
138
+ except Exception as e:
139
+ print(f"Error adding Stochastic: {str(e)}")
140
+ return df
141
+
142
+ def add_williams_r(self, df, window=14):
143
+ """Add Williams %R"""
144
+ try:
145
+ df['Williams_R'] = ta.momentum.williams_r(df['High'], df['Low'], df['Close'], window=window)
146
+ return df
147
+ except Exception as e:
148
+ print(f"Error adding Williams %R: {str(e)}")
149
+ return df
150
+
151
+ def add_atr(self, df, window=14):
152
+ """Add Average True Range"""
153
+ try:
154
+ df['ATR'] = ta.volatility.average_true_range(df['High'], df['Low'], df['Close'], window=window)
155
+ df['ATR_ratio'] = df['ATR'] / df['Close'] # Normalized ATR
156
+ return df
157
+ except Exception as e:
158
+ print(f"Error adding ATR: {str(e)}")
159
+ return df
160
+
161
+ def add_additional_indicators(self, df):
162
+ """Add additional technical indicators"""
163
+ try:
164
+ # Commodity Channel Index
165
+ df['CCI'] = ta.trend.cci(df['High'], df['Low'], df['Close'], window=20)
166
+
167
+ # Rate of Change
168
+ df['ROC'] = ta.momentum.roc(df['Close'], window=12)
169
+
170
+ # Money Flow Index
171
+ df['MFI'] = ta.volume.money_flow_index(df['High'], df['Low'], df['Close'], df['Volume'], window=14)
172
+
173
+ # Parabolic SAR
174
+ df['PSAR'] = ta.trend.psar_down(df['High'], df['Low'], df['Close'])
175
+
176
+ # Aroon indicators
177
+ aroon = ta.trend.AroonIndicator(df['High'], df['Low'], window=25)
178
+ df['Aroon_Up'] = aroon.aroon_up()
179
+ df['Aroon_Down'] = aroon.aroon_down()
180
+
181
+ return df
182
+ except Exception as e:
183
+ print(f"Error adding additional indicators: {str(e)}")
184
+ return df
185
+
186
+ def add_volume_indicators(self, df):
187
+ """Add volume-based indicators"""
188
+ try:
189
+ # Volume Moving Average
190
+ df['Volume_SMA'] = ta.volume.volume_sma(df['Close'], df['Volume'], window=20)
191
+
192
+ # Volume Weighted Average Price (VWAP)
193
+ df['VWAP'] = ta.volume.volume_weighted_average_price(df['High'], df['Low'], df['Close'], df['Volume'])
194
+
195
+ # On Balance Volume
196
+ df['OBV'] = ta.volume.on_balance_volume(df['Close'], df['Volume'])
197
+
198
+ # Accumulation/Distribution Line
199
+ df['ADL'] = ta.volume.acc_dist_index(df['High'], df['Low'], df['Close'], df['Volume'])
200
+
201
+ # Chaikin Money Flow
202
+ df['CMF'] = ta.volume.chaikin_money_flow(df['High'], df['Low'], df['Close'], df['Volume'], window=20)
203
+
204
+ return df
205
+ except Exception as e:
206
+ print(f"Error adding volume indicators: {str(e)}")
207
+ return df
208
+
209
+ def get_indicator_summary(self, df):
210
+ """Get summary of all calculated indicators"""
211
+ try:
212
+ indicator_columns = [col for col in df.columns if col not in ['Open', 'High', 'Low', 'Close', 'Volume']]
213
+
214
+ summary = {
215
+ 'total_indicators': len(indicator_columns),
216
+ 'trend_indicators': [col for col in indicator_columns if any(x in col for x in ['SMA', 'EMA', 'MACD', 'PSAR', 'Aroon'])],
217
+ 'momentum_indicators': [col for col in indicator_columns if any(x in col for x in ['RSI', 'Stoch', 'Williams', 'ROC', 'CCI'])],
218
+ 'volatility_indicators': [col for col in indicator_columns if any(x in col for x in ['BB', 'ATR'])],
219
+ 'volume_indicators': [col for col in indicator_columns if any(x in col for x in ['Volume', 'VWAP', 'OBV', 'ADL', 'CMF', 'MFI'])]
220
+ }
221
+
222
+ return summary
223
+ except Exception as e:
224
+ print(f"Error getting indicator summary: {str(e)}")
225
+ return {}
uv.lock ADDED
The diff for this file is too large to render. See raw diff