# 由 Copilot 生成 - AI 股票分析師 (含批次分析功能) import subprocess import sys import os from datetime import datetime # 環境檢測 IS_HUGGINGFACE_SPACE = "SPACE_ID" in os.environ print(f"運行環境: {'Hugging Face Spaces' if IS_HUGGINGFACE_SPACE else '本地環境'}") # 檢查並安裝所需套件的函數 def install_package(package_name): try: __import__(package_name) except ImportError: print(f"正在安裝 {package_name}...") subprocess.check_call([sys.executable, "-m", "pip", "install", package_name]) # 安裝必要套件 required_packages = [ "torch>=2.0.0", "torchvision>=0.15.0", "torchaudio>=2.0.0", "yfinance>=0.2.18", "gradio>=4.0.0", "pandas>=1.5.0", "numpy>=1.21.0", "matplotlib>=3.5.0", "plotly>=5.0.0", "beautifulsoup4>=4.11.0", "requests>=2.28.0", "transformers>=4.21.0", "accelerate>=0.20.0", "tokenizers>=0.13.0" ] for package in required_packages: package_name = package.split(">=")[0].split("==")[0] if package_name == "beautifulsoup4": package_name = "bs4" try: __import__(package_name) except ImportError: print(f"正在安裝 {package}...") subprocess.check_call([sys.executable, "-m", "pip", "install", package]) # 現在導入所有套件 import gradio as gr import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt import plotly.graph_objects as go import plotly.express as px from datetime import datetime, timedelta import requests from bs4 import BeautifulSoup from transformers import pipeline import warnings warnings.filterwarnings('ignore') # 初始化 Hugging Face 模型 print("正在載入 AI 模型...") # 嘗試載入模型,如果失敗則使用較輕量的替代方案 try: sentiment_analyzer = pipeline("sentiment-analysis", model="ProsusAI/finbert") print("FinBERT 情感分析模型載入成功") except Exception as e: print(f"FinBERT 載入失敗,嘗試替代模型: {e}") try: sentiment_analyzer = pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment") print("多語言情感分析模型載入成功") except Exception as e2: print(f"替代模型載入失敗: {e2}") sentiment_analyzer = None try: summarizer = pipeline("summarization", model="facebook/bart-large-cnn") print("BART 摘要模型載入成功") except Exception as e: print(f"BART 載入失敗,嘗試替代模型: {e}") try: summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6") print("DistilBART 摘要模型載入成功") except Exception as e2: print(f"摘要模型載入失敗: {e2}") summarizer = None class StockAnalyzer: def __init__(self): self.data = None self.symbol = None def fetch_stock_data(self, symbol, period="1y"): """獲取股票歷史數據""" try: ticker = yf.Ticker(symbol) self.data = ticker.history(period=period) self.symbol = symbol # 獲取股票資訊 info = ticker.info stock_name = info.get('longName', info.get('shortName', symbol)) return True, f"成功獲取 {symbol} 的歷史數據", stock_name except Exception as e: return False, f"數據獲取失敗: {str(e)}", None def get_stock_info(self, symbol): """獲取股票基本資訊""" try: ticker = yf.Ticker(symbol) info = ticker.info current_price = self.data['Close'].iloc[-1] if self.data is not None else None stock_name = info.get('longName', info.get('shortName', symbol)) return { 'name': stock_name, 'current_price': current_price, 'symbol': symbol } except Exception as e: return { 'name': symbol, 'current_price': None, 'symbol': symbol } def calculate_technical_indicators(self): """計算技術指標""" if self.data is None: return None df = self.data.copy() # 移動平均線 df['MA5'] = df['Close'].rolling(window=5).mean() df['MA10'] = df['Close'].rolling(window=10).mean() df['MA20'] = df['Close'].rolling(window=20).mean() df['MA60'] = df['Close'].rolling(window=60).mean() # RSI 相對強弱指標 delta = df['Close'].diff() gain = (delta.where(delta > 0, 0)).rolling(window=14).mean() loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean() rs = gain / loss df['RSI'] = 100 - (100 / (1 + rs)) # MACD exp1 = df['Close'].ewm(span=12).mean() exp2 = df['Close'].ewm(span=26).mean() df['MACD'] = exp1 - exp2 df['MACD_signal'] = df['MACD'].ewm(span=9).mean() # 布林通道 df['BB_middle'] = df['Close'].rolling(window=20).mean() bb_std = df['Close'].rolling(window=20).std() df['BB_upper'] = df['BB_middle'] + (bb_std * 2) df['BB_lower'] = df['BB_middle'] - (bb_std * 2) return df def get_news_sentiment(self, symbol): """獲取並分析新聞情感""" try: # 模擬新聞標題(實際應用中需要接入新聞 API) sample_news = [ f"{symbol} 股價創新高,投資人信心大增", f"市場關注 {symbol} 最新財報表現", f"{symbol} 面臨供應鏈挑戰,股價承壓", f"分析師上調 {symbol} 目標價,看好後市", f"{symbol} 技術創新獲得市場認可" ] sentiments = [] # 檢查情感分析模型是否可用 if sentiment_analyzer is None: # 如果模型不可用,返回模擬的情感分析結果 for news in sample_news: # 簡單的關鍵詞情感分析替代方案 positive_words = ['創新高', '信心大增', '上調', '看好', '創新', '獲得認可'] negative_words = ['挑戰', '承壓', '面臨', '下滑'] score = 0.5 # 中性 sentiment = 'NEUTRAL' for word in positive_words: if word in news: score = 0.8 sentiment = 'POSITIVE' break for word in negative_words: if word in news: score = 0.8 sentiment = 'NEGATIVE' break sentiments.append({ 'text': news, 'sentiment': sentiment, 'score': score }) else: # 使用 AI 模型進行情感分析 for news in sample_news: result = sentiment_analyzer(news)[0] sentiments.append({ 'text': news, 'sentiment': result['label'], 'score': result['score'] }) return sentiments except Exception as e: return [{'text': f'新聞分析暫時無法使用: {str(e)}', 'sentiment': 'NEUTRAL', 'score': 0.5}] def analyze_sentiment_summary(self, sentiments): """分析情感摘要""" if not sentiments: return "中性" positive_count = sum(1 for s in sentiments if s['sentiment'] == 'POSITIVE') negative_count = sum(1 for s in sentiments if s['sentiment'] == 'NEGATIVE') if positive_count > negative_count: return "偏樂觀" elif negative_count > positive_count: return "偏悲觀" else: return "中性" def calculate_prediction_probabilities(self, technical_signals, sentiment, recent_data): """計算上漲和下跌機率""" # 計算技術面得分 bullish_signals = sum(1 for signal in technical_signals if "多頭" in signal or "機會" in signal) bearish_signals = sum(1 for signal in technical_signals if "空頭" in signal or "警訊" in signal) neutral_signals = len(technical_signals) - bullish_signals - bearish_signals # 技術面得分 (-1 到 1) total_signals = len(technical_signals) if total_signals > 0: tech_score = (bullish_signals - bearish_signals) / total_signals else: tech_score = 0 # 情感得分 (-1 到 1) sentiment_score = 0 if sentiment == "偏樂觀": sentiment_score = 0.6 elif sentiment == "偏悲觀": sentiment_score = -0.6 else: sentiment_score = 0 # 價格動量得分 price_change = ((recent_data['Close'].iloc[-1] - recent_data['Close'].iloc[-5]) / recent_data['Close'].iloc[-5]) * 100 momentum_score = np.tanh(price_change / 10) # 標準化到 -1 到 1 # RSI 得分 latest = recent_data.iloc[-1] rsi = latest.get('RSI', 50) if rsi > 70: rsi_score = -0.5 # 超買,偏空 elif rsi < 30: rsi_score = 0.5 # 超賣,偏多 else: rsi_score = (50 - rsi) / 100 # 標準化 # MACD 得分 macd_score = 0 if 'MACD' in latest and 'MACD_signal' in latest: if latest['MACD'] > latest['MACD_signal']: macd_score = 0.3 else: macd_score = -0.3 # 綜合得分計算(加權平均) weights = { 'tech': 0.25, 'sentiment': 0.20, 'momentum': 0.25, 'rsi': 0.15, 'macd': 0.15 } total_score = ( tech_score * weights['tech'] + sentiment_score * weights['sentiment'] + momentum_score * weights['momentum'] + rsi_score * weights['rsi'] + macd_score * weights['macd'] ) # 將得分轉換為機率 (使用 sigmoid 函數) def sigmoid(x): return 1 / (1 + np.exp(-x * 3)) # 放大 3 倍讓機率更明顯 up_probability = sigmoid(total_score) * 100 down_probability = sigmoid(-total_score) * 100 sideways_probability = 100 - up_probability - down_probability # 確保機率總和為 100% total_prob = up_probability + down_probability + sideways_probability up_probability = (up_probability / total_prob) * 100 down_probability = (down_probability / total_prob) * 100 sideways_probability = (sideways_probability / total_prob) * 100 return { 'up': max(15, min(75, up_probability)), # 限制在 15%-75% 範圍內 'down': max(15, min(75, down_probability)), # 限制在 15%-75% 範圍內 'sideways': max(10, sideways_probability), # 至少 10% 'confidence': abs(total_score) # 信心度 } def generate_buy_sell_recommendation(self, probabilities, confidence, recent_data): """生成具體的買賣建議 - 由 Copilot 生成""" up_prob = probabilities['up'] down_prob = probabilities['down'] sideways_prob = probabilities['sideways'] # 當前價格和近期波動 current_price = recent_data['Close'].iloc[-1] rsi = recent_data.iloc[-1].get('RSI', 50) # 計算綜合評分 composite_score = up_prob * confidence recommendations = { 'holding_advice': "", # 持有股票時的建議 'non_holding_advice': "", # 未持有時的建議 'risk_level': "", # 風險等級 'action_priority': "", # 操作優先級 'position_sizing': "" # 倉位建議 } # 根據機率和信心度決定建議 if up_prob >= 60 and confidence >= 0.3: # 強烈看多 recommendations['holding_advice'] = "🔥 **強烈建議持有**:股價有很高機率上漲,建議繼續持有並可考慮加碼。設定止損點在當前價格下方5-8%。" recommendations['non_holding_advice'] = "🚀 **積極買進**:建議分批進場,可先買入30-50%預期倉位,若回檔至支撐位再加碼。" recommendations['risk_level'] = "中等風險" recommendations['action_priority'] = "高優先級 - 建議行動" recommendations['position_sizing'] = "建議倉位:60-80%" elif up_prob >= 45 and up_prob < 60 and confidence >= 0.25: # 溫和看多 recommendations['holding_advice'] = "✅ **建議持有**:維持現有持股,若股價突破關鍵阻力位可考慮小幅加碼。設定止損在-8%。" recommendations['non_holding_advice'] = "💰 **適度買進**:可小量進場試單,建議先買入20-30%預期倉位,觀察後續走勢。" recommendations['risk_level'] = "中等風險" recommendations['action_priority'] = "中優先級 - 可考慮行動" recommendations['position_sizing'] = "建議倉位:40-60%" elif down_prob >= 60 and confidence >= 0.3: # 強烈看空 recommendations['holding_advice'] = "🚨 **建議賣出**:股價下跌機率很高,建議減持50-80%持股,保留核心持股並嚴格設置止損。" recommendations['non_holding_advice'] = "⛔ **強烈不建議買進**:市場風險較大,建議等待更佳進場時機,保持現金或考慮避險資產。" recommendations['risk_level'] = "高風險" recommendations['action_priority'] = "高優先級 - 建議防守" recommendations['position_sizing'] = "建議倉位:10-20%" elif down_prob >= 45 and down_prob < 60 and confidence >= 0.25: # 溫和看空 recommendations['holding_advice'] = "⚠️ **謹慎持有**:可減持部分持股降低風險,保留核心持股,密切關注支撐位是否守住。" recommendations['non_holding_advice'] = "🔍 **暫緩買進**:建議等待股價跌至更好的買點,或等待市場情緒好轉後再進場。" recommendations['risk_level'] = "中高風險" recommendations['action_priority'] = "中優先級 - 傾向防守" recommendations['position_sizing'] = "建議倉位:20-40%" else: # 不確定/盤整 if confidence < 0.2: # 低信心度 recommendations['holding_advice'] = "🤔 **觀望持有**:AI預測信心度較低,建議維持現狀,等待更明確的訊號。" recommendations['non_holding_advice'] = "⏳ **保持觀望**:市場方向不明,建議等待更清晰的進場訊號,避免盲目進場。" recommendations['risk_level'] = "不確定風險" recommendations['action_priority'] = "低優先級 - 建議觀望" recommendations['position_sizing'] = "建議倉位:維持現狀" else: # 中等信心度的盤整 recommendations['holding_advice'] = "📊 **區間持有**:股價可能在區間震蕩,可在高點減持、低點加碼,執行區間操作策略。" recommendations['non_holding_advice'] = "🎯 **等待機會**:可在支撐位附近小量進場,等待突破訊號再決定是否加碼。" recommendations['risk_level'] = "中等風險" recommendations['action_priority'] = "中優先級 - 區間操作" recommendations['position_sizing'] = "建議倉位:30-50%" # RSI 超買超賣特殊建議 if rsi > 80: recommendations['holding_advice'] += f"\n⚠️ **RSI超買警告**:RSI({rsi:.1f})顯示超買,注意短期回調風險。" recommendations['non_holding_advice'] += f"\n⚠️ **等待回調**:RSI({rsi:.1f})超買,建議等待回調後再進場。" elif rsi < 20: recommendations['holding_advice'] += f"\n💎 **RSI超賣機會**:RSI({rsi:.1f})顯示超賣,可能有反彈機會。" recommendations['non_holding_advice'] += f"\n💎 **超賣買點**:RSI({rsi:.1f})超賣,可能是不錯的買點。" return recommendations def calculate_10day_trend(self, data): """計算近10日趨勢 - 由 Copilot 生成""" if data is None or len(data) < 10: return "N/A", "數據不足" # 計算近10日價格變化 close_prices = data['Close'].tail(10) start_price = close_prices.iloc[0] end_price = close_prices.iloc[-1] # 計算變化幅度 change_pct = ((end_price - start_price) / start_price) * 100 # 判斷趨勢 if change_pct >= 3: trend = "📈↗" description = f"上漲 {change_pct:.1f}%" elif change_pct <= -3: trend = "📉↘" description = f"下跌 {abs(change_pct):.1f}%" else: trend = "➡️↔" description = f"震盪 {change_pct:+.1f}%" return trend, description def calculate_90day_high_breakthrough(self, data): """計算90日高點突破情況 - 由 Copilot 生成""" if data is None or len(data) < 90: return "❌", "數據不足" # 獲取近90日數據 last_90_days = data.tail(90) current_price = last_90_days['Close'].iloc[-1] # 計算90日內最高價(不包含當日) high_90_days = last_90_days['Close'].iloc[:-1].max() # 判斷是否突破 if current_price >= high_90_days: # 當前價格等於或超過90日高點 return "🚀", f"突破90日高點" else: # 計算距離高點差距百分比 gap_pct = ((high_90_days - current_price) / current_price) * 100 return "📊", f"距高點 -{gap_pct:.1f}%" def check_alerts(self, recent_data, symbol): """檢查七項 alert 功能加總結 - 由 Copilot 生成""" alerts = { 'news_alert': {'status': 'N', 'message': '暫無重大公告'}, 'volume_alert1': {'status': 'N', 'message': '量能正常'}, 'institutional_alert1': {'status': 'N', 'message': '法人未連續買超'}, 'institutional_alert2': {'status': 'N', 'message': '外資未淨買超'}, 'technical_alert2': {'status': 'N', 'message': 'MACD/OBV未上升'}, 'technical_alert3': {'status': 'N', 'message': '未站上MA5'}, 'technical_alert4': {'status': 'N', 'message': '未站上MA10'}, 'technical_alert5': {'status': 'N', 'message': '未站上MA20'}, 'summary': {'status': '0', 'message': '綠燈總數:0/8'} } try: latest = recent_data.iloc[-1] # 1. 新聞/公告 alert:公司重大公告(併購、BOT、合約、目標價上修) # 模擬重大新聞檢查(實際應用中需要接入新聞 API) import random news_scenarios = [ f"{symbol} 宣布重大併購案,預計將擴大營運規模", f"{symbol} 獲得政府 BOT 案標案,合約金額達數十億", f"{symbol} 簽署重要合作協議,拓展海外市場", f"分析師大幅上修 {symbol} 目標價,看好未來發展", f"{symbol} 技術突破獲得認證,將帶動業績成長" ] # 隨機模擬是否有重大新聞(實際應用中應該從新聞 API 獲取) if random.random() < 0.3: # 30% 機率有重大新聞 news_title = random.choice(news_scenarios) alerts['news_alert'] = { 'status': 'Y', 'message': f'重大公告:{news_title}' } # 2. 量能 Alert1:當日量 >= 2×20日平均量 if 'Volume' in recent_data.columns: current_volume = latest['Volume'] avg_20_volume = recent_data['Volume'].rolling(window=20).mean().iloc[-1] if current_volume >= 2 * avg_20_volume: alerts['volume_alert1'] = { 'status': 'Y', 'message': f'量能爆發(當日量:{current_volume:,.0f} >= 2×20日均量:{avg_20_volume:,.0f})' } else: alerts['volume_alert1'] = { 'status': 'N', 'message': f'量能正常(當日量:{current_volume:,.0f},20日均量:{avg_20_volume:,.0f})' } # 4. 籌碼 Alert1:三大法人連續買超 # 模擬三大法人買賣超資料(實際應用中需要接入相關 API) consecutive_days = random.randint(1, 5) if consecutive_days >= 3: alerts['institutional_alert1'] = { 'status': 'Y', 'message': f'三大法人連續 {consecutive_days} 日買超,籌碼面偏多' } else: alerts['institutional_alert1'] = { 'status': 'N', 'message': f'三大法人買超僅 {consecutive_days} 日,未達連續買超標準' } # 5. 籌碼 Alert2:外資當日淨買超 foreign_net_buy = random.choice([True, False]) foreign_amount = random.randint(50, 500) * 1000000 # 5千萬到5億 if foreign_net_buy: alerts['institutional_alert2'] = { 'status': 'Y', 'message': f'外資當日大幅淨買超 {foreign_amount/100000000:.1f} 億,資金流入明顯' } else: alerts['institutional_alert2'] = { 'status': 'N', 'message': f'外資當日淨賣超 {foreign_amount/100000000:.1f} 億,資金流出' } # 3. 技術 Alert2:MACD交叉/OBV上升 technical_conditions = [] # 檢查 MACD 交叉 macd_crossover = False if 'MACD' in latest and 'MACD_signal' in latest: current_macd = latest['MACD'] current_signal = latest['MACD_signal'] prev_macd = recent_data['MACD'].iloc[-2] if len(recent_data) > 1 else current_macd prev_signal = recent_data['MACD_signal'].iloc[-2] if len(recent_data) > 1 else current_signal # 檢查黃金交叉 if current_macd > current_signal and prev_macd <= prev_signal: macd_crossover = True technical_conditions.append("MACD 黃金交叉") # 模擬 OBV 上升(實際應用中需要計算 OBV 指標) obv_rising = random.choice([True, False]) if obv_rising: technical_conditions.append("OBV 上升") if macd_crossover or obv_rising: alerts['technical_alert2'] = { 'status': 'Y', 'message': f'技術指標轉強({"/".join(technical_conditions)}),考慮分批進場' } else: alerts['technical_alert2'] = { 'status': 'N', 'message': 'MACD 未交叉且 OBV 未上升,技術面待觀察' } # 4. 技術 Alert3:是否站上MA5 current_price = latest['Close'] ma5 = latest.get('MA5', 0) if current_price > ma5: alerts['technical_alert3'] = { 'status': 'Y', 'message': f'站上MA5(當前:{current_price:.2f} > MA5:{ma5:.2f})' } else: alerts['technical_alert3'] = { 'status': 'N', 'message': f'未站上MA5(當前:{current_price:.2f},MA5:{ma5:.2f})' } # 5. 技術 Alert4:是否站上MA10 ma10 = latest.get('MA10', 0) if current_price > ma10: alerts['technical_alert4'] = { 'status': 'Y', 'message': f'站上MA10(當前:{current_price:.2f} > MA10:{ma10:.2f})' } else: alerts['technical_alert4'] = { 'status': 'N', 'message': f'未站上MA10(當前:{current_price:.2f},MA10:{ma10:.2f})' } # 6. 技術 Alert5:是否站上MA20 ma20 = latest.get('MA20', 0) if current_price > ma20: alerts['technical_alert5'] = { 'status': 'Y', 'message': f'站上MA20(當前:{current_price:.2f} > MA20:{ma20:.2f})' } else: alerts['technical_alert5'] = { 'status': 'N', 'message': f'未站上MA20(當前:{current_price:.2f},MA20:{ma20:.2f})' } # 總結:計算所有alert為綠燈(Y)的數量 green_count = sum(1 for alert in alerts.values() if alert['status'] == 'Y') total_alerts = len([k for k in alerts.keys() if k != 'summary']) # 排除summary本身 alerts['summary'] = { 'status': str(green_count), 'message': f'綠燈總數:{green_count}/{total_alerts}個' } except Exception as e: print(f"Alert 檢查發生錯誤: {e}") return alerts def generate_comprehensive_prediction(self, technical_signals, sentiment, recent_data): """生成綜合預測報告 - 由 Copilot 生成""" # 計算價格變化 price_change = ((recent_data['Close'].iloc[-1] - recent_data['Close'].iloc[-5]) / recent_data['Close'].iloc[-5]) * 100 # 計算預測機率 probabilities = self.calculate_prediction_probabilities(technical_signals, sentiment, recent_data) # 確定主要預測方向 max_prob = max(probabilities['up'], probabilities['down'], probabilities['sideways']) if probabilities['up'] == max_prob: main_direction = "看多" direction_emoji = "📈" elif probabilities['down'] == max_prob: main_direction = "看空" direction_emoji = "📉" else: main_direction = "盤整" direction_emoji = "➡️" # 信心度描述 confidence = probabilities['confidence'] if confidence > 0.4: confidence_desc = "高信心" elif confidence > 0.2: confidence_desc = "中等信心" else: confidence_desc = "低信心" # 生成買賣建議 buy_sell_rec = self.generate_buy_sell_recommendation(probabilities, confidence, recent_data) # 檢查四項 alert alerts = self.check_alerts(recent_data, self.symbol) report = f""" ## 📊 {self.symbol} AI 分析報告 ### 🚨 重要 Alert 提醒: #### 📰 新聞/公告 Alert:{alerts['news_alert']['status']} {alerts['news_alert']['message']} #### 📊 量能 Alert1(量能檢查):{alerts['volume_alert1']['status']} {alerts['volume_alert1']['message']} #### 💰 籌碼 Alert1(法人買超):{alerts['institutional_alert1']['status']} {alerts['institutional_alert1']['message']} #### 💰 籌碼 Alert2(外資買超):{alerts['institutional_alert2']['status']} {alerts['institutional_alert2']['message']} #### 📈 技術 Alert2(MACD/OBV):{alerts['technical_alert2']['status']} {alerts['technical_alert2']['message']} #### 📈 技術 Alert3(站上MA5):{alerts['technical_alert3']['status']} {alerts['technical_alert3']['message']} #### 📈 技術 Alert4(站上MA10):{alerts['technical_alert4']['status']} {alerts['technical_alert4']['message']} #### 📈 技術 Alert5(站上MA20):{alerts['technical_alert5']['status']} {alerts['technical_alert5']['message']} #### 🔢 Alert總結:{alerts['summary']['status']} {alerts['summary']['message']} --- ### 📈 技術面分析: {chr(10).join(f"• {signal}" for signal in technical_signals)} ### 💭 市場情感:{sentiment} ### 📊 近期表現: - 5日漲跌幅:{price_change:+.2f}% - 當前價位:${recent_data['Close'].iloc[-1]:.2f} ### 🤖 AI 預測機率(短期 1-7天): | 方向 | 機率 | 說明 | |------|------|------| | 📈 **上漲** | **{probabilities['up']:.1f}%** | 股價向上突破的可能性 | | 📉 **下跌** | **{probabilities['down']:.1f}%** | 股價向下修正的可能性 | | ➡️ **盤整** | **{probabilities['sideways']:.1f}%** | 股價維持震盪的可能性 | ### 🎯 主要預測方向: {direction_emoji} **{main_direction}** ({confidence_desc} - {confidence*100:.0f}%) ### � **具體投資建議** --- #### 🏠 **若您目前持有此股票:** {buy_sell_rec['holding_advice']} #### 💰 **若您目前未持有此股票:** {buy_sell_rec['non_holding_advice']} #### 📊 **投資參數建議:** - **風險等級:** {buy_sell_rec['risk_level']} - **操作優先級:** {buy_sell_rec['action_priority']} - **{buy_sell_rec['position_sizing']}** ### 📋 一般性投資策略: """ # 根據最高機率給出一般策略 if probabilities['up'] > 50: report += """ - 💡 **多頭策略**:考慮逢低加碼或持有現有部位 - 🎯 **目標設定**:關注上方阻力位,設定合理獲利目標 - 🛡️ **風險管理**:設置止損點保護資本""" elif probabilities['down'] > 50: report += """ - 💡 **防守策略**:考慮減碼或等待更佳進場點 - 🎯 **支撐觀察**:留意下方支撐位是否守住 - 🛡️ **風險管理**:避免追高,控制倉位大小""" else: report += """ - 💡 **中性策略**:保持觀望,等待明確方向訊號 - 🎯 **區間操作**:可考慮在支撐阻力區間內操作 - 🛡️ **風險管理**:小部位測試,嚴格執行停損""" report += f""" ### 📅 中期展望(1個月): 基於當前技術面和市場情緒分析,建議持續關注: - 關鍵技術位:支撐與阻力區間 - 市場情緒變化:新聞面和資金流向 - 整體大盤走勢:系統性風險評估 ⚠️ **重要風險提醒**: - 此分析基於歷史數據和 AI 模型預測,僅供參考 - 投資有風險,請謹慎評估並做好風險管理 - 建議結合個人財務狀況和投資目標做決策 - 請勿將此作為唯一投資依據 --- *預測信心度:{confidence*100:.0f}% | 分析時間:{datetime.now().strftime('%Y-%m-%d %H:%M')} | 由 Copilot 生成* """ return report def generate_prediction(self, df, news_sentiment): """生成預測分析""" if df is None or len(df) < 30: return "數據不足,無法進行預測分析" # 獲取最新數據 latest = df.iloc[-1] recent_data = df.tail(20) # 技術分析信號 technical_signals = [] # 價格趋势 if latest['Close'] > latest['MA20']: technical_signals.append("價格在20日均線之上(多頭信號)") else: technical_signals.append("價格在20日均線之下(空頭信號)") # RSI 分析 rsi = latest['RSI'] if rsi > 70: technical_signals.append(f"RSI({rsi:.1f}) 超買警訊") elif rsi < 30: technical_signals.append(f"RSI({rsi:.1f}) 超賣機會") else: technical_signals.append(f"RSI({rsi:.1f}) 正常範圍") # MACD 分析 if latest['MACD'] > latest['MACD_signal']: technical_signals.append("MACD 呈現多頭排列") else: technical_signals.append("MACD 呈現空頭排列") # 新聞情感分析 sentiment_summary = self.analyze_sentiment_summary(news_sentiment) # 綜合預測 prediction = self.generate_comprehensive_prediction(technical_signals, sentiment_summary, recent_data) return prediction # 創建分析器實例 analyzer = StockAnalyzer() def analyze_stock(symbol): """主要分析函數""" if not symbol.strip(): return None, "請輸入股票代碼", "" # 獲取數據 result = analyzer.fetch_stock_data(symbol.upper()) if len(result) == 3: success, message, stock_name = result else: success, message = result stock_name = None if not success: return None, message, "" # 計算技術指標 df = analyzer.calculate_technical_indicators() # 創建價格圖表 fig = go.Figure() # 添加K線圖 fig.add_trace(go.Candlestick( x=df.index, open=df['Open'], high=df['High'], low=df['Low'], close=df['Close'], name='價格' )) # 添加移動平均線 fig.add_trace(go.Scatter(x=df.index, y=df['MA5'], name='MA5', line=dict(color='orange'))) fig.add_trace(go.Scatter(x=df.index, y=df['MA20'], name='MA20', line=dict(color='blue'))) fig.update_layout( title=f'{symbol} 股價走勢與技術指標', xaxis_title='日期', yaxis_title='價格', height=600 ) # 獲取新聞情感 news_sentiment = analyzer.get_news_sentiment(symbol) # 生成預測 prediction = analyzer.generate_prediction(df, news_sentiment) return fig, "分析完成!", prediction def get_chinese_name(symbol): """獲取股票中文簡稱 - 由 Copilot 生成""" # 台股股票中文名稱對照表 tw_stock_names = { '2330.TW':'台積電', '2317.TW':'鴻海', '2308.TW':'台達電', '2454.TW':'聯發科', '2881.TW':'富邦金', '2382.TW':'廣達', '2412.TW':'中華電', '2882.TW':'國泰金', '2891.TW':'中信金', '3711.TW':'日月光投控', '2886.TW':'兆豐金', '6669.TW':'緯穎', '2345.TW':'智邦', '2303.TW':'聯電', '2884.TW':'玉山金', '2357.TW':'華碩', '2885.TW':'元大金', '2887.TW':'台新新光金', '3231.TW':'緯創', '1216.TW':'統一', '2892.TW':'第一金', '2383.TW':'台光電', '2880.TW':'華南金', '3045.TW':'台灣大', '2301.TW':'光寶科', '2603.TW':'長榮', '6505.TW':'台塑化', '5880.TW':'合庫金', '3017.TW':'奇鋐', '2327.TW':'國巨*', '3653.TW':'健策', '2207.TW':'和泰車', '2890.TW':'永豐金', '3008.TW':'大立光', '2059.TW':'川湖', '1303.TW':'南亞', '4904.TW':'遠傳', '2002.TW':'中鋼', '6919.TW':'康霈*', '2379.TW':'瑞昱', '2395.TW':'研華', '3661.TW':'世芯-KY', '3034.TW':'聯詠', '2912.TW':'統一超', '2883.TW':'凱基金', '2360.TW':'致茂', '1301.TW':'台塑', '3037.TW':'欣興', '2801.TW':'彰銀', '2408.TW':'南亞科', '2368.TW':'金像電', '2615.TW':'萬海', '2618.TW':'長榮航', '5876.TW':'上海商銀', '1504.TW':'東元', '2449.TW':'京元電子', '2376.TW':'技嘉', '3665.TW':'貿聯-KY', '6446.TW':'藥華藥', '5871.TW':'中租-KY', '4938.TW':'和碩', '2609.TW':'陽明', '1519.TW':'華城', '1101.TW':'台泥', '3443.TW':'創意', '1326.TW':'台化', '3533.TW':'嘉澤', '2404.TW':'漢唐', '2356.TW':'英業達', '4958.TW':'臻鼎-KY', '3044.TW':'健鼎', '3036.TW':'文曄', '2344.TW':'華邦電', '2834.TW':'臺企銀', '1590.TW':'亞德客-KY', '1402.TW':'遠東新', '8046.TW':'南電', '2324.TW':'仁寶', '1102.TW':'亞泥', '2812.TW':'台中銀', '2610.TW':'華航', '8464.TW':'億豐', '2105.TW':'正新', '9910.TW':'豐泰', '1476.TW':'儒鴻', '2474.TW':'可成', '3706.TW':'神達', '3481.TW':'群創', '1605.TW':'華新', '3702.TW':'大聯大', '6239.TW':'力成', '5269.TW':'祥碩', '6770.TW':'力積電', '2347.TW':'聯強', '2385.TW':'群光', '2409.TW':'友達', '6415.TW':'矽力*-KY', '2354.TW':'鴻準', '2027.TW':'大成鋼', '6781.TW':'AES-KY', '2377.TW':'微星', '3005.TW':'神基', '1503.TW':'士電', '2353.TW':'宏碁', '6789.TW':'采鈺', '2542.TW':'興富發', '1229.TW':'聯華', '2313.TW':'華通', '6526.TW':'達發', '2371.TW':'大同', '6472.TW':'保瑞', '9904.TW':'寶成', '9945.TW':'潤泰新', '6139.TW':'亞翔', '6515.TW':'穎崴', '6409.TW':'旭隼', '1802.TW':'台玻', '1513.TW':'中興電', '2838.TW':'聯邦銀', '2049.TW':'上銀', '2646.TW':'星宇航空', '2633.TW':'台灣高鐵', '8210.TW':'勤誠', '1477.TW':'聚陽', '1795.TW':'美時', '6805.TW':'富世達', '2258.TW':'鴻華先進-創', '6176.TW':'瑞儀', '8454.TW':'富邦媒', '2809.TW':'京城銀', '4763.TW':'材料*-KY', '2645.TW':'長榮航太', '2845.TW':'遠東銀', '6442.TW':'光聖', '5434.TW':'崇越', '6191.TW':'精成科', '9941.TW':'裕融', '2352.TW':'佳世達', '2915.TW':'潤泰全', '2539.TW':'櫻花建', '6285.TW':'啟碁', '2889.TW':'國票金', '6531.TW':'愛普*', '3023.TW':'信邦', '1319.TW':'東陽', '4583.TW':'台灣精銳', '6890.TW':'來億-KY', '6691.TW':'洋基工程', '2540.TW':'愛山林', '6005.TW':'群益證', '2634.TW':'漢翔', '1736.TW':'喬山', '3376.TW':'新日興', '2492.TW':'華新科', '9917.TW':'中保科', '2498.TW':'宏達電', '2206.TW':'三陽工業', '6196.TW':'帆宣', '1560.TW':'中砂', '3189.TW':'景碩', '5522.TW':'遠雄', '3596.TW':'智易', '3406.TW':'玉晶光', '2606.TW':'裕民', '1722.TW':'台肥', '1717.TW':'長興', '2597.TW':'潤弘', '2451.TW':'創見', '4766.TW':'南寶', '2337.TW':'旺宏', '1210.TW':'大成', '9958.TW':'世紀鋼', '5469.TW':'瀚宇博', '2006.TW':'東和鋼鐵', '3019.TW':'亞光', '6257.TW':'矽格', '2637.TW':'慧洋-KY', '6592.TW':'和潤企業', '2504.TW':'國產', '1907.TW':'永豐餘', '3030.TW':'德律', '1215.TW':'卜蜂', '3035.TW':'智原', '7722.TW':'LINEPAY', '6414.TW':'樺漢', '1773.TW':'勝一', '2211.TW':'長榮鋼', '5234.TW':'達興材料', '6944.TW':'兆聯實業', '6412.TW':'群電', '3450.TW':'聯鈞', '2458.TW':'義隆', '2543.TW':'皇昌', '3532.TW':'台勝科', '6213.TW':'聯茂', '1231.TW':'聯華食', '2850.TW':'新產', '2015.TW':'豐興', '2923.TW':'鼎固-KY', '9939.TW':'宏全', '2855.TW':'統一證', '2607.TW':'榮運', '2201.TW':'裕隆', '9921.TW':'巨大', '4915.TW':'致伸', '6670.TW':'復盛應用', '2441.TW':'超豐', '6757.TW':'台灣虎航', '2204.TW':'中華', '8926.TW':'台汽電', '2421.TW':'建準', '2867.TW':'三商壽', '3515.TW':'華擎', '6214.TW':'精誠', '2903.TW':'遠百', '3583.TW':'辛耘', '1609.TW':'大亞', '8028.TW':'昇陽半導體', '2388.TW':'威盛', '2548.TW':'華固', '6278.TW':'台表科', '5388.TW':'中磊', '9914.TW':'美利達', '8996.TW':'高力', '3413.TW':'京鼎', '2023.TW':'燁輝', '2467.TW':'志聖', '2455.TW':'全新', '2363.TW':'矽統', '2312.TW':'金寶', '3042.TW':'晶技', '8070.TW':'長華*', '1808.TW':'潤隆', '6550.TW':'北極星藥業-KY', '2393.TW':'億光', '9907.TW':'統一實', '9933.TW':'中鼎', '2328.TW':'廣宇', '2208.TW':'台船', '1514.TW':'亞力', '2374.TW':'佳能', '2101.TW':'南港', '1227.TW':'佳格', '1314.TW':'中石化', '2501.TW':'國建', '2481.TW':'強茂', '4919.TW':'新唐', '2329.TW':'華泰', '3714.TW':'富采', '6282.TW':'康舒', '8016.TW':'矽創', '2362.TW':'藍天', '2439.TW':'美律', '1434.TW':'福懋', '2897.TW':'王道銀行', '2707.TW':'晶華', '2530.TW':'華建', '6491.TW':'晶碩', '3715.TW':'定穎投控', '3010.TW':'華立', '2359.TW':'所羅門', '2392.TW':'正崴', '2247.TW':'汎德永業', '6271.TW':'同欣電', '3013.TW':'晟銘電', '6116.TW':'彩晶', '6949.TW':'沛爾生醫-創', '4770.TW':'上品', '7749.TW':'意騰-KY', '1232.TW':'大統益', '3563.TW':'牧德', '8112.TW':'至上', '6177.TW':'達麗', '1409.TW':'新纖', '2014.TW':'中鴻', '8033.TW':'雷虎', '8422.TW':'可寧衛', '1440.TW':'南紡', '3014.TW':'聯陽', '2476.TW':'鉅祥', '5534.TW':'長虹', '2520.TW':'冠德', '2428.TW':'興勤', '2836.TW':'高雄銀', '2820.TW':'華票', '6605.TW':'帝寶', '8478.TW':'東哥遊艇', '6456.TW':'GIS-KY', '3592.TW':'瑞鼎', '8150.TW':'南茂', '1104.TW':'環泥', '3006.TW':'晶豪科', '6962.TW':'奕力-KY', '4961.TW':'天鈺', '6768.TW':'志強-KY', '6579.TW':'研揚', '1608.TW':'華榮', '6269.TW':'台郡', '8081.TW':'致新', '9802.TW':'鈺齊-KY', '2849.TW':'安泰銀', '6197.TW':'佳必琪', '3617.TW':'碩天', '4722.TW':'國精化', '2727.TW':'王品', '1904.TW':'正隆', '1723.TW':'中碳', '2106.TW':'建大', '1707.TW':'葡萄王', '2851.TW':'中再保', '3029.TW':'零壹', '5607.TW':'遠雄港', '9937.TW':'全國', '9911.TW':'櫻花', '2367.TW':'燿華', '2480.TW':'敦陽科', '2486.TW':'一詮', '3703.TW':'欣陸', '1712.TW':'興農', '6854.TW':'錼創科技-KY創', '6449.TW':'鈺邦', '6873.TW':'泓德能源', '6719.TW':'力智', '9940.TW':'信義', '9930.TW':'中聯資源', '6589.TW':'台康生技', '2316.TW':'楠梓電', '1536.TW':'和大', '4536.TW':'拓凱', '8114.TW':'振樺電', '6937.TW':'天虹', '2524.TW':'京城', '1419.TW':'新紡', '2231.TW':'為升', '6753.TW':'龍德造船', '6451.TW':'訊芯-KY', '2227.TW':'裕日車', '3016.TW':'嘉晶', '6901.TW':'鑽石投資', '6869.TW':'雲豹能源', '2515.TW':'中工', '2545.TW':'皇翔', '2535.TW':'達欣工', '9938.TW':'百和', '3673.TW':'TPK-KY', '3026.TW':'禾伸堂', '2608.TW':'嘉里大榮', '2402.TW':'毅嘉', '3059.TW':'華晶科', '2704.TW':'國賓', '9925.TW':'新保', '8039.TW':'台虹', '3380.TW':'明泰', '3167.TW':'大量', '3705.TW':'永信', '6533.TW':'晶心科', '9908.TW':'大台北', '6806.TW':'森崴能源', '5007.TW':'三星', '1442.TW':'名軒', '4551.TW':'智伸科', '6965.TW':'中傑-KY', '1234.TW':'黑松', '2009.TW':'第一銅', '1789.TW':'神隆', '6206.TW':'飛捷', '6183.TW':'關貿', '2731.TW':'雄獅', '2511.TW':'太子', '5284.TW':'jpp-KY', '4104.TW':'佳醫', '3545.TW':'敦泰', '2351.TW':'順德', '6438.TW':'迅得', '3708.TW':'上緯投控', '3305.TW':'昇貿', '8021.TW':'尖點', '2472.TW':'立隆電', '1313.TW':'聯成', '3416.TW':'融程電', '8131.TW':'福懋科', '3090.TW':'日電貿', '3704.TW':'合勤控', '4576.TW':'大銀微系統', '2355.TW':'敬鵬', '2464.TW':'盟立', '2753.TW':'八方雲集', '2401.TW':'凌陽', '1903.TW':'士紙', '4968.TW':'立積', '6541.TW':'泰福-KY', '2031.TW':'新光鋼', '2373.TW':'震旦行', '2493.TW':'揚博', '2832.TW':'台產', '2905.TW':'三商', '3033.TW':'威健', '2605.TW':'新興', '2103.TW':'台橡', '5243.TW':'乙盛-KY', '6166.TW':'凌華', '2010.TW':'春源', '2723.TW':'美食-KY', '1909.TW':'榮成', '1905.TW':'華紙', '1522.TW':'堤維西', '2348.TW':'海悅', '8462.TW':'柏文', '6782.TW':'視陽', '6189.TW':'豐藝', '5222.TW':'全訊', '6230.TW':'尼得科超眾', '6235.TW':'華孚', '2528.TW':'皇普', '1436.TW':'華友聯', '4755.TW':'三福化', '4532.TW':'瑞智', '6581.TW':'鋼聯', '3694.TW':'海華', '2233.TW':'宇隆', '1726.TW':'永記', '1612.TW':'宏泰', '2331.TW':'精英', '6024.TW':'群益期', '1307.TW':'三芳', '1304.TW':'台聚', '3022.TW':'威強電', '1702.TW':'南僑', '2108.TW':'南帝', '6534.TW':'正瀚-創', '4736.TW':'泰博', '1532.TW':'勤美', '2547.TW':'日勝生', '2466.TW':'冠西電', '2546.TW':'根基', '2630.TW':'亞航', '2617.TW':'台航', '7740.TW':'熙特爾-創', '3576.TW':'聯合再生', '1563.TW':'巧新', '1710.TW':'東聯', '1718.TW':'中纖', '3605.TW':'宏致', '5306.TW':'桂盟', '1103.TW':'嘉泥', '4906.TW':'正文', '6525.TW':'捷敏-KY', '8404.TW':'百和興業-KY', '1537.TW':'廣隆', '1711.TW':'永光', '2104.TW':'國際中橡', '2612.TW':'中航', '2436.TW':'偉詮電', '2332.TW':'友訊', '1312.TW':'國喬', '6863.TW':'永道-KY', '6923.TW':'中台', '2457.TW':'飛宏', '2340.TW':'台亞', '2034.TW':'允強', '6790.TW':'永豐實', '8163.TW':'達方', '8499.TW':'鼎炫-KY', '4771.TW':'望隼', '6215.TW':'和椿', '8341.TW':'日友', '2338.TW':'光罩', '2534.TW':'宏盛', '2908.TW':'特力', '3032.TW':'偉訓', '3015.TW':'全漢', '1720.TW':'生達', '1582.TW':'信錦', '1614.TW':'三洋電', '2429.TW':'銘旺科', '2913.TW':'農林', '2636.TW':'台驊控股', '6192.TW':'巨路', '3048.TW':'益登', '1235.TW':'興泰', '2323.TW':'中環', '4977.TW':'眾達-KY', '6464.TW':'台數科', '4306.TW':'炎洲', '3701.TW':'大眾控', '6153.TW':'嘉聯益', '6957.TW':'裕慶-KY', '1604.TW':'聲寶', '1218.TW':'泰山', '3056.TW':'富華新', '1203.TW':'味王', '1615.TW':'大山', '6914.TW':'阜爾運通', '8213.TW':'志超', '9927.TW':'泰銘', '6202.TW':'盛群', '3645.TW':'達邁', '1110.TW':'東泥', '3149.TW':'正達', '8110.TW':'華東', '6655.TW':'科定', '4571.TW':'鈞興-KY', '2365.TW':'昆盈', '2536.TW':'宏普', '9942.TW':'茂順', '4526.TW':'東台', '2489.TW':'瑞軒', '5225.TW':'東科-KY', '5525.TW':'順天', '9926.TW':'新海', '5531.TW':'鄉林', '6115.TW':'鎰勝', '1618.TW':'合機', '2102.TW':'泰豐', '8374.TW':'羅昇', '8467.TW':'波力-KY', '4164.TW':'承業醫', '3712.TW':'永崴投控', '2375.TW':'凱美', '4137.TW':'麗豐-KY', '6830.TW':'汎銓', '9924.TW':'福興', '5258.TW':'虹堡', '2013.TW':'中鋼構', '2228.TW':'劍麟', '8045.TW':'達運光電', '4739.TW':'康普', '2762.TW':'世界健身-KY', '1321.TW':'大洋', '4960.TW':'誠美材', '3622.TW':'洋華', '9943.TW':'好樂迪', '8271.TW':'宇瞻', '4142.TW':'國光生', '3003.TW':'健和興', '2423.TW':'固緯', '2387.TW':'精元', '2852.TW':'第一保', '1714.TW':'和桐', '2420.TW':'新巨', '4438.TW':'廣越', '3454.TW':'晶睿', '8261.TW':'富鼎', '4746.TW':'台耀', '6184.TW':'大豐電', '2397.TW':'友通', '3062.TW':'建漢', '1709.TW':'和益', '1201.TW':'味全', '5203.TW':'訊連', '5288.TW':'豐祥-KY', '6443.TW':'元晶', '3312.TW':'弘憶股', '8249.TW':'菱光', '8215.TW':'明基材', '6933.TW':'AMAX-KY', '6117.TW':'迎廣', '1603.TW':'華電', '1708.TW':'東鹼', '3004.TW':'豐達科', '2478.TW':'大毅', '3130.TW':'一零四', '6277.TW':'宏正', '4967.TW':'十銓', '6862.TW':'三集瑞-KY', '6585.TW':'鼎基', '3028.TW':'增你強', '2419.TW':'仲琦', '2450.TW':'神腦', '3209.TW':'全科', '1713.TW':'國化', '1786.TW':'科妍', '2107.TW':'厚生', '6958.TW':'日盛台駿', '3679.TW':'新至陞', '4119.TW':'旭富', '9918.TW':'欣天然', '2029.TW':'盛餘', '1225.TW':'福懋油', '2614.TW':'東森', '2406.TW':'國碩', '2369.TW':'菱生', '2505.TW':'國揚', '1597.TW':'直得', '2349.TW':'錸德', '4927.TW':'泰鼎-KY', '7736.TW':'虎山', '6706.TW':'惠特', '2114.TW':'鑫永銓', '2414.TW':'精技', '2433.TW':'互盛電', '1308.TW':'亞聚', '2442.TW':'新美齊', '2527.TW':'宏璟', '6281.TW':'全國電', '6120.TW':'達運', '3504.TW':'揚明光', '6672.TW':'騰輝電子-KY', '1342.TW':'八貫', '1535.TW':'中宇', '1616.TW':'億泰', '2459.TW':'敦吉', '2706.TW':'第一店', '6994.TW':'富威電力', '5608.TW':'四維航', '4994.TW':'傳奇', '6209.TW':'今國光', '1305.TW':'華夏', '2020.TW':'美亞', '2417.TW':'圓剛', '2405.TW':'輔信', '4572.TW':'駐龍', '4916.TW':'事欣科', '5292.TW':'華懋', '5519.TW':'隆大', '8473.TW':'山林水', '1737.TW':'臺鹽', '1315.TW':'達新', '1444.TW':'力麗', '9905.TW':'大華', '5471.TW':'松翰', '3535.TW':'晶彩科', '6112.TW':'邁達特', '6715.TW':'嘉基', '1437.TW':'勤益控', '2453.TW':'凌群', '2495.TW':'普安', '1108.TW':'幸福', '6756.TW':'威鋒電子', '6416.TW':'瑞祺電通', '3501.TW':'維熹', '1558.TW':'伸興', '1760.TW':'寶齡富錦', '2497.TW':'怡利電', '2816.TW':'旺旺保', '4935.TW':'茂林-KY', '5521.TW':'工信', '8105.TW':'凌巨', '9946.TW':'三發地產', '4566.TW':'時碩工業', '2514.TW':'龍邦', '2236.TW':'百達-KY', '1734.TW':'杏輝', '1810.TW':'和成', '1256.TW':'鮮活果汁-KY', '5538.TW':'東明-KY', '8482.TW':'商億-KY', '1316.TW':'上曜', '1583.TW':'程泰', '2028.TW':'威致', '3055.TW':'蔚華科', '3257.TW':'虹冠電', '4976.TW':'佳凌', '3049.TW':'精金', '2426.TW':'鼎元', '1109.TW':'信大', '1457.TW':'宜進', '2427.TW':'三商電', '3447.TW':'展達', '6887.TW':'寶綠特-KY', '9906.TW':'欣巴巴', '6477.TW':'安集', '1447.TW':'力鵬', '1515.TW':'力山', '1217.TW':'愛之味', '2012.TW':'春雨', '2008.TW':'高興昌', '6201.TW':'亞弘電', '3338.TW':'泰碩', '4942.TW':'嘉彰', '4912.TW':'聯德控股-KY', '6928.TW':'攸泰科技', '6689.TW':'伊雲谷', '2342.TW':'茂矽', '2701.TW':'萬企', '1525.TW':'江申', '8103.TW':'瀚荃', '3266.TW':'昇陽', '3530.TW':'晶相光', '3716.TW':'中化控股', '5285.TW':'界霖', '5283.TW':'禾聯碩', '5515.TW':'建國', '6625.TW':'必應', '3528.TW':'安馳', '8442.TW':'威宏-KY', '1455.TW':'集盛', '1725.TW':'元禎', '2748.TW':'雲品', '3138.TW':'耀登', '2538.TW':'基泰', '2601.TW':'益航', '1464.TW':'得力', '1472.TW':'三洋實業', '6743.TW':'安普新', '6695.TW':'芯鼎', '6657.TW':'華安', '4569.TW':'六方科-KY', '4540.TW':'全球傳動', '6838.TW':'台新藥', '1524.TW':'耿鼎', '1219.TW':'福壽', '1310.TW':'台苯', '5706.TW':'鳳凰', '4564.TW':'元翎', '4952.TW':'凌通', '1527.TW':'鑽全', '1727.TW':'中華化', '2062.TW':'橋椿', '2109.TW':'華豐', '2007.TW':'燁興', '1459.TW':'聯發', '1309.TW':'台達化', '6168.TW':'宏齊', '6224.TW':'聚鼎', '6776.TW':'展碁國際', '6885.TW':'全福生技', '6955.TW':'邦睿生技-創', '9934.TW':'成霖', '6558.TW':'興能高', '6165.TW':'浪凡', '5533.TW':'皇鼎', '4737.TW':'華廣', '3356.TW':'奇偶', '1611.TW':'中電', '2017.TW':'官田鋼', '2239.TW':'英利-KY', '2485.TW':'兆赫', '3047.TW':'訊舟', '1438.TW':'三地開發', '1414.TW':'東和', '8367.TW':'建新國際', '9931.TW':'欣高', '3717.TW':'聯嘉投控', '1460.TW':'宏遠', '1783.TW':'和康生', '3040.TW':'遠見', '2722.TW':'夏都', '2364.TW':'倫飛', '2030.TW':'彰源', '1598.TW':'岱宇', '1443.TW':'立益物流', '2254.TW':'巨鎧精密-創', '2477.TW':'美隆電', '4934.TW':'太極', '8104.TW':'錸寶', '8463.TW':'潤泰材', '6742.TW':'澤米', '4562.TW':'穎漢', '2462.TW':'良得電', '3168.TW':'眾福科', '1423.TW':'利華', '1463.TW':'強盛新', '1473.TW':'台南', '1752.TW':'南光', '3051.TW':'力特', '3024.TW':'憶聲', '2613.TW':'中櫃', '2468.TW':'華經', '2506.TW':'太設', '4439.TW':'冠星-KY', '6799.TW':'來頡', '6906.TW':'現觀科', '8011.TW':'台通', '6794.TW':'向榮生技-創', '9935.TW':'慶豐富', '2910.TW':'統領', '1733.TW':'五鼎', '1806.TW':'冠軍', '1451.TW':'年興', '1529.TW':'樂事綠能', '1435.TW':'中福', '2739.TW':'寒舍', '3031.TW':'佰鴻', '3060.TW':'銘異', '2488.TW':'漢平', '4989.TW':'榮科', '6128.TW':'上福', '6205.TW':'詮欣', '4764.TW':'雙鍵', '3557.TW':'嘉威', '3311.TW':'閎暉', '6668.TW':'中揚光', '6931.TW':'青松健康', '2484.TW':'希華', '2509.TW':'全坤建', '3046.TW':'建碁', '3038.TW':'全台', '2399.TW':'映泰', '1587.TW':'吉茂', '6951.TW':'青新-創', '9919.TW':'康那香', '4557.TW':'永新-KY', '6591.TW':'動力-KY', '6283.TW':'淳安', '8222.TW':'寶一', '1730.TW':'花仙子', '2250.TW':'IKKA-KY', '2516.TW':'新建', '2537.TW':'聯上發', '3041.TW':'揚智', '2465.TW':'麗臺', '2241.TW':'艾姆勒', '1809.TW':'中釉', '9955.TW':'佳龍', '6504.TW':'南六', '3543.TW':'州巧', '3588.TW':'通嘉', '8476.TW':'台境*', '6952.TW':'大武山', '6918.TW':'愛派司', '6754.TW':'匯僑設計', '1589.TW':'永冠-KY', '1533.TW':'車王電', '1341.TW':'富林-KY', '2705.TW':'六福', '2460.TW':'建通', '1339.TW':'昭輝', '7721.TW':'微程式', '4555.TW':'氣立', '4414.TW':'如興', '6582.TW':'申豐', '4108.TW':'懷特', '3669.TW':'圓展', '6909.TW':'創控', '1528.TW':'恩德', '2038.TW':'海光', '2425.TW':'承啟', '2906.TW':'高林', '2611.TW':'志信', '2642.TW':'宅配通', '2430.TW':'燦坤', '2302.TW':'麗正', '1817.TW':'凱撒衛', '1731.TW':'美吾華', '8481.TW':'政伸', '5244.TW':'弘凱', '6606.TW':'建德工業', '8411.TW':'福貞-KY', '8162.TW':'微矽電子-創', '8072.TW':'陞泰', '6902.TW':'GOGOLOOK', '2115.TW':'六暉-KY', '1233.TW':'天仁', '2413.TW':'環科', '2461.TW':'光群雷', '1446.TW':'宏和', '1617.TW':'榮星', '6807.TW':'峰源-KY', '6796.TW':'晉弘', '6792.TW':'詠業', '7631.TW':'聚賢研發-創', '7705.TW':'三商餐飲', '6426.TW':'統新', '6136.TW':'富爾特', '3346.TW':'麗清', '4545.TW':'銘鈺', '4588.TW':'玖鼎電力', '4949.TW':'有成精密', '4552.TW':'力達-KY', '4148.TW':'全宇生技-KY', '3591.TW':'艾笛森', '5484.TW':'慧友', '6216.TW':'居易', '2022.TW':'聚亨', '1530.TW':'亞崴', '1325.TW':'恆大', '1439.TW':'雋揚', '3052.TW':'夆典', '3027.TW':'盛達', '6834.TW':'天二科技', '6835.TW':'圓裕', '6861.TW':'睿生光電', '6936.TW':'永鴻生技', '3025.TW':'星通', '2945.TW':'三商家購', '1721.TW':'三晃', '2069.TW':'運錩', '1517.TW':'利奇', '1568.TW':'倉佑', '2471.TW':'資通', '2483.TW':'百容', '6666.TW':'羅麗芬-KY', '7732.TW':'金興精密', '6598.TW':'ABC-KY', '6552.TW':'易華電', '6423.TW':'億而得-創', '6142.TW':'友勁', '6108.TW':'競國', '3652.TW':'精聯', '6698.TW':'旭暉應材', '2415.TW':'錩新', '3058.TW':'立德', '1220.TW':'台榮', '2305.TW':'全友', '3094.TW':'聯傑', '6671.TW':'三能-KY', '3437.TW':'榮創', '4106.TW':'雃博', '4560.TW':'強信-KY', '6155.TW':'鈞寶', '5215.TW':'科嘉-KY', '4155.TW':'訊映', '4956.TW':'光鋐', '3518.TW':'柏騰', '6658.TW':'聯策', '8487.TW':'愛爾達-創', '8438.TW':'昶昕', '1236.TW':'宏亞', '1416.TW':'廣豐', '1410.TW':'南染', '1540.TW':'喬福', '1475.TW':'業旺', '1506.TW':'正道', '1468.TW':'昶和', '1541.TW':'錩泰', '1531.TW':'高林股', '2248.TW':'華勝-KY', '1906.TW':'寶隆', '2712.TW':'遠雄來', '3296.TW':'勝德', '4190.TW':'佐登-KY', '5546.TW':'永固-KY', '6133.TW':'金橋', '2616.TW':'山隆', '3054.TW':'立萬利', '3050.TW':'鈺德', '2390.TW':'云辰', '1762.TW':'中化生', '2025.TW':'千興', '1521.TW':'大億', '1470.TW':'大統新創', '1466.TW':'聚隆', '1445.TW':'大宇', '2032.TW':'新鋼', '2702.TW':'華園', '2901.TW':'欣欣', '4999.TW':'鑫禾', '8466.TW':'美吉吉-KY', '9944.TW':'新麗', '4581.TW':'光隆精密-KY', '4930.TW':'燦星網', '4720.TW':'德淵', '1626.TW':'艾美特-KY', '1454.TW':'台富', '1338.TW':'廣華-KY', '1323.TW':'永裕', '1452.TW':'宏益', '2033.TW':'佳大', '3092.TW':'鴻碩', '3021.TW':'鴻名', '3011.TW':'今皓', '2440.TW':'太空梭', '2432.TW':'倚天酷碁-創', '4426.TW':'利勤', '3419.TW':'譁裕', '5906.TW':'台南-KY', '6405.TW':'悅城', '3607.TW':'谷崧', '3002.TW':'歐格', '3164.TW':'景岳', '2024.TW':'志聯', '1453.TW':'大將', '1449.TW':'佳和', '1417.TW':'嘉裕', '1432.TW':'大魯閣', '4133.TW':'亞諾法', '6243.TW':'迅杰', '6152.TW':'百一', '9902.TW':'台火', '6771.TW':'平和環保-創', '6674.TW':'鋐寶科技', '8429.TW':'金麗-KY', '3686.TW':'達能', '1474.TW':'弘裕', '1805.TW':'寶徠', '1735.TW':'日勝化', '2482.TW':'連宇', '2438.TW':'翔耀', '2431.TW':'聯昌', '1471.TW':'首利', '1337.TW':'再生-KY', '6969.TW':'成信實業*-創', '6645.TW':'金萬林-創', '8940.TW':'新天地', '3550.TW':'聯穎', '6141.TW':'柏承', '1465.TW':'偉全', '2904.TW':'匯僑', '2496.TW':'卓越', '1467.TW':'南緯', '1340.TW':'勝悅-KY', '1732.TW':'毛寶', '6916.TW':'華凌', '6924.TW':'榮惠-KY創', '9928.TW':'中視', '9929.TW':'秋雨', '5907.TW':'大洋-KY', '4440.TW':'宜新實業', '1456.TW':'怡華', '1539.TW':'巨庭', '2444.TW':'兆勁', '2939.TW':'永邑-KY', '2491.TW':'吉祥全', '1413.TW':'宏洲', '1418.TW':'東華', '1526.TW':'日馳', '2424.TW':'隴華', '2929.TW':'淘帝-KY', '3150.TW':'鈺寶-創', '3308.TW':'聯德', '8201.TW':'無敵', '3043.TW':'科風', '1776.TW':'展宇', '2243.TW':'宏旭-KY', '1512.TW':'瑞利', '1324.TW':'地球', '8443.TW':'阿瘦', '6988.TW':'威力暘-創', '6164.TW':'華興', '6226.TW':'光鼎', '6431.TW':'光麗-KY', '6573.TW':'虹揚-KY', '6641.TW':'基士德-KY', '8488.TW':'吉源-KY', '1441.TW':'大東', '3057.TW':'喬鼎', '9912.TW':'偉聯', '3494.TW':'誠研', '4807.TW':'日成-KY', '1516.TW':'川飛', '3229.TW':'晟鈦', '2434.TW':'統懋', '3432.TW':'台端', } # 美股股票中文名稱對照表 us_stock_names = { 'AAPL': '蘋果', 'MSFT': '微軟', 'GOOGL': '谷歌', 'AMZN': '亞馬遜', 'TSLA': '特斯拉', 'META': 'Meta', 'NVDA': '輝達', 'NFLX': '網飛', 'AMD': '超微', 'INTC': '英特爾', 'ORCL': '甲骨文', 'CRM': 'Salesforce', 'ADBE': 'Adobe', 'PYPL': 'PayPal', 'UBER': 'Uber', 'SPOT': 'Spotify', 'ZOOM': 'Zoom', 'SHOP': 'Shopify', 'SQ': 'Block', 'TWTR': '推特', 'SNAP': 'Snapchat', 'PINS': 'Pinterest', 'DOCU': 'DocuSign', 'ROKU': 'Roku', 'PLTR': 'Palantir', 'COIN': 'Coinbase', 'RBLX': 'Roblox', 'RIVN': 'Rivian', 'LCID': 'Lucid', 'NIO': '蔚來', 'XPEV': '小鵬', 'LI': '理想', 'BABA': '阿里巴巴', 'JD': '京東', 'PDD': '拼多多', 'BIDU': '百度', 'TME': '騰訊音樂', 'BILI': 'B站', 'VTI': '全市場ETF', 'VOO': 'S&P500ETF', 'QQQ': '納斯達克ETF', 'SPY': 'SPDR S&P500', 'IWM': '羅素2000', 'EFA': '歐澳遠東ETF', 'EEM': '新興市場ETF', 'VNQ': '房地產ETF', 'GLD': '黃金ETF', 'TLT': '長期國債ETF', 'BTC-USD': '比特幣', 'ETH-USD': '以太幣', '^GSPC': 'S&P500指數', '^DJI': '道瓊指數', '^IXIC': '納斯達克指數', } # 首先查找台股 if symbol in tw_stock_names: return tw_stock_names[symbol] # 然後查找美股 if symbol in us_stock_names: return us_stock_names[symbol] # 如果都找不到,返回原始名稱(通常是從 yfinance 獲取的英文名稱) return symbol def create_results_table(results): """創建結果表格 - 由 Copilot 生成""" if not results: return "" # 創建表格 HTML table_html = """
""" for result in results: # 判斷預測方向和顏色 if result['error_message']: direction = "❌ 錯誤" row_color = "#fff2f2" holding_advice = "N/A" buying_advice = "N/A" news_alert = "N/A" volume_alert1 = "N/A" institutional_alert1 = "N/A" institutional_alert2 = "N/A" technical_alert2 = "N/A" technical_alert3 = "N/A" technical_alert4 = "N/A" technical_alert5 = "N/A" summary_alert = "N/A" else: up_prob = float(result['up_probability']) down_prob = float(result['down_probability']) sideways_prob = float(result['sideways_probability']) confidence = float(result['confidence']) / 100.0 # 轉換為小數 if up_prob > down_prob and up_prob > sideways_prob: direction = "📈 看多" row_color = "#f0fff0" # 淡綠色 elif down_prob > up_prob and down_prob > sideways_prob: direction = "📉 看空" row_color = "#fff0f0" # 淡紅色 else: direction = "➡️ 盤整" row_color = "#f8f8f8" # 淡灰色 # 生成簡化的買賣建議 if up_prob >= 60 and confidence >= 0.3: holding_advice = "🔥 強烈持有" buying_advice = "🚀 積極買進" elif up_prob >= 45 and confidence >= 0.25: holding_advice = "✅ 建議持有" buying_advice = "💰 適度買進" elif down_prob >= 60 and confidence >= 0.3: holding_advice = "🚨 建議賣出" buying_advice = "⛔ 不建議買進" elif down_prob >= 45 and confidence >= 0.25: holding_advice = "⚠️ 謹慎持有" buying_advice = "🔍 暫緩買進" else: if confidence < 0.2: holding_advice = "🤔 觀望持有" buying_advice = "⏳ 保持觀望" else: holding_advice = "📊 區間持有" buying_advice = "🎯 等待機會" # Alert 狀態顯示 news_alert = f"{'🟢' if result.get('news_alert') == 'Y' else '🔴'} {result.get('news_alert', 'N')}" volume_alert1 = f"{'🟢' if result.get('volume_alert1') == 'Y' else '🔴'} {result.get('volume_alert1', 'N')}" institutional_alert1 = f"{'🟢' if result.get('institutional_alert1') == 'Y' else '🔴'} {result.get('institutional_alert1', 'N')}" institutional_alert2 = f"{'🟢' if result.get('institutional_alert2') == 'Y' else '🔴'} {result.get('institutional_alert2', 'N')}" technical_alert2 = f"{'🟢' if result.get('technical_alert2') == 'Y' else '🔴'} {result.get('technical_alert2', 'N')}" technical_alert3 = f"{'🟢' if result.get('technical_alert3') == 'Y' else '🔴'} {result.get('technical_alert3', 'N')}" technical_alert4 = f"{'🟢' if result.get('technical_alert4') == 'Y' else '🔴'} {result.get('technical_alert4', 'N')}" technical_alert5 = f"{'🟢' if result.get('technical_alert5') == 'Y' else '🔴'} {result.get('technical_alert5', 'N')}" summary_alert = f"🔢 {result.get('summary', '0')}" status = "✅ 成功" if not result['error_message'] else f"❌ {result['error_message'][:20]}..." # 獲取中文名稱 chinese_name = get_chinese_name(result['symbol']) # 顯示近10日趨勢 - 由 Copilot 生成 trend_display = f"{result.get('trend_10day_icon', 'N/A')} {result.get('trend_10day_desc', '')}" if result['error_message']: trend_display = "❌ N/A" # 顯示90日高點突破 - 由 Copilot 生成 high_90_display = f"{result.get('high_90_icon', 'N/A')} {result.get('high_90_desc', '')}" if result['error_message']: high_90_display = "❌ N/A" table_html += f""" """ table_html += """
中文名稱 股票代號 當前價格 近10日漲跌 90日高點突破 上漲機率(%) 下跌機率(%) 盤整機率(%) 信心度(%) 新聞 量能1 籌碼1 籌碼2 技術2 技術3 技術4 技術5 總結 預測方向 持股建議 買進建議 狀態
{chinese_name} {result['symbol']} {result['current_price']} {trend_display} {high_90_display} {result['up_probability']} {result['down_probability']} {result['sideways_probability']} {result['confidence']} {news_alert} {volume_alert1} {institutional_alert1} {institutional_alert2} {technical_alert2} {technical_alert3} {technical_alert4} {technical_alert5} {summary_alert} {direction} {holding_advice} {buying_advice} {status}
🚨 十項 Alert 說明:
📰 新聞: 公司重大公告(併購、BOT、合約、目標價上修)
📊 量能1: 當日量 >= 2×20日平均量 | 量能2: 突破價格阻力位(顯示阻力位和目標價)
💰 籌碼1: 三大法人連續買超 | 籌碼2: 外資當日淨買超↑
📈 技術1: 價格突破20日高 | 技術2: MACD交叉/OBV上升
📈 技術3: 是否站上MA5 | 技術4: 是否站上MA10 | 技術5: 是否站上MA20
90日高點突破: 🚀 突破90日高點 | 📊 距高點差距百分比
�🔢 總結: 所有Alert為綠燈(Y)的數量加總
🟢 Y = 達到條件 | 🔴 N = 未達到條件

