AlanRex commited on
Commit
c834fcf
·
verified ·
1 Parent(s): 3a5ca62

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -49
app.py CHANGED
@@ -724,19 +724,26 @@ class RiskAnalyzer:
724
  return covariance / market_variance if market_variance != 0 else 0
725
  # ========================== 風險管理模組 END ==========================
726
 
727
- def get_stock_data(symbol, period='1y'):
728
- """獲取股票資料"""
 
 
 
 
 
 
 
 
 
729
  try:
730
- stock = yf.Ticker(symbol)
731
- data = stock.history(period=period)
732
- if data.empty and symbol == 'TXF=F':
733
- stock = yf.Ticker('0050.TW')
734
- data = stock.history(period=period)
735
- if data.empty:
736
- stock = yf.Ticker('^TWII')
737
- data = stock.history(period=period)
738
  return data
739
- except:
 
740
  return pd.DataFrame()
741
 
742
  def get_us_market_data():
@@ -805,49 +812,71 @@ def simple_statistical_predict(data, predict_days=5):
805
  'confidence': max(0.6, 1 - volatility * 2)
806
  }
807
 
808
- def calculate_new_features(df):
809
  """
810
- 計算新的技術指標特徵 - 針對新特徵需求
 
 
 
 
 
 
 
 
 
811
  """
812
- if df.empty:
813
- return df
814
 
815
- # 1. return_t-1 – 前一日報酬率
 
 
 
816
  df['return_t-1'] = df['Close'].pct_change()
817
 
818
- # 2. return_t-5 過去 5 日累積報酬率
819
  df['return_t-5'] = (df['Close'] / df['Close'].shift(5) - 1)
820
 
821
- # 3. MA5_close 5 日移動平均價
822
  df['MA5_close'] = df['Close'].rolling(window=5).mean()
823
 
824
- # 4. MA20_close 20 日移動平均價
825
- df['MA20_close'] = df['Close'].rolling(window=20).mean()
826
-
827
- # 5. volatility_5d – 5 日報酬標準差(短期波動)
828
  df['volatility_5d'] = df['return_t-1'].rolling(window=5).std()
829
 
830
- # 6. volume_ratio_5d 今日成交量 ÷ 5 日均量
831
  df['volume_5d_avg'] = df['Volume'].rolling(window=5).mean()
832
  df['volume_ratio_5d'] = df['Volume'] / df['volume_5d_avg']
833
 
834
- # 7. RSI_14 14 RSI 指標
835
- delta = df['Close'].diff()
836
- gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
837
- loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
838
- rs = gain / loss
839
- df['RSI_14'] = 100 - (100 / (1 + rs))
840
-
841
- # 8. MACD_diff – MACD - signal(趨勢強弱)
842
  exp1 = df['Close'].ewm(span=12).mean()
843
  exp2 = df['Close'].ewm(span=26).mean()
844
  macd_line = exp1 - exp2
845
  signal_line = macd_line.ewm(span=9).mean()
846
  df['MACD_diff'] = macd_line - signal_line
847
 
848
- # 移除輔助欄位
849
- if 'volume_5d_avg' in df.columns:
850
- df = df.drop('volume_5d_avg', axis=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
 
852
  return df
853
 
@@ -1062,23 +1091,43 @@ def advanced_xgboost_predict(predict_days=5):
1062
  traceback.print_exc()
1063
  return None
1064
 
1065
- def get_prediction(data, predict_days=5):
1066
  """
1067
- 【【模型預測控制器】】
1068
- 根據 USE_ADVANCED_MODEL 的設定,呼叫對應的預測模型。
1069
- """
1070
- if USE_ADVANCED_MODEL:
1071
- print(f"模式: 進階XGBoost模型 | 預測天期: {predict_days}天")
1072
- prediction = advanced_xgboost_predict(predict_days)
1073
- # 如果進階模型預測失敗,則自動降級使用簡易模型
1074
- if prediction is not None:
1075
- return prediction
1076
- else:
1077
- print("進階模型預測失敗,自動降級為簡易統計模型。")
1078
 
1079
- # 預設或降級時執行簡易模型
1080
- print(f"模式: 簡易統計模型 | 預測天期: {predict_days}天")
1081
- return simple_statistical_predict(data, predict_days)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1082
 
1083
  def calculate_technical_indicators(df):
1084
  """計算技術指標"""
 
724
  return covariance / market_variance if market_variance != 0 else 0
725
  # ========================== 風險管理模組 END ==========================
726
 
727
+ def get_stock_data(symbol, period):
728
+ """
729
+ 從 yfinance 獲取股票數據
730
+
731
+ Args:
732
+ symbol: 股票代碼
733
+ period: 數據時間段(例如 '1mo', '3mo', '1y')
734
+
735
+ Returns:
736
+ pd.DataFrame: 股票數據
737
+ """
738
  try:
739
+ ticker = yf.Ticker(symbol)
740
+ data = ticker.history(period=period)
741
+ if data.empty:
742
+ print(f"警告:無法獲取 {symbol} 的數據")
743
+ return pd.DataFrame()
 
 
 
744
  return data
745
+ except Exception as e:
746
+ print(f"獲取 {symbol} 數據時發生錯誤:{e}")
747
  return pd.DataFrame()
748
 
749
  def get_us_market_data():
 
812
  'confidence': max(0.6, 1 - volatility * 2)
813
  }
