LewisBabong commited on
Commit
9da7bae
·
verified ·
1 Parent(s): 7937294

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -199
app.py CHANGED
@@ -1,4 +1,5 @@
1
  import datetime
 
2
  import numpy as np
3
  import pandas as pd
4
  import plotly.graph_objects as go
@@ -7,90 +8,42 @@ import tensorflow as tf
7
  import yfinance as yf
8
  from sklearn.preprocessing import MinMaxScaler
9
  from prophet import Prophet
10
- import os
11
 
12
  # Configuration de la page
13
- st.set_page_config(
14
- page_title="Prédiction des Cours MSFT",
15
- page_icon="📈",
16
- layout="wide",
17
- initial_sidebar_state="expanded"
18
- )
19
-
20
- # CSS personnalisé pour un design moderne
21
  st.markdown("""
22
  <style>
23
  .main-title {
24
  font-size: 2.5rem;
25
- font-weight: 700;
26
- color: #1E3A8A;
27
- margin-bottom: 1rem;
28
- text-align: center;
29
- }
30
- .section-header {
31
- font-size: 1.8rem;
32
- font-weight: 600;
33
- color: #2563EB;
34
- margin-top: 2rem;
35
- margin-bottom: 1rem;
36
- }
37
- .info-box {
38
- background-color: #F8FAFC;
39
- padding: 1rem;
40
- border-radius: 8px;
41
- border-left: 4px solid #2563EB;
42
- margin-bottom: 1rem;
43
- }
44
- .stButton>button {
45
- background-color: #2563EB;
46
- color: white;
47
- border-radius: 8px;
48
- padding: 0.5rem 1rem;
49
- }
50
- .stButton>button:hover {
51
- background-color: #1E40AF;
52
- color: white;
53
- }
54
- .sidebar .sidebar-content {
55
- background-color: #F1F5F9;
56
  }
57
  </style>
 
58
  """, unsafe_allow_html=True)
59
 
60
- # En-tête
61
- st.markdown("<div class='main-title'>📈 Prédiction des Cours de l'Action Microsoft (MSFT)</div>", unsafe_allow_html=True)
62
- st.markdown("<div class='info-box'>Analyse et prévisions des cours de Microsoft (MSFT) basées sur des modèles de Deep Learning (RNN) et Neural Prophet. Personnalisez les paramètres dans la barre latérale pour explorer les données et les prédictions.</div>", unsafe_allow_html=True)
63
-
64
  # Barre latérale
65
- with st.sidebar:
66
- st.header("⚙️ Paramètres")
67
- period = st.selectbox("Période des données", ["4y", "3y", "2y", "1y"], index=0)
68
- model_choice = st.radio("Modèle de prédiction", ["RNN", "Neural Prophet"], index=0)
69
- steps = st.slider("Jours à prédire", min_value=1, max_value=30, value=15, step=1)
70
- st.markdown("### 📊 Indicateurs Techniques")
71
- show_sma = st.checkbox("Moyennes Mobiles (SMA)", value=True)
72
- show_rsi = st.checkbox("RSI", value=True)
73
- show_macd = st.checkbox("MACD", value=True)
74
- show_table = st.checkbox("Afficher le tableau des prédictions", value=True)
75
- download_csv = st.checkbox("Télécharger les prédictions (CSV)", value=True)
76
-
77
- # Fonction pour charger les données
78
  @st.cache_data(ttl=3600)
79
- def load_data(period):
80
- try:
81
- end_date = datetime.datetime.now().strftime('%Y-%m-%d')
82
- start_date = (datetime.datetime.now() - pd.Timedelta(days=365*int(period[0]))).strftime('%Y-%m-%d')
83
- data = yf.download("MSFT", start=start_date, end=end_date)[['Close']]
84
- if data.empty:
85
- raise ValueError("Aucune donnée disponible pour MSFT.")
86
- return data
87
- except Exception as e:
88
- st.error(f"❌ Erreur lors du chargement des données : {str(e)}")
89
- st.stop()
90
 
