AlanRex commited on
Commit
4944d5f
·
verified ·
1 Parent(s): be3e2e8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -78
app.py CHANGED
@@ -933,112 +933,80 @@ def advanced_xgboost_predict(predict_days=5):
933
 
934
  taiex_data = calculate_technical_indicators(taiex_data)
935
  taiex_data = calculate_new_features(taiex_data)
 
 
936
 
937
- # 強制重新獲取美股數據
 
 
 
 
 
938
  print("正在獲取美股數據...")
939
  us_market_data = get_us_market_data()
940
 
941
- # 獲取新聞情緒分數
942
  try:
943
  if predictor is not None:
944
  sentiment_score_raw = predictor.get_news_index()
945
- if sentiment_score_raw is None:
946
- sentiment_score_raw = 0
947
  print(f"新聞情緒分數: {sentiment_score_raw}")
948
  else:
949
  sentiment_score_raw = 0
950
  except:
951
  sentiment_score_raw = 0
952
 
953
- # 準備特徵數據
954
  latest_data = taiex_data.iloc[-1]
955
- yesterday_close = latest_data['Close']
956
-
957
- # 特徵列表保持不變
958
- new_feature_columns = [
959
- 'return_t-1',
960
- 'return_t-5',
961
- 'MA5_close',
962
- 'volatility_5d',
963
- 'volume_ratio_5d',
964
- 'MACD_diff',
965
- 'MACDvol',
966
- 'RSI_14',
967
- 'ADX',
968
- 'volume_weighted_return'
969
-
970
- ]
971
-
972
- # 獲取美股報酬率
973
  dji_return = 0
974
  sox_return = 0
975
-
976
  try:
977
  dji_data = get_stock_data('^DJI', '5d')
978
  if not dji_data.empty and len(dji_data) >= 2:
979
  dji_return = (dji_data['Close'].iloc[-1] / dji_data['Close'].iloc[-2] - 1)
980
- print(f"道瓊報酬率: {dji_return:.4f}")
981
- except:
982
- pass
983
-
984
  try:
985
  sox_data = get_stock_data('^SOX', '5d')
986
  if not sox_data.empty and len(sox_data) >= 2:
987
  sox_return = (sox_data['Close'].iloc[-1] / sox_data['Close'].iloc[-2] - 1)
988
- print(f"費半報酬率: {sox_return:.4f}")
989
- except:
990
- pass
991
-
992
- # 建立特徵向量
993
- features_list = []
994
- feature_names = []
995
-
996
- for feature in new_feature_columns:
997
- if feature in latest_data.index:
998
- value = latest_data[feature]
999
- if pd.isna(value):
1000
- if 'return' in feature: default_value = 0.0
1001
- elif 'MA' in feature: default_value = latest_data['Close'] if not pd.isna(latest_data['Close']) else 100
1002
- elif 'volatility' in feature: default_value = 0.02
1003
- elif 'volume_ratio' in feature: default_value = 1.0
1004
- elif 'MACD' in feature: default_value = 0.0
1005
- else: default_value = 0.0
1006
-
1007
- features_list.append(default_value)
1008
- else:
1009
- features_list.append(value)
1010
-
1011
- feature_names.append(feature)
1012
 
1013
- # 添加其他特徵
1014
- features_list.extend([dji_return, sox_return, yesterday_close, sentiment_score_raw])
1015
- feature_names.extend(['dji_return_t-1', 'sox_return_t-1', 'close', 'NEWS'])
1016
-
1017
- # 轉換為 DataFrame
1018
- input_df = pd.DataFrame([features_list], columns=feature_names)
 
 
 
1019
 
1020
- print(f"特徵向量: {[f'{f:.4f}' for f in features_list[:5]]}...") # 只顯示前5個
1021
- # 🔍 新增這段:完整印出本次預測輸入��料
1022
  print("\n=== 📊 本次預測輸入特徵 DataFrame ===")
1023
  print(input_df)
1024
- print("=== ✅ 檢查以上特徵是否每次都有變 ===\n")
1025
 
1026
- # 進行預測
1027
  predictions = xgb_model.predict('xgboost_model', input_df)
1028
 
1029
  if predictions is None:
1030
  return None
1031
 
1032
- # 處理預測結果
1033
- pred_mapping = {
1034
- 1: 'Change_pct_t1_pred',
1035
- 5: 'Change_pct_t5_pred',
1036
- 10: 'Change_pct_t10_pred',
1037
- 20: 'Change_pct_t20_pred'
1038
- }
1039
-
1040
- available_days = [1, 5, 10, 20]
1041
- closest_day = min(available_days, key=lambda x: abs(x - predict_days))
1042
  pred_key = pred_mapping[closest_day]
1043
 
1044
  predicted_change_pct = predictions[pred_key]
@@ -1047,11 +1015,7 @@ def advanced_xgboost_predict(predict_days=5):
1047
 
1048
  print(f"XGBoost預測結果 - 漲幅: {predicted_change_pct:+.2f}%, 時間: {datetime.now().strftime('%H:%M:%S')}")
1049
 
1050
- return {
1051
- 'predicted_price': predicted_price,
1052
- 'change_pct': predicted_change_pct,
1053
- 'confidence': 0.75
1054
- }
1055
 
1056
  except Exception as e:
1057
  print(f"XGBoost 預測錯誤: {e}")
@@ -1146,7 +1110,15 @@ def calculate_technical_indicators(df):
1146
  df['-DI'] = (df['-DM'].ewm(com=13, adjust=False).mean() / df['TR'].ewm(com=13, adjust=False).mean()) * 100
1147
  df['DX'] = abs(df['+DI'] - df['-DI']) / (df['+DI'] + df['-DI']) * 100