814
 
815
+ def calculate_features(stock_data, dji_data=None, sox_data=None, news_score=0.1):
816
  """
817
+ 從股票數據計算 XGBoostModel 所需的特徵
818
+
819
+ Args:
820
+ stock_data: 來自 yfinance 的股票數據
821
+ dji_data: 道瓊指數數據
822
+ sox_data: 費半指數數據
823
+ news_score: 新聞情緒分數(預設 0.1)
824
+
825
+ Returns:
826
+ pd.DataFrame: 包含特徵的 DataFrame
827
  """
828
+ df = stock_data.copy()
 
829
 
830
+ # 1. close - 前一日收盤價
831
+ df['close'] = df['Close']
832
+
833
+ # 2. return_t-1 - 前一日報酬率
834
  df['return_t-1'] = df['Close'].pct_change()
835
 
836
+ # 3. return_t-5 - 過去 5 日累積報酬率
837
  df['return_t-5'] = (df['Close'] / df['Close'].shift(5) - 1)
838
 
839
+ # 4. MA5_close - 5 日移動平均價
840
  df['MA5_close'] = df['Close'].rolling(window=5).mean()
841
 
842
+ # 5. volatility_5d - 5 日報酬標準差
 
 
 
843
  df['volatility_5d'] = df['return_t-1'].rolling(window=5).std()
844
 
845
+ # 6. volume_ratio_5d - 今日成交量 ÷ 5 日均量
846
  df['volume_5d_avg'] = df['Volume'].rolling(window=5).mean()
847
  df['volume_ratio_5d'] = df['Volume'] / df['volume_5d_avg']
848
 
849
+ # 7. MACD_diff - MACD - signal
 
 
 
 
 
 
 
850
  exp1 = df['Close'].ewm(span=12).mean()
851
  exp2 = df['Close'].ewm(span=26).mean()
852
  macd_line = exp1 - exp2
853
  signal_line = macd_line.ewm(span=9).mean()
854
  df['MACD_diff'] = macd_line - signal_line
855
 
856
+ # 8. dji_return_t-1 - 前一日道瓊指數報酬率
857
+ if dji_data is not None and not dji_data.empty:
858
+ df['dji_return_t-1'] = dji_data['Close'].pct_change()
859
+ else:
860
+ df['dji_return_t-1'] = 0.0
861
+
862
+ # 9. sox_return_t-1 - 前一日費半指數報酬率
863
+ if sox_data is not None and not sox_data.empty:
864
+ df['sox_return_t-1'] = sox_data['Close'].pct_change()
865
+ else:
866
+ df['sox_return_t-1'] = 0.0
867
+
868
+ # 10. NEWS - 新聞情緒分數
869
+ df['NEWS'] = news_score
870
+
871
+ # 選擇 XGBoostModel 所需的特徵
872
+ feature_columns = [
873
+ 'close', 'return_t-1', 'return_t-5', 'MA5_close', 'volatility_5d',
874
+ 'volume_ratio_5d', 'MACD_diff', 'dji_return_t-1', 'sox_return_t-1', 'NEWS'
875
+ ]
876
+ df = df[feature_columns]
877
+
878
+ # 移除 NaN 值
879
+ df = df.fillna(method='ffill').fillna(0)
880
 
881
  return df
882
 
 
1091
  traceback.print_exc()
1092
  return None
1093
 
1094
+ def get_prediction(stock_data, days):
1095
  """
1096
+ 為給定的股票數據生成預測
 
 
 
 
 
 
 
 
 
 
1097
 
1098
+ Args:
1099
+ stock_data: 股價歷史資料
1100
+ days: 預測天數 (1, 5, 10, 20)
1101
+
1102
+ Returns:
1103
+ float: 預測的漲幅百分比
1104
+ """
1105
+ try:
1106
+ # 獲取道瓊和費半數據
1107
+ dji_data = get_stock_data('^DJI', '1mo')
1108
+ sox_data = get_stock_data('^SOX', '1mo')
1109
+
1110
+ # 計算特徵(使用最新一天數據)
1111
+ features_df = calculate_features(stock_data, dji_data, sox_data, news_score=0.1)
1112
+ if features_df.empty:
1113
+ return None
1114
+
1115
+ # 只取最新一天的特徵
1116
+ latest_features = features_df.tail(1)
1117
+
1118
+ # 初始化 XGBoost 模型
1119
+ model = XGBoostModel()
1120
+
1121
+ # 進行預測
1122
+ predictions = model.predict('xgboost_model', latest_features)
1123
+ if predictions is None:
1124
+ return None
1125
+
1126
+ target_key = f'Change_pct_t{days}_pred'
1127
+ return predictions.get(target_key, 0.0)
1128
+ except Exception as e:
1129
+ print(f"預測失敗:{e}")
1130
+ return None
1131
 
1132
  def calculate_technical_indicators(df):
1133
  """計算技術指標"""