91
  # Fonction pour calculer les indicateurs techniques
92
  def compute_indicators(df):
93
- df = df.copy()
94
  df['SMA20'] = df['Close'].rolling(window=20).mean()
95
  df['SMA50'] = df['Close'].rolling(window=50).mean()
96
  df['SMA200'] = df['Close'].rolling(window=200).mean()
@@ -108,175 +61,200 @@ def compute_indicators(df):
108
 
109
  df['Buy_RSI'] = df['RSI'] < 30
110
  df['Sell_RSI'] = df['RSI'] > 70
 
111
  df['Buy_MACD'] = (df['MACD'] > df['Signal']) & (df['MACD'].shift(1) <= df['Signal'].shift(1))
112
  df['Sell_MACD'] = (df['MACD'] < df['Signal']) & (df['MACD'].shift(1) >= df['Signal'].shift(1))
 
113
  df['Buy_Signal'] = df['Buy_RSI'] | df['Buy_MACD']
114
  df['Sell_Signal'] = df['Sell_RSI'] | df['Sell_MACD']
115
 
116
  return df
117
 
118
- # Fonction pour les prédictions Prophet
119
  def predict_with_prophet(df, steps):
120
- try:
121
- df_prophet = df.reset_index()[['Date', 'Close']].rename(columns={'Date': 'ds', 'Close': 'y'})
122
- model = Prophet(daily_seasonality=True, yearly_seasonality=True, weekly_seasonality=True)
123
- model.fit(df_prophet)
124
- future = model.make_future_dataframe(periods=steps, freq='B')
125
- forecast = model.predict(future)
126
- forecast_filtered = forecast[['ds', 'yhat']].tail(steps).set_index('ds')
127
- forecast_filtered.columns = ['Prix Prédit']
128
- return forecast_filtered, model, forecast
129
- except Exception as e:
130
- st.error(f"❌ Erreur lors de la prédiction avec Prophet : {str(e)}")
131
- st.stop()
132
-
133
- # Fonction pour les prédictions RNN
134
- def predict_with_rnn(df, steps, model_path="models/model_rnn_MSFT.h5"):
135
- try:
136
- if not os.path.exists(model_path):
137
- raise FileNotFoundError(f"Le modèle RNN ({model_path}) est introuvable.")
138
- model = tf.keras.models.load_model(model_path)
139
- scaler = MinMaxScaler()
140
- scaled_data = scaler.fit_transform(df[['Close']])
141
- last_60_days = scaled_data[-60:]
142
- prediction_list = []
143
- input_seq = last_60_days.copy()
144
- for _ in range(steps):
145
- pred = model.predict(input_seq.reshape(1, -1, 1), verbose=0)[0]
146
- prediction_list.append(pred)
147
- pred = pred.reshape(1, 1)
148
- input_seq = np.append(input_seq[1:], pred, axis=0)
149
- predictions = scaler.inverse_transform(np.array(prediction_list))
150
- future_dates = pd.date_range(start=df.index[-1] + pd.Timedelta(days=1), periods=steps, freq='B')
151
- return pd.DataFrame(predictions, columns=["Prix Prédit"], index=future_dates)
152
- except Exception as e:
153
- st.error(f"❌ Erreur lors de la prédiction avec RNN : {str(e)}")
154
- st.stop()
155
-
156
- # Chargement des données
157
- data = load_data(period)
158
  data = compute_indicators(data)
159
 