買賣建議說明:
🔥強烈持有/🚀積極買進: 高機率上漲且高信心度
✅建議持有/💰適度買進: 中高機率上漲
🚨建議賣出/⛔不建議買進: 高機率下跌且高信心度
⚠️謹慎持有/🔍暫緩買進: 中高機率下跌
🤔觀望持有/⏳保持觀望: 低信心度預測
📊區間持有/🎯等待機會: 盤整機率較高
註:此建議僅供參考,請結合個人情況謹慎投資 - 由 Copilot 生成
""" return table_html def create_batch_analysis_charts(results): """創建批次分析結果圖表""" if not results: return None, None, None, None # 過濾出成功分析的結果 success_results = [r for r in results if r['error_message'] == ''] if not success_results: return None, None, None, None # 準備數據 symbols = [r['symbol'] for r in success_results] up_probs = [float(r['up_probability']) for r in success_results] down_probs = [float(r['down_probability']) for r in success_results] sideways_probs = [float(r['sideways_probability']) for r in success_results] confidence = [float(r['confidence']) for r in success_results] # 1. 機率比較柱狀圖 fig_bar = go.Figure() fig_bar.add_trace(go.Bar(name='上漲機率', x=symbols, y=up_probs, marker_color='green', opacity=0.8)) fig_bar.add_trace(go.Bar(name='下跌機率', x=symbols, y=down_probs, marker_color='red', opacity=0.8)) fig_bar.add_trace(go.Bar(name='盤整機率', x=symbols, y=sideways_probs, marker_color='gray', opacity=0.8)) fig_bar.update_layout( title='📊 股票預測機率比較', xaxis_title='股票代號', yaxis_title='機率 (%)', barmode='group', height=500, showlegend=True, xaxis_tickangle=-45 ) # 2. 信心度散佈圖 fig_scatter = go.Figure() # 根據最高機率決定顏色 colors = [] for i in range(len(success_results)): if up_probs[i] > down_probs[i] and up_probs[i] > sideways_probs[i]: colors.append('green') # 看多 elif down_probs[i] > up_probs[i] and down_probs[i] > sideways_probs[i]: colors.append('red') # 看空 else: colors.append('gray') # 盤整 fig_scatter.add_trace(go.Scatter( x=symbols, y=confidence, mode='markers+text', marker=dict( size=[max(prob) for prob in zip(up_probs, down_probs, sideways_probs)], sizemode='diameter', sizeref=2, color=colors, opacity=0.7, line=dict(width=2, color='white') ), text=[f"{conf:.1f}%" for conf in confidence], textposition="middle center", name='信心度' )) fig_scatter.update_layout( title='🎯 預測信心度分佈 (圓圈大小=最高機率)', xaxis_title='股票代號', yaxis_title='信心度 (%)', height=500, xaxis_tickangle=-45 ) # 3. 綜合評分雷達圖 (取前6支股票) radar_data = success_results[:6] # 限制顯示數量避免過於擁擠 fig_radar = go.Figure() categories = ['上漲機率', '信心度', '綜合評分'] for i, result in enumerate(radar_data): # 計算綜合評分 (上漲機率 * 信心度 / 100) composite_score = float(result['up_probability']) * float(result['confidence']) / 100 values = [ float(result['up_probability']), float(result['confidence']), composite_score ] fig_radar.add_trace(go.Scatterpolar( r=values + [values[0]], # 閉合雷達圖 theta=categories + [categories[0]], fill='toself', name=result['symbol'], opacity=0.6 )) fig_radar.update_layout( polar=dict( radialaxis=dict( visible=True, range=[0, 100] ) ), title='📈 股票綜合評分雷達圖 (前6支)', height=500, showlegend=True ) # 4. 機率分佈餅圖統計 # 統計各種預測傾向的數量 bullish_count = sum(1 for r in success_results if float(r['up_probability']) > max(float(r['down_probability']), float(r['sideways_probability']))) bearish_count = sum(1 for r in success_results if float(r['down_probability']) > max(float(r['up_probability']), float(r['sideways_probability']))) neutral_count = len(success_results) - bullish_count - bearish_count fig_pie = go.Figure(data=[go.Pie( labels=['看多股票', '看空股票', '盤整股票'], values=[bullish_count, bearish_count, neutral_count], marker_colors=['green', 'red', 'gray'], textinfo='label+percent+value', hovertemplate='%{label}
數量: %{value}
比例: %{percent}' )]) fig_pie.update_layout( title='🥧 整體市場情緒分佈', height=400 ) return fig_bar, fig_scatter, fig_radar, fig_pie def batch_analyze_stocks(stock_list_input): """批次分析股票清單""" # 檢查輸入是否為空 if not stock_list_input or not stock_list_input.strip(): return "❌ 請輸入股票代碼!可用逗號、空格或換行分隔多個股票代碼。", "", None, None, None, None, "" try: # 解析股票清單(支援多種分隔符) import re stock_symbols = re.split(r'[,\s\n]+', stock_list_input.strip()) stock_symbols = [symbol.strip().upper() for symbol in stock_symbols if symbol.strip()] if not stock_symbols: return "❌ 未找到有效的股票代碼!", "", None, None, None, None, "" # 準備結果列表 results = [] progress_messages = [] progress_messages.append(f"📊 開始批次分析 {len(stock_symbols)} 支股票...") # 分析每支股票 for i, symbol in enumerate(stock_symbols, 1): progress_messages.append(f"\n🔍 正在分析 ({i}/{len(stock_symbols)}): {symbol}") try: # 獲取股票數據 result = analyzer.fetch_stock_data(symbol.upper()) if len(result) == 3: success, message, stock_name = result else: success, message = result stock_name = symbol if not success: # 記錄錯誤 results.append({ 'symbol': symbol, 'name': stock_name or symbol, 'current_price': 'N/A', 'up_probability': 'ERROR', 'down_probability': 'ERROR', 'sideways_probability': 'ERROR', 'confidence': 'ERROR', 'trend_10day_icon': 'N/A', 'trend_10day_desc': '數據不足', 'high_90_icon': 'N/A', 'high_90_desc': '數據不足', 'news_alert': 'N/A', 'volume_alert1': 'N/A', 'institutional_alert1': 'N/A', 'institutional_alert2': 'N/A', 'technical_alert2': 'N/A', 'technical_alert3': 'N/A', 'technical_alert4': 'N/A', 'technical_alert5': 'N/A', 'summary': 'N/A', 'news_message': '', 'volume_alert1_message': '', 'institutional_alert1_message': '', 'institutional_alert2_message': '', 'technical_alert2_message': '', 'technical_alert3_message': '', 'technical_alert4_message': '', 'technical_alert5_message': '', 'summary_message': '', 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'error_message': message }) progress_messages.append(f"❌ {symbol}: {message}") continue # 計算技術指標 df = analyzer.calculate_technical_indicators() if df is None or len(df) < 30: results.append({ 'symbol': symbol, 'name': stock_name or symbol, 'current_price': 'N/A', 'up_probability': 'ERROR', 'down_probability': 'ERROR', 'sideways_probability': 'ERROR', 'confidence': 'ERROR', 'trend_10day_icon': 'N/A', 'trend_10day_desc': '數據不足', 'high_90_icon': 'N/A', 'high_90_desc': '數據不足', 'news_alert': 'N/A', 'volume_alert1': 'N/A', 'institutional_alert1': 'N/A', 'institutional_alert2': 'N/A', 'technical_alert2': 'N/A', 'technical_alert3': 'N/A', 'technical_alert4': 'N/A', 'technical_alert5': 'N/A', 'summary': 'N/A', 'news_message': '', 'volume_alert1_message': '', 'volume_alert2_message': '', 'institutional_alert1_message': '', 'institutional_alert2_message': '', 'technical_alert1_message': '', 'technical_alert2_message': '', 'technical_alert3_message': '', 'technical_alert4_message': '', 'technical_alert5_message': '', 'summary_message': '', 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'error_message': '數據不足,無法分析' }) progress_messages.append(f"❌ {symbol}: 數據不足") continue # 獲取新聞情感 news_sentiment = analyzer.get_news_sentiment(symbol) sentiment_summary = analyzer.analyze_sentiment_summary(news_sentiment) # 計算預測機率 recent_data = df.tail(20) technical_signals = [] # 簡化的技術信號計算 latest = df.iloc[-1] if latest['Close'] > latest['MA20']: technical_signals.append("價格在20日均線之上") else: technical_signals.append("價格在20日均線之下") probabilities = analyzer.calculate_prediction_probabilities( technical_signals, sentiment_summary, recent_data ) # 獲取股票資訊 stock_info = analyzer.get_stock_info(symbol) # 檢查四項 alert alerts = analyzer.check_alerts(recent_data, symbol) # 計算近10日趨勢 - 由 Copilot 生成 trend_icon, trend_desc = analyzer.calculate_10day_trend(df) # 計算90日高點突破情況 - 由 Copilot 生成 high_90_icon, high_90_desc = analyzer.calculate_90day_high_breakthrough(df) # 記錄成功結果 results.append({ 'symbol': symbol, 'name': stock_info['name'], 'current_price': f"{latest['Close']:.2f}" if latest['Close'] else 'N/A', 'up_probability': f"{probabilities['up']:.1f}", 'down_probability': f"{probabilities['down']:.1f}", 'sideways_probability': f"{probabilities['sideways']:.1f}", 'confidence': f"{probabilities['confidence']*100:.1f}", 'trend_10day_icon': trend_icon, 'trend_10day_desc': trend_desc, 'high_90_icon': high_90_icon, 'high_90_desc': high_90_desc, 'news_alert': alerts['news_alert']['status'], 'volume_alert1': alerts['volume_alert1']['status'], 'institutional_alert1': alerts['institutional_alert1']['status'], 'institutional_alert2': alerts['institutional_alert2']['status'], 'technical_alert2': alerts['technical_alert2']['status'], 'technical_alert3': alerts['technical_alert3']['status'], 'technical_alert4': alerts['technical_alert4']['status'], 'technical_alert5': alerts['technical_alert5']['status'], 'summary': alerts['summary']['status'], 'news_message': alerts['news_alert']['message'], 'volume_alert1_message': alerts['volume_alert1']['message'], 'institutional_alert1_message': alerts['institutional_alert1']['message'], 'institutional_alert2_message': alerts['institutional_alert2']['message'], 'technical_alert2_message': alerts['technical_alert2']['message'], 'technical_alert3_message': alerts['technical_alert3']['message'], 'technical_alert4_message': alerts['technical_alert4']['message'], 'technical_alert5_message': alerts['technical_alert5']['message'], 'summary_message': alerts['summary']['message'], 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'error_message': '' }) progress_messages.append(f"✅ {symbol}: 分析完成") except Exception as e: # 處理未預期的錯誤 results.append({ 'symbol': symbol, 'name': symbol, 'current_price': 'N/A', 'up_probability': 'ERROR', 'down_probability': 'ERROR', 'sideways_probability': 'ERROR', 'confidence': 'ERROR', 'trend_10day_icon': 'N/A', 'trend_10day_desc': '數據不足', 'high_90_icon': 'N/A', 'high_90_desc': '數據不足', 'news_alert': 'N/A', 'volume_alert1': 'N/A', 'institutional_alert1': 'N/A', 'institutional_alert2': 'N/A', 'technical_alert2': 'N/A', 'technical_alert3': 'N/A', 'technical_alert4': 'N/A', 'technical_alert5': 'N/A', 'summary': 'N/A', 'news_message': '', 'volume_alert1_message': '', 'institutional_alert1_message': '', 'institutional_alert2_message': '', 'technical_alert2_message': '', 'technical_alert3_message': '', 'technical_alert4_message': '', 'technical_alert5_message': '', 'summary_message': '', 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'error_message': f'未預期錯誤: {str(e)}' }) progress_messages.append(f"❌ {symbol}: 未預期錯誤") # 統計結果 success_count = len([r for r in results if r['error_message'] == '']) error_count = len(results) - success_count summary_message = f""" 📈 批次分析完成! 📊 **分析統計:** - 總計股票數:{len(stock_symbols)} - 成功分析:{success_count} - 分析失敗:{error_count} 📊 **圖表已生成:** - 📊 機率比較柱狀圖 - 🎯 信心度散佈圖 - 📈 綜合評分雷達圖 - 🥧 市場情緒餅圖 🎯 **排序規則:按(上漲機率×信心度)降序排列** - 由 Copilot 生成 🎯 **請查看下方圖表和表格進行投資決策分析!** """ progress_log = "\n".join(progress_messages) # 按(上漲機率最高,信心度最高)排序結果 - 由 Copilot 生成 try: # 僅對成功分析的股票進行排序 valid_results = [r for r in results if r['error_message'] == ''] error_results = [r for r in results if r['error_message'] != ''] # 對有效結果按上漲機率×信心度排序(降序) def calculate_sort_key(result): try: up_prob = float(result['up_probability']) / 100.0 confidence = float(result['confidence']) / 100.0 return up_prob * confidence except: return 0 valid_results.sort(key=calculate_sort_key, reverse=True) # 重組結果:排序後的有效結果 + 錯誤結果 results = valid_results + error_results except Exception as e: print(f"排序過程中發生錯誤: {e}") # 創建圖表和結果表格 chart_bar, chart_scatter, chart_radar, chart_pie = create_batch_analysis_charts(results) results_table = create_results_table(results) return summary_message, progress_log, chart_bar, chart_scatter, chart_radar, chart_pie, results_table except Exception as e: return f"❌ 批次分析過程中發生錯誤:{str(e)}", "", None, None, None, None, "" def smart_recommend_stocks(stock_list_input): """智能推薦股票 - 挑選信心度最高的上漲和下跌股票 - 由 Copilot 生成""" # 檢查輸入是否為空 if not stock_list_input or not stock_list_input.strip(): return "❌ 請輸入股票代碼!可用逗號、空格或換行分隔多個股票代碼。", "", "" try: # 解析股票清單(支援多種分隔符) import re stock_symbols = re.split(r'[,\s\n]+', stock_list_input.strip()) stock_symbols = [symbol.strip().upper() for symbol in stock_symbols if symbol.strip()] if not stock_symbols: return "❌ 未找到有效的股票代碼!", "", "" # 準備結果列表 results = [] progress_messages = [] progress_messages.append(f"🤖 開始智能推薦分析 {len(stock_symbols)} 支股票...") # 分析每支股票 for i, symbol in enumerate(stock_symbols, 1): progress_messages.append(f"\n🔍 正在分析 ({i}/{len(stock_symbols)}): {symbol}") try: # 獲取股票數據 result = analyzer.fetch_stock_data(symbol.upper()) if len(result) == 3: success, message, stock_name = result else: success, message = result stock_name = symbol if not success: progress_messages.append(f"❌ {symbol}: {message}") continue # 計算技術指標 df = analyzer.calculate_technical_indicators() if df is None or len(df) < 30: progress_messages.append(f"❌ {symbol}: 數據不足") continue # 獲取新聞情感 news_sentiment = analyzer.get_news_sentiment(symbol) sentiment_summary = analyzer.analyze_sentiment_summary(news_sentiment) # 計算預測機率 recent_data = df.tail(20) technical_signals = [] # 簡化的技術信號計算 latest = df.iloc[-1] if latest['Close'] > latest['MA20']: technical_signals.append("價格在20日均線之上") else: technical_signals.append("價格在20日均線之下") probabilities = analyzer.calculate_prediction_probabilities( technical_signals, sentiment_summary, recent_data ) # 獲取股票資訊 stock_info = analyzer.get_stock_info(symbol) # 檢查 Alert alerts = analyzer.check_alerts(recent_data, symbol) # 計算近10日趨勢 trend_icon, trend_desc = analyzer.calculate_10day_trend(df) # 計算90日高點突破情況 - 由 Copilot 生成 high_90_icon, high_90_desc = analyzer.calculate_90day_high_breakthrough(df) # 計算綜合評分(機率 × 信心度) recommendation_score = max(probabilities['up'], probabilities['down']) * probabilities['confidence'] # 記錄成功結果 results.append({ 'symbol': symbol, 'name': stock_info['name'], 'current_price': f"{latest['Close']:.2f}" if latest['Close'] else 'N/A', 'up_probability': probabilities['up'], 'down_probability': probabilities['down'], 'sideways_probability': probabilities['sideways'], 'confidence': probabilities['confidence'], 'recommendation_score': recommendation_score, 'alerts': alerts, 'trend_icon': trend_icon, 'trend_desc': trend_desc, 'high_90_icon': high_90_icon, 'high_90_desc': high_90_desc, 'analysis_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') }) progress_messages.append(f"✅ {symbol}: 分析完成") except Exception as e: progress_messages.append(f"❌ {symbol}: 未預期錯誤") if not results: return "❌ 所有股票分析都失敗了,請檢查股票代碼。", "\n".join(progress_messages), "" # 按上漲信心度和下跌信心度分別排序,取最高的10檔 - 由 Copilot 生成 all_stocks = results.copy() # 計算上漲信心度和下跌信心度 for stock in all_stocks: # 上漲信心度 = 上漲機率 × 總信心度 (當上漲機率大於下跌機率時) if stock['up_probability'] >= stock['down_probability']: stock['up_confidence_score'] = stock['up_probability'] * stock['confidence'] else: stock['up_confidence_score'] = 0 # 下跌信心度 = 下跌機率 × 總信心度 (當下跌機率大於上漲機率時) if stock['down_probability'] >= stock['up_probability']: stock['down_confidence_score'] = stock['down_probability'] * stock['confidence'] else: stock['down_confidence_score'] = 0 # 按上漲信心度排序,取前10檔 up_sorted_stocks = [stock for stock in all_stocks if stock['up_confidence_score'] > 0] up_sorted_stocks.sort(key=lambda x: x['up_confidence_score'], reverse=True) top_10_up_confidence = up_sorted_stocks[:10] # 按下跌信心度排序,取前10檔 down_sorted_stocks = [stock for stock in all_stocks if stock['down_confidence_score'] > 0] down_sorted_stocks.sort(key=lambda x: x['down_confidence_score'], reverse=True) top_10_down_confidence = down_sorted_stocks[:10] progress_messages.append(f"\n🎯 推薦完成!") progress_messages.append(f"🚀 上漲信心度最高:{len(top_10_up_confidence)} 支") progress_messages.append(f"📉 下跌信心度最高:{len(top_10_down_confidence)} 支") progress_log = "\n".join(progress_messages) # 生成推薦報告 recommendation_html = create_recommendation_table(top_10_up_confidence, top_10_down_confidence) summary_message = f""" 🤖 **智能推薦完成!** 📊 **分析統計:** - 總計分析:{len(stock_symbols)} 支股票 - 成功分析:{len(results)} 支股票 - 上漲信心度最高:{len(top_10_up_confidence)} 支股票 - 下跌信心度最高:{len(top_10_down_confidence)} 支股票 🎯 **推薦標準:** - 上漲信心度 = 上漲機率 × 信心度(當上漲機率≥下跌機率時) - 下跌信心度 = 下跌機率 × 信心度(當下跌機率≥上漲機率時) - 包含近10日趨勢(漲跌)分析 - 特別標示:量能1、籌碼1、技術2~4皆Y的股票 💡 **下方顯示詳細推薦結果和Alert狀態!** """ return summary_message, progress_log, recommendation_html except Exception as e: return f"❌ 智能推薦過程中發生錯誤:{str(e)}", "", "" def create_recommendation_table(up_confidence_stocks, down_confidence_stocks): """創建推薦結果表格 - 按上漲信心度和下跌信心度排序 - 由 Copilot 生成""" def check_special_alert(alerts): """檢查是否量能1、籌碼1、技術2~4皆Y - 由 Copilot 生成""" return (alerts['volume_alert1']['status'] == 'Y' and alerts['institutional_alert1']['status'] == 'Y' and alerts['technical_alert2']['status'] == 'Y' and alerts['technical_alert3']['status'] == 'Y' and alerts['technical_alert4']['status'] == 'Y') def generate_prediction_reason(stock): """生成預測主要原因 - 由 Copilot 生成""" alerts = stock['alerts'] up_prob = stock['up_probability'] down_prob = stock['down_probability'] confidence = stock['confidence'] score = stock.get('recommendation_score', 0) # 統計Y的數量 y_count = sum(1 for key in ['volume_alert1', 'institutional_alert1', 'technical_alert2', 'technical_alert3', 'technical_alert4'] if alerts[key]['status'] == 'Y') reasons = [] # 根據綜合評分高低分析原因 if score >= 50: # 高評分 if up_prob > down_prob: reasons.append(f"看多信號強({up_prob:.0f}%>{ down_prob:.0f}%)") if confidence >= 0.7: reasons.append(f"高信心度({confidence*100:.0f}%)") if y_count >= 4: reasons.append(f"多項指標達標({y_count}/5)") elif y_count >= 2: reasons.append(f"部分指標達標({y_count}/5)") elif score <= 30: # 低評分 if down_prob > up_prob: reasons.append(f"看空信號({down_prob:.0f}%>{ up_prob:.0f}%)") if confidence <= 0.4: reasons.append(f"信心度偏低({confidence*100:.0f}%)") if y_count <= 1: reasons.append(f"指標不佳({y_count}/5)") else: reasons.append(f"指標混合({y_count}/5)") else: # 中等評分 if abs(up_prob - down_prob) < 10: reasons.append("上下機率接近") if up_prob > down_prob: reasons.append(f"微偏看多({up_prob:.0f}%)") else: reasons.append(f"微偏看空({down_prob:.0f}%)") reasons.append(f"中等信心度({confidence*100:.0f}%)") # 特別情況 if check_special_alert(alerts): reasons.append("⭐全指標達標") # 趨勢影響 trend_icon = stock.get('trend_icon', '') if '📈' in trend_icon or 'UP' in trend_icon: reasons.append("近期走勢上升") elif '📉' in trend_icon or 'DOWN' in trend_icon: reasons.append("近期走勢下降") return ";".join(reasons[:3]) # 最多顯示3個原因 html = """

