AlanRex commited on
Commit
631b6c3
·
verified ·
1 Parent(s): c834fcf

Upload 2 files

Browse files
Files changed (1) hide show
  1. app.py +49 -98
app.py CHANGED
@@ -724,26 +724,19 @@ class RiskAnalyzer:
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,71 +805,49 @@ def simple_statistical_predict(data, predict_days=5):
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,43 +1062,23 @@ def advanced_xgboost_predict(predict_days=5):
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
  """計算技術指標"""
 
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
  '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
  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
  """計算技術指標"""