160
- # Affichage des données historiques
161
- st.markdown("<div class='section-header'>📊 Données Historiques</div>", unsafe_allow_html=True)
162
- fig_historical = go.Figure()
163
- fig_historical.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Cours de clôture', line=dict(color='#2563EB')))
164
- fig_historical.update_layout(
165
- title="Historique du Cours MSFT",
166
- xaxis_title="Date",
167
- yaxis_title="Prix ($)",
168
- template="plotly_white",
169
- hovermode="x unified"
170
- )
171
- st.plotly_chart(fig_historical, use_container_width=True)
172
-
173
- # Prédictions
174
- st.markdown(f"<div class='section-header'>🔮 Prédictions sur {steps} jours avec {model_choice}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
175
  if model_choice == "Neural Prophet":
176
- pred_df, prophet_model, forecast_full = predict_with_prophet(data, steps)
177
- # Composants Prophet
178
- st.markdown("<div class='info-box'>"
179
- "<h4>🧠 Analyse des Composants Prophet</h4>"
180
- "Ce graphique décompose les prédictions en : <br>"
181
- "- <b>Tendance</b> : Évolution générale du prix.<br>"
182
- "- <b>Saisonnalité</b> : Patterns hebdomadaires et annuels.<br>"
183
- "- <b>Incertitude</b> : Intervalle de confiance des prédictions."
184
- "</div>", unsafe_allow_html=True)
 
 
 
 
 
 
185
  fig_components = prophet_model.plot_components(forecast_full)
186
  st.pyplot(fig_components)
 
 
 
 
 
 
187
  else:
188
- pred_df = predict_with_rnn(data, steps)
 
 
 
 
 
189
 
190
- # Graphique combiné (historique + prédictions)
191
- fig_combined = go.Figure()
192
- fig_combined.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Historique', line=dict(color='#2563EB')))
193
- fig_combined.add_trace(go.Scatter(x=pred_df.index, y=pred_df['Prix Prédit'], mode='lines+markers', name='Prédictions', line=dict(color='#EF4444')))
 
 
 
194
  buy_signals = data[data['Buy_Signal']]
195
  sell_signals = data[data['Sell_Signal']]
196
- fig_combined.add_trace(go.Scatter(
197
- x=buy_signals.index, y=buy_signals['Close'],
198
- mode='markers', name='Signal Achat',
199
- marker=dict(color='green', size=10, symbol='triangle-up')
 
 
 
 
 
 
200
  ))
201
- fig_combined.add_trace(go.Scatter(
202
- x=sell_signals.index, y=sell_signals['Close'],
203
- mode='markers', name='Signal Vente',
204
- marker=dict(color='red', size=10, symbol='triangle-down')
 
 
 
205
  ))
206
- fig_combined.update_layout(
207
- title=f"Prédictions ({model_choice}) sur {steps} jours",
208
- xaxis_title="Date",
209
- yaxis_title="Prix ($)",
210
- template="plotly_white",
211
- hovermode="x unified"
212
- )
213
- st.plotly_chart(fig_combined, use_container_width=True)
214
-
215
- # Indicateurs techniques
216
- st.markdown("<div class='section-header'>📉 Indicateurs Techniques</div>", unsafe_allow_html=True)
217
- st.markdown("<div class='info-box'>"
218
- "Les indicateurs techniques aident à identifier les tendances et opportunités : <br>"
219
- "- <b>SMA</b> : Moyennes mobiles (20, 50, 200 jours).<br>"
220
- "- <b>RSI</b> : Surachat (>70) ou survente (<30).<br>"
221
- "- <b>MACD</b> : Croisements pour détecter des signaux d'achat/vente."
222
- "</div>", unsafe_allow_html=True)
223
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  if show_sma:
225
  fig_sma = go.Figure()
226
- fig_sma.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close', line=dict(color='#2563EB')))
227
- fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA20'], mode='lines', name='SMA20', line=dict(color='#F59E0B')))
228
- fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA50'], mode='lines', name='SMA50', line=dict(color='#10B981')))
229
- fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA200'], mode='lines', name='SMA200', line=dict(color='#EF4444')))
230
- fig_sma.update_layout(title="Moyennes Mobiles", xaxis_title="Date", yaxis_title="Prix ($)", template="plotly_white")
231
  st.plotly_chart(fig_sma, use_container_width=True)
232
 
 
233
  if show_rsi:
234
  fig_rsi = go.Figure()
235
- fig_rsi.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='#F59E0B')))
236
- fig_rsi.add_hline(y=70, line_dash='dash', line_color='red', annotation_text="Surachat")
237
- fig_rsi.add_hline(y=30, line_dash='dash', line_color='green', annotation_text="Survente")
238
- fig_rsi.update_layout(title="RSI (Relative Strength Index)", xaxis_title="Date", yaxis_title="RSI", template="plotly_white")
239
  st.plotly_chart(fig_rsi, use_container_width=True)