🤖 AI 智能推薦結果

""" # 上漲信心度最高表格 if up_confidence_stocks: html += """

🚀 上漲信心度最高 (Top 10)

""" for i, stock in enumerate(up_confidence_stocks, 1): alerts = stock['alerts'] chinese_name = get_chinese_name(stock['symbol']) # 檢查特殊標示 is_special = check_special_alert(alerts) row_style = "background-color: #fff9c4; border: 2px solid #f39c12;" if is_special else "background-color: #f0fff0;" special_marker = "⭐" if is_special else "" # Alert 狀態顯示 alert_displays = {} for alert_key in ['volume_alert1', 'institutional_alert1', 'technical_alert2', 'technical_alert3', 'technical_alert4']: status = alerts[alert_key]['status'] alert_displays[alert_key] = f"{'🟢' if status == 'Y' else '🔴'} {status}" # 計算上漲信心度評分和生成主要原因 confidence_score = stock.get('up_confidence_score', 0) main_reason = generate_prediction_reason(stock) html += f""" """ html += """
排名 中文名稱 股票代號 當前價格 近10日趨勢 90日高點突破 上漲機率(%) 下跌機率(%) 信心度(%) 上漲信心度 主要原因 量能1 籌碼1 技術2 技術3 技術4
#{i} {special_marker} {chinese_name} {stock['symbol']} {stock['current_price']} {stock['trend_icon']} {stock['trend_desc']} {stock['high_90_icon']} {stock['high_90_desc']} {stock['up_probability']:.1f}% {stock['down_probability']:.1f}% {stock['confidence']*100:.1f}% {confidence_score:.1f} {main_reason} {alert_displays['volume_alert1']} {alert_displays['institutional_alert1']} {alert_displays['technical_alert2']} {alert_displays['technical_alert3']} {alert_displays['technical_alert4']}
""" # 下跌信心度最高表格 if down_confidence_stocks: html += """

