Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -532,7 +532,8 @@ app.layout = html.Div([
|
|
| 532 |
'box-shadow': '0 2px 10px rgba(0,0,0,0.1)'
|
| 533 |
})
|
| 534 |
])
|
| 535 |
-
|
|
|
|
| 536 |
# 台指期獨立預測回調函數
|
| 537 |
@app.callback(
|
| 538 |
[dash.dependencies.Output('taiex-prediction-results', 'children'),
|
|
@@ -545,15 +546,90 @@ def update_taiex_prediction(predict_days):
|
|
| 545 |
if data.empty:
|
| 546 |
return html.Div("無法獲取台指期資料"), {}
|
| 547 |
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
if prediction is None:
|
| 551 |
-
return html.Div("資料不足,無法進行預測"), {}
|
| 552 |
-
|
| 553 |
current_price = data['Close'].iloc[-1]
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 557 |
|
| 558 |
# 預測結果卡片
|
| 559 |
color = '#00C851' if change_pct >= 0 else '#FF4444'
|
|
|
|
| 532 |
'box-shadow': '0 2px 10px rgba(0,0,0,0.1)'
|
| 533 |
})
|
| 534 |
])
|
| 535 |
+
# 創建一個列表來儲存所有的預測點數據
|
| 536 |
+
all_predictions_data = []
|
| 537 |
# 台指期獨立預測回調函數
|
| 538 |
@app.callback(
|
| 539 |
[dash.dependencies.Output('taiex-prediction-results', 'children'),
|
|
|
|
| 546 |
if data.empty:
|
| 547 |
return html.Div("無法獲取台指期資料"), {}
|
| 548 |
|
| 549 |
+
# 獲取最後的歷史數據點
|
| 550 |
+
last_historical_date = data.index[-1]
|
|
|
|
|
|
|
|
|
|
| 551 |
current_price = data['Close'].iloc[-1]
|
| 552 |
+
|
| 553 |
+
# --- 關鍵修改開始 ---
|
| 554 |
+
|
| 555 |
+
# 1. 收集所有需要的預測點
|
| 556 |
+
all_predict_options = [1, 5, 10, 20, 60]
|
| 557 |
+
|
| 558 |
+
# 篩選出使用者選擇天數或更短的所有預測選項
|
| 559 |
+
points_to_calculate = [d for d in all_predict_options if d <= predict_days]
|
| 560 |
+
|
| 561 |
+
# 清空舊的預測數據,重新計算
|
| 562 |
+
all_predictions_data.clear()
|
| 563 |
+
|
| 564 |
+
# 添加歷史的最後一個點作為起始點
|
| 565 |
+
all_predictions_data.append({
|
| 566 |
+
'date': last_historical_date,
|
| 567 |
+
'price': current_price,
|
| 568 |
+
'days': 0, # 0天代表歷史數據
|
| 569 |
+
'is_historical': True
|
| 570 |
+
})
|
| 571 |
+
|
| 572 |
+
# 計算並儲存每個預測點
|
| 573 |
+
for d in points_to_calculate:
|
| 574 |
+
prediction = simple_lstm_predict(data, d)
|
| 575 |
+
if prediction:
|
| 576 |
+
future_date = last_historical_date + timedelta(days=d)
|
| 577 |
+
all_predictions_data.append({
|
| 578 |
+
'date': future_date,
|
| 579 |
+
'price': prediction['predicted_price'],
|
| 580 |
+
'days': d,
|
| 581 |
+
'is_historical': False,
|
| 582 |
+
'change_pct': prediction['change_pct'] # 為了顏色判斷
|
| 583 |
+
})
|
| 584 |
+
|
| 585 |
+
# 將預測點數據轉換為 DataFrame,方便繪圖
|
| 586 |
+
predictions_df = pd.DataFrame(all_predictions_data)
|
| 587 |
+
predictions_df = predictions_df.sort_values(by='date') # 確保日期排序正確
|
| 588 |
+
|
| 589 |
+
# 找到最後一個預測點的顏色
|
| 590 |
+
final_prediction_info = predictions_df[predictions_df['days'] == predict_days].iloc[0] if predict_days in predictions_df['days'].values else None
|
| 591 |
+
final_color = '#00C851' if final_prediction_info and final_prediction_info['change_pct'] >= 0 else '#FF4444'
|
| 592 |
+
arrow = '📈' if final_color == '#00C851' else '📉'
|
| 593 |
+
|
| 594 |
+
# 建立預測趨勢圖
|
| 595 |
+
fig = go.Figure()
|
| 596 |
+
|
| 597 |
+
# 添加歷史價格線 (最近30天)
|
| 598 |
+
recent_data = data.tail(30)
|
| 599 |
+
fig.add_trace(go.Scatter(
|
| 600 |
+
x=recent_data.index,
|
| 601 |
+
y=recent_data['Close'],
|
| 602 |
+
mode='lines',
|
| 603 |
+
name='歷史價格',
|
| 604 |
+
line=dict(color='#FFA726', width=2)
|
| 605 |
+
))
|
| 606 |
+
|
| 607 |
+
# 添加連接所有預測點的趨勢線
|
| 608 |
+
fig.add_trace(go.Scatter(
|
| 609 |
+
x=predictions_df['date'],
|
| 610 |
+
y=predictions_df['price'],
|
| 611 |
+
mode='lines+markers', # 同時顯示線和點
|
| 612 |
+
name='預測趨勢',
|
| 613 |
+
line=dict(color=final_color, width=3, dash='dash'), # 使用最終預測的顏色
|
| 614 |
+
marker=dict(size=8)
|
| 615 |
+
))
|
| 616 |
+
|
| 617 |
+
# 為了區分不同天數的點,我們可以再添加一次點,但這次只添加 marker
|
| 618 |
+
# 這樣可以為每個點設置不同的顏色和大小(如果需要)
|
| 619 |
+
for index, row in predictions_df.iterrows():
|
| 620 |
+
if not row['is_historical']:
|
| 621 |
+
point_color = '#00C851' if row['change_pct'] >= 0 else '#FF4444'
|
| 622 |
+
fig.add_trace(go.Scatter(
|
| 623 |
+
x=[row['date']],
|
| 624 |
+
y=[row['price']],
|
| 625 |
+
mode='markers',
|
| 626 |
+
name=f'{row["days"]}日預測點',
|
| 627 |
+
marker=dict(size=10, color=point_color, line=dict(width=2, color='DarkSlateGrey')), # 稍微加點邊框
|
| 628 |
+
legendgroup=f'points', # 將所有點分到同一個圖例組
|
| 629 |
+
showlegend=True if row['days'] in [1, 5, 10, 20, 60] else False # 只顯示主要天數的點在圖例
|
| 630 |
+
))
|
| 631 |
+
|
| 632 |
+
# --- 關鍵修改結束 ---
|
| 633 |
|
| 634 |
# 預測結果卡片
|
| 635 |
color = '#00C851' if change_pct >= 0 else '#FF4444'
|