240
 
 
241
  if show_macd:
242
  fig_macd = go.Figure()
243
- fig_macd.add_trace(go.Scatter(x=data.index, y=data['MACD'], mode='lines', name='MACD', line=dict(color='#2563EB')))
244
- fig_macd.add_trace(go.Scatter(x=data.index, y=data['Signal'], mode='lines', name='Signal', line=dict(color='#F59E0B')))
245
- fig_macd.update_layout(title="MACD", xaxis_title="Date", yaxis_title="Valeur", template="plotly_white")
246
  st.plotly_chart(fig_macd, use_container_width=True)
247
 
248
- # Tableau des prédictions
249
  if show_table:
250
- st.markdown("<div class='section-header'>🧾 Tableau des Prédictions</div>", unsafe_allow_html=True)
251
- st.dataframe(pred_df.style.format("{:.2f}").background_gradient(cmap='Blues'), use_container_width=True)
252
 
253
  # Statistiques
254
- with st.sidebar:
255
- st.markdown("### 📊 Statistiques")
256
- last_close = float(data['Close'].iloc[-1])
257
- last_pred = float(pred_df['Prix Prédit'].iloc[-1])
258
- st.metric("Prix actuel", f"{last_close:.2f} $")
259
- st.metric("Prix prédit (dernier)", f"{last_pred:.2f} $")
260
- variation = last_pred - last_close
261
- percent = (variation / last_close) * 100
262
- st.metric("Variation", f"{variation:.2f} $", delta=f"{percent:.2f}%")
263
-
264
- # Téléchargement CSV
 
 
265
  if download_csv:
266
- csv = pred_df.to_csv(index=True).encode('utf-8')
267
  st.download_button(
268
- label="📥 Télécharger les prédictions (CSV)",
269
- data=csv,
270
- file_name="msft_predictions.csv",
271
- mime="text/csv",
272
- use_container_width=True
273
  )
274
 
275
- # Pied de page
276
  st.markdown("""
277
- <hr style='margin-top: 2rem;'>
278
- <div style='text-align: center; color: #64748B;'>
279
- Développé par <strong>Ntonga Babong Lewis</strong> | 2025 ©<br>
280
- Propulsé par Streamlit, Prophet, et TensorFlow
281
  </div>
282
  """, unsafe_allow_html=True)
 
1
  import datetime
2
+
3
  import numpy as np
4
  import pandas as pd
5
  import plotly.graph_objects as go
 
8
  import yfinance as yf
9
  from sklearn.preprocessing import MinMaxScaler
10
  from prophet import Prophet
 
11
 
12
  # Configuration de la page
13
+ st.set_page_config(page_title="Prédiction MSFT", layout="wide")
14
+
15
+ # En-tête
 
 
 
 
 
16
  st.markdown("""
17
  <style>
18
  .main-title {
19
  font-size: 2.5rem;
20
+ font-weight: bold;
21
+ color: #2E86C1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  }
23
  </style>
24
+ <div class='main-title'>📈 Prédiction des Cours de l'Action Microsoft (MSFT)</div>
25
  """, unsafe_allow_html=True)
26
 
 
 
 
 
27
  # Barre latérale