📉 下跌信心度最高 (Top 10)

""" for i, stock in enumerate(down_confidence_stocks, 1): alerts = stock['alerts'] chinese_name = get_chinese_name(stock['symbol']) # 檢查特殊標示 is_special = check_special_alert(alerts) row_style = "background-color: #fff9c4; border: 2px solid #f39c12;" if is_special else "background-color: #fff0f0;" special_marker = "⭐" if is_special else "" # Alert 狀態顯示 alert_displays = {} for alert_key in ['volume_alert1', 'institutional_alert1', 'technical_alert2', 'technical_alert3', 'technical_alert4']: status = alerts[alert_key]['status'] alert_displays[alert_key] = f"{'🟢' if status == 'Y' else '🔴'} {status}" # 計算下跌信心度評分和生成主要原因 confidence_score = stock.get('down_confidence_score', 0) main_reason = generate_prediction_reason(stock) html += f""" """ html += """
排名 中文名稱 股票代號 當前價格 近10日趨勢 90日高點突破 上漲機率(%) 下跌機率(%) 信心度(%) 下跌信心度 主要原因 量能1 籌碼1 技術2 技術3 技術4
#{i} {special_marker} {chinese_name} {stock['symbol']} {stock['current_price']} {stock['trend_icon']} {stock['trend_desc']} {stock['high_90_icon']} {stock['up_probability']:.1f}% {stock['down_probability']:.1f}% {stock['confidence']*100:.1f}% {confidence_score:.1f} {main_reason} {alert_displays['volume_alert1']} {alert_displays['institutional_alert1']} {alert_displays['technical_alert2']} {alert_displays['technical_alert3']} {alert_displays['technical_alert4']}
""" html += """

