Spaces:
Running
Running
earnliners
commited on
Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
import
|
2 |
-
from datetime import datetime, timedelta
|
3 |
import yfinance as yf
|
|
|
4 |
import numpy as np
|
5 |
import pandas as pd
|
6 |
from sklearn.decomposition import PCA
|
@@ -9,6 +9,25 @@ from sklearn.ensemble import RandomForestClassifier
|
|
9 |
import shap
|
10 |
import matplotlib.pyplot as plt
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
class DataFetcher:
|
13 |
"""Fetches historical financial data using yfinance."""
|
14 |
def __init__(self, ticker, nb_days):
|
@@ -21,8 +40,8 @@ class DataFetcher:
|
|
21 |
end_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
22 |
start_date = end_date - timedelta(days=self.nb_days)
|
23 |
end_date = end_date + timedelta(days=1)
|
|
|
24 |
self.data = yf.download(self.ticker, start=start_date, end=end_date, interval="1h")
|
25 |
-
return self.data
|
26 |
|
27 |
class FinancialDataProcessor:
|
28 |
"""Processes financial data to calculate returns, scenarios, and probabilities."""
|
@@ -111,9 +130,9 @@ class StrategyBuilder:
|
|
111 |
def analyze_feature_importance(self, shap_values, feature_names):
|
112 |
"""Analyzes feature importance based on SHAP values."""
|
113 |
if isinstance(shap_values, list):
|
114 |
-
shap_values = shap_values[1]
|
115 |
|
116 |
-
if len(shap_values.shape) == 3:
|
117 |
shap_values = shap_values[:, :, 1]
|
118 |
|
119 |
mean_abs_shap = np.mean(np.abs(shap_values), axis=0)
|
@@ -126,6 +145,8 @@ class StrategyBuilder:
|
|
126 |
'Mean_Abs_SHAP': mean_abs_shap
|
127 |
}).sort_values(by='Mean_Abs_SHAP', ascending=False)
|
128 |
|
|
|
|
|
129 |
return feature_importance
|
130 |
|
131 |
def refine_thresholds(self, feature_importance, buy_threshold=0.5, sell_threshold=0.5):
|
@@ -170,13 +191,18 @@ class Backtester:
|
|
170 |
|
171 |
return portfolio_values, position, entry_price
|
172 |
|
173 |
-
def
|
174 |
-
"""Runs the complete trading analysis."""
|
175 |
try:
|
176 |
-
|
177 |
-
|
|
|
|
|
178 |
|
179 |
-
|
|
|
|
|
|
|
|
|
180 |
processed_data = processor.calculate_returns().calculate_probabilities()
|
181 |
|
182 |
pca_transformer = PCATransformer(n_components=1)
|
@@ -194,223 +220,30 @@ def run_analysis():
|
|
194 |
portfolio_values, final_position, entry_price = backtester.backtest(buy_threshold, sell_threshold)
|
195 |
|
196 |
last_row = processed_data.iloc[-1]
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
return True
|
217 |
|
218 |
except Exception as e:
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
# Run analysis automatically on page load
|
227 |
-
run_analysis()
|
228 |
-
|
229 |
-
# Auto-refresh every 5 minutes
|
230 |
-
st.empty()
|
231 |
-
st.markdown("*Data updates automatically every 5 minutes*")
|
232 |
-
if st.button("Refresh Now"):
|
233 |
-
run_analysis()
|
234 |
-
|
235 |
-
# Educational Slides Section
|
236 |
-
st.header("Educational Slides")
|
237 |
-
|
238 |
-
with st.expander("Slide 1: Introduction", expanded=False):
|
239 |
-
st.subheader("Real-Time Crypto Trading Bot Using Machine Learning and PCA")
|
240 |
-
st.markdown("""
|
241 |
-
**Subtitle:** Leveraging Financial Data Analysis for Optimal Trading Decisions
|
242 |
-
|
243 |
-
**Overview:**
|
244 |
-
This system integrates real-time financial data, machine learning, and principal component analysis (PCA)
|
245 |
-
to automate trading decisions in cryptocurrency markets.
|
246 |
-
""")
|
247 |
-
|
248 |
-
with st.expander("Slide 2: Objective", expanded=False):
|
249 |
-
st.subheader("Main Goals")
|
250 |
-
st.markdown("""
|
251 |
-
- Develop an automated trading system that optimizes buy and sell decisions based on historical financial data
|
252 |
-
- Use machine learning models, specifically Random Forest, to predict market movements
|
253 |
-
- Implement Principal Component Analysis (PCA) for dimensionality reduction and feature extraction
|
254 |
-
- Backtest the system and evaluate portfolio performance
|
255 |
-
""")
|
256 |
-
|
257 |
-
with st.expander("Slide 3: Key Concepts", expanded=False):
|
258 |
-
st.subheader("Core Technologies and Methods")
|
259 |
-
st.markdown("""
|
260 |
-
- **Logarithmic Return:** A continuous-time return calculation used to model price changes in markets
|
261 |
-
- **Principal Component Analysis (PCA):** A dimensionality reduction technique to extract meaningful features
|
262 |
-
- **Machine Learning:** Using Random Forest to classify "Buy" and "Sell" scenarios
|
263 |
-
- **SHAP Values:** A method to interpret model outputs through feature contribution analysis
|
264 |
-
""")
|
265 |
-
|
266 |
-
with st.expander("Slide 4: Data Collection and Preprocessing", expanded=False):
|
267 |
-
col1, col2 = st.columns(2)
|
268 |
-
with col1:
|
269 |
-
st.markdown("### Data Fetching")
|
270 |
-
st.markdown("""
|
271 |
-
- **Source:** Yahoo Finance (yfinance)
|
272 |
-
- **Data:** Historical cryptocurrency data
|
273 |
-
- **Interval:** Hourly data points
|
274 |
-
- **Period:** Last 50 days
|
275 |
-
""")
|
276 |
-
with col2:
|
277 |
-
st.markdown("### Preprocessing")
|
278 |
-
st.markdown("""
|
279 |
-
- Calculate logarithmic returns
|
280 |
-
- Classify scenarios (Buy/Sell)
|
281 |
-
- Adjust returns for sell scenarios
|
282 |
-
- Handle missing values and outliers
|
283 |
-
""")
|
284 |
-
|
285 |
-
with st.expander("Slide 5: Principal Component Analysis (PCA)", expanded=False):
|
286 |
-
st.subheader("PCA Process")
|
287 |
-
st.markdown("""
|
288 |
-
1. **Data Standardization:**
|
289 |
-
```
|
290 |
-
X' = (X - μ) / σ
|
291 |
-
```
|
292 |
-
|
293 |
-
2. **Covariance Matrix:**
|
294 |
-
```
|
295 |
-
Cov(X) = 1/(n-1) Σ(Xi - μ)(Xi - μ)ᵀ
|
296 |
-
```
|
297 |
-
|
298 |
-
3. **Eigenvalue Decomposition:**
|
299 |
-
- Find principal components
|
300 |
-
- Sort by variance explained
|
301 |
-
|
302 |
-
4. **Dimensionality Reduction:**
|
303 |
-
- Transform data to lower dimensions
|
304 |
-
- Preserve important features
|
305 |
-
""")
|
306 |
-
|
307 |
-
with st.expander("Slide 6: Machine Learning Strategy", expanded=False):
|
308 |
-
col1, col2 = st.columns(2)
|
309 |
-
with col1:
|
310 |
-
st.markdown("### Model Architecture")
|
311 |
-
st.markdown("""
|
312 |
-
- Random Forest Classifier
|
313 |
-
- Feature selection from PCA
|
314 |
-
- Binary classification (Buy/Sell)
|
315 |
-
""")
|
316 |
-
with col2:
|
317 |
-
st.markdown("### Training Process")
|
318 |
-
st.markdown("""
|
319 |
-
- Cross-validation
|
320 |
-
- Hyperparameter tuning
|
321 |
-
- Performance metrics
|
322 |
-
- Model evaluation
|
323 |
-
""")
|
324 |
-
|
325 |
-
with st.expander("Slide 7: SHAP Analysis", expanded=False):
|
326 |
-
st.subheader("Shapley Additive Explanations")
|
327 |
-
st.markdown("""
|
328 |
-
**SHAP Value Formula:**
|
329 |
-
```
|
330 |
-
φᵢ(f) = 1/|N|! Σ [f(S ∪ {i}) - f(S)]
|
331 |
-
```
|
332 |
-
|
333 |
-
**Key Components:**
|
334 |
-
- Feature importance ranking
|
335 |
-
- Individual prediction explanations
|
336 |
-
- Global model interpretation
|
337 |
-
""")
|
338 |
-
|
339 |
-
with st.expander("Slide 8: Strategy Refinement", expanded=False):
|
340 |
-
st.subheader("Dynamic Strategy Adjustment")
|
341 |
-
st.markdown("""
|
342 |
-
1. **Threshold Refinement:**
|
343 |
-
- Use SHAP values to identify key features
|
344 |
-
- Adjust thresholds based on importance
|
345 |
-
|
346 |
-
2. **Signal Processing:**
|
347 |
-
- Buy signal strengthening
|
348 |
-
- Sell signal validation
|
349 |
-
- Risk management integration
|
350 |
-
""")
|
351 |
-
|
352 |
-
with st.expander("Slide 9: Backtesting Framework", expanded=False):
|
353 |
-
st.markdown("""
|
354 |
-
### Portfolio Value Calculation
|
355 |
-
```
|
356 |
-
Portfolio Valueₜ₊₁ = Portfolio Valueₜ × (Pₜ₊₁/Pₜ)
|
357 |
-
```
|
358 |
-
|
359 |
-
### Trading Logic
|
360 |
-
- Buy when probability > threshold
|
361 |
-
- Sell when probability > threshold
|
362 |
-
- Position management
|
363 |
-
|
364 |
-
### Performance Metrics
|
365 |
-
- Total Return
|
366 |
-
- Risk Metrics
|
367 |
-
- Sharpe Ratio
|
368 |
-
""")
|
369 |
-
|
370 |
-
with st.expander("Slide 10: Real-Time Interface", expanded=False):
|
371 |
-
st.subheader("Streamlit Dashboard Features")
|
372 |
-
st.markdown("""
|
373 |
-
- Live trading signals
|
374 |
-
- Portfolio performance tracking
|
375 |
-
- Position monitoring
|
376 |
-
- Automatic updates
|
377 |
-
- Historical performance
|
378 |
-
""")
|
379 |
-
|
380 |
-
with st.expander("Slide 11: Summary", expanded=False):
|
381 |
-
st.markdown("""
|
382 |
-
### Key System Components
|
383 |
-
- Automated trading system
|
384 |
-
- ML & PCA integration
|
385 |
-
- SHAP-based interpretation
|
386 |
-
- Real-time analytics
|
387 |
-
- Performance tracking
|
388 |
-
""")
|
389 |
-
|
390 |
-
with st.expander("Slide 12: Future Improvements", expanded=False):
|
391 |
-
st.markdown("""
|
392 |
-
### Planned Enhancements
|
393 |
-
1. Additional data sources integration
|
394 |
-
2. Advanced optimization techniques
|
395 |
-
3. Live trading deployment
|
396 |
-
4. Enhanced risk management
|
397 |
-
5. Portfolio diversification
|
398 |
-
""")
|
399 |
-
|
400 |
-
with st.expander("Slide 13: Q&A", expanded=False):
|
401 |
-
st.markdown("""
|
402 |
-
### Questions & Discussion
|
403 |
-
|
404 |
-
Thank you for exploring our trading system! For questions or suggestions:
|
405 |
-
- System architecture
|
406 |
-
- Implementation details
|
407 |
-
- Performance metrics
|
408 |
-
- Future developments
|
409 |
-
""")
|
410 |
-
|
411 |
-
# Footer
|
412 |
-
st.markdown("---")
|
413 |
-
st.markdown("*Support Development & Info : ")
|
414 |
-
st.markdown("Send your email in comment to your btc donation at ")
|
415 |
-
st.markdown("1P9R71C6JYJxrPVEzMz4K3hoHYGRW39A9A")
|
416 |
-
# Educational Slides Section dona
|
|
|
1 |
+
import os
|
|
|
2 |
import yfinance as yf
|
3 |
+
from datetime import datetime, timedelta
|
4 |
import numpy as np
|
5 |
import pandas as pd
|
6 |
from sklearn.decomposition import PCA
|
|
|
9 |
import shap
|
10 |
import matplotlib.pyplot as plt
|
11 |
|
12 |
+
class MP3Playlist:
|
13 |
+
"""Handles MP3 playlist functionality by listing and displaying .mp3 files in the app directory."""
|
14 |
+
def __init__(self, root_dir="."):
|
15 |
+
self.root_dir = root_dir
|
16 |
+
self.mp3_files = []
|
17 |
+
|
18 |
+
def scan_for_mp3(self):
|
19 |
+
"""Scans the root directory for .mp3 files."""
|
20 |
+
self.mp3_files = [file for file in os.listdir(self.root_dir) if file.endswith(".mp3")]
|
21 |
+
|
22 |
+
def display_playlist(self):
|
23 |
+
"""Displays the MP3 playlist."""
|
24 |
+
if not self.mp3_files:
|
25 |
+
print("No MP3 files found in the root directory.")
|
26 |
+
else:
|
27 |
+
print("\n=== MP3 Playlist ===")
|
28 |
+
for i, file in enumerate(self.mp3_files, start=1):
|
29 |
+
print(f"{i}. {file}")
|
30 |
+
|
31 |
class DataFetcher:
|
32 |
"""Fetches historical financial data using yfinance."""
|
33 |
def __init__(self, ticker, nb_days):
|
|
|
40 |
end_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
41 |
start_date = end_date - timedelta(days=self.nb_days)
|
42 |
end_date = end_date + timedelta(days=1)
|
43 |
+
print(f"Fetching data from {start_date} to {end_date}")
|
44 |
self.data = yf.download(self.ticker, start=start_date, end=end_date, interval="1h")
|
|
|
45 |
|
46 |
class FinancialDataProcessor:
|
47 |
"""Processes financial data to calculate returns, scenarios, and probabilities."""
|
|
|
130 |
def analyze_feature_importance(self, shap_values, feature_names):
|
131 |
"""Analyzes feature importance based on SHAP values."""
|
132 |
if isinstance(shap_values, list):
|
133 |
+
shap_values = shap_values[1] # Use second class for binary classification
|
134 |
|
135 |
+
if len(shap_values.shape) == 3: # Handle multi-output cases
|
136 |
shap_values = shap_values[:, :, 1]
|
137 |
|
138 |
mean_abs_shap = np.mean(np.abs(shap_values), axis=0)
|
|
|
145 |
'Mean_Abs_SHAP': mean_abs_shap
|
146 |
}).sort_values(by='Mean_Abs_SHAP', ascending=False)
|
147 |
|
148 |
+
print("Feature Importance based on Shapley Values:")
|
149 |
+
print(feature_importance)
|
150 |
return feature_importance
|
151 |
|
152 |
def refine_thresholds(self, feature_importance, buy_threshold=0.5, sell_threshold=0.5):
|
|
|
191 |
|
192 |
return portfolio_values, position, entry_price
|
193 |
|
194 |
+
def main():
|
|
|
195 |
try:
|
196 |
+
# MP3 Playlist Feature
|
197 |
+
playlist = MP3Playlist()
|
198 |
+
playlist.scan_for_mp3()
|
199 |
+
playlist.display_playlist()
|
200 |
|
201 |
+
# Financial Data Processing and Strategy
|
202 |
+
fetcher = DataFetcher(ticker="BTC-USD", nb_days=200)
|
203 |
+
fetcher.fetch_data()
|
204 |
+
|
205 |
+
processor = FinancialDataProcessor(fetcher.data)
|
206 |
processed_data = processor.calculate_returns().calculate_probabilities()
|
207 |
|
208 |
pca_transformer = PCATransformer(n_components=1)
|
|
|
220 |
portfolio_values, final_position, entry_price = backtester.backtest(buy_threshold, sell_threshold)
|
221 |
|
222 |
last_row = processed_data.iloc[-1]
|
223 |
+
print("\n=== Final Position and Market Values ===")
|
224 |
+
print(f"Final Portfolio Value: ${portfolio_values[-1]:.2f}")
|
225 |
+
print(f"Current Position: {final_position or 'No position'}")
|
226 |
+
if final_position:
|
227 |
+
print(f"Entry Price: ${entry_price:.2f}")
|
228 |
+
print(f"Latest Close Price: ${last_row['Close']:.2f}")
|
229 |
+
print("\nDecision Metrics:")
|
230 |
+
print(f"Buy%: {last_row['Buy%']:.4f} | Sell%: {last_row['Sell%']:.4f}")
|
231 |
+
print(f"PCA_Buy%: {last_row['PCA_Buy%']:.4f} | PCA_Sell%: {last_row['PCA_Sell%']:.4f}")
|
232 |
+
print(f"Applied Thresholds - Buy: {buy_threshold:.2f}, Sell: {sell_threshold:.2f}")
|
233 |
+
|
234 |
+
plt.figure(figsize=(12, 6))
|
235 |
+
plt.plot(processed_data.index[1:], portfolio_values, label='Portfolio Value', color='blue')
|
236 |
+
plt.title('Portfolio Value Over Time (Backtest)')
|
237 |
+
plt.xlabel('Date')
|
238 |
+
plt.ylabel('Portfolio Value ($)')
|
239 |
+
plt.legend()
|
240 |
+
plt.grid()
|
241 |
+
plt.show()
|
|
|
242 |
|
243 |
except Exception as e:
|
244 |
+
print(f"An error occurred: {e}")
|
245 |
+
import traceback
|
246 |
+
traceback.print_exc()
|
247 |
+
|
248 |
+
if __name__ == "__main__":
|
249 |
+
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|