28
+ st.sidebar.title("🔧 Paramètres de Prédiction")
29
+ st.sidebar.markdown("## 📈 Indicateurs techniques")
30
+ show_sma = st.sidebar.checkbox("Afficher SMA (20/50/200)", value=True)
31
+ show_rsi = st.sidebar.checkbox("Afficher RSI", value=True)
32
+ show_macd = st.sidebar.checkbox("Afficher MACD", value=True)
33
+ model_choice = st.sidebar.radio("Modèle utilisé", ["RNN", "Neural Prophet"])
34
+ steps = st.sidebar.slider("Jours à prédire", 1, 30, 15)
35
+ show_table = st.sidebar.checkbox("Afficher les valeurs prédictives", True)
36
+ download_csv = st.sidebar.checkbox("Téléchargement CSV", True)
37
+
38
+
39
+ # Données historiques
 
40
  @st.cache_data(ttl=3600)
41
+ def load_data():
42
+ return yf.download("MSFT", start="2020-01-01", end=datetime.datetime.now().strftime('%Y-%m-%d'))[['Close']]
43
+
 
 
 
 
 
 
 
 
44
 
45
  # Fonction pour calculer les indicateurs techniques
46
  def compute_indicators(df):
 
47
  df['SMA20'] = df['Close'].rolling(window=20).mean()
48
  df['SMA50'] = df['Close'].rolling(window=50).mean()
49
  df['SMA200'] = df['Close'].rolling(window=200).mean()
 
61
 
62
  df['Buy_RSI'] = df['RSI'] < 30
63
  df['Sell_RSI'] = df['RSI'] > 70
64
+
65
  df['Buy_MACD'] = (df['MACD'] > df['Signal']) & (df['MACD'].shift(1) <= df['Signal'].shift(1))
66
  df['Sell_MACD'] = (df['MACD'] < df['Signal']) & (df['MACD'].shift(1) >= df['Signal'].shift(1))
67
+
68
  df['Buy_Signal'] = df['Buy_RSI'] | df['Buy_MACD']
69
  df['Sell_Signal'] = df['Sell_RSI'] | df['Sell_MACD']
70
 
71
  return df
72
 
73
+
74
  def predict_with_prophet(df, steps):
75
+ df = df.copy()
76
+ if 'Date' not in df.columns or 'Close' not in df.columns:
77
+ df = df.rename(columns={'ds': 'Date', 'y': 'Close'})
78
+
79
+ df_prophet = df.reset_index()[['Date', 'Close']]
80
+ df_prophet.columns = ['ds', 'y']
81
+
82
+ model = Prophet(daily_seasonality=True)
83
+ model.fit(df_prophet)
84
+
85
+ future = model.make_future_dataframe(periods=steps)
86
+ forecast = model.predict(future)
87
+
88
+ forecast_filtered = forecast[['ds', 'yhat']].set_index('ds').tail(steps)
89
+ forecast_filtered.columns = ['Prix Prédit']
90
+ return forecast_filtered, model, forecast
91
+
92
+
93
+ data = load_data()
94
+
95
+ if data.empty:
96
+ st.error("❌ Échec du chargement des données. Aucune donnée disponible pour MSFT.")
97
+ st.stop()
98
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  data = compute_indicators(data)
100
 
101
+ st.subheader("📊 Évolution Historique du Cours")
102
+ st.line_chart(data['Close'])
103
+
104
+ # Normalisation
105
+ scaler = MinMaxScaler()
106
+ scaled_data = scaler.fit_transform(data[['Close']])
107
+ last_60_days = scaled_data[-60:]
108
+
109
+ # Chargement du modèle
110
+ model_path = "model_lstm_MSFT.h5" if model_choice == "LSTM" else "model_rnn_MSFT.h5"
111
+ model = tf.keras.models.load_model(model_path)
112
+
113
+
114
+ # Fonction de prédiction
115
+ def predict_next_days(model, last_sequence, steps=15):
116
+ prediction_list = []
117
+ input_seq = last_sequence.copy()
118
+ for _ in range(steps):
119
+ pred = model.predict(input_seq.reshape(1, -1, 1), verbose=0)[0]
120
+ prediction_list.append(pred)
121
+ pred = pred.reshape(1, 1)
122
+ input_seq = np.append(input_seq[1:], pred, axis=0)
123
+ return scaler.inverse_transform(np.array(prediction_list))
124
+
125
+
126
  if model_choice == "Neural Prophet":