📊 智能推薦說明:
上漲機率:AI預測股價上漲的可能性百分比
下跌機率:AI預測股價下跌的可能性百分比
信心度:AI對此預測的信心程度,數值越高越可信
信心度評分:上漲信心度 = 上漲機率 × 信心度;下跌信心度 = 下跌機率 × 信心度
主要原因:解釋評分高低的關鍵因素和預測依據
近10日趨勢:📈↗ 上漲 | 📉↘ 下跌 | ➡️↔ 震盪
90日高點突破:🚀 突破90日高點 | 📊 距高點差距百分比
特別標示 ⭐:量能1、籌碼1、技術2~4皆為Y的股票
Alert 燈號:🟢 = 達到條件 (Y) | 🔴 = 未達條件 (N)
註:此推薦僅供參考,請結合個人投資策略謹慎決策 - 由 Copilot 生成

""" return html # 創建 Gradio 界面 with gr.Blocks(title="AI 股票分析師", theme=gr.themes.Soft()) as app: gr.Markdown( """ # 📈 AI 股票分析師 ### 🤖 使用 Hugging Face 模型進行智能股票分析 **✨ 核心功能:** - 📊 **完整技術指標**:MA、RSI、MACD、布林通道分析 - 🧠 **AI 情感分析**:使用 FinBERT 模型分析市場情緒 - 🎯 **機率預測**:提供上漲/下跌/盤整機率百分比 - 🚨 **十項 Alert 提醒**:新聞、量能×2、籌碼×2、技術×5、總結 細分警示 - 💼 **買賣建議**:針對持股/未持股提供具體投資建議 - 📈 **智能策略**:根據信心度給出個性化投資策略 - 🎚️ **倉位建議**:提供合理的倉位配置建議 - 🖼️ **互動圖表**:動態視覺化技術指標走勢 - 📁 **批次分析**:一次分析多支股票並匯出詳細報告 **🚀 使用方法:** 單支分析輸入股票代碼,批次分析直接在文本框中輸入多個股票代碼即可! **💡 新功能亮點:** 現在提供差異化的買賣建議 - 持有股票時建議觀望/賣出/持有,未持有時建議加碼買進/觀望! """ ) # 建立分頁 with gr.Tabs(): with gr.TabItem("🎯 單支股票分析"): with gr.Row(): with gr.Column(scale=1): stock_input = gr.Textbox( label="股票代碼", placeholder="例如:AAPL, TSLA, 2330.TW", value="2330.TW" ) analyze_btn = gr.Button("開始分析", variant="primary", size="lg") status_output = gr.Textbox( label="分析狀態", lines=2, interactive=False ) with gr.Column(scale=2): chart_output = gr.Plot(label="股價走勢圖") prediction_output = gr.Markdown(label="AI 分析報告") # 事件綁定 analyze_btn.click( fn=analyze_stock, inputs=[stock_input], outputs=[chart_output, status_output, prediction_output] ) # 範例按鈕 gr.Examples( examples=[ ["AAPL"], ["TSLA"], ["2330.TW"], ["MSFT"], ["GOOGL"] ], inputs=[stock_input] ) with gr.TabItem("📊 批次股票分析"): gr.Markdown( """ ### 📁 批次分析功能 **📋 使用步驟:** 1. 在下方文本框中輸入股票代碼 2. 支援多種分隔方式:逗號、空格或換行 3. 例如:`AAPL, TSLA, 2330.TW` 或 `AAPL MSFT GOOGL` 4. 點擊「開始批次分析」按鈕查看結果 **📈 輸出內容:** - 📊 機率比較柱狀圖:直觀對比各股票預測機率 - 🎯 信心度散佈圖:顯示預測可靠性分佈 - 📈 綜合評分雷達圖:多維度股票評分比較 - 🥧 市場情緒餅圖:整體多空情緒統計 - 📈 **近10日趨勢**:顯示股價短期漲跌情況 - 由 Copilot 生成 - 🎯 **智能排序**:按(上漲機率×信心度)降序排列 - 由 Copilot 生成 - 🚨 **十項 Alert 提醒**:新聞、量能×2、籌碼×2、技術×5、總結等全面警示 - �💼 **買賣建議表格**:針對持股與非持股提供具體建議 - 📊 **詳細分析表格**:包含所有機率、信心度與投資建議 - 即時進度顯示和完整錯誤處理 **💡 買賣建議特色:** - 🏠 **持股建議**:持有、賣出、觀望等具體行動 - 💰 **買進建議**:積極買進、適度買進、暫緩等建議 - 🎚️ **倉位建議**:根據信心度提供合理倉位配置 - ⚠️ **風險警示**:超買超賣等特殊情況提醒 """ ) # 股票代碼輸入區域 stock_list_input = gr.Textbox( label="📝 輸入股票代碼", placeholder="例如:AAPL, TSLA, 2330.TW, MSFT, GOOGL\n或用空格、換行分隔", lines=3, value="AAPL, TSLA, 2330.TW, MSFT, GOOGL", info="支援逗號、空格或換行分隔多個股票代碼" ) # 範例按鈕 gr.Examples( examples=[ ["AAPL, MSFT, GOOGL, AMZN, TSLA"], ["2330.TW, 2317.TW, 2454.TW, 3711.TW, 2382.TW"], ["JPM, BAC, WFC, C, GS"], ["JNJ, PFE, ABBV, UNH, CVS"], ["BTC-USD, ETH-USD, ^GSPC, ^DJI, ^IXIC"] ], inputs=[stock_list_input], label="💡 快速範例" ) with gr.Row(): batch_analyze_btn = gr.Button( "🚀 開始批次分析", variant="primary", size="lg", scale=1 ) with gr.Row(): with gr.Column(scale=1): batch_summary = gr.Markdown(label="📊 分析摘要") with gr.Column(scale=1): batch_progress = gr.Textbox( label="📋 分析進度", lines=10, interactive=False, max_lines=15 ) # 圖表顯示區域 gr.Markdown("## 📈 視覺化分析結果") with gr.Row(): with gr.Column(scale=1): chart_probability = gr.Plot(label="📊 股票預測機率比較") with gr.Column(scale=1): chart_confidence = gr.Plot(label="🎯 預測信心度分佈") with gr.Row(): with gr.Column(scale=1): chart_radar = gr.Plot(label="📈 綜合評分雷達圖") with gr.Column(scale=1): chart_sentiment = gr.Plot(label="🥧 整體市場情緒分佈") # 詳細結果表格 gr.Markdown("## 📋 詳細分析結果") results_table = gr.HTML(label="分析結果表格") # 批次分析事件綁定 batch_analyze_btn.click( fn=batch_analyze_stocks, inputs=[stock_list_input], outputs=[ batch_summary, batch_progress, chart_probability, chart_confidence, chart_radar, chart_sentiment, results_table ] ) with gr.TabItem("🤖 智能推薦"): gr.Markdown( """ ### 🤖 AI 智能推薦功能 **🎯 推薦原理:** - 基於 **綜合評分** = 預測機率 × 信心度 - 自動篩選出上漲和下跌趨勢最明確的股票 - 按評分高低排序,推薦最有潜力的前5名股票 **📊 推薦內容:** - 📈 **看多推薦**:上漲機率最高且信心度最強的股票 - 📉 **看空推薦**:下跌機率最高且信心度最強的股票 - 🚨 **完整Alert**:顯示所有8項Alert燈號狀態 - 💯 **綜合評分**:客觀量化的推薦強度指標 **💡 使用方式:** 1. 在下方輸入想要分析的股票代碼清單 2. 系統會自動分析所有股票 3. 智能挑選出最值得關注的看多/看空標的 4. 提供詳細的機率、信心度和Alert狀態 **⚡ 特色優勢:** - 🎯 **精準篩選**:只顯示趨勢明確的高潛力股票 - 📊 **量化排序**:客觀的綜合評分排名系統 - 🚨 **全面警示**:8項Alert完整風險評估 - 💡 **簡化決策**:直接獲得最值得關注的標的 """ ) # 股票代碼輸入區域 smart_stock_input = gr.Textbox( label="📝 輸入分析股票代碼", placeholder="例如:AAPL, TSLA, 2330.TW, MSFT, GOOGL, AMZN, NVDA, META\n或用空格、換行分隔", lines=4, value="AAPL, TSLA, 2330.TW, MSFT, GOOGL, AMZN, NVDA, META, 2317.TW, 2454.TW", info="建議輸入10-20支股票以獲得更好的推薦效果" ) # 範例按鈕 gr.Examples( examples=[ ["AAPL, MSFT, GOOGL, AMZN, TSLA, NVDA, META, NFLX, AMD, INTC"], ["2330.TW, 2317.TW, 2454.TW, 2382.TW, 2303.TW, 2881.TW, 2883.TW, 2886.TW, 2891.TW, 2892.TW"], ["JPM, BAC, WFC, C, GS, MS, BLK, AXP, COF, SCHW"], ["JNJ, PFE, ABBV, UNH, CVS, MRK, BMY, GILD, AMGN, LLY"], ["BTC-USD, ETH-USD, ^GSPC, ^DJI, ^IXIC, GLD, TLT, VTI, QQQ, SPY"], ["BABA, JD, PDD, BIDU, NIO, XPEV, LI, TME, BILI, IQ"] ], inputs=[smart_stock_input], label="💡 快速範例(不同類型股票組合)" ) with gr.Row(): smart_recommend_btn = gr.Button( "🤖 開始智能推薦", variant="primary", size="lg", scale=1 ) with gr.Row(): with gr.Column(scale=1): smart_summary = gr.Markdown(label="📊 推薦摘要") with gr.Column(scale=1): smart_progress = gr.Textbox( label="📋 分析進度", lines=10, interactive=False, max_lines=15 ) # 推薦結果顯示區域 gr.Markdown("## 🏆 智能推薦結果") smart_results_table = gr.HTML(label="智能推薦表格") # 智能推薦事件綁定 smart_recommend_btn.click( fn=smart_recommend_stocks, inputs=[smart_stock_input], outputs=[ smart_summary, smart_progress, smart_results_table ] ) # 啟動應用 if __name__ == "__main__": print("正在啟動 AI 股票分析師...") # 簡化的啟動邏輯 try: if IS_HUGGINGFACE_SPACE: # Hugging Face Spaces 環境 - 使用預設配置 print("在 Hugging Face Spaces 中啟動...") app.launch() else: # 本地環境 - 嘗試多個端口 print("在本地環境中啟動...") ports_to_try = [7860, 7861, 7862, 7863, 7864, 7865] launched = False for port in ports_to_try: try: print(f"嘗試端口 {port}...") app.launch( share=True, server_name="0.0.0.0", server_port=port, show_error=True, quiet=False ) launched = True break except OSError as e: if "port" in str(e).lower(): print(f"端口 {port} 不可用,嘗試下一個...") continue else: raise e if not launched: print("所有預設端口都被佔用,使用隨機端口...") app.launch( share=True, server_name="0.0.0.0", server_port=0, # 0 表示自動分配端口 show_error=True ) except Exception as e: print(f"啟動失敗: {e}") print("請檢查端口使用情況或嘗試重新啟動") raise e