|
|
""" |
|
|
LLM Investment Advisor Service |
|
|
|
|
|
提供投資策略的AI分析服務,包含: |
|
|
- 投資建議生成 |
|
|
- 風險評估 |
|
|
- 市場洞察 |
|
|
- Prompt工程管理 |
|
|
""" |
|
|
|
|
|
import os |
|
|
import json |
|
|
import time |
|
|
import logging |
|
|
import hashlib |
|
|
from typing import Dict, Any, Optional, Tuple |
|
|
|
|
|
from openai import OpenAI |
|
|
try: |
|
|
from config_openai import OPENAI_CONFIG, RATE_LIMITS |
|
|
except Exception: |
|
|
OPENAI_CONFIG = { |
|
|
'api_key': os.environ.get('OPENAI_API_KEY') or os.environ.get('OPENROUTER_API_KEY', ''), |
|
|
'model': os.environ.get('OPENAI_MODEL', os.environ.get('OPENROUTER_MODEL', 'gpt-4')), |
|
|
'timeout': int(os.environ.get('LLM_TIMEOUT', '60')), |
|
|
'max_tokens': int(os.environ.get('LLM_MAX_TOKENS', '3000')), |
|
|
'temperature': float(os.environ.get('LLM_TEMPERATURE', '0.7')) |
|
|
} |
|
|
RATE_LIMITS = { |
|
|
'max_retries': int(os.environ.get('LLM_MAX_RETRIES', '3')), |
|
|
'retry_delay': int(os.environ.get('LLM_RETRY_DELAY', '2')) |
|
|
} |
|
|
|
|
|
# 設定日誌 |
|
|
logging.basicConfig(level=logging.INFO) |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
class PromptManager: |
|
|
"""管理不同的Prompt模板""" |
|
|
|
|
|
def __init__(self): |
|
|
self.system_prompt = self._get_system_prompt() |
|
|
|
|
|
def _get_system_prompt(self) -> str: |
|
|
"""系統提示詞 - 定義基金經理人專家角色""" |
|
|
return """你是一位頂尖的基金經理人與投資策略師,擁有超過20年橫跨牛熊市的實戰經驗。你的專長是將複雜的金融數據轉化為清晰、易於理解的語言,為大眾投資者提供專業見解。 |
|
|
|
|
|
你的溝通風格: |
|
|
- **權威且親切**:你的語氣充滿自信與專業,但同時讓非專業人士感到安心與信賴。 |
|
|
- **教育家精神**:你會用生動的比喻來解釋關鍵指標,例如將「夏普比率」比喻為投資的「性價比」,或將「最大回落」形容為「最顛簸的一段路」。 |
|
|
- **客觀中立**:你總是基於數據進行分析,同時點出潛在的盲點與風險。 |
|
|
|
|
|
你的任務是根據接下來提供的策略回測數據,撰寫一份專業的投資策略分析報告。""" |
|
|
|
|
|
def build_strategy_context(self, strategy_data: Dict[str, Any]) -> str: |
|
|
"""將策略資料轉換為結構化context,並附帶指標提示""" |
|
|
return f""" |
|
|
策略基本資訊: |
|
|
- 策略編號:{strategy_data.get('id', 'N/A')} |
|
|
- 策略名稱:{strategy_data.get('name', 'N/A')} |
|
|
- 投資目標:{strategy_data.get('role', 'N/A')} |
|
|
- 建立時間:{strategy_data.get('date', 'N/A')} |
|
|
- 建立者:{strategy_data.get('username', 'N/A')} |
|
|
|
|
|
核心績效指標: |
|
|
- 年化報酬率:{strategy_data.get('annual_ret', 0):.2%} (衡量平均每年賺取多少利潤) |
|
|
- 年化波動率:{strategy_data.get('vol', 0):.2%} (衡量資產價值的波動風險,越高代表起伏越大) |
|
|
- 年化夏普比率:{strategy_data.get('annual_sr', 0):.2f} (衡量每一單位風險能換來多少報酬,可視為「投資CP值」) |
|
|
- 最大回落(MDD):{strategy_data.get('mdd', 0):.2%} (衡量策略從最高點到最低點可能出現的最大虧損幅度) |
|
|
|
|
|
進階參考指標: |
|
|
- Alpha值:{strategy_data.get('alpha', 0):.4f} (相對於市場基準的超額報酬能力) |
|
|
- Beta值:{strategy_data.get('beta', 0):.4f} (與市場波動的關聯性,大於1代表比市場更敏感) |
|
|
- VaR (10天, 95%信心):{strategy_data.get('var10', 0):.2%} (預估在未來10天內,有95%的機率虧損不會超過此比例) |
|
|
- R-squared:{strategy_data.get('r2', 0):.4f} (策略表現有多大比例可由市場表現來解釋) |
|
|
|
|
|
投資組合配置: |
|
|
- 包含資產:{', '.join(strategy_data.get('assets', []))} |
|
|
- 市場類型:{'台灣市場' if strategy_data.get('tw', True) else '美國市場'} |
|
|
""" |
|
|
|
|
|
def get_investment_advice_prompt(self, strategy_data: Dict[str, Any], |
|
|
use_cot: bool = False, |
|
|
use_v2: bool = True, |
|
|
risk_tolerance: str = "moderate") -> str: |
|
|
"""生成結構化投資建議報告的完整Prompt - 使用外部模板 |
|
|
|
|
|
Args: |
|
|
strategy_data: 策略數據 |
|
|
use_cot: 是否使用 Chain-of-Thought 模式(預設 False) |
|
|
use_v2: 是否使用 V2 Context-Aware Prompt(預設 True,推薦) |
|
|
risk_tolerance: 風險承受度 (conservative/moderate/aggressive) |
|
|
|
|
|
Returns: |
|
|
完整的 prompt 字串 |
|
|
""" |
|
|
try: |
|
|
# V2 Context-Aware Prompt (推薦,解決評價不一致問題) |
|
|
if use_v2: |
|
|
from prompts.investment_advice_v2 import get_context_aware_prompt, get_simplified_context_prompt |
|
|
logger.info(f"Using V2 Context-Aware Prompt (CoT={use_cot}, risk={risk_tolerance})") |
|
|
if use_cot: |
|
|
return get_context_aware_prompt(strategy_data, risk_tolerance=risk_tolerance, use_cot=True) |
|
|
else: |
|
|
# 簡化版,但仍有 context |
|
|
return get_simplified_context_prompt(strategy_data) |
|
|
|
|
|
# V1 Prompt (舊版,保留向後兼容) |
|
|
elif use_cot: |
|
|
# 使用 CoT 版本 |
|
|
from prompts.investment_advice_cot import get_cot_analysis_prompt |
|
|
logger.info("Using V1 Chain-of-Thought prompt") |
|
|
return get_cot_analysis_prompt(strategy_data) |
|
|
else: |
|
|
# 使用原版(結構化輸出) |
|
|
from prompts.investment_advice import get_comprehensive_analysis_prompt |
|
|
logger.info("Using V1 standard prompt") |
|
|
return get_comprehensive_analysis_prompt(strategy_data) |
|
|
except ImportError as e: |
|
|
# 回退到內建模板 |
|
|
logger.warning(f"Could not import prompts module ({e}), using built-in template") |
|
|
return self._get_builtin_prompt(strategy_data) |
|
|
|
|
|
def _get_builtin_prompt(self, strategy_data: Dict[str, Any]) -> str: |
|
|
"""內建模板作為回退方案""" |
|
|
context = self.build_strategy_context(strategy_data) |
|
|
return f"""{self.system_prompt} |
|
|
|
|
|
{context} |
|
|
|
|
|
請嚴格遵循以下結構,為這份投資策略撰寫一份專業分析報告: |
|
|
|
|
|
--- |
|
|
|
|
|
### **【投資策略總評:給您的執行摘要】** |
|
|
*在這部分,請用2-3句話總結這個策略的核心特點與績效等級。直接點出它適合哪一種類型的投資者。* |
|
|
|
|
|
### **【績效深度解析:白話解讀關鍵指標】** |
|
|
*在這部分,請選擇2-3個最重要的指標(例如:夏普比率、最大回落),並用生動的比喻解釋它們在此策略中的意義。* |
|
|
- **指標1**:[指標名稱] - [用比喻解釋其表現] |
|
|
- **指標2**:[指標名稱] - [用比喻解釋其表現] |
|
|
|
|
|
### **【策略的亮點與潛在風險】** |
|
|
*客觀分析此策略的優缺點。* |
|
|
- **👍 亮點 (Strengths)**:[至少列出2點,例如:在特定市場環境下表現優異、風險控制得當等] |
|
|
- **🤔 潛在風險 (Weaknesses/Risks)**:[至少列出2點,例如:資產過於集中、對利率變化敏感等] |
|
|
|
|
|
### **【給您的具體投資建議】** |
|
|
*提供清晰、可執行的建議。* |
|
|
1. **核心觀點**:[明確指出「繼續持有」、「考慮調整」或「尋找替代方案」] |
|
|
2. **優化建議**:[提出1-2項具體優化方向,例如:「可考慮納入 OOO 類型的資產以分散風險」或「建議將再平衡頻率調整為 X 個月一次」] |
|
|
3. **風險管理**:[提醒投資者應該注意的市場訊號或事件] |
|
|
|
|
|
### **【未來展望與提醒】** |
|
|
*提供一個前瞻性的總結,並附上免責聲明。* |
|
|
|
|
|
--- |
|
|
|
|
|
請用繁體中文回答,確保報告結構完整、語氣專業且易於理解。""" |
|
|
|
|
|
|
|
|
class LLMInvestmentAdvisor: |
|
|
"""LLM投資顧問主類""" |
|
|
|
|
|
def __init__(self, api_key: Optional[str] = None): |
|
|
"""初始化LLM服務""" |
|
|
provider = os.environ.get('LLM_PROVIDER', 'openai').lower() |
|
|
base_url = None |
|
|
default_headers = None |
|
|
|
|
|
if provider == 'openrouter': |
|
|
self.api_key = api_key or os.environ.get('OPENROUTER_API_KEY') or OPENAI_CONFIG.get('api_key') |
|
|
base_url = os.environ.get('OPENROUTER_BASE_URL', 'https://openrouter.ai/api/v1') |
|
|
self.model = os.environ.get('OPENROUTER_MODEL', OPENAI_CONFIG.get('model', 'openrouter/auto')) |
|
|
default_headers = { |
|
|
'HTTP-Referer': os.environ.get('OPENROUTER_REFERER', ''), |
|
|
'X-Title': os.environ.get('OPENROUTER_TITLE', 'TPM') |
|
|
} |
|
|
else: |
|
|
self.api_key = api_key or os.environ.get('OPENAI_API_KEY') or OPENAI_CONFIG.get('api_key') |
|
|
self.model = os.environ.get('OPENAI_MODEL', OPENAI_CONFIG.get('model', 'gpt-4')) |
|
|
|
|
|
if not self.api_key or self.api_key == 'your-api-key-here': |
|
|
raise ValueError("LLM API key is required. Please set OPENAI_API_KEY or OPENROUTER_API_KEY.") |
|
|
|
|
|
self.client = OpenAI( |
|
|
api_key=self.api_key, |
|
|
base_url=base_url, |
|
|
timeout=OPENAI_CONFIG.get('timeout', 30), |
|
|
default_headers=default_headers |
|
|
) |
|
|
self.prompt_manager = PromptManager() |
|
|
self.max_tokens = OPENAI_CONFIG.get('max_tokens', 2000) |
|
|
self.temperature = OPENAI_CONFIG.get('temperature', 0.7) |
|
|
|
|
|
# 快取設定 |
|
|
self.cache: Dict[str, Tuple[str, float]] = {} |
|
|
self.cache_timeout = 3600 # 1小時快取 |
|
|
self.mock_mode = os.environ.get('MOCK_LLM', 'false').lower() in ('1', 'true', 'yes') |
|
|
|
|
|
def _is_cache_valid(self, cache_time: float) -> bool: |
|
|
"""檢查快取是否有效""" |
|
|
return time.time() - cache_time < self.cache_timeout |
|
|
|
|
|
def generate_advice(self, strategy_id: str, strategy_data: Dict[str, Any], |
|
|
use_cot: bool = False, |
|
|
use_v2: bool = True, |
|
|
risk_tolerance: str = "moderate") -> str: |
|
|
"""生成投資建議 |
|
|
|
|
|
Args: |
|
|
strategy_id: 策略ID |
|
|
strategy_data: 策略資料字典 |
|
|
use_cot: 是否使用 Chain-of-Thought 模式(預設 False) |
|
|
use_v2: 是否使用 V2 Context-Aware Prompt(預設 True) |
|
|
risk_tolerance: 風險承受度 (conservative/moderate/aggressive) |
|
|
|
|
|
Returns: |
|
|
str: 投資建議文本 |
|
|
""" |
|
|
stable_payload = json.dumps(strategy_data, sort_keys=True).encode('utf-8') |
|
|
cache_digest = hashlib.sha256(stable_payload).hexdigest() |
|
|
# 快取鍵包含版本和風險承受度資訊 |
|
|
cache_key = f"advice_{strategy_id}_{cache_digest}_v{2 if use_v2 else 1}_cot{use_cot}_risk{risk_tolerance}" |
|
|
|
|
|
# 檢查快取 |
|
|
if cache_key in self.cache: |
|
|
advice, cache_time = self.cache[cache_key] |
|
|
if self._is_cache_valid(cache_time): |
|
|
logger.info(f"Returning cached advice for strategy {strategy_id} (V2={use_v2}, CoT={use_cot}, risk={risk_tolerance})") |
|
|
return advice |
|
|
|
|
|
try: |
|
|
# 構建prompt(根據參數選擇版本) |
|
|
prompt = self.prompt_manager.get_investment_advice_prompt( |
|
|
strategy_data, |
|
|
use_cot=use_cot, |
|
|
use_v2=use_v2, |
|
|
risk_tolerance=risk_tolerance |
|
|
) |
|
|
|
|
|
# Mock 模式:不呼叫外部API |
|
|
if self.mock_mode: |
|
|
logger.info("MOCK_LLM enabled, returning fallback advice without external API call") |
|
|
response = self._get_fallback_advice(strategy_data) |
|
|
else: |
|
|
# 調用LLM API |
|
|
response = self._call_openai_with_retry(prompt) |
|
|
|
|
|
# 快取結果 |
|
|
self.cache[cache_key] = (response, time.time()) |
|
|
logger.info(f"Generated new advice for strategy {strategy_id} (CoT={use_cot})") |
|
|
return response |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error generating advice for strategy {strategy_id}: {str(e)}") |
|
|
return self._get_fallback_advice(strategy_data) |
|
|
|
|
|
def clear_cache(self): |
|
|
"""清除快取""" |
|
|
self.cache.clear() |
|
|
logger.info("LLM advice cache cleared") |
|
|
|
|
|
def _call_openai_with_retry(self, prompt: str) -> str: |
|
|
"""調用OpenAI API,包含重試機制 |
|
|
|
|
|
Args: |
|
|
prompt: 完整的prompt |
|
|
|
|
|
Returns: |
|
|
str: API回應內容 |
|
|
""" |
|
|
max_retries = RATE_LIMITS.get('max_retries', 3) |
|
|
retry_delay = RATE_LIMITS.get('retry_delay', 2) |
|
|
|
|
|
for attempt in range(max_retries): |
|
|
try: |
|
|
response = self.client.chat.completions.create( |
|
|
model=self.model, |
|
|
messages=[ |
|
|
{"role": "system", "content": "你是一位專業的投資顧問。"}, |
|
|
{"role": "user", "content": prompt} |
|
|
], |
|
|
max_tokens=self.max_tokens, |
|
|
temperature=self.temperature, |
|
|
top_p=0.9 |
|
|
) |
|
|
|
|
|
return response.choices[0].message.content.strip() |
|
|
|
|
|
except Exception as e: |
|
|
status_code = getattr(e, 'status_code', None) |
|
|
is_rate_limited = status_code == 429 or 'rate limit' in str(e).lower() |
|
|
if attempt < max_retries - 1 and (is_rate_limited or True): |
|
|
wait_time = retry_delay ** attempt |
|
|
logger.warning(f"LLM API error, retrying in {wait_time}s... (attempt {attempt + 1}/{max_retries}): {str(e)}") |
|
|
time.sleep(wait_time) |
|
|
continue |
|
|
logger.error(f"LLM API error after {max_retries} attempts: {str(e)}") |
|
|
raise e |
|
|
|
|
|
def _get_fallback_advice(self, strategy_data: Dict[str, Any]) -> str: |
|
|
"""獲取fallback投資建議 - 使用原本的詳細 prompt 結構""" |
|
|
try: |
|
|
# 嘗試使用 prompts/investment_advice.py 的模板 |
|
|
from prompts.investment_advice import get_comprehensive_analysis_prompt |
|
|
# 直接返回 prompt 作為 fallback(模擬 LLM 回覆的結構) |
|
|
prompt = get_comprehensive_analysis_prompt(strategy_data) |
|
|
# 提取 prompt 中的策略數據部分,生成基本回覆 |
|
|
return self._generate_basic_analysis(strategy_data) |
|
|
except ImportError: |
|
|
return self._generate_basic_analysis(strategy_data) |
|
|
|
|
|
def _generate_basic_analysis(self, strategy_data: Dict[str, Any]) -> str: |
|
|
"""生成基本分析(當無法調用 LLM 時)""" |
|
|
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) |
|
|
var = strategy_data.get('var10', 0) |
|
|
r2 = strategy_data.get('r2', 0) |
|
|
assets = strategy_data.get('assets', []) |
|
|
|
|
|
# 評估表現等級 |
|
|
ret_level = "優秀" if annual_ret > 0.15 else "良好" if annual_ret > 0.08 else "一般" if annual_ret > 0 else "需改善" |
|
|
risk_level = "低風險" if vol < 0.15 else "中風險" if vol < 0.25 else "高風險" |
|
|
sharpe_level = "優良" if sharpe > 1.5 else "良好" if sharpe > 1.0 else "一般" if sharpe > 0.5 else "需改善" |
|
|
|
|
|
return f""" |
|
|
## 📊 策略總評 |
|
|
這是一個{ret_level}的投資策略,年化報酬率達到{annual_ret:.1%},屬於{risk_level}等級。策略的風險調整後報酬表現{sharpe_level},夏普比率為{sharpe:.2f},顯示出{"良好" if sharpe > 1.0 else "一般"}的風險管理能力。 |
|
|
|
|
|
## 📈 關鍵指標深度解析 |
|
|
|
|
|
### 💰 報酬表現 |
|
|
- **年化報酬率**:{annual_ret:.2%} - 這個報酬率在當前市場環境下表現{'優異' if annual_ret > 0.12 else '良好' if annual_ret > 0.08 else '一般'},{'超越' if annual_ret > 0.1 else '接近' if annual_ret > 0.05 else '低於'}市場平均水準 |
|
|
- **風險調整報酬**:{sharpe:.2f} - 夏普比率{'超過1.0' if sharpe > 1.0 else '接近1.0' if sharpe > 0.8 else '低於1.0'},表示每承擔一單位風險能獲得{'良好' if sharpe > 1.0 else '一般'}的超額報酬 |
|
|
|
|
|
### ⚠️ 風險評估 |
|
|
- **波動率**:{vol:.2%} - 年化波動率{'較低' if vol < 0.15 else '適中' if vol < 0.25 else '較高'},顯示策略的穩定性{'良好' if vol < 0.2 else '一般'} |
|
|
- **最大回落**:{mdd:.2%} - 最大虧損幅度{'控制在合理範圍' if abs(mdd) < 0.1 else '需要關注'},風險控制{'得當' if abs(mdd) < 0.15 else '有待改善'} |
|
|
- **VaR (95%)**:{var:.2%} - 在95%的信心水準下,單日最大可能虧損為{abs(var):.2%} |
|
|
|
|
|
### 📊 市場關聯性 |
|
|
- **Alpha值**:{alpha:.4f} - {'正向' if alpha > 0 else '負向'}超額收益,顯示策略{'優於' if alpha > 0 else '弱於'}市場基準表現 |
|
|
- **Beta值**:{beta:.2f} - 策略與市場的關聯性{'較高' if beta > 1.1 else '適中' if beta > 0.9 else '較低'},市場波動1%時,策略預期波動{beta:.2f}% |
|
|
- **R-squared**:{r2:.2%} - 策略表現有{r2:.1%}可由市場變動解釋 |
|
|
|
|
|
## 🎯 策略優劣分析 |
|
|
|
|
|
### 👍 亮點優勢 |
|
|
- **風險調整報酬{'優異' if sharpe > 1.5 else '良好' if sharpe > 1.0 else '一般'}**:夏普比率{sharpe:.2f}顯示策略在控制風險的同時能創造{'優質' if sharpe > 1.5 else '良好' if sharpe > 1.0 else '基本'}的報酬 |
|
|
- **資產配置{'合理' if len(assets) > 3 else '需強化'}**:包含{len(assets)}個標的,{'有效' if len(assets) > 5 else '適度' if len(assets) > 3 else '需增加'}分散投資風險 |
|
|
- **市場適應性**:Alpha值{alpha:.4f}顯示策略{'具有' if alpha > 0 else '缺乏'}超額收益能力 |
|
|
|
|
|
### 🤔 潛在風險 |
|
|
- **市場敏感度**:Beta值{beta:.2f}表示策略{'高度' if beta > 1.2 else '適度' if beta > 0.8 else '低度'}受市場波動影響 |
|
|
- **回檔風險**:最大回落{mdd:.2%}顯示在極端市場情況下可能面臨{'較大' if abs(mdd) > 0.2 else '中等' if abs(mdd) > 0.1 else '有限'}的虧損 |
|
|
- **集中度風險**:需要{'特別' if len(assets) < 5 else '持續'}關注資產配置是否過於集中在特定行業或地區 |
|
|
|
|
|
## 💡 具體投資建議 |
|
|
|
|
|
### 1. 核心觀點 |
|
|
**建議**:{'✅ 繼續持有並定期調整' if annual_ret > 0.1 and sharpe > 1.0 else '⚠️ 考慮優化配置' if annual_ret > 0.05 else '❌ 需要重新評估策略'} |
|
|
|
|
|
**理由**: |
|
|
- 報酬表現{'符合' if annual_ret > 0.08 else '未達'}預期目標 |
|
|
- 風險控制{'良好' if sharpe > 1.0 else '需要改善'} |
|
|
- 市場適應性{'優異' if alpha > 0.02 else '適中' if alpha > 0 else '不佳'} |
|
|
|
|
|
### 2. 優化方向 |
|
|
- **資產配置調整**:可考慮納入更多{'防禦性資產(如公債、公用事業)' if vol > 0.2 else '成長性資產(如科技股、新興市場)'}以{'降低整體風險' if vol > 0.2 else '提升報酬潛力'} |
|
|
- **再平衡頻率**:建議將再平衡頻率調整為{'每月' if vol > 0.25 else '每季度' if vol > 0.15 else '每半年'}一次,以適應市場變化 |
|
|
- **風險暴露管理**:{'考慮降低' if beta > 1.2 else '可適度提高' if beta < 0.8 else '維持當前'}市場Beta暴露 |
|
|
|
|
|
### 3. 風險管理 |
|
|
- **止損設定**:建議設定止損點在{abs(mdd)*1.3:.1%}(當前最大回落的1.3倍),避免過大虧損 |
|
|
- **倉位控制**:在市場波動加劇時,{'建議降低倉位至70-80%' if vol > 0.25 else '可維持滿倉' if vol < 0.15 else '維持80-90%倉位'} |
|
|
- **監控指標**: |
|
|
- 持續關注VaR指標,當VaR超過{abs(var)*1.5:.2%}時應考慮降低風險 |
|
|
- 密切追蹤市場波動性變化(VIX指數等) |
|
|
- 定期檢視Alpha表現,確保策略持續創造超額收益 |
|
|
|
|
|
## 🔮 未來展望 |
|
|
|
|
|
基於當前市場環境和策略表現,預期未來3-6個月內: |
|
|
|
|
|
- **報酬預期**:策略將維持{'穩定增長' if sharpe > 1.2 else '波動' if sharpe > 0.8 else '震盪'}表現,年化報酬率預計在{annual_ret*0.8:.1%}至{annual_ret*1.2:.1%}之間 |
|
|
- **風險展望**:市場波動性{'可能上升' if vol > 0.2 else '預期維持穩定'},建議投資者{'提高警覺' if vol > 0.2 else '保持耐心'} |
|
|
- **調整建議**:定期檢視(建議每{'月' if vol > 0.25 else '季度'}一次)並適時調整,以應對市場變化 |
|
|
|
|
|
### 關鍵提醒 |
|
|
⚠️ **免責聲明**:此為基於歷史數據的模擬分析結果,過去績效不代表未來表現。實際投資請謹慎評估個人風險承受能力,並建議諮詢專業投資顧問。 |
|
|
|
|
|
📝 **行動建議**: |
|
|
1. 定期監控策略表現(建議每週檢視一次) |
|
|
2. 設定明確的投資目標和停損點 |
|
|
3. 保持投資組合的靈活性,適時調整 |
|
|
4. 持續學習市場動態,提升投資判斷力 |
|
|
|
|
|
*本分析報告生成於{strategy_data.get('name', 'N/A')}策略,僅供參考。* |
|
|
""" |
|
|
|
|
|
# Duplicate clear_cache removed |
|
|
|
|
|
|
|
|
# 創建全域實例 |
|
|
llm_advisor = None |
|
|
|
|
|
def get_llm_advisor() -> LLMInvestmentAdvisor: |
|
|
"""獲取LLM顧問實例""" |
|
|
global llm_advisor |
|
|
if llm_advisor is None: |
|
|
llm_advisor = LLMInvestmentAdvisor() |
|
|
return llm_advisor
|
|
|
|