127
+ data_prophet = data.copy()
128
+ pred_df, prophet_model, forecast_full = predict_with_prophet(data_prophet, steps)
129
+
130
+ st.subheader("📆 Composants Prophet (Tendance, Saison, etc.)")
131
+
132
+ # Explication des graphiques Prophet
133
+ st.markdown("""
134
+ <div style='border: 1px solid #ccc; padding: 1rem; border-radius: 10px; background-color: #f9f9f9'>
135
+ <h4>🧠 <u>Explication des Graphiques Prophet</u></h4>
136
+ - Le **graphique principal** montre les valeurs réelles (points noirs) et les prévisions effectuées par Prophet (ligne bleue), accompagnées d'une **zone d'incertitude** (en bleu clair).
137
+ - Le **graphique des composantes** détaille la **tendance globale**, les **saisonnalités hebdomadaires et annuelles**, et d'autres patterns identifiés par le modèle.
138
+ Ces éléments vous permettent de comprendre non seulement où le prix est supposé aller, mais aussi *pourquoi* Prophet fait cette prédiction.
139
+ </div>
140
+ """, unsafe_allow_html=True)
141
+
142
  fig_components = prophet_model.plot_components(forecast_full)
143
  st.pyplot(fig_components)
144
+
145
+ fig_forecast = prophet_model.plot(forecast_full)
146
+ st.pyplot(fig_forecast)
147
+
148
+
149
+
150
  else:
151
+ predictions = predict_next_days(model, last_60_days, steps)
152
+ future_dates = pd.date_range(start=data.index[-1] + pd.Timedelta(days=1), periods=steps)
153
+ pred_df = pd.DataFrame(predictions, columns=["Prix Prédit"], index=future_dates)
154
+
155
+ # Visualisation interactive
156
+ st.subheader(f"🔮 Prédiction sur {steps} jours avec {model_choice}")
157
 
158
+ st.markdown(f"""
159
+ ℹ️ <u><b>Prédiction sur {steps} jours :</b></u>
160
+ Ce graphique montre les cours historiques ainsi que les prédictions du modèle {model_choice}.
161
+ Les triangles verts 🔺 représentent des **opportunités d'achat** possibles, et les triangles rouges 🔻 des **ventes potentielles**.
162
+ """, unsafe_allow_html=True)
163
+
164
+ pred_df.index = pd.to_datetime(pred_df.index)
165
  buy_signals = data[data['Buy_Signal']]
166
  sell_signals = data[data['Sell_Signal']]
167
+ fig = go.Figure()
168
+ fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Historique'))
169
+ fig.add_trace(go.Scatter(x=pred_df.index, y=pred_df['Prix Prédit'], mode='lines+markers', name='Prédictions',
170
+ line=dict(color='red')))
171
+ fig.add_trace(go.Scatter(
172
+ x=buy_signals.index,
173
+ y=buy_signals['Close'],
174
+ mode='markers',
175
+ marker=dict(color='green', size=10, symbol='triangle-up'),
176
+ name='Signal Achat'
177
  ))
178
+
179
+ fig.add_trace(go.Scatter(
180
+ x=sell_signals.index,
181
+ y=sell_signals['Close'],
182
+ mode='markers',
183
+ marker=dict(color='red', size=10, symbol='triangle-down'),
184
+ name='Signal Vente'
185
  ))
