This commit is contained in:
oficcejo
2026-02-27 15:15:49 +08:00
parent cfda09f3e4
commit 63628ffdd5
7 changed files with 2014 additions and 3 deletions
+21
View File
@@ -8,6 +8,27 @@
## 投资认知提升合集:https://www.bilibili.com/video/BV1ugBMBAEbW
如果你希望能在股市中长久生存下去,建议你能把上面的合集看完,会对你有很大帮助的!
## ⭐ 2026.2.27更新 - 宏观周期分析 🧭
**全新板块:康波周期 × 美林投资时钟 × 中国政策分析**
基于视频[康波周期理论](https://www.bilibili.com/video/BV1QNcEzREzY)和视频[美林投资时钟](https://www.bilibili.com/video/BV1Zuf5BUEhH),由4位AI分析师协同研判当前宏观经济所处的周期位置!
**核心功能:**
- 🌊 **康波周期分析** — 判断当前处于50-60年长周期的哪个阶段(回升/繁荣/衰退/萧条)
-**美林投资时钟** — 判断当前处于3-5年中短周期的哪个象限(复苏/过热/滞胀/衰退)
- 🏛️ **中国政策分析** — 货币/财政/产业/房地产政策全面解读(中国化第三维度)
- 👔 **首席宏观策略师** — 三维综合研判,"周期仪表盘"资产配置建议
- 📊 **自动采集宏观数据** — GDP、CPI/PPI、PMI、M2、LPR利率、大宗商品等
**适用场景:**
- 战略性资产配置决策(买房/创业/大额投资)
- 中短期投资组合调整
- 理解当前经济环境,避免"在高点接盘、在低点割肉"
---
## ⭐ 2026.2.27更新 - AI模型自由切换 🤖
**重大改进:AI模型全局可配置化**
+30 -3
View File
@@ -276,6 +276,9 @@ def main():
</div>
""", unsafe_allow_html=True)
# 学习资源展示
st.info("📺 **新手必看干货**:为了在股市长久生存,建议您观看 👉 [股票知识讲解合集](https://www.bilibili.com/video/BV1Y2FGzzEeS/) 和 [投资认知提升合集](https://www.bilibili.com/video/BV1ugBMBAEbW) 👈,相信会对您有很大帮助!")
# 侧边栏
with st.sidebar:
# 快捷导航 - 移到顶部
@@ -285,7 +288,7 @@ def main():
if st.button("🏠 股票分析", width='stretch', key="nav_home", help="返回首页,进行单只股票的深度分析"):
# 清除所有功能页面标志
for key in ['show_history', 'show_monitor', 'show_config', 'show_main_force',
'show_sector_strategy', 'show_longhubang', 'show_portfolio', 'show_low_price_bull', 'show_news_flow']:
'show_sector_strategy', 'show_longhubang', 'show_portfolio', 'show_low_price_bull', 'show_news_flow', 'show_macro_cycle']:
if key in st.session_state:
del st.session_state[key]
@@ -344,7 +347,14 @@ def main():
if st.button("📰 新闻流量", width='stretch', key="nav_news_flow", help="新闻流量监测与短线指导"):
st.session_state.show_news_flow = True
for key in ['show_history', 'show_monitor', 'show_config', 'show_main_force',
'show_sector_strategy', 'show_portfolio', 'show_smart_monitor', 'show_low_price_bull', 'show_longhubang']:
'show_sector_strategy', 'show_portfolio', 'show_smart_monitor', 'show_low_price_bull', 'show_longhubang', 'show_macro_cycle']:
if key in st.session_state:
del st.session_state[key]
if st.button("🧭 宏观周期", width='stretch', key="nav_macro_cycle", help="康波周期 × 美林投资时钟 × 政策分析"):
st.session_state.show_macro_cycle = True
for key in ['show_history', 'show_monitor', 'show_config', 'show_main_force',
'show_sector_strategy', 'show_portfolio', 'show_smart_monitor', 'show_low_price_bull', 'show_longhubang', 'show_news_flow']:
if key in st.session_state:
del st.session_state[key]
@@ -462,7 +472,18 @@ def main():
1. 数据获取 → 2. 技术分析
3. 基本面分析 → 4. 资金分析
5. 情绪数据(ARBR) → 6. 新闻(qstock)
7. AI团队分析 → 8. 团队讨论 → 9. 决策
7. AI分析 → 8. 团队讨论 → 9. 决策
""")
# 学习资源
with st.expander("📺 学习视频合集"):
st.markdown("""
**📢 B站干货合集**
如果你希望能在股市中长久生存下去,建议你能把下面的合集看完,会对你有很大帮助的!
- 📚 [股票知识讲解合集](https://www.bilibili.com/video/BV1Y2FGzzEeS/)
- 🧠 [投资认知提升合集](https://www.bilibili.com/video/BV1ugBMBAEbW)
""")
# 检查是否显示历史记录
@@ -523,6 +544,12 @@ def main():
if 'show_news_flow' in st.session_state and st.session_state.show_news_flow:
display_news_flow_monitor()
return
# 检查是否显示宏观周期分析
if 'show_macro_cycle' in st.session_state and st.session_state.show_macro_cycle:
from macro_cycle_ui import display_macro_cycle
display_macro_cycle()
return
# 检查是否显示环境配置
if 'show_config' in st.session_state and st.session_state.show_config:
+458
View File
@@ -0,0 +1,458 @@
"""
宏观周期分析 - AI智能体模块
包含四位专业分析师:康波周期分析师、美林时钟分析师、中国政策分析师、首席宏观策略师
"""
from deepseek_client import DeepSeekClient
from typing import Dict, Any
import time
import config
class MacroCycleAgents:
"""宏观周期AI智能体集合"""
def __init__(self, model=None):
self.model = model or config.DEFAULT_MODEL_NAME
self.deepseek_client = DeepSeekClient(model=self.model)
print(f"[宏观周期] AI智能体系统初始化 (模型: {self.model})")
def kondratieff_wave_agent(self, macro_data_text: str) -> Dict[str, Any]:
"""
康波周期分析师 - 判断当前处于康德拉季耶夫长波的哪个阶段
职责:
- 分析当前技术革命阶段(第五轮信息技术康波的位置)
- 判断回升/繁荣/衰退/萧条四阶段中的位置
- 分析大宗商品与康波的关系
- 给出战略性资产配置方向
"""
print("🌊 康波周期分析师正在分析...")
time.sleep(1)
prompt = f"""
你是一位资深的康德拉季耶夫长波周期研究专家,拥有深厚的经济史研究功底,深入研究过周金涛先生的"人生发财靠康波"理论。
以下是当前中国的宏观经济数据:
{macro_data_text}
请你基于康波周期理论,对当前全球和中国经济进行深度分析:
## 一、康波周期基础判断
### 1. 历史康波定位
回顾历史五轮康波周期(蒸汽机→铁路钢铁→电力化工→汽车计算机→信息技术),判断:
- 当前处于第五轮信息技术康波的哪个具体阶段(回升期/繁荣期/衰退期/萧条期)?
- 给出判断依据和关键特征
- 该阶段大约始于何年,预计持续到何年?
### 2. 技术革命驱动分析
- 第五轮康波的核心技术(互联网/移动互联网)是否已经进入红利消退期?
- AI人工智能、新能源、生物科技等是否有可能成为第六轮康波的驱动力?
- 新旧技术转换的当前进展如何?
### 3. 大宗商品与康波
- 当前大宗商品(黄金、原油、铜等)的表现是否符合康波阶段特征?
- 结合数据判断是否处于康波衰退期的大宗商品超级牛市阶段?
## 二、康波阶段特征验证
对照当前经济数据,验证是否符合你判断的康波阶段特征:
- GDP增速趋势是否匹配?
- 通胀水平(CPI/PPI)是否匹配?
- 资产价格(股市、房地产)走势是否匹配?
- 就业与社会情绪是否匹配?
- 政策环境是否匹配?
## 三、康波视角下的战略建议
### 1. 当前阶段的核心策略
- 整体应该进攻还是防守?
- 应该积累现金还是配置资产?
### 2. 战略资产配置方向
给出康波视角的大类资产配置建议:
- 股票(配置比例建议及方向)
- 债券(配置比例建议)
- 大宗商品/黄金(配置比例建议)
- 现金(配置比例建议)
- 房地产(配置建议)
### 3. 布局下一轮康波
- 如果第六轮康波即将到来,应提前布局哪些方向?
- 需要回避哪些夕阳产业?
### 4. 对普通人的人生建议
根据周金涛"人生发财靠康波"的理念,当前阶段普通人应该:
- 在职业选择上注意什么?
- 在投资理财上注意什么?
- 在消费与储蓄上如何平衡?
## 四、康波周期仪表盘
请给出一个简洁的康波定位总结:
- 🌊 当前康波阶段:[回升期/繁荣期/衰退期/萧条期]
- 📍 阶段进度:[初期/中期/末期]
- ⏱️ 预计本阶段剩余时间:约X年
- 🎯 核心策略关键词:[如"防守为主,播种未来"]
- ⚠️ 信心度:[1-10分]
请给出专业、深入、有数据支撑的分析报告。
"""
messages = [
{"role": "system", "content": "你是全球顶尖的康德拉季耶夫长波周期研究专家,深研周金涛的理论体系,擅长将60年长周期框架应用于当前经济形势分析,帮助投资者做出战略性决策。"},
{"role": "user", "content": prompt}
]
analysis = self.deepseek_client.call_api(messages, max_tokens=6000)
print(" ✓ 康波周期分析师分析完成")
return {
"agent_name": "康波周期分析师",
"agent_icon": "🌊",
"agent_role": "判断当前处于康德拉季耶夫长波(50-60年大周期)的哪个阶段,给出战略性资产配置方向",
"analysis": analysis,
"focus_areas": ["康波定位", "技术革命", "大宗商品超级周期", "战略资产配置"],
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
def merrill_lynch_clock_agent(self, macro_data_text: str) -> Dict[str, Any]:
"""
美林投资时钟分析师 - 判断当前处于美林时钟的哪个象限
职责:
- 根据经济增长和通胀两个维度判断象限
- 结合中国特色(政策第三维度)
- 给出中短期资产配置建议
"""
print("⏰ 美林时钟分析师正在分析...")
time.sleep(1)
prompt = f"""
你是一位精通美林投资时钟理论的资深资产配置策略师,同时深入了解中国经济的特殊性,能够将经典美林时钟做"中国化改造"
以下是当前中国的宏观经济数据:
{macro_data_text}
请基于美林投资时钟理论,对当前中国的经济周期进行分析:
## 一、经典美林时钟定位
### 1. 两大核心指标研判
**经济增长维度(↑/→/↓):**
- GDP增速趋势判断(同比、环比、PMI佐证)
- 工业增加值/制造业景气度
- 消费、投资、出口三驾马车的状态
- 综合判断:经济增长向上还是向下?
**通货膨胀维度(↑/→/↓):**
- CPI走势分析(核心CPI
- PPI走势分析
- M2/社融与信贷扩张情况
- 综合判断:通胀向上还是向下?
### 2. 象限定位
根据以上两个维度,判断当前处于美林时钟的哪个象限:
- 🟢 复苏期(增长↑ + 通胀↓)→ 配股票
- 🔴 过热期(增长↑ + 通胀↑)→ 配商品
- 🟡 滞胀期(增长↓ + 通胀↑)→ 持现金
- 🔵 衰退期(增长↓ + 通胀↓)→ 配债券
### 3. 时钟转动方向
- 当前正从哪个象限向哪个象限转动?
- 预计转动速度如何?(中国时钟转动通常比美国快)
- 是否存在"跳跃""逆转"的可能?
## 二、中国化美林时钟(三维分析)
### 1. 第三维度:政策方向
这是中国版美林时钟最重要的增量分析:
- 货币政策方向(宽松/中性/收紧?):分析LPR、MLF、准备金率等
- 财政政策方向(积极/稳健/收缩?):分析专项债、减税降费等
- 产业政策方向:重点扶持哪些领域?
- 房地产政策方向:放松还是收紧?
- 政策的即时效果和滞后效应
### 2. 中国特色修正
- 中国利率市场化程度对时钟的影响
- 政府干预对时钟转动的扭曲效应
- A股散户占比高对资产定价的影响
- 房地产作为"第五类资产"的配置考量
## 三、资产配置建议
### 1. 基于当前象限的配置
给出各大类资产的具体配置比例建议:
| 资产类别 | 配置比例 | 理由 |
|---------|---------|------|
| A股股票 | X% | ... |
| 债券/固收 | X% | ... |
| 大宗商品/黄金 | X% | ... |
| 现金/货币基金 | X% | ... |
| 房地产 | X% | ... |
### 2. 板块/行业建议
- 当前象限最受益的行业/板块(3-5个)
- 应规避的行业/板块(2-3个)
- "政策友好型"重点关注方向
### 3. 时间框架
- 当前配置建议的有效期约多久?
- 需要密切关注哪些信号来判断时钟转动?
## 四、美林时钟仪表盘
请给出一个简洁的定位总结:
- ⏰ 当前象限:[复苏期/过热期/滞胀期/衰退期]
- 📊 经济增长:[↑上行/→持平/↓下行]
- 📈 通胀水平:[↑上行/→持平/↓下行]
- 🏛️ 政策方向:[宽松/中性/收紧]
- 🎯 最优资产:[股票/商品/现金/债券]
- ⚠️ 信心度:[1-10分]
请给出专业、数据驱动的分析报告。
"""
messages = [
{"role": "system", "content": "你是一位精通美林投资时钟理论的顶级资产配置策略师,擅长将经典框架进行中国化改造,加入政策分析作为第三维度,帮助中国投资者做出精准的中短期资产配置决策。"},
{"role": "user", "content": prompt}
]
analysis = self.deepseek_client.call_api(messages, max_tokens=6000)
print(" ✓ 美林时钟分析师分析完成")
return {
"agent_name": "美林时钟分析师",
"agent_icon": "",
"agent_role": "判断当前处于美林投资时钟的哪个象限(3-5年中短周期),给出资产配置建议",
"analysis": analysis,
"focus_areas": ["经济增长", "通胀水平", "政策方向", "资产配置"],
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
def china_policy_agent(self, macro_data_text: str) -> Dict[str, Any]:
"""
中国政策分析师 - 分析中国特色政策环境
职责:
- 分析当前政策环境
- 评估政策对周期的影响
- 识别政策驱动的投资机会
"""
print("🏛️ 中国政策分析师正在分析...")
time.sleep(1)
prompt = f"""
你是一位资深的中国宏观政策研究专家,深谙中国经济的"有形之手"运作方式,擅长从政策信号中挖掘投资机会。
以下是当前中国的宏观经济数据和新闻:
{macro_data_text}
请从政策角度进行深度分析:
## 一、当前政策全景
### 1. 货币政策分析
- 央行近期操作解读(降准/降息/MLF/逆回购等)
- LPR利率走势及未来方向
- M2增速与社融规模分析
- 流动性环境评估:宽松/适度/偏紧?
- 对标历史政策宽松周期,当前处于什么阶段?
### 2. 财政政策分析
- 专项债发行规模和进度
- 减税降费政策力度
- 基建投资方向和力度
- 财政赤字率水平
- 是否有大规模刺激计划的信号?
### 3. 产业政策分析
- 当前国家战略重点方向(如AI、新能源、半导体、生物医药等)
- "专精特新"等政策支持力度
- 国产替代进展
- 数字经济/新质生产力政策
### 4. 房地产政策分析
- 限购限贷政策变化
- 房贷利率走势
- 保交楼/房企纾困进展
- 房地产政策的底线和目标
## 二、政策对周期的影响
### 1. 政策是"顺周期"还是"逆周期"
- 当前的政策是在托底经济还是防止过热?
- 政策的主要目标是什么(稳增长/防风险/调结构)?
### 2. 政策对美林时钟的扭曲效应
- 政策宽松是否可能让时钟"跳跃"
- 政策刺激是否可能造成"短暂过热"的假象?
- 历史上类似政策环境下市场的表现
### 3. 政策拐点信号
- 需要关注哪些政策信号来判断下一步方向?
- 最可能的政策转向时间节点
## 三、政策驱动的投资机会
### 1. "政策友好型"资产
列出当前最受政策青睐的领域和方向
### 2. 政策支持的具体行业/板块
给出3-5个受益于当前政策环境的行业
### 3. 政策风险警示
哪些领域面临政策收紧或监管风险?
## 四、政策环境仪表盘
请给出简洁总结:
- 🏛️ 货币政策:[极宽松/宽松/中性/偏紧/收紧]
- 💰 财政政策:[大力刺激/积极/稳健/收缩]
- 🏭 产业政策重点:[3-5个关键词]
- 🏠 房地产政策:[大力托底/政策松绑/中性/调控]
- 🎯 政策核心目标:[一句话概括]
- ⚠️ 政策转向风险:[高/中/低]
请给出专业、深入的政策分析报告。
"""
messages = [
{"role": "system", "content": "你是一位资深的中国宏观经济政策研究专家,深入了解中国政府的经济调控方式和政策意图,擅长从政策中发现投资机会和风险。"},
{"role": "user", "content": prompt}
]
analysis = self.deepseek_client.call_api(messages, max_tokens=5000)
print(" ✓ 中国政策分析师分析完成")
return {
"agent_name": "中国政策分析师",
"agent_icon": "🏛️",
"agent_role": "分析中国特色政策环境,评估政策对周期的影响,识别政策驱动的投资机会",
"analysis": analysis,
"focus_areas": ["货币政策", "财政政策", "产业政策", "房地产政策", "政策拐点"],
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
def chief_macro_strategist_agent(self, kondratieff_report: str, merrill_report: str, policy_report: str, macro_data_text: str) -> Dict[str, Any]:
"""
首席宏观策略师 - 综合三位分析师的观点,形成最终策略
职责:
- 整合康波、美林时钟、政策三个维度
- 构建"周期仪表盘"
- 给出最终的综合建议
"""
print("👔 首席宏观策略师正在综合研判...")
time.sleep(1)
prompt = f"""
你是一位顶级的首席宏观策略师,你需要整合三位分析师的报告,形成最终的综合判断和投资策略。
【康波周期分析师报告】
{kondratieff_report}
【美林时钟分析师报告】
{merrill_report}
【中国政策分析师报告】
{policy_report}
请你综合以上三份报告,进行最终的综合研判:
## 一、周期仪表盘(双指针+政策风向标)
构建一个完整的"周期仪表盘"
### 康波指针(战略方向)
- 当前阶段:[回升期/繁荣期/衰退期/萧条期]
- 阶段进度:[初期/中期/末期]
- 战略方向:[进攻/稳健/防守/极度防守]
### 美林指针(战术节奏)
- 当前象限:[复苏/过热/滞胀/衰退]
- 转动方向:向[下一个象限]转动
- 战术方向:[积极做多/获利了结/持币观望/配置债券]
### 政策风向标(中国特色)
- 政策方向:[强力宽松/宽松/中性/收紧]
- 对周期的影响:[加速/减缓/扭曲/逆转]
### 双指针共振分析
- 两个指针方向是否一致?
- 共振或矛盾意味着什么?
- 综合信号:[强烈看多/偏多/中性/偏空/强烈看空]
## 二、综合资产配置建议
### 1. 最终配置方案
结合康波(战略)+ 美林(战术)+ 政策(催化),给出最终的资产配置建议:
| 资产类别 | 推荐配置 | 康波逻辑 | 美林逻辑 | 政策逻辑 |
|---------|---------|---------|---------|---------|
| A股/港股 | X% | ... | ... | ... |
| 债券/固收 | X% | ... | ... | ... |
| 黄金 | X% | ... | ... | ... |
| 大宗商品 | X% | ... | ... | ... |
| 现金 | X% | ... | ... | ... |
| 房地产 | X% | ... | ... | ... |
### 2. 重点板块/方向(3-5个)
结合三个维度共振的最优方向
### 3. 风险警示
需要高度警惕的风险因素
## 三、不同人群的具体建议
### 1. 保守型投资者(风险厌恶)
- 资产配置建议
- 核心策略
### 2. 稳健型投资者(平衡风险收益)
- 资产配置建议
- 核心策略
### 3. 进取型投资者(愿承受风险)
- 资产配置建议
- 核心策略
## 四、核心观点总结
请用简洁有力的语言总结:
1. **一句话定位**:当前经济周期的核心判断
2. **核心策略**:用一句话概括应对策略
3. **最大机会**:当前最值得把握的方向
4. **最大风险**:最需要警惕的风险
5. **时间节点**:下一个重要的周期转折点大约在何时
## 五、周金涛名言对照
选择一句最契合当前阶段的周金涛名言,并解释为什么这句话适用于当下。
请给出权威、全面、可操作的综合策略报告。
"""
messages = [
{"role": "system", "content": "你是一位世界级的首席宏观策略师,擅长将康波长周期、美林投资时钟和中国政策环境三个维度有机结合,为投资者提供既有战略高度又有战术灵活性的综合投资策略。你的判断沉稳、客观、有数据支撑。"},
{"role": "user", "content": prompt}
]
analysis = self.deepseek_client.call_api(messages, max_tokens=6000)
print(" ✓ 首席宏观策略师综合研判完成")
return {
"agent_name": "首席宏观策略师",
"agent_icon": "👔",
"agent_role": "整合康波周期、美林时钟、中国政策三维分析,构建周期仪表盘,给出最终综合策略",
"analysis": analysis,
"focus_areas": ["周期仪表盘", "综合资产配置", "双指针共振", "分人群建议"],
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
# 测试
if __name__ == "__main__":
print("=" * 60)
print("测试宏观周期AI智能体系统")
print("=" * 60)
agents = MacroCycleAgents()
print(f"模型: {agents.model}")
print("初始化完成")
+559
View File
@@ -0,0 +1,559 @@
"""
宏观周期分析 - 数据采集模块
采集宏观经济数据(GDP、CPI/PPI、PMI、利率、M2、大宗商品等)
用于康波周期和美林投资时钟分析
"""
import akshare as ak
import pandas as pd
from datetime import datetime, timedelta
import warnings
import time
import logging
import traceback
warnings.filterwarnings('ignore')
logger = logging.getLogger(__name__)
class MacroCycleDataFetcher:
"""宏观经济数据采集器"""
def __init__(self):
print("[宏观周期] 数据采集器初始化...")
self.max_retries = 3
def _safe_request(self, func, *args, **kwargs):
"""安全请求,带重试"""
for i in range(self.max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if i < self.max_retries - 1:
time.sleep(2)
else:
logger.warning(f"请求失败: {e}")
return None
def get_all_macro_data(self) -> dict:
"""
获取所有宏观经济数据
Returns:
dict: 包含多维度宏观数据的字典
"""
print("\n[宏观周期] 开始采集宏观经济数据...")
data = {
"success": False,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"gdp": {},
"cpi_ppi": {},
"pmi": {},
"money_supply": {},
"interest_rate": {},
"market_indices": {},
"commodities": {},
"real_estate": {},
"employment": {},
"news": [],
"errors": []
}
# 1. GDP
print(" 1/9 获取GDP数据...")
try:
gdp_data = self._get_gdp_data()
if gdp_data:
data["gdp"] = gdp_data
print(" ✓ GDP数据获取成功")
except Exception as e:
data["errors"].append(f"GDP: {e}")
print(f" ✗ GDP数据获取失败: {e}")
# 2. CPI/PPI
print(" 2/9 获取CPI/PPI数据...")
try:
cpi_ppi = self._get_cpi_ppi_data()
if cpi_ppi:
data["cpi_ppi"] = cpi_ppi
print(" ✓ CPI/PPI数据获取成功")
except Exception as e:
data["errors"].append(f"CPI/PPI: {e}")
print(f" ✗ CPI/PPI获取失败: {e}")
# 3. PMI
print(" 3/9 获取PMI数据...")
try:
pmi = self._get_pmi_data()
if pmi:
data["pmi"] = pmi
print(" ✓ PMI数据获取成功")
except Exception as e:
data["errors"].append(f"PMI: {e}")
print(f" ✗ PMI获取失败: {e}")
# 4. 货币供应量 M2
print(" 4/9 获取货币供应数据...")
try:
money = self._get_money_supply()
if money:
data["money_supply"] = money
print(" ✓ 货币供应数据获取成功")
except Exception as e:
data["errors"].append(f"货币供应: {e}")
print(f" ✗ 货币供应获取失败: {e}")
# 5. 利率
print(" 5/9 获取利率数据...")
try:
rate = self._get_interest_rate()
if rate:
data["interest_rate"] = rate
print(" ✓ 利率数据获取成功")
except Exception as e:
data["errors"].append(f"利率: {e}")
print(f" ✗ 利率获取失败: {e}")
# 6. 市场指数
print(" 6/9 获取市场指数...")
try:
indices = self._get_market_indices()
if indices:
data["market_indices"] = indices
print(" ✓ 市场指数获取成功")
except Exception as e:
data["errors"].append(f"市场指数: {e}")
print(f" ✗ 市场指数获取失败: {e}")
# 7. 大宗商品
print(" 7/9 获取大宗商品数据...")
try:
commodities = self._get_commodities_data()
if commodities:
data["commodities"] = commodities
print(" ✓ 大宗商品数据获取成功")
except Exception as e:
data["errors"].append(f"大宗商品: {e}")
print(f" ✗ 大宗商品获取失败: {e}")
# 8. 房地产
print(" 8/9 获取房地产数据...")
try:
real_estate = self._get_real_estate_data()
if real_estate:
data["real_estate"] = real_estate
print(" ✓ 房地产数据获取成功")
except Exception as e:
data["errors"].append(f"房地产: {e}")
print(f" ✗ 房地产获取失败: {e}")
# 9. 财经新闻
print(" 9/9 获取财经新闻...")
try:
news = self._get_macro_news()
if news:
data["news"] = news
print(f" ✓ 获取{len(news)}条新闻")
except Exception as e:
data["errors"].append(f"新闻: {e}")
print(f" ✗ 新闻获取失败: {e}")
# 判断是否有足够数据
valid_count = sum(1 for k in ["gdp", "cpi_ppi", "pmi", "money_supply",
"interest_rate", "market_indices", "commodities"]
if data.get(k))
if valid_count >= 3:
data["success"] = True
print(f"\n[宏观周期] 数据采集完成,成功获取 {valid_count}/7 项核心数据")
else:
print(f"\n[宏观周期] 数据不足(仅 {valid_count}/7 项),分析可能不够准确")
data["success"] = True # 仍允许分析
return data
def _get_gdp_data(self) -> dict:
"""获取GDP数据"""
result = {}
try:
# 中国GDP年度
df = self._safe_request(ak.macro_china_gdp)
if df is not None and not df.empty:
recent = df.tail(8)
result["yearly"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["yearly"].append(item)
except Exception as e:
logger.warning(f"GDP年度数据获取失败: {e}")
try:
# 季度GDP增速
df = self._safe_request(ak.macro_china_gdp_yearly)
if df is not None and not df.empty:
recent = df.tail(12)
result["quarterly_growth"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["quarterly_growth"].append(item)
except Exception as e:
logger.warning(f"GDP季度数据获取失败: {e}")
return result if result else None
def _get_cpi_ppi_data(self) -> dict:
"""获取CPI和PPI数据"""
result = {}
try:
# CPI月度
df = self._safe_request(ak.macro_china_cpi_monthly)
if df is not None and not df.empty:
recent = df.tail(12)
result["cpi_monthly"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["cpi_monthly"].append(item)
except Exception as e:
logger.warning(f"CPI数据获取失败: {e}")
try:
# PPI月度
df = self._safe_request(ak.macro_china_ppi_yearly)
if df is not None and not df.empty:
recent = df.tail(12)
result["ppi_monthly"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["ppi_monthly"].append(item)
except Exception as e:
logger.warning(f"PPI数据获取失败: {e}")
return result if result else None
def _get_pmi_data(self) -> dict:
"""获取PMI数据"""
result = {}
try:
# 制造业PMI
df = self._safe_request(ak.macro_china_pmi_yearly)
if df is not None and not df.empty:
recent = df.tail(12)
result["manufacturing_pmi"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["manufacturing_pmi"].append(item)
except Exception as e:
logger.warning(f"制造业PMI获取失败: {e}")
try:
# 非制造业PMI(财新)
df = self._safe_request(ak.macro_china_cx_pmi_yearly)
if df is not None and not df.empty:
recent = df.tail(12)
result["caixin_pmi"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["caixin_pmi"].append(item)
except Exception as e:
logger.warning(f"财新PMI获取失败: {e}")
return result if result else None
def _get_money_supply(self) -> dict:
"""获取货币供应量"""
result = {}
try:
df = self._safe_request(ak.macro_china_money_supply)
if df is not None and not df.empty:
recent = df.tail(12)
result["m2_data"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["m2_data"].append(item)
except Exception as e:
logger.warning(f"货币供应数据获取失败: {e}")
return result if result else None
def _get_interest_rate(self) -> dict:
"""获取利率数据"""
result = {}
try:
# LPR利率
df = self._safe_request(ak.macro_china_lpr)
if df is not None and not df.empty:
recent = df.tail(12)
result["lpr"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["lpr"].append(item)
except Exception as e:
logger.warning(f"LPR利率获取失败: {e}")
return result if result else None
def _get_market_indices(self) -> dict:
"""获取主要市场指数"""
result = {}
indices = {
"sh_index": "sh000001", # 上证指数
"sz_index": "sz399001", # 深证成指
"cyb_index": "sz399006", # 创业板指
}
for name, code in indices.items():
try:
df = self._safe_request(
ak.stock_zh_index_daily,
symbol=code
)
if df is not None and not df.empty:
latest = df.tail(1).iloc[0]
prev = df.tail(2).iloc[0] if len(df) >= 2 else latest
change_pct = 0
if prev["close"] > 0:
change_pct = (latest["close"] - prev["close"]) / prev["close"] * 100
# 计算近期涨跌
recent_60 = df.tail(60)
pct_60d = 0
if len(recent_60) >= 60:
pct_60d = (latest["close"] - recent_60.iloc[0]["close"]) / recent_60.iloc[0]["close"] * 100
result[name] = {
"close": round(float(latest["close"]), 2),
"change_pct": round(change_pct, 2),
"pct_60d": round(pct_60d, 2),
"high_52w": round(float(df.tail(250)["high"].max()), 2) if len(df) >= 250 else None,
"low_52w": round(float(df.tail(250)["low"].min()), 2) if len(df) >= 250 else None,
}
except Exception as e:
logger.warning(f"指数{name}获取失败: {e}")
return result if result else None
def _get_commodities_data(self) -> dict:
"""获取大宗商品数据"""
result = {}
# 黄金
try:
df = self._safe_request(ak.futures_main_sina, symbol="AU0", start_date=(datetime.now() - timedelta(days=365)).strftime("%Y%m%d"), end_date=datetime.now().strftime("%Y%m%d"))
if df is not None and not df.empty:
latest = df.tail(1).iloc[0]
first = df.head(1).iloc[0]
ytd_pct = (float(latest["收盘价"]) - float(first["收盘价"])) / float(first["收盘价"]) * 100 if float(first["收盘价"]) > 0 else 0
result["gold"] = {
"price": round(float(latest["收盘价"]), 2),
"ytd_change_pct": round(ytd_pct, 2),
"name": "沪金主力"
}
except Exception as e:
logger.warning(f"黄金数据获取失败: {e}")
# 原油
try:
df = self._safe_request(ak.futures_main_sina, symbol="SC0", start_date=(datetime.now() - timedelta(days=365)).strftime("%Y%m%d"), end_date=datetime.now().strftime("%Y%m%d"))
if df is not None and not df.empty:
latest = df.tail(1).iloc[0]
first = df.head(1).iloc[0]
ytd_pct = (float(latest["收盘价"]) - float(first["收盘价"])) / float(first["收盘价"]) * 100 if float(first["收盘价"]) > 0 else 0
result["crude_oil"] = {
"price": round(float(latest["收盘价"]), 2),
"ytd_change_pct": round(ytd_pct, 2),
"name": "原油主力"
}
except Exception as e:
logger.warning(f"原油数据获取失败: {e}")
# 铜
try:
df = self._safe_request(ak.futures_main_sina, symbol="CU0", start_date=(datetime.now() - timedelta(days=365)).strftime("%Y%m%d"), end_date=datetime.now().strftime("%Y%m%d"))
if df is not None and not df.empty:
latest = df.tail(1).iloc[0]
first = df.head(1).iloc[0]
ytd_pct = (float(latest["收盘价"]) - float(first["收盘价"])) / float(first["收盘价"]) * 100 if float(first["收盘价"]) > 0 else 0
result["copper"] = {
"price": round(float(latest["收盘价"]), 2),
"ytd_change_pct": round(ytd_pct, 2),
"name": "沪铜主力"
}
except Exception as e:
logger.warning(f"铜数据获取失败: {e}")
return result if result else None
def _get_real_estate_data(self) -> dict:
"""获取房地产相关数据"""
result = {}
try:
df = self._safe_request(ak.macro_china_real_estate)
if df is not None and not df.empty:
recent = df.tail(12)
result["data"] = []
for _, row in recent.iterrows():
item = {}
for col in df.columns:
item[col] = str(row[col])
result["data"].append(item)
except Exception as e:
logger.warning(f"房地产数据获取失败: {e}")
return result if result else None
def _get_macro_news(self) -> list:
"""获取宏观经济相关新闻"""
news_list = []
try:
df = self._safe_request(ak.stock_info_global_em)
if df is not None and not df.empty:
for _, row in df.head(50).iterrows():
news_list.append({
"title": str(row.get("标题", "")),
"publish_time": str(row.get("发布时间", "")),
"content": str(row.get("概要", ""))[:300]
})
except Exception as e:
logger.warning(f"新闻获取失败: {e}")
return news_list
def format_data_for_ai(self, data: dict) -> str:
"""将数据格式化为AI分析所需的文本"""
parts = []
parts.append(f"===== 宏观经济数据报告 =====")
parts.append(f"数据采集时间: {data.get('timestamp', '未知')}")
parts.append("")
# GDP
if data.get("gdp"):
parts.append("【一、GDP数据】")
gdp = data["gdp"]
if gdp.get("yearly"):
parts.append("近年GDP:")
for item in gdp["yearly"][-4:]:
parts.append(f" {item}")
if gdp.get("quarterly_growth"):
parts.append("季度GDP增速:")
for item in gdp["quarterly_growth"][-8:]:
parts.append(f" {item}")
parts.append("")
# CPI/PPI
if data.get("cpi_ppi"):
parts.append("【二、CPI/PPI通胀数据】")
cp = data["cpi_ppi"]
if cp.get("cpi_monthly"):
parts.append("近12个月CPI:")
for item in cp["cpi_monthly"]:
parts.append(f" {item}")
if cp.get("ppi_monthly"):
parts.append("近12个月PPI:")
for item in cp["ppi_monthly"]:
parts.append(f" {item}")
parts.append("")
# PMI
if data.get("pmi"):
parts.append("【三、PMI景气指数】")
pmi = data["pmi"]
if pmi.get("manufacturing_pmi"):
parts.append("制造业PMI50为荣枯线):")
for item in pmi["manufacturing_pmi"]:
parts.append(f" {item}")
if pmi.get("caixin_pmi"):
parts.append("财新PMI:")
for item in pmi["caixin_pmi"]:
parts.append(f" {item}")
parts.append("")
# 货币供应
if data.get("money_supply"):
parts.append("【四、货币供应量】")
ms = data["money_supply"]
if ms.get("m2_data"):
parts.append("M0/M1/M2数据:")
for item in ms["m2_data"]:
parts.append(f" {item}")
parts.append("")
# 利率
if data.get("interest_rate"):
parts.append("【五、利率数据】")
ir = data["interest_rate"]
if ir.get("lpr"):
parts.append("LPR利率:")
for item in ir["lpr"]:
parts.append(f" {item}")
parts.append("")
# 市场指数
if data.get("market_indices"):
parts.append("【六、市场指数】")
mi = data["market_indices"]
for name, info in mi.items():
label = {"sh_index": "上证指数", "sz_index": "深证成指", "cyb_index": "创业板指"}.get(name, name)
parts.append(f" {label}: {info['close']} (日涨跌: {info['change_pct']:+.2f}%, 60日涨跌: {info.get('pct_60d', 0):+.2f}%)")
if info.get("high_52w"):
parts.append(f" 52周最高: {info['high_52w']} 52周最低: {info['low_52w']}")
parts.append("")
# 大宗商品
if data.get("commodities"):
parts.append("【七、大宗商品】")
for name, info in data["commodities"].items():
parts.append(f" {info['name']}: {info['price']} (年涨跌: {info['ytd_change_pct']:+.2f}%)")
parts.append("")
# 房地产
if data.get("real_estate"):
parts.append("【八、房地产数据】")
re_data = data["real_estate"]
if re_data.get("data"):
for item in re_data["data"][-4:]:
parts.append(f" {item}")
parts.append("")
# 新闻
if data.get("news"):
parts.append("【九、近期宏观经济新闻】")
for idx, news in enumerate(data["news"][:20], 1):
parts.append(f" {idx}. [{news.get('publish_time', '')}] {news.get('title', '')}")
if news.get('content'):
parts.append(f" {news['content'][:150]}")
parts.append("")
return "\n".join(parts)
# 测试
if __name__ == "__main__":
print("=" * 60)
print("测试宏观周期数据采集")
print("=" * 60)
fetcher = MacroCycleDataFetcher()
data = fetcher.get_all_macro_data()
if data.get("success"):
formatted = fetcher.format_data_for_ai(data)
print(formatted[:5000])
print(f"\n... (总长度: {len(formatted)} 字符)")
else:
print(f"数据采集失败: {data.get('errors')}")
+149
View File
@@ -0,0 +1,149 @@
"""
宏观周期分析 - 综合研判引擎
协调数据采集与AI分析,生成完整的宏观周期分析报告
"""
from macro_cycle_agents import MacroCycleAgents
from macro_cycle_data import MacroCycleDataFetcher
from typing import Dict, Any
import time
import json
import logging
import config
class MacroCycleEngine:
"""宏观周期综合研判引擎"""
def __init__(self, model=None):
self.model = model or config.DEFAULT_MODEL_NAME
self.agents = MacroCycleAgents(model=self.model)
self.data_fetcher = MacroCycleDataFetcher()
self.logger = logging.getLogger(__name__)
if not self.logger.handlers:
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s %(name)s: %(message)s')
print(f"[宏观周期引擎] 初始化完成 (模型: {self.model})")
def run_full_analysis(self, progress_callback=None) -> Dict[str, Any]:
"""
运行完整的宏观周期分析流程
Args:
progress_callback: 进度回调函数 (progress_pct, status_text)
Returns:
完整的分析结果
"""
print("\n" + "=" * 60)
print("🧭 宏观周期分析系统启动")
print("=" * 60)
results = {
"success": False,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"raw_data": {},
"formatted_data": "",
"agents_analysis": {},
"data_errors": []
}
try:
# 阶段1:数据采集
if progress_callback:
progress_callback(5, "📊 正在采集宏观经济数据...")
print("\n[阶段1] 宏观经济数据采集...")
print("-" * 60)
raw_data = self.data_fetcher.get_all_macro_data()
results["raw_data"] = raw_data
results["data_errors"] = raw_data.get("errors", [])
if not raw_data.get("success"):
print("⚠ 数据采集未完全成功,尝试继续分析...")
# 格式化数据
formatted_text = self.data_fetcher.format_data_for_ai(raw_data)
results["formatted_data"] = formatted_text
if progress_callback:
progress_callback(15, "✓ 数据采集完成")
print("✓ 数据采集和格式化完成")
print(f" 数据文本长度: {len(formatted_text)} 字符")
# 阶段2AI智能体分析
print("\n[阶段2] AI智能体分析集群工作中...")
print("-" * 60)
agents_results = {}
# 2.1 康波周期分析师
if progress_callback:
progress_callback(20, "🌊 康波周期分析师正在分析...")
print("1/4 康波周期分析师...")
kondratieff_result = self.agents.kondratieff_wave_agent(formatted_text)
agents_results["kondratieff"] = kondratieff_result
if progress_callback:
progress_callback(35, "✓ 康波分析完成")
# 2.2 美林时钟分析师
if progress_callback:
progress_callback(40, "⏰ 美林时钟分析师正在分析...")
print("2/4 美林时钟分析师...")
merrill_result = self.agents.merrill_lynch_clock_agent(formatted_text)
agents_results["merrill"] = merrill_result
if progress_callback:
progress_callback(55, "✓ 美林时钟分析完成")
# 2.3 中国政策分析师
if progress_callback:
progress_callback(60, "🏛️ 中国政策分析师正在分析...")
print("3/4 中国政策分析师...")
policy_result = self.agents.china_policy_agent(formatted_text)
agents_results["policy"] = policy_result
if progress_callback:
progress_callback(75, "✓ 政策分析完成")
# 2.4 首席宏观策略师(综合三位分析师的报告)
if progress_callback:
progress_callback(80, "👔 首席宏观策略师正在综合研判...")
print("4/4 首席宏观策略师综合研判...")
chief_result = self.agents.chief_macro_strategist_agent(
kondratieff_report=kondratieff_result.get("analysis", ""),
merrill_report=merrill_result.get("analysis", ""),
policy_report=policy_result.get("analysis", ""),
macro_data_text=formatted_text
)
agents_results["chief"] = chief_result
if progress_callback:
progress_callback(95, "✓ 综合研判完成")
results["agents_analysis"] = agents_results
results["success"] = True
print("\n" + "=" * 60)
print("✓ 宏观周期分析完成!")
print("=" * 60)
if progress_callback:
progress_callback(100, "✅ 分析完成!")
except Exception as e:
print(f"\n✗ 分析过程出错: {e}")
import traceback
traceback.print_exc()
results["error"] = str(e)
return results
# 测试
if __name__ == "__main__":
print("=" * 60)
print("测试宏观周期分析引擎")
print("=" * 60)
engine = MacroCycleEngine()
print("引擎初始化完成")
+427
View File
@@ -0,0 +1,427 @@
"""
宏观周期分析 - PDF报告生成模块
生成康波周期 × 美林投资时钟 × 中国政策分析的完整PDF报告
"""
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from datetime import datetime
import os
import tempfile
import re
class MacroCyclePDFGenerator:
"""宏观周期分析PDF报告生成器"""
def __init__(self):
"""初始化PDF生成器"""
self.setup_fonts()
def setup_fonts(self):
"""设置中文字体"""
try:
font_paths = [
'C:/Windows/Fonts/msyh.ttc', # 微软雅黑
'C:/Windows/Fonts/simsun.ttc', # 宋体
'C:/Windows/Fonts/simhei.ttf', # 黑体
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', # Linux
'/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf',
]
for font_path in font_paths:
if os.path.exists(font_path):
try:
pdfmetrics.registerFont(TTFont('ChineseFont', font_path))
self.chinese_font = 'ChineseFont'
print(f"[宏观PDF] 成功加载字体: {font_path}")
return
except:
continue
self.chinese_font = 'Helvetica'
print("[宏观PDF] 警告: 未找到中文字体,使用默认字体")
except Exception as e:
print(f"[宏观PDF] 字体设置失败: {e}")
self.chinese_font = 'Helvetica'
def generate_pdf(self, result_data: dict, output_path: str = None) -> str:
"""
生成宏观周期分析PDF报告
Args:
result_data: 分析结果数据
output_path: 输出路径,如果为None则生成临时文件
Returns:
PDF文件路径
"""
try:
if output_path is None:
temp_dir = tempfile.gettempdir()
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_path = os.path.join(temp_dir, f"宏观周期报告_{timestamp}.pdf")
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
rightMargin=0.5*inch,
leftMargin=0.5*inch,
topMargin=0.5*inch,
bottomMargin=0.5*inch
)
story = []
# 1. 标题页
story.extend(self._create_title_page(result_data))
story.append(PageBreak())
# 2. 首席宏观策略师综合研判(最重要,放最前面)
story.extend(self._create_chief_section(result_data))
story.append(PageBreak())
# 3. 康波周期分析
story.extend(self._create_kondratieff_section(result_data))
story.append(PageBreak())
# 4. 美林投资时钟分析
story.extend(self._create_merrill_section(result_data))
story.append(PageBreak())
# 5. 中国政策分析
story.extend(self._create_policy_section(result_data))
# 6. 结束语
story.extend(self._create_ending())
# 生成PDF
doc.build(story)
print(f"[宏观PDF] 报告生成成功: {output_path}")
return output_path
except Exception as e:
print(f"[宏观PDF] 生成失败: {e}")
import traceback
traceback.print_exc()
raise
def _clean_markdown(self, text: str) -> str:
"""清理Markdown标记,转换为适合PDF的纯文本/HTML"""
if not text:
return ""
# 移除markdown粗体 **text** → text
text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', text)
# 移除markdown斜体 *text* → text
text = re.sub(r'\*(.*?)\*', r'<i>\1</i>', text)
# 移除markdown标题 ## → 空
text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
# 移除markdown链接 [text](url) → text
text = re.sub(r'\[(.*?)\]\(.*?\)', r'\1', text)
# 移除markdown表格分隔线
text = re.sub(r'\|[-:]+\|[-:| ]+\|', '', text)
# 替换换行
text = text.replace('\n', '<br/>')
return text
def _split_text_to_paragraphs(self, text: str, styles: dict, max_chars: int = 0) -> list:
"""将长文本分段为多个Paragraph,避免单段过长溢出"""
elements = []
if not text:
return elements
if max_chars > 0 and len(text) > max_chars:
text = text[:max_chars] + "...(更多内容请查看网页版完整报告)"
# 按段落分割
paragraphs = text.split('\n\n')
for para in paragraphs:
para = para.strip()
if not para:
continue
# 清理markdown
cleaned = self._clean_markdown(para)
if cleaned:
try:
elements.append(Paragraph(cleaned, styles['Small']))
elements.append(Spacer(1, 0.08*inch))
except Exception:
# 如果格式化失败,用纯文本
plain = re.sub(r'<[^>]+>', '', cleaned)
elements.append(Paragraph(plain, styles['Small']))
elements.append(Spacer(1, 0.08*inch))
return elements
def _create_title_page(self, data: dict) -> list:
"""创建标题页"""
styles = self._get_styles()
elements = []
elements.append(Spacer(1, 1.5*inch))
# 主标题
elements.append(Paragraph("宏观周期分析报告", styles['Title']))
elements.append(Spacer(1, 0.3*inch))
# 副标题
elements.append(Paragraph(
"康波周期 × 美林投资时钟 × 中国政策分析",
styles['Heading2']
))
elements.append(Spacer(1, 0.8*inch))
# 报告信息
timestamp = data.get('timestamp', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
info_text = f"""
<para align=center>
<b>生成时间:</b> {timestamp}<br/>
<b>分析框架:</b> 三维周期定位系统<br/>
<b>AI分析师:</b> 4位专业分析师协同研判<br/>
<b>分析维度:</b> 康波长周期 · 美林中短周期 · 中国政策环境<br/>
<b>数据来源:</b> AKShare宏观经济数据
</para>
"""
elements.append(Paragraph(info_text, styles['Normal']))
elements.append(Spacer(1, 0.5*inch))
# 分析师团队
team_text = """
<para align=center>
<b>AI分析师团队:</b><br/>
康波周期分析师 · 美林时钟分析师 · 中国政策分析师 · 首席宏观策略师
</para>
"""
elements.append(Paragraph(team_text, styles['Normal']))
elements.append(Spacer(1, 0.8*inch))
# 免责声明
elements.append(Paragraph(
"<para align=center><i>本报告由AI系统自动生成,仅供学习研究参考,不构成投资建议。<br/>"
"周期理论是认知框架而非精确预测工具。投资有风险,入市需谨慎。</i></para>",
styles['Small']
))
return elements
def _create_chief_section(self, data: dict) -> list:
"""创建首席宏观策略师综合研判部分"""
styles = self._get_styles()
elements = []
elements.append(Paragraph("一、首席宏观策略师 — 综合研判", styles['Heading1']))
elements.append(Spacer(1, 0.15*inch))
elements.append(Paragraph(
"<i>整合康波周期、美林投资时钟、中国政策三个维度,构建周期仪表盘,给出最终综合投资策略。</i>",
styles['Small']
))
elements.append(Spacer(1, 0.15*inch))
chief = data.get('agents_analysis', {}).get('chief', {})
analysis = chief.get('analysis', '暂无分析结果')
elements.extend(self._split_text_to_paragraphs(analysis, styles, max_chars=5000))
return elements
def _create_kondratieff_section(self, data: dict) -> list:
"""创建康波周期分析部分"""
styles = self._get_styles()
elements = []
elements.append(Paragraph("二、康波周期分析 — 60年长周期定位", styles['Heading1']))
elements.append(Spacer(1, 0.15*inch))
elements.append(Paragraph(
"<i>基于康德拉季耶夫长波理论(周金涛\"人生发财靠康波\"),判断当前处于第五轮信息技术康波的阶段位置。</i>",
styles['Small']
))
elements.append(Spacer(1, 0.15*inch))
kondratieff = data.get('agents_analysis', {}).get('kondratieff', {})
analysis = kondratieff.get('analysis', '暂无分析结果')
elements.extend(self._split_text_to_paragraphs(analysis, styles, max_chars=5000))
return elements
def _create_merrill_section(self, data: dict) -> list:
"""创建美林投资时钟分析部分"""
styles = self._get_styles()
elements = []
elements.append(Paragraph("三、美林投资时钟 — 中短周期定位", styles['Heading1']))
elements.append(Spacer(1, 0.15*inch))
elements.append(Paragraph(
"<i>基于经济增长与通胀两大维度,结合中国政策方向(第三维度),判断当前处于美林时钟的哪个象限。</i>",
styles['Small']
))
elements.append(Spacer(1, 0.15*inch))
merrill = data.get('agents_analysis', {}).get('merrill', {})
analysis = merrill.get('analysis', '暂无分析结果')
elements.extend(self._split_text_to_paragraphs(analysis, styles, max_chars=5000))
return elements
def _create_policy_section(self, data: dict) -> list:
"""创建中国政策分析部分"""
styles = self._get_styles()
elements = []
elements.append(Paragraph("四、中国政策环境分析", styles['Heading1']))
elements.append(Spacer(1, 0.15*inch))
elements.append(Paragraph(
"<i>深度分析货币政策、财政政策、产业政策、房地产政策,评估政策对周期的影响和投资机会。</i>",
styles['Small']
))
elements.append(Spacer(1, 0.15*inch))
policy = data.get('agents_analysis', {}).get('policy', {})
analysis = policy.get('analysis', '暂无分析结果')
elements.extend(self._split_text_to_paragraphs(analysis, styles, max_chars=5000))
return elements
def _create_ending(self) -> list:
"""创建结束语"""
styles = self._get_styles()
elements = []
elements.append(Spacer(1, 0.5*inch))
elements.append(Paragraph(
"<para align=center><i>--- 报告结束 ---<br/>"
"本报告由宏观周期AI分析系统自动生成<br/>"
"康波是罗盘,美林是航海图,政策是季风<br/>"
"愿你在经济的海洋中,驶向属于自己的财富彼岸</i></para>",
styles['Normal']
))
return elements
def _get_styles(self) -> dict:
"""获取样式"""
styles = getSampleStyleSheet()
custom_styles = {
'Title': ParagraphStyle(
'MacroTitle',
parent=styles['Title'],
fontName=self.chinese_font,
fontSize=26,
textColor=colors.HexColor('#302b63'),
spaceAfter=30,
alignment=TA_CENTER
),
'Heading1': ParagraphStyle(
'MacroHeading1',
parent=styles['Heading1'],
fontName=self.chinese_font,
fontSize=16,
textColor=colors.HexColor('#0f0c29'),
spaceAfter=12,
spaceBefore=12
),
'Heading2': ParagraphStyle(
'MacroHeading2',
parent=styles['Heading2'],
fontName=self.chinese_font,
fontSize=14,
textColor=colors.HexColor('#302b63'),
spaceAfter=10,
spaceBefore=10,
alignment=TA_CENTER
),
'Normal': ParagraphStyle(
'MacroNormal',
parent=styles['Normal'],
fontName=self.chinese_font,
fontSize=11,
leading=16,
alignment=TA_JUSTIFY
),
'Small': ParagraphStyle(
'MacroSmall',
parent=styles['Normal'],
fontName=self.chinese_font,
fontSize=9,
leading=14,
alignment=TA_LEFT
)
}
return custom_styles
def generate_macro_cycle_markdown(result_data: dict) -> str:
"""生成宏观周期分析的Markdown报告"""
parts = []
timestamp = result_data.get('timestamp', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
parts.append("# 🧭 宏观周期分析报告\n")
parts.append(f"**生成时间**: {timestamp}\n")
parts.append("**分析框架**: 康波周期 × 美林投资时钟 × 中国政策分析\n")
parts.append("---\n")
agents = result_data.get('agents_analysis', {})
# 首席策略师
chief = agents.get('chief', {})
if chief:
parts.append("## 👔 一、首席宏观策略师 — 综合研判\n")
parts.append(chief.get('analysis', '暂无分析结果'))
parts.append("\n\n---\n")
# 康波周期
kondratieff = agents.get('kondratieff', {})
if kondratieff:
parts.append("## 🌊 二、康波周期分析 — 60年长周期定位\n")
parts.append(kondratieff.get('analysis', '暂无分析结果'))
parts.append("\n\n---\n")
# 美林时钟
merrill = agents.get('merrill', {})
if merrill:
parts.append("## ⏰ 三、美林投资时钟 — 中短周期定位\n")
parts.append(merrill.get('analysis', '暂无分析结果'))
parts.append("\n\n---\n")
# 政策分析
policy = agents.get('policy', {})
if policy:
parts.append("## 🏛️ 四、中国政策环境分析\n")
parts.append(policy.get('analysis', '暂无分析结果'))
parts.append("\n\n---\n")
# 免责声明
parts.append("\n> ⚠️ **免责声明**: 本报告由AI系统自动生成,仅供学习研究参考,不构成投资建议。")
parts.append("周期理论是认知框架而非精确预测工具。投资有风险,入市需谨慎。\n")
return "\n".join(parts)
# 测试
if __name__ == "__main__":
print("=" * 60)
print("测试宏观周期PDF生成器")
print("=" * 60)
test_data = {
"success": True,
"timestamp": "2026-02-27 14:00:00",
"agents_analysis": {
"chief": {"analysis": "综合研判测试内容..."},
"kondratieff": {"analysis": "康波分析测试内容..."},
"merrill": {"analysis": "美林时钟测试内容..."},
"policy": {"analysis": "政策分析测试内容..."},
}
}
generator = MacroCyclePDFGenerator()
output_path = generator.generate_pdf(test_data)
print(f"测试PDF生成: {output_path}")
+370
View File
@@ -0,0 +1,370 @@
"""
宏观周期分析 - UI界面模块
展示康波周期 + 美林投资时钟 + 中国政策分析的综合结果
"""
import streamlit as st
import time
from datetime import datetime
from macro_cycle_engine import MacroCycleEngine
from macro_cycle_pdf import MacroCyclePDFGenerator, generate_macro_cycle_markdown
def display_macro_cycle():
"""显示宏观周期分析主界面"""
st.markdown("""
<div style="background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);
padding: 2rem; border-radius: 15px; margin-bottom: 1.5rem;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);">
<h1 style="color: #fff; margin: 0; font-size: 2rem;">
🧭 宏观周期分析
</h1>
<p style="color: rgba(255,255,255,0.8); margin: 0.5rem 0 0 0; font-size: 1.1rem;">
康波周期 × 美林投资时钟 × 中国政策分析 — AI驱动的宏观经济周期研判
</p>
</div>
""", unsafe_allow_html=True)
# 标签页
tab1, tab2 = st.tabs(["📊 周期分析", "📚 理论介绍"])
with tab1:
display_analysis_tab()
with tab2:
display_theory_tab()
def display_analysis_tab():
"""显示分析标签页"""
# 简介
st.markdown("""
> **分析说明**:本模块基于视频[康波周期理论](https://www.bilibili.com/video/BV1QNcEzREzY)50-60年长周期)和视频[美林投资时钟](https://www.bilibili.com/video/BV1Zuf5BUEhH)3-5年中短周期),
> 结合中国政策环境(第三维度),由4位AI分析师协同研判当前宏观经济所处的周期位置,并给出资产配置建议。
""")
st.markdown("""
**🤖 AI分析师团队:**
- 🌊 **康波周期分析师** — 60年长周期战略定位(回升→繁荣→衰退→萧条)
- ⏰ **美林时钟分析师** — 3-5年中短周期战术定位(复苏→过热→滞胀→衰退)
- 🏛️ **中国政策分析师** — 政策第三维度(货币/财政/产业/房地产)
- 👔 **首席宏观策略师** — 三维综合研判,最终资产配置建议
""")
st.markdown("---")
# 操作按钮
col1, col2 = st.columns([2, 2])
with col1:
analyze_button = st.button("🚀 开始宏观周期分析", type="primary", key="macro_analyze")
with col2:
if st.button("🔄 清除结果", key="macro_clear"):
if 'macro_cycle_result' in st.session_state:
del st.session_state.macro_cycle_result
st.success("已清除分析结果")
st.rerun()
st.markdown("---")
# 开始分析
if analyze_button:
if 'macro_cycle_result' in st.session_state:
del st.session_state.macro_cycle_result
run_macro_cycle_analysis()
# 显示结果
if 'macro_cycle_result' in st.session_state:
result = st.session_state.macro_cycle_result
if result.get("success"):
display_analysis_results(result)
else:
st.error(f"❌ 分析失败: {result.get('error', '未知错误')}")
def run_macro_cycle_analysis():
"""运行宏观周期分析"""
import config
model = config.DEFAULT_MODEL_NAME
progress_bar = st.progress(0)
status_text = st.empty()
def progress_callback(pct, text):
progress_bar.progress(pct)
status_text.text(text)
try:
engine = MacroCycleEngine(model=model)
result = engine.run_full_analysis(progress_callback=progress_callback)
if result.get("success"):
st.session_state.macro_cycle_result = result
time.sleep(1)
status_text.empty()
progress_bar.empty()
st.rerun()
else:
st.error(f"❌ 分析失败: {result.get('error', '未知错误')}")
except Exception as e:
st.error(f"❌ 分析过程出错: {str(e)}")
import traceback
st.code(traceback.format_exc())
finally:
progress_bar.empty()
status_text.empty()
def display_analysis_results(result):
"""显示分析结果"""
agents = result.get("agents_analysis", {})
timestamp = result.get("timestamp", "")
st.success(f"✅ 分析完成于 {timestamp}")
# 数据采集状态
data_errors = result.get("data_errors", [])
if data_errors:
with st.expander("⚠️ 部分数据采集失败(不影响分析)"):
for err in data_errors:
st.warning(f"{err}")
# 四个分析师报告
report_tabs = st.tabs([
"👔 综合策略",
"🌊 康波周期",
"⏰ 美林时钟",
"🏛️ 政策分析"
])
# Tab 1: 首席宏观策略师(综合)
with report_tabs[0]:
chief = agents.get("chief", {})
if chief:
st.markdown("""
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 1.2rem; border-radius: 12px; margin-bottom: 1rem;
color: white;">
<h3 style="margin: 0; color: white;">👔 首席宏观策略师 — 综合研判</h3>
<p style="margin: 0.3rem 0 0 0; opacity: 0.9; font-size: 0.95rem;">
整合康波周期 + 美林投资时钟 + 中国政策三维分析,给出最终投资策略
</p>
</div>
""", unsafe_allow_html=True)
st.markdown(chief.get("analysis", "暂无分析结果"))
else:
st.info("暂无综合策略分析结果")
# Tab 2: 康波周期分析师
with report_tabs[1]:
kondratieff = agents.get("kondratieff", {})
if kondratieff:
st.markdown("""
<div style="background: linear-gradient(135deg, #0575E6 0%, #021B79 100%);
padding: 1.2rem; border-radius: 12px; margin-bottom: 1rem;
color: white;">
<h3 style="margin: 0; color: white;">🌊 康波周期分析师 — 60年长周期定位</h3>
<p style="margin: 0.3rem 0 0 0; opacity: 0.9; font-size: 0.95rem;">
基于康德拉季耶夫长波理论,判断当前处于第五轮信息技术康波的哪个阶段
</p>
</div>
""", unsafe_allow_html=True)
st.markdown(kondratieff.get("analysis", "暂无分析结果"))
else:
st.info("暂无康波周期分析结果")
# Tab 3: 美林时钟分析师
with report_tabs[2]:
merrill = agents.get("merrill", {})
if merrill:
st.markdown("""
<div style="background: linear-gradient(135deg, #f5af19 0%, #f12711 100%);
padding: 1.2rem; border-radius: 12px; margin-bottom: 1rem;
color: white;">
<h3 style="margin: 0; color: white;">⏰ 美林投资时钟分析师 — 中短周期定位</h3>
<p style="margin: 0.3rem 0 0 0; opacity: 0.9; font-size: 0.95rem;">
基于经济增长+通胀+政策三维度,判断当前处于美林时钟的哪个象限
</p>
</div>
""", unsafe_allow_html=True)
st.markdown(merrill.get("analysis", "暂无分析结果"))
else:
st.info("暂无美林时钟分析结果")
# Tab 4: 中国政策分析师
with report_tabs[3]:
policy = agents.get("policy", {})
if policy:
st.markdown("""
<div style="background: linear-gradient(135deg, #e53935 0%, #b71c1c 100%);
padding: 1.2rem; border-radius: 12px; margin-bottom: 1rem;
color: white;">
<h3 style="margin: 0; color: white;">🏛️ 中国政策分析师 — 政策第三维度</h3>
<p style="margin: 0.3rem 0 0 0; opacity: 0.9; font-size: 0.95rem;">
深度分析货币政策、财政政策、产业政策、房地产政策对周期和投资的影响
</p>
</div>
""", unsafe_allow_html=True)
st.markdown(policy.get("analysis", "暂无分析结果"))
else:
st.info("暂无政策分析结果")
# 导出报告
st.markdown("---")
display_pdf_export_section(result)
def display_pdf_export_section(result):
"""显示PDF/Markdown导出部分"""
st.subheader("📄 导出报告")
col1, col2, col3, col4 = st.columns([2, 1, 1, 1])
with col1:
st.write("将宏观周期分析报告导出为PDF或Markdown文件,方便保存和分享")
with col2:
if st.button("📥 生成PDF报告", type="primary", width='content', key="macro_pdf_gen"):
with st.spinner("正在生成PDF报告..."):
try:
generator = MacroCyclePDFGenerator()
pdf_path = generator.generate_pdf(result)
with open(pdf_path, "rb") as f:
pdf_bytes = f.read()
st.session_state.macro_pdf_data = pdf_bytes
ts = result.get('timestamp', datetime.now().strftime('%Y%m%d_%H%M%S')).replace(':', '').replace(' ', '_')
st.session_state.macro_pdf_filename = f"宏观周期报告_{ts}.pdf"
st.success("✅ PDF报告生成成功!")
st.rerun()
except Exception as e:
st.error(f"❌ PDF生成失败: {str(e)}")
with col3:
if st.button("📝 生成Markdown", type="secondary", width='content', key="macro_md_gen"):
with st.spinner("正在生成Markdown报告..."):
try:
markdown_content = generate_macro_cycle_markdown(result)
st.session_state.macro_md_data = markdown_content
ts = result.get('timestamp', datetime.now().strftime('%Y%m%d_%H%M%S')).replace(':', '').replace(' ', '_')
st.session_state.macro_md_filename = f"宏观周期报告_{ts}.md"
st.success("✅ Markdown报告生成成功!")
st.rerun()
except Exception as e:
st.error(f"❌ Markdown生成失败: {str(e)}")
with col4:
if 'macro_pdf_data' in st.session_state:
st.download_button(
label="💾 下载PDF",
data=st.session_state.macro_pdf_data,
file_name=st.session_state.macro_pdf_filename,
mime="application/pdf",
width='content',
key="macro_pdf_dl"
)
if 'macro_md_data' in st.session_state:
st.download_button(
label="💾 下载Markdown",
data=st.session_state.macro_md_data,
file_name=st.session_state.macro_md_filename,
mime="text/markdown",
width='content',
key="macro_md_dl"
)
def display_theory_tab():
"""显示理论介绍标签页"""
st.markdown("""
## 📖 两大周期理论简介
---
### 🌊 康德拉季耶夫长波(康波周期)
**创始人**:苏联经济学家尼古拉·康德拉季耶夫(1920s)
**中国推广者**:周金涛("周期天王",中信建投首席经济学家)
**核心思想**:资本主义经济存在约 **50-60年** 的超长周期,由重大技术革命驱动。
**四个阶段**
| 阶段 | 持续时间 | 特征 | 最优资产 |
|------|---------|------|---------|
| 🌱 **回升期** | ~15年 | 新技术商业化,经济从底部爬起 | 股票、新兴产业 |
| ☀️ **繁荣期** | ~15年 | 技术全面铺开,高速增长 | 几乎所有资产 |
| 🍂 **衰退期** | ~10年 | 泡沫破裂,增速放缓 | 大宗商品→现金 |
| ❄️ **萧条期** | ~10年 | 全面收缩,资产便宜 | 现金→布局未来 |
**历史五轮康波**
1. **1780s-1840s**:蒸汽机革命
2. **1840s-1890s**:铁路与钢铁
3. **1890s-1940s**:电力与化工
4. **1940s-1990s**:汽车与计算机
5. **1990s-2050s?**:信息技术革命(当前)
> *"人生发财靠康波。每个人的财富积累,一定不要以为是你多有本事,财富积累完全来源于经济周期运动的时间给你的机会。"* — 周金涛
---
### ⏰ 美林投资时钟
**创始人**:美林证券分析师(2004年)
**核心指标**:经济增长 × 通货膨胀
**四个象限**
| 象限 | 经济 | 通胀 | 最优资产 | 典型特征 |
|------|------|------|---------|---------|
| 🟢 **复苏期** | ↑ | ↓ | **股票** | 盈利改善,利率低 |
| 🔴 **过热期** | ↑ | ↑ | **大宗商品** | 需求旺盛,加息 |
| 🟡 **滞胀期** | ↓ | ↑ | **现金** | 成本上升,利润缩水 |
| 🔵 **衰退期** | ↓ | ↓ | **债券** | 降息,避险需求 |
**中国化改造**
- 增加 **政策方向** 作为第三维度
- 缩短时钟转动周期(中国约1-3年一轮,美国3-5年)
- 增加 **房地产** 作为第五类资产
- 重视 **政策友好型** 资产
---
### 🤝 两大理论的结合使用
| 维度 | 康波周期 | 美林时钟 |
|------|---------|---------|
| **时间尺度** | 50-60年 | 3-5年 |
| **驱动力** | 技术革命(供给侧) | 增长+通胀(需求侧) |
| **用途** | 人生战略决策 | 投资组合调整 |
| **比喻** | 🔭 望远镜 | 🔬 显微镜 |
| **角色** | 罗盘(大方向) | 航海图(风浪变化) |
**结合方法**
- 康波定 **战略方向**(进攻/防守)
- 美林定 **战术节奏**(具体配什么)
- 政策作为 **催化剂**(加速/扭曲周期)
> *"双指针一致时信心更强,矛盾时要谨慎。"*
---
### ⚠️ 免责声明
本分析仅供学习研究参考,不构成任何投资建议。周期理论是认知框架而非精确预测工具。
投资有风险,入市需谨慎。
""")
# 主入口
if __name__ == "__main__":
display_macro_cycle()