Sources: extracted from two upstream archives (skill-repo, skills-main),
merged with the following policy:
- 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or
../../.agents/skills on a foreign machine) discarded
- 3 real name collisions with identical content (ai-pair, ifind-http-api,
zhipu-websearch) kept as one copy
- Functional overlaps deduped keeping the strongest variant:
- docx family: kept docx (official, full toolchain) + docx-cn
(GB/T 9704 Chinese official-document constants),
dropped docx_writer (no scripts, name collided with docx)
- humanizer family: kept humanizer-zh (6 zh reference docs),
dropped humanizer (en, redundant for CN workflow)
- Skills that only ran in a foreign environment removed:
ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill,
claude-driver
- alphapai excluded from this public repo because its SKILL.md hard-coded
live credentials
Result: 25 skills, 572 files, ~7.5 MB.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
470 lines
16 KiB
Python
470 lines
16 KiB
Python
"""
|
||
投资分析引擎
|
||
提供基本面分析、技术面分析和估值分析功能
|
||
"""
|
||
|
||
import pandas as pd
|
||
import numpy as np
|
||
from typing import Dict, List, Tuple, Optional
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
|
||
|
||
class InvestmentRating(Enum):
|
||
"""投资评级"""
|
||
BUY = "买入"
|
||
ACCUMULATE = "增持"
|
||
HOLD = "持有"
|
||
REDUCE = "减持"
|
||
SELL = "卖出"
|
||
|
||
|
||
class RiskLevel(Enum):
|
||
"""风险等级"""
|
||
LOW = "低风险"
|
||
LOW_MEDIUM = "中低风险"
|
||
MEDIUM = "中等风险"
|
||
MEDIUM_HIGH = "中高风险"
|
||
HIGH = "高风险"
|
||
|
||
|
||
@dataclass
|
||
class TechnicalAnalysis:
|
||
"""技术分析结果"""
|
||
trend: str # 趋势判断
|
||
support_level: float # 支撑位
|
||
resistance_level: float # 阻力位
|
||
volatility: float # 波动率
|
||
ma_status: str # 均线状态
|
||
technical_summary: str # 技术总结
|
||
|
||
|
||
@dataclass
|
||
class FundamentalAnalysis:
|
||
"""基本面分析结果"""
|
||
roe: float # 净资产收益率
|
||
roe_comment: str # ROE评价
|
||
pe_ttm: float # 市盈率TTM
|
||
pb_lf: float # 市净率LF
|
||
valuation_comment: str # 估值评价
|
||
fundamental_summary: str # 基本面总结
|
||
|
||
|
||
@dataclass
|
||
class InvestmentRecommendation:
|
||
"""投资建议"""
|
||
rating: InvestmentRating
|
||
target_price: float
|
||
risk_level: RiskLevel
|
||
recommendation_text: str
|
||
key_factors: List[str]
|
||
|
||
|
||
class AnalysisEngine:
|
||
"""
|
||
投资分析引擎
|
||
"""
|
||
|
||
# ROE评价标准
|
||
ROE_THRESHOLDS = {
|
||
'excellent': 20,
|
||
'good': 15,
|
||
'average': 10,
|
||
'poor': 5
|
||
}
|
||
|
||
# PE评价标准(参考值,实际应根据行业调整)
|
||
PE_THRESHOLDS = {
|
||
'undervalued': 15,
|
||
'fair': 25,
|
||
'overvalued': 35
|
||
}
|
||
|
||
# PB评价标准
|
||
PB_THRESHOLDS = {
|
||
'undervalued': 1.5,
|
||
'fair': 3.0,
|
||
'overvalued': 5.0
|
||
}
|
||
|
||
def __init__(self, price_df: pd.DataFrame, financial_data: Dict):
|
||
"""
|
||
初始化分析引擎
|
||
|
||
Args:
|
||
price_df: 价格数据DataFrame
|
||
financial_data: 财务数据字典
|
||
"""
|
||
self.price_df = price_df.copy()
|
||
self.financial_data = financial_data
|
||
|
||
# 计算涨跌幅和收益率
|
||
if 'pct_chg' not in self.price_df.columns and 'close' in self.price_df.columns:
|
||
self.price_df['pct_chg'] = self.price_df['close'].pct_change() * 100
|
||
|
||
def analyze_technical(self) -> TechnicalAnalysis:
|
||
"""
|
||
技术分析
|
||
|
||
Returns:
|
||
TechnicalAnalysis对象
|
||
"""
|
||
df = self.price_df
|
||
|
||
# 计算均线
|
||
if 'ma5' not in df.columns:
|
||
df['ma5'] = df['close'].rolling(window=5).mean()
|
||
if 'ma10' not in df.columns:
|
||
df['ma10'] = df['close'].rolling(window=10).mean()
|
||
if 'ma20' not in df.columns:
|
||
df['ma20'] = df['close'].rolling(window=20).mean()
|
||
|
||
latest = df.iloc[-1]
|
||
|
||
# 趋势判断
|
||
if latest['close'] > latest['ma5'] > latest['ma10'] > latest['ma20']:
|
||
trend = "强势上涨"
|
||
elif latest['close'] > latest['ma5'] > latest['ma10']:
|
||
trend = "震荡上行"
|
||
elif latest['close'] < latest['ma5'] < latest['ma10'] < latest['ma20']:
|
||
trend = "强势下跌"
|
||
elif latest['close'] < latest['ma5'] < latest['ma10']:
|
||
trend = "震荡下行"
|
||
else:
|
||
trend = "震荡整理"
|
||
|
||
# 计算支撑位和阻力位(基于近期高低点)
|
||
recent_data = df.tail(20)
|
||
support_level = recent_data['low'].min()
|
||
resistance_level = recent_data['high'].max()
|
||
|
||
# 计算波动率
|
||
returns = df['close'].pct_change().dropna()
|
||
volatility = returns.std() * np.sqrt(52) * 100 # 年化波动率
|
||
|
||
# 均线状态
|
||
if latest['ma5'] > latest['ma20']:
|
||
ma_status = "多头排列"
|
||
elif latest['ma5'] < latest['ma20']:
|
||
ma_status = "空头排列"
|
||
else:
|
||
ma_status = "均线粘合"
|
||
|
||
# 技术总结
|
||
if trend in ["强势上涨", "震荡上行"] and ma_status == "多头排列":
|
||
technical_summary = "技术面呈上升趋势,建议关注回调买入机会。"
|
||
elif trend in ["强势下跌", "震荡下行"]:
|
||
technical_summary = "技术面呈下降趋势,建议观望或减仓。"
|
||
else:
|
||
technical_summary = "技术面呈震荡格局,建议高抛低吸。"
|
||
|
||
return TechnicalAnalysis(
|
||
trend=trend,
|
||
support_level=round(support_level, 2),
|
||
resistance_level=round(resistance_level, 2),
|
||
volatility=round(volatility, 2),
|
||
ma_status=ma_status,
|
||
technical_summary=technical_summary
|
||
)
|
||
|
||
def analyze_fundamental(self) -> FundamentalAnalysis:
|
||
"""
|
||
基本面分析
|
||
|
||
Returns:
|
||
FundamentalAnalysis对象
|
||
"""
|
||
# 获取ROE
|
||
roe = self.financial_data.get('roe_wgt', 0) or self.financial_data.get('roe', 0)
|
||
|
||
# ROE评价
|
||
if roe >= self.ROE_THRESHOLDS['excellent']:
|
||
roe_comment = "ROE表现优异,公司盈利能力强劲"
|
||
elif roe >= self.ROE_THRESHOLDS['good']:
|
||
roe_comment = "ROE表现良好,盈利能力较强"
|
||
elif roe >= self.ROE_THRESHOLDS['average']:
|
||
roe_comment = "ROE处于行业平均水平"
|
||
else:
|
||
roe_comment = "ROE偏低,需关注盈利能力改善"
|
||
|
||
# 获取PE和PB
|
||
pe_ttm = self.financial_data.get('pe_ttm', 0) or self.price_df['pe_ttm'].iloc[-1] if 'pe_ttm' in self.price_df.columns else 0
|
||
pb_lf = self.financial_data.get('pb_lf', 0) or self.price_df['pb_lf'].iloc[-1] if 'pb_lf' in self.price_df.columns else 0
|
||
|
||
# 估值评价
|
||
if pe_ttm <= self.PE_THRESHOLDS['undervalued'] and pb_lf <= self.PB_THRESHOLDS['undervalued']:
|
||
valuation_comment = "估值处于历史低位,具备较高安全边际"
|
||
elif pe_ttm <= self.PE_THRESHOLDS['fair']:
|
||
valuation_comment = "估值处于合理区间"
|
||
elif pe_ttm <= self.PE_THRESHOLDS['overvalued']:
|
||
valuation_comment = "估值略高,需关注业绩成长性"
|
||
else:
|
||
valuation_comment = "估值偏高,注意追高风险"
|
||
|
||
# 基本面总结
|
||
if roe >= self.ROE_THRESHOLDS['good'] and pe_ttm <= self.PE_THRESHOLDS['fair']:
|
||
fundamental_summary = "公司基本面健康,盈利能力强,估值合理,具备投资价值。"
|
||
elif roe >= self.ROE_THRESHOLDS['good']:
|
||
fundamental_summary = "公司盈利能力较强,但估值偏高,建议等待回调机会。"
|
||
else:
|
||
fundamental_summary = "公司基本面一般,建议谨慎观望。"
|
||
|
||
return FundamentalAnalysis(
|
||
roe=round(roe, 2) if roe else 0,
|
||
roe_comment=roe_comment,
|
||
pe_ttm=round(pe_ttm, 2) if pe_ttm else 0,
|
||
pb_lf=round(pb_lf, 2) if pb_lf else 0,
|
||
valuation_comment=valuation_comment,
|
||
fundamental_summary=fundamental_summary
|
||
)
|
||
|
||
def generate_recommendation(self,
|
||
current_price: float,
|
||
fundamental: FundamentalAnalysis = None,
|
||
technical: TechnicalAnalysis = None) -> InvestmentRecommendation:
|
||
"""
|
||
生成投资建议
|
||
|
||
Args:
|
||
current_price: 当前价格
|
||
fundamental: 基本面分析结果
|
||
technical: 技术面分析结果
|
||
|
||
Returns:
|
||
InvestmentRecommendation对象
|
||
"""
|
||
if fundamental is None:
|
||
fundamental = self.analyze_fundamental()
|
||
if technical is None:
|
||
technical = self.analyze_technical()
|
||
|
||
# 综合评分
|
||
score = 0
|
||
|
||
# 基本面评分
|
||
if fundamental.roe >= self.ROE_THRESHOLDS['excellent']:
|
||
score += 3
|
||
elif fundamental.roe >= self.ROE_THRESHOLDS['good']:
|
||
score += 2
|
||
elif fundamental.roe >= self.ROE_THRESHOLDS['average']:
|
||
score += 1
|
||
|
||
# 估值评分
|
||
if fundamental.pe_ttm <= self.PE_THRESHOLDS['undervalued']:
|
||
score += 3
|
||
elif fundamental.pe_ttm <= self.PE_THRESHOLDS['fair']:
|
||
score += 2
|
||
elif fundamental.pe_ttm <= self.PE_THRESHOLDS['overvalued']:
|
||
score += 1
|
||
|
||
# 技术面评分
|
||
if technical.trend in ["强势上涨", "震荡上行"]:
|
||
score += 2
|
||
elif technical.trend == "震荡整理":
|
||
score += 1
|
||
|
||
# 风险等级
|
||
if technical.volatility > 50:
|
||
risk_level = RiskLevel.HIGH
|
||
elif technical.volatility > 35:
|
||
risk_level = RiskLevel.MEDIUM_HIGH
|
||
elif technical.volatility > 25:
|
||
risk_level = RiskLevel.MEDIUM
|
||
elif technical.volatility > 15:
|
||
risk_level = RiskLevel.LOW_MEDIUM
|
||
else:
|
||
risk_level = RiskLevel.LOW
|
||
|
||
# 目标价格计算(基于PE和支撑阻力)
|
||
target_price_pe = current_price * (self.PE_THRESHOLDS['fair'] / max(fundamental.pe_ttm, 1))
|
||
target_price_resistance = technical.resistance_level * 1.1
|
||
target_price = round((target_price_pe + target_price_resistance) / 2, 2)
|
||
|
||
# 投资建议
|
||
key_factors = []
|
||
|
||
if score >= 6:
|
||
rating = InvestmentRating.BUY
|
||
recommendation_text = f"综合基本面和技术面分析,该股投资价值较高。目标价{target_price}元,建议逢低买入。"
|
||
key_factors.append("盈利能力强劲,ROE表现优异")
|
||
elif score >= 4:
|
||
rating = InvestmentRating.ACCUMULATE
|
||
recommendation_text = f"公司基本面良好,建议关注回调机会逐步建仓。目标价{target_price}元。"
|
||
key_factors.append("基本面稳健,估值合理")
|
||
elif score >= 2:
|
||
rating = InvestmentRating.HOLD
|
||
recommendation_text = "公司基本面一般,当前估值合理,建议持有观望。"
|
||
key_factors.append("基本面中性,估值合理")
|
||
else:
|
||
rating = InvestmentRating.REDUCE
|
||
recommendation_text = "公司基本面较弱或估值偏高,建议谨慎或减仓。"
|
||
key_factors.append("基本面一般或估值偏高")
|
||
|
||
if technical.trend in ["强势上涨", "震荡上行"]:
|
||
key_factors.append("技术面呈上升趋势")
|
||
elif technical.trend in ["强势下跌", "震荡下行"]:
|
||
key_factors.append("技术面呈下降趋势")
|
||
|
||
if fundamental.pe_ttm <= self.PE_THRESHOLDS['undervalued']:
|
||
key_factors.append("估值处于历史低位")
|
||
|
||
return InvestmentRecommendation(
|
||
rating=rating,
|
||
target_price=target_price,
|
||
risk_level=risk_level,
|
||
recommendation_text=recommendation_text,
|
||
key_factors=key_factors
|
||
)
|
||
|
||
def generate_core_summary(self,
|
||
fundamental: FundamentalAnalysis = None,
|
||
technical: TechnicalAnalysis = None,
|
||
recommendation: InvestmentRecommendation = None) -> List[str]:
|
||
"""
|
||
生成核心提要要点
|
||
|
||
Returns:
|
||
要点列表
|
||
"""
|
||
if fundamental is None:
|
||
fundamental = self.analyze_fundamental()
|
||
if technical is None:
|
||
technical = self.analyze_technical()
|
||
if recommendation is None:
|
||
# 获取最新价格
|
||
latest_price = self.price_df['close'].iloc[-1] if 'close' in self.price_df.columns else 0
|
||
recommendation = self.generate_recommendation(latest_price, fundamental, technical)
|
||
|
||
summary_points = []
|
||
|
||
# ROE要点
|
||
if fundamental.roe > 0:
|
||
summary_points.append(
|
||
f"该公司最新净资产收益率(ROE)为{fundamental.roe}%,{fundamental.roe_comment}"
|
||
)
|
||
|
||
# 估值要点
|
||
if fundamental.pe_ttm > 0:
|
||
summary_points.append(
|
||
f"当前市盈率(TTM)为{fundamental.pe_ttm}倍,{fundamental.valuation_comment}"
|
||
)
|
||
|
||
# 技术面要点
|
||
summary_points.append(
|
||
f"技术面显示股价呈现{technical.trend}趋势,{technical.technical_summary}"
|
||
)
|
||
|
||
# 投资建议要点
|
||
summary_points.append(
|
||
f"给予\"{recommendation.rating.value}\"评级,目标价格{recommendation.target_price}元,风险等级为{recommendation.risk_level.value}"
|
||
)
|
||
|
||
return summary_points
|
||
|
||
def get_price_statistics(self) -> Dict:
|
||
"""
|
||
获取价格统计数据
|
||
|
||
Returns:
|
||
统计数据字典
|
||
"""
|
||
df = self.price_df
|
||
|
||
if len(df) == 0:
|
||
return {}
|
||
|
||
return {
|
||
'latest_price': round(df['close'].iloc[-1], 2),
|
||
'highest_price': round(df['high'].max(), 2),
|
||
'lowest_price': round(df['low'].min(), 2),
|
||
'avg_price': round(df['close'].mean(), 2),
|
||
'total_change': round(((df['close'].iloc[-1] / df['close'].iloc[0]) - 1) * 100, 2),
|
||
'max_daily_gain': round(df['pct_chg'].max(), 2) if 'pct_chg' in df.columns else 0,
|
||
'max_daily_loss': round(df['pct_chg'].min(), 2) if 'pct_chg' in df.columns else 0,
|
||
'volatility': round(df['close'].pct_change().std() * np.sqrt(52) * 100, 2)
|
||
}
|
||
|
||
|
||
def perform_comprehensive_analysis(price_df: pd.DataFrame,
|
||
financial_data: Dict,
|
||
current_price: float = None) -> Dict:
|
||
"""
|
||
执行综合分析并返回所有结果
|
||
|
||
Args:
|
||
price_df: 价格数据
|
||
financial_data: 财务数据
|
||
current_price: 当前价格(可选)
|
||
|
||
Returns:
|
||
包含所有分析结果的字典
|
||
"""
|
||
engine = AnalysisEngine(price_df, financial_data)
|
||
|
||
if current_price is None:
|
||
current_price = price_df['close'].iloc[-1]
|
||
|
||
technical = engine.analyze_technical()
|
||
fundamental = engine.analyze_fundamental()
|
||
recommendation = engine.generate_recommendation(current_price, fundamental, technical)
|
||
summary_points = engine.generate_core_summary(fundamental, technical, recommendation)
|
||
price_stats = engine.get_price_statistics()
|
||
|
||
return {
|
||
'technical': technical,
|
||
'fundamental': fundamental,
|
||
'recommendation': recommendation,
|
||
'summary_points': summary_points,
|
||
'price_stats': price_stats
|
||
}
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# 测试代码
|
||
import numpy as np
|
||
|
||
# 创建模拟数据
|
||
dates = pd.date_range(start='2025-01-01', periods=60, freq='W')
|
||
np.random.seed(42)
|
||
prices = 30 + np.cumsum(np.random.randn(60) * 0.5)
|
||
|
||
price_df = pd.DataFrame({
|
||
'date': dates,
|
||
'open': prices * 0.98,
|
||
'high': prices * 1.03,
|
||
'low': prices * 0.97,
|
||
'close': prices,
|
||
'volume': np.random.randint(1000000, 5000000, 60),
|
||
'pe_ttm': 25 + np.random.randn(60) * 2,
|
||
'pb_lf': 3 + np.random.randn(60) * 0.2
|
||
})
|
||
|
||
financial_data = {
|
||
'roe_wgt': 16.5,
|
||
'pe_ttm': 25.3,
|
||
'pb_lf': 3.1,
|
||
'sec_name': '测试公司'
|
||
}
|
||
|
||
# 执行分析
|
||
results = perform_comprehensive_analysis(price_df, financial_data)
|
||
|
||
print("=== 技术分析 ===")
|
||
print(f"趋势: {results['technical'].trend}")
|
||
print(f"支撑位: {results['technical'].support_level}")
|
||
print(f"阻力位: {results['technical'].resistance_level}")
|
||
|
||
print("\n=== 基本面分析 ===")
|
||
print(f"ROE: {results['fundamental'].roe}%")
|
||
print(f"PE TTM: {results['fundamental'].pe_ttm}")
|
||
print(f"PB LF: {results['fundamental'].pb_lf}")
|
||
|
||
print("\n=== 投资建议 ===")
|
||
print(f"评级: {results['recommendation'].rating.value}")
|
||
print(f"目标价: {results['recommendation'].target_price}元")
|
||
print(f"风险等级: {results['recommendation'].risk_level.value}")
|
||
|
||
print("\n=== 核心提要 ===")
|
||
for i, point in enumerate(results['summary_points'], 1):
|
||
print(f"{i}. {point}")
|