186
+ fig.update_layout(xaxis_title='Date', yaxis_title='Prix ($)', template='plotly_white')
187
+ st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
+ # Graphique des indicateurs techniques
190
+ st.subheader("📉 Indicateurs Techniques")
191
+
192
+ st.markdown("""
193
+ ℹ️ <u><b>Explication :</b></u>
194
+ Les indicateurs techniques vous aident à identifier les tendances du marché.
195
+ - **SMA** : Moyennes mobiles à court, moyen et long terme.
196
+ - **RSI** : Indique si une action est surachetée (>70) ou survendue (<30).
197
+ - **MACD** : Compare deux moyennes exponentielles et détecte des croisements pour signaler des opportunités.
198
+ """, unsafe_allow_html=True)
199
+
200
+ # Affichage des moyennes mobiles
201
  if show_sma:
202
  fig_sma = go.Figure()
203
+ fig_sma.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
204
+ fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA20'], mode='lines', name='SMA20'))
205
+ fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA50'], mode='lines', name='SMA50'))
206
+ fig_sma.add_trace(go.Scatter(x=data.index, y=data['SMA200'], mode='lines', name='SMA200'))
207
+ fig_sma.update_layout(title="Moyennes Mobiles", template="plotly_white")
208
  st.plotly_chart(fig_sma, use_container_width=True)
209
 
210
+ # RSI
211
  if show_rsi:
212
  fig_rsi = go.Figure()
213
+ fig_rsi.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='orange')))
214
+ fig_rsi.add_hline(y=70, line_dash='dash', line_color='red')
215
+ fig_rsi.add_hline(y=30, line_dash='dash', line_color='green')
216
+ fig_rsi.update_layout(title="RSI (Relative Strength Index)", yaxis_title="RSI", template="plotly_white")
217
  st.plotly_chart(fig_rsi, use_container_width=True)
218
 
219
+ # MACD
220
  if show_macd:
221
  fig_macd = go.Figure()
222
+ fig_macd.add_trace(go.Scatter(x=data.index, y=data['MACD'], mode='lines', name='MACD'))
223
+ fig_macd.add_trace(go.Scatter(x=data.index, y=data['Signal'], mode='lines', name='Signal'))
224
+ fig_macd.update_layout(title="MACD", yaxis_title="Valeur", template="plotly_white")
225
  st.plotly_chart(fig_macd, use_container_width=True)
226
 
227
+ # Affichage des données
228
  if show_table:
229
+ st.subheader("🧾 Valeurs Prédites")
230
+ st.dataframe(pred_df.style.format("{:.2f}"))
231
 
232
  # Statistiques
233
+ st.sidebar.markdown("## 📊 Statistiques")
234
+ last_close = float(data['Close'].iloc[-1])
235
+ last_pred = float(pred_df.iloc[-1, 0])
236
+ if isinstance(last_close, pd.Series):
237
+ last_close = last_close.values[0]
238
+ st.sidebar.metric("Prix actuel", f"{float(last_close):.2f} $")
239
+
240
+ st.sidebar.metric("Prix prédit (dernier)", f"{pred_df.iloc[-1, 0]:.2f} $")
241
+ variation = last_pred - last_close
242
+ percent = (variation / last_close) * 100
243
+ st.sidebar.metric("Variation", f"{variation:.2f} $", delta=f"{percent:.2f} %")
244
+
245
+ # Bouton de téléchargement
246
  if download_csv:
 
247
  st.download_button(
248
+ label="📥 Télécharger les prédictions CSV",
249
+ data=pred_df.to_csv().encode('utf-8'),
250
+ file_name='predictions_msft.csv',
251
+ mime='text/csv',
 
252
  )
253
 
254
+ # Footer
255
  st.markdown("""
256
+ <hr style='margin-top: 51px;'>
257
+ <div style='text-align: center;'>
258
+ Développé par <strong>Ntonga Babong Lewis</strong> - 2025
 
259
  </div>
260
  """, unsafe_allow_html=True)