""" 投資建議 Prompt V2 - Context Engineering + Prompt Engineering 核心改進: 1. Context Engineering: 加入用戶背景、市場環境、評分標準 2. Prompt Engineering: 強制一致性邏輯、嚴格輸出格式 3. 前端整合: 支援 Markdown 渲染 """ from typing import Dict, Any from datetime import datetime # ===== Context Engineering ===== def get_market_context(tw: bool = True) -> Dict[str, Any]: """ 獲取市場環境背景(從資料庫計算實際數據) 整合: - 資料庫:從 stock_price_tw (0050.TW) 和 stock_price (SPY) 計算 - 快取:1小時 TTL 避免重複計算 - Fallback:資料庫查詢失敗時使用靜態資料 """ try: # 嘗試使用資料庫計算的實際市場數據 from market_benchmark import get_market_benchmark benchmark = get_market_benchmark() context = benchmark.get_market_context(tw) # 如果是 fallback,記錄警告 if context.get('is_fallback'): import logging logging.warning(f"Using fallback market data for {'TW' if tw else 'US'}") return context except ImportError: # market_benchmark 模組不存在,使用靜態資料 import logging logging.warning("market_benchmark module not found, using static data") return _get_static_market_context(tw) except Exception as e: # 其他錯誤,使用靜態資料 import logging logging.error(f"Error loading market context: {e}, using static data") return _get_static_market_context(tw) def _get_static_market_context(tw: bool) -> Dict[str, Any]: """靜態市場資料(Fallback)""" if tw: return { "market_name": "台灣加權指數(0050.TW)", "ytd_return": 0.18, "avg_5y_return": 0.09, "volatility": 0.15, "sentiment": "neutral", "is_fallback": True } else: return { "market_name": "S&P 500(SPY)", "ytd_return": 0.22, "avg_5y_return": 0.12, "volatility": 0.14, "sentiment": "bull", "is_fallback": True } def get_investor_profile(risk_tolerance: str = "moderate") -> Dict[str, Any]: """ 投資人背景設定 (未來可從用戶資料庫讀取) Args: risk_tolerance: conservative/moderate/aggressive """ profiles = { "conservative": { "label": "保守型", "max_acceptable_mdd": -0.15, # 最大可接受回落 "target_sharpe": 1.5, # 目標夏普比率 "description": "重視資本保全,追求穩定收益" }, "moderate": { "label": "穩健型", "max_acceptable_mdd": -0.25, "target_sharpe": 1.0, "description": "平衡風險與報酬" }, "aggressive": { "label": "積極型", "max_acceptable_mdd": -0.40, "target_sharpe": 0.8, "description": "追求高報酬,願意承擔較高風險" } } return profiles.get(risk_tolerance, profiles["moderate"]) def get_evaluation_criteria() -> Dict[str, Any]: """ 明確的評分標準 (解決評價不一致問題) """ return { "sharpe_ratio": { "excellent": 2.0, # >= 2.0 "good": 1.5, # >= 1.5 "acceptable": 1.0, # >= 1.0 "poor": 0.5, # >= 0.5 "very_poor": 0.0 # < 0.5 }, "annual_return": { "tw": {"excellent": 0.15, "good": 0.10, "acceptable": 0.08, "poor": 0.05}, "us": {"excellent": 0.18, "good": 0.12, "acceptable": 0.10, "poor": 0.06} }, "mdd": { "low_risk": -0.15, # < -15% 算低風險 "medium_risk": -0.25, # -15% ~ -25% "high_risk": -0.40, # -25% ~ -40% "extreme_risk": -0.40 # > -40% }, "beta": { "defensive": 0.8, # < 0.8 "balanced": 1.2, # 0.8 ~ 1.2 "aggressive": 1.2 # > 1.2 } } # ===== Prompt Engineering ===== def get_context_aware_prompt(strategy_data: Dict[str, Any], risk_tolerance: str = "moderate", use_cot: bool = True) -> str: """ Context-Aware Prompt with Strict Evaluation Logic Args: strategy_data: 策略數據 risk_tolerance: 風險承受度 (conservative/moderate/aggressive) use_cot: 是否使用 Chain-of-Thought """ # 提取數據 annual_ret = strategy_data.get('annual_ret', 0) vol = strategy_data.get('vol', 0) sharpe = strategy_data.get('annual_sr', 0) mdd = strategy_data.get('mdd', 0) alpha = strategy_data.get('alpha', 0) beta = strategy_data.get('beta', 0) var10 = strategy_data.get('var10', 0) r2 = strategy_data.get('r2', 0) assets = strategy_data.get('assets', []) name = strategy_data.get('name', 'N/A') role = strategy_data.get('role', 'N/A') tw = strategy_data.get('tw', True) # Context Engineering market_ctx = get_market_context(tw) investor_profile = get_investor_profile(risk_tolerance) criteria = get_evaluation_criteria() # 構建評分邏輯 evaluation_logic = f""" ## 評分標準與邏輯 (CRITICAL: 必須嚴格遵守) ### 1. 夏普比率評級 ```python if sharpe >= {criteria['sharpe_ratio']['excellent']}: rating = "優秀" description = "風險調整後報酬表現卓越" elif sharpe >= {criteria['sharpe_ratio']['good']}: rating = "良好" description = "風險調整後報酬表現良好" elif sharpe >= {criteria['sharpe_ratio']['acceptable']}: rating = "可接受" description = "風險調整後報酬尚可" elif sharpe >= {criteria['sharpe_ratio']['poor']}: rating = "待改善" description = "風險調整後報酬偏低" else: rating = "不佳" description = "風險調整後報酬表現不佳" ``` **本策略夏普比率: {sharpe:.2f}** → 請依上述邏輯給予評級,並保持一致性。 ### 2. 報酬率評級 (相對於市場基準) - 市場基準: {market_ctx['market_name']} 近5年平均 {market_ctx['avg_5y_return']:.1%} - 本策略: {annual_ret:.2%} - 相對表現: {((annual_ret / market_ctx['avg_5y_return']) - 1) * 100:+.1f}% ### 3. 風險評級 - 最大回落: {mdd:.2%} - 投資人可接受範圍: {investor_profile['max_acceptable_mdd']:.1%} - 超出程度: {((abs(mdd) / abs(investor_profile['max_acceptable_mdd'])) - 1) * 100:+.1f}% ### 4. 市場相關性 - Beta: {beta:.2f} - 類型: {"防禦型 (< 0.8)" if beta < criteria['beta']['defensive'] else "均衡型 (0.8-1.2)" if beta < criteria['beta']['balanced'] else "進攻型 (> 1.2)"} - 預期波動: 市場變動 1%,策略預期變動 {beta:.2f}% ### 5. 超額收益能力 - Alpha: {alpha:.4f} - 解釋: {"創造超額收益 ✓" if alpha > 0.01 else "與市場同步 ≈" if alpha >= -0.01 else "落後市場 ✗"} """ # 一致性邏輯檢查 consistency_check = f""" ## 一致性邏輯檢查 (MUST FOLLOW) ⚠️ **禁止自相矛盾**: 1. 如果夏普比率評級為「優秀」,整體評價不能說「表現一般」 2. 如果報酬率遠超市場,風險評價不能忽略這個亮點 3. 如果 MDD 超出可接受範圍,必須在風險警示中明確指出 ✅ **評價優先順序**: 1. 首先看風險調整後報酬 (夏普比率) → 這是最重要的指標 2. 其次看絕對報酬 vs 市場基準 3. 最後看風險承受度匹配性 📊 **本策略快速判讀**: - 夏普 {sharpe:.2f}: {"優秀 ✓" if sharpe >= 2.0 else "良好 ✓" if sharpe >= 1.5 else "可接受 ○" if sharpe >= 1.0 else "待改善 ✗"} - 報酬 {annual_ret:.2%} vs 市場 {market_ctx['avg_5y_return']:.1%}: {"超越 ✓" if annual_ret > market_ctx['avg_5y_return'] * 1.2 else "接近 ○" if annual_ret > market_ctx['avg_5y_return'] * 0.8 else "落後 ✗"} - 風險 {mdd:.2%}: {"可接受 ✓" if abs(mdd) <= abs(investor_profile['max_acceptable_mdd']) else "偏高 ⚠️"} """ # CoT 推理步驟 cot_steps = """ ## 推理步驟 (Chain-of-Thought) 請按以下順序思考並輸出: **步驟 1: 指標解讀** - 先單獨解讀每個指標的絕對值 - 再與市場基準比較 - 最後與投資人預期比較 **步驟 2: 綜合評分** - 根據評分標準,給出各維度評級 - 注意保持一致性(不要有矛盾) - 找出最突出的優勢和劣勢 **步驟 3: 情境分析** - 假設投入 100 萬資金 - 最好情況能賺多少?(基於年化報酬) - 最壞情況會虧多少?(基於 MDD) - 承受 1 單位風險能換多少報酬?(基於夏普) **步驟 4: 投資建議** - 這個策略適合哪種投資人? - 在什麼市場環境下表現最好? - 需要做哪些調整才能更好? """ if use_cot else "" # 嚴格禁止事項 strict_prohibitions = f""" ## ⛔ 嚴格禁止事項 (CRITICAL - MUST FOLLOW) 1. **禁止自己假設或生成市場數據** - ❌ 禁止說「假設台灣加權指數同期間年化報酬率為 12%...」 - ❌ 禁止說「為了更精確的比較,我們需要...」 - ✅ **必須使用已提供的市場基準數據**: {market_ctx['market_name']} 近5年平均 {market_ctx['avg_5y_return']:.1%} 2. **禁止模糊或矛盾的評價** - ❌ 禁止說「優秀的投資策略...風險調整後報酬表現一般」 - ❌ 禁止說「良好但待改善」 - ✅ 必須根據夏普比率給出**明確且一致**的評級 3. **禁止使用模板化語言** - ❌ 禁止說「策略基本資訊回顧」「歷史表現趨勢分析」等空泛標題 - ✅ 必須根據**實際數據**給出具體分析 4. **市場基準說明** - 台灣市場: 使用 **0050.TW (元大台灣50)** 作為市場代理指標 - 理由: 追蹤台灣市值前50大公司,涵蓋約70%市值,流動性高 - 美國市場: 使用 **SPY (SPDR S&P 500 ETF)** 作為市場代理指標 - **直接使用提供的數據,不要質疑或假設其他數據** """ # 輸出格式要求(專業深度版) output_format = """ ## 輸出格式要求 (STRICT) **目標對象**:專業投資人、進階使用者 **字數控制**:1500-2000 字 **特色**:顯示完整推理過程、技術性分析、數學計算 請用以下 Markdown 格式輸出: ```markdown ## 📊 策略總評 [一句話總結:綜合評級 + 核心特性] (不超過 30 字) --- ## 🎯 核心指標分析 ### 風險調整後報酬 **夏普比率 {sharpe:.2f}** → [優秀/良好/可接受/待改善] ``` 推理過程: - 業界標準: ≥2.0 優秀, ≥1.5 良好, ≥1.0 可接受 - 本策略: {sharpe:.2f} - 意義: 每承受 1% 風險,獲得 {sharpe:.2f}% 超額報酬 → 結論: [具體評價] ``` ### 報酬表現 **年化報酬 {annual_ret:.2%}** vs **市場基準 {market_ctx['avg_5y_return']:.1%}** ``` 推理過程: - 絕對報酬: {annual_ret:.2%} - 相對市場: {((annual_ret / market_ctx['avg_5y_return']) - 1) * 100:+.1f}% - 情境假設: 投入 100 萬,一年後預期變為 {100 * (1 + annual_ret):.1f} 萬 → 結論: [超越/接近/落後]市場表現 ``` ### 風險評估 **最大回落 {mdd:.2%}** | **波動率 {vol:.2%}** ``` 推理過程: - 歷史最大虧損: {mdd:.2%} - 投資人可接受範圍: {investor_profile['max_acceptable_mdd']:.1%} - 情境假設: 投入 100 萬,最壞情況虧損 {abs(100 * mdd):.1f} 萬 → 結論: 風險水平 [低/中/高],[適合/不適合] {investor_profile['label']}投資人 ``` --- ## 💡 投資建議 ### ✅ 策略亮點 1. [最突出的優勢,用數據支持] 2. [第二個優勢] ### ⚠️ 風險提示 1. [最主要的風險,量化說明] 2. [次要風險] ### 🎯 適合對象 - **投資人類型**: [保守/穩健/積極] - **投資期限**: [短期/中期/長期] - **市場環境**: [牛市/震盪/熊市] ### 🔧 優化建議 [1-2 個具體的改進方向] --- ## 📈 未來展望 [基於當前市場環境 {market_ctx['sentiment']},給出 3-6 個月展望] --- *本分析基於歷史數據回測,過往績效不代表未來表現。建議搭配即時市場分析與專業投資顧問。* ``` ⚠️ **重要**: 1. 禁止使用模糊詞彙(「優秀但一般」「良好卻待改善」) 2. 每個評價必須有數據支持 3. 推理過程要顯示計算邏輯 4. 結論必須與推理過程一致 """ # 組合完整 Prompt full_prompt = f""" 你是一位資深投資顧問(CFA, 20+ 年經驗)。請基於以下背景與數據,提供專業投資分析。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## 投資人背景 - 風險承受度:**{investor_profile['label']}** ({investor_profile['description']}) - 目標夏普比率:≥ {investor_profile['target_sharpe']:.1f} - 可接受最大回落:{investor_profile['max_acceptable_mdd']:.1%} ## 市場環境 - 市場:{market_ctx['market_name']} - 今年表現:{market_ctx['ytd_return']:.1%} - 近5年平均:{market_ctx['avg_5y_return']:.1%} - 市場情緒:{market_ctx['sentiment']} ## 策略資訊 - 名稱:{name} - 目標:{role} - 持股:{', '.join(assets[:5])}{"..." if len(assets) > 5 else ""} (共 {len(assets)} 檔) ## 績效數據 | 指標 | 數值 | |------|------| | 年化報酬率 | {annual_ret:.1%} | | 年化波動率 | {vol:.1%} | | 夏普比率 | {sharpe:.1f} | | 最大回落 (MDD) | {mdd:.2%} | | Alpha | {alpha:.1f} | | Beta | {beta:.2f} | | VaR (95%) | {var10:.2%} | | R² | {r2:.2%} | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ {strict_prohibitions} {evaluation_logic} {consistency_check} {cot_steps} {output_format} 現在請開始分析,記住:**數據驅動,邏輯一致,評價明確,禁止假設市場數據**。 """ return full_prompt def get_simplified_context_prompt(strategy_data: Dict[str, Any]) -> str: """ 教育性詳細版 Context-Aware Prompt(為普羅大眾設計,預設模式) 目標對象:投資新手、一般散戶 特色: - 白話文解釋每個指標的意義 - 舉例說明(投入100萬的情境) - 說明為什麼這個數字重要 - 提供具體優化建議 - 字數控制在 1000-1500 字 適用於:use_cot=False(預設模式,不顯示推理步驟,但內容詳盡) """ annual_ret = strategy_data.get('annual_ret', 0) sharpe = strategy_data.get('annual_sr', 0) vol = strategy_data.get('vol', 0) mdd = strategy_data.get('mdd', 0) beta = strategy_data.get('beta', 0) alpha = strategy_data.get('alpha', 0) var10 = strategy_data.get('var10', 0) r2 = strategy_data.get('r2', 0) tw = strategy_data.get('tw', True) assets = strategy_data.get('assets', []) name = strategy_data.get('name', 'N/A') market_ctx = get_market_context(tw) criteria = get_evaluation_criteria() # 評分邏輯 sharpe_rating = "優秀" if sharpe >= 2.0 else "良好" if sharpe >= 1.5 else "可接受" if sharpe >= 1.0 else "待改善" return_vs_market = ((annual_ret / market_ctx['avg_5y_return']) - 1) * 100 return f""" 你是一位資深投資教育講師,專門為**投資新手和普羅大眾**解釋投資策略。 你的任務是: 1. **用白話文**解釋每個績效指標的意義 2. **說明為什麼**這個指標重要 3. **給予具體的優化建議** 4. **避免使用過多專業術語**,如果必須使用,請解釋清楚 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## 策略基本資訊 - **策略名稱**: {name} - **投資市場**: {'🇹🇼 台灣股市' if tw else '🇺🇸 美國股市'} - **持股標的**: {', '.join(assets[:10])}{"..." if len(assets) > 10 else ""} (共 {len(assets)} 檔) - **對比基準**: {market_ctx['market_name']} (近5年平均 {market_ctx['avg_5y_return']:.1%}) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## 📊 核心績效對比表(你的策略 vs 市場) | 指標 | 你的策略 | 市場基準 | 差異 | 評價 | |------|---------|---------|------|------| | 📈 年化報酬率 | {annual_ret:.2%} | {market_ctx['avg_5y_return']:.1%} | {return_vs_market:+.1f}% | {'🚀 大勝' if return_vs_market > 50 else '✅ 超越' if return_vs_market > 0 else '❌ 落後'} | | ⭐ 夏普比率 | {sharpe:.2f} | ~1.0 | {(sharpe - 1.0):+.2f} | {sharpe_rating} | | 📊 波動率 | {vol:.2%} | {market_ctx.get('volatility', 0.20):.1%} | {(vol - market_ctx.get('volatility', 0.20)) * 100:+.1f}% | {'⚠️ 較高' if vol > market_ctx.get('volatility', 0.20) * 1.2 else '✅ 適中'} | | ⚠️ 最大回落 | {mdd:.2%} | ~-30% | {'更深' if abs(mdd) > 0.30 else '相近'} | {'❌ 風險高' if abs(mdd) > 0.30 else '✅ 可控'} | ## 🎯 主動管理能力 | 指標 | 數值 | 說明 | |------|------|------| | 🎯 Alpha (超額報酬) | {alpha:.4f} | {'✅ 打敗市場' if alpha > 0.01 else '≈ 跟隨市場' if alpha >= -0.01 else '❌ 落後市場'} | | ⚖️ Beta (市場相關性) | {beta:.2f} | {'🔥 進攻型 (Beta > 1.2)' if beta > 1.2 else '⚖️ 均衡型 (Beta 0.8-1.2)' if beta > 0.8 else '🛡️ 防禦型 (Beta < 0.8)'} | | 📐 R² (可解釋度) | {r2:.2%} | 策略中 {r2:.1%} 的波動來自市場影響 | | 📉 VaR (風險值) | {var10:.2%} | 95%信心水準下的最大單日損失 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ⛔ 重要指示 1. **禁止假設數據** - 市場基準 {market_ctx['avg_5y_return']:.1%} 已提供,直接使用 2. **評級必須一致** - 夏普 {sharpe:.2f} = 「{sharpe_rating}」 3. **用白話文** - 避免過多專業術語 4. **解釋每個指標** - 說明它的意義和為什麼重要 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## 📝 輸出格式(教育性詳細版) 請用 1200-1600 字,包含以下內容: ```markdown ## 📊 一句話總評 [根據夏普比率和報酬率,給一個清晰的總評,30字內] --- ## 📋 你選了哪些股票? {', '.join(assets[:15])}{"..." if len(assets) > 15 else ""}(共 {len(assets)} 檔) **組合特性:** - **產業分布**: [分析持股集中在哪些產業,例如:科技股佔50%、金融股佔30%] - **風險分散度**: [評估是否分散,例如:持股{len(assets)}檔,{'分散良好' if len(assets) >= 8 else '偏集中' if len(assets) >= 5 else '非常集中'}] - **代表性個股**: [列出前3-5檔重要持股,簡述其特色] **💡 持股建議:** [根據持股數量和類型,給予是否需要調整的建議] --- ## 📊 績效表現分析(vs 市場基準) ### 1️⃣ 賺錢能力:年化報酬率 {annual_ret:.2%} **白話文解釋:** 假設你投入 100 萬,一年後預期變成 **{100 * (1 + annual_ret):.1f} 萬**({'賺' if annual_ret > 0 else '虧'} {abs(100 * annual_ret):.1f} 萬)。 **vs 市場表現:** - 📈 你的策略:{annual_ret:.2%} - 📊 市場平均:{market_ctx['avg_5y_return']:.1%}({market_ctx['market_name']}) - 🎯 相對表現:{return_vs_market:+.1f}% **評價:** {'🚀 遠超市場表現!' if return_vs_market > 50 else '✅ 打敗市場' if return_vs_market > 20 else '✓ 略勝市場' if return_vs_market > 0 else '❌ 落後市場'} **為什麼重要?** [解釋報酬率是投資最直觀的指標,但不能只看報酬率,還要考慮風險] --- ### 2️⃣ 投資CP值:夏普比率 {sharpe:.2f} → {sharpe_rating} **白話文解釋:** 「CP值」就是夏普比率!每承受 1 元風險,你能賺 {sharpe:.2f} 元報酬。 **評級:** - ⭐⭐⭐ 優秀 (≥ 2.0) - CP值超高! - ⭐⭐ 良好 (≥ 1.5) - CP值不錯 - ⭐ 可接受 (≥ 1.0) - CP值及格 ← {'你在這裡' if 1.0 <= sharpe < 1.5 else ''} - 待改善 (< 1.0) - CP值偏低 **為什麼重要?** [解釋夏普比率是同時考慮報酬和風險的指標,比單看報酬率更全面] --- ### 3️⃣ 最大虧損風險:最大回落 {mdd:.2%} **白話文解釋:** 投入 100 萬,最慘的時候會虧到剩 **{100 * (1 + mdd):.1f} 萬**(虧損 {abs(100 * mdd):.1f} 萬)。 **vs 市場風險:** - 你的策略:{mdd:.2%} - 一般市場:約 -30% - 評價:{'❌ 風險較高' if abs(mdd) > 0.30 else '✅ 風險可控'} **心理測試:** [問投資人是否能接受這個程度的虧損] --- ### 4️⃣ 主動選股價值:Alpha {alpha:.4f} & Beta {beta:.2f} **Alpha 超額報酬:** {'✅ +{alpha:.2%} 打敗市場' if alpha > 0.01 else '≈ 跟隨市場' if alpha >= -0.01 else '❌ 落後市場'} **Beta 市場連動:** {'🔥 進攻型' if beta > 1.2 else '⚖️ 均衡型' if beta > 0.8 else '🛡️ 防禦型'} **白話文解釋:** - Alpha:扣除市場影響後,你的選股能力創造的額外報酬 - Beta:當市場漲 1%,你的策略預期漲 {beta:.2f}% **為什麼重要?** [解釋主動選股的價值,以及不同市場環境下的策略表現] --- ## 🎯 給投資人的建議 ### ✅ 這個策略的優勢 [列出2-3個具體優點,用數據支持] ### ⚠️ 需要注意的風險 [列出2-3個具體風險,量化說明] ### 🔧 如何優化這個策略? [給3個具體的優化建議] 1. [建議1:例如分散持股、調整權重等] 2. [建議2:例如設定停損點] 3. [建議3:例如定期再平衡] ### 💼 適合什麼樣的投資人? - **風險承受度**: [保守/穩健/積極] - **投資期限**: [建議持有多久] - **市場環境**: [適合牛市/震盪/熊市] - **資金用途**: [閒錢/退休金/教育基金] --- ## 📈 總結 [用2-3句話總結這個策略的核心特點,並給出明確的投資建議] --- *💡 小提醒:過去績效不代表未來表現,投資一定有風險,建議搭配專業顧問意見。* ``` ⚠️ **輸出要求**: 1. **字數**: 1000-1500 字(教育性內容,不能太少) 2. **語氣**: 親切、易懂,像在跟朋友聊天 3. **避免**: 「策略基本資訊回顧」等空泛標題 4. **必須**: 解釋每個指標的意義和重要性 5. **必須**: 給出具體的優化建議 """