1148
  df['ADX'] = df['DX'].ewm(com=13, adjust=False).mean()
1149
-
 
 
 
 
 
 
 
 
1150
  return df
1151
 
1152
  def calculate_volume_profile(df, num_bins=50):
 
933
 
934
  taiex_data = calculate_technical_indicators(taiex_data)
935
  taiex_data = calculate_new_features(taiex_data)
936
+
937
+
938
 
939
+ # 新增 volume_weighted_return 計算
940
+ if 'return_t-1' in taiex_data.columns and 'Volume' in taiex_data.columns:
941
+ taiex_data['volume_weighted_return'] = abs(taiex_data['return_t-1']) * taiex_data['Volume']
942
+ else:
943
+ taiex_data['volume_weighted_return'] = 0
944
+
945
  print("正在獲取美股數據...")
946
  us_market_data = get_us_market_data()
947
 
 
948
  try:
949
  if predictor is not None:
950
  sentiment_score_raw = predictor.get_news_index()
951
+ if sentiment_score_raw is None: sentiment_score_raw = 0
 
952
  print(f"新聞情緒分數: {sentiment_score_raw}")
953
  else:
954
  sentiment_score_raw = 0
955
  except:
956
  sentiment_score_raw = 0
957
 
 
958
  latest_data = taiex_data.iloc[-1]
959
+
960
+ # 【【修改點】】定義完整的特徵列表
961
+ feature_columns_map = {
962
+ 'close': latest_data.get('Close', 0),
963
+ 'return_t-1': latest_data.get('return_t-1', 0),
964
+ 'return_t-5': latest_data.get('return_t-5', 0),
965
+ 'MA5_close': latest_data.get('MA5_close', 0),
966
+ 'volatility_5d': latest_data.get('volatility_5d', 0),
967
+ 'volume_ratio_5d': latest_data.get('volume_ratio_5d', 0),
968
+ 'MACD_diff': latest_data.get('MACD_diff', 0),
969
+ 'NEWS': sentiment_score_raw,
970
+ 'MACDvol': latest_data.get('MACDvol', 0),
971
+ 'RSI_14': latest_data.get('RSI', 0), # 注意: app.py中計算的欄位名為 'RSI'
972
+ 'ADX': latest_data.get('ADX', 0),
973
+ 'volume_weighted_return': latest_data.get('volume_weighted_return', 0)
974
+ }
975
+
 
976
  dji_return = 0
977
  sox_return = 0
 
978
  try:
979
  dji_data = get_stock_data('^DJI', '5d')
980
  if not dji_data.empty and len(dji_data) >= 2:
981
  dji_return = (dji_data['Close'].iloc[-1] / dji_data['Close'].iloc[-2] - 1)
982
+ except: pass
 
 
 
983
  try:
984
  sox_data = get_stock_data('^SOX', '5d')
985
  if not sox_data.empty and len(sox_data) >= 2:
986
  sox_return = (sox_data['Close'].iloc[-1] / sox_data['Close'].iloc[-2] - 1)
987
+ except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
988
 
989
+ feature_columns_map['dji_return_t-1'] = dji_return
990
+ feature_columns_map['sox_return_t-1'] = sox_return
991
+
992
+ # 處理可能的 NaN 值
993
+ for key, value in feature_columns_map.items():
994
+ if pd.isna(value):
995
+ feature_columns_map[key] = 0
996
+
997
+ input_df = pd.DataFrame([feature_columns_map])
998
 
 
 
999
  print("\n=== 📊 本次預測輸入特徵 DataFrame ===")
1000
  print(input_df)
1001
+ print("======================================\n")
1002
 
 
1003
  predictions = xgb_model.predict('xgboost_model', input_df)
1004
 
1005
  if predictions is None:
1006
  return None
1007
 
1008
+ pred_mapping = {1: 'Change_pct_t1_pred', 5: 'Change_pct_t5_pred', 10: 'Change_pct_t10_pred', 20: 'Change_pct_t20_pred'}
1009
+ closest_day = min(pred_mapping.keys(), key=lambda x: abs(x - predict_days))
 
 
 
 
 
 
 
 
1010
  pred_key = pred_mapping[closest_day]
1011
 
1012
  predicted_change_pct = predictions[pred_key]
 
1015
 
1016
  print(f"XGBoost預測結果 - 漲幅: {predicted_change_pct:+.2f}%, 時間: {datetime.now().strftime('%H:%M:%S')}")
1017
 
1018
+ return {'predicted_price': predicted_price, 'change_pct': predicted_change_pct, 'confidence': 0.75}
 
 
 
 
1019
 
1020
  except Exception as e:
1021
  print(f"XGBoost 預測錯誤: {e}")
 
1110
  df['-DI'] = (df['-DM'].ewm(com=13, adjust=False).mean() / df['TR'].ewm(com=13, adjust=False).mean()) * 100
1111
  df['DX'] = abs(df['+DI'] - df['-DI']) / (df['+DI'] + df['-DI']) * 100
1112
  df['ADX'] = df['DX'].ewm(com=13, adjust=False).mean()
1113
+
1114
+ # 【【新增】】計算成交量MACD (MACDvol)
1115
+ if 'Volume' in df.columns and not df['Volume'].isnull().all():
1116
+ exp1_vol = df['Volume'].ewm(span=12, adjust=False).mean()
1117
+ exp2_vol = df['Volume'].ewm(span=26, adjust=False).mean()
1118
+ df['MACDvol'] = exp1_vol - exp2_vol
1119
+ else:
1120
+ df['MACDvol'] = 0 # 如果沒有成交量數據,則設為0
1121
+
1122
  return df
1123
 
1124
  def calculate_volume_profile(df, num_bins=50):