From 63628ffdd54c8a222e992915dba0d35579f194df Mon Sep 17 00:00:00 2001 From: oficcejo Date: Fri, 27 Feb 2026 15:15:49 +0800 Subject: [PATCH] update --- README.md | 21 ++ app.py | 33 ++- macro_cycle_agents.py | 458 ++++++++++++++++++++++++++++++++++ macro_cycle_data.py | 559 ++++++++++++++++++++++++++++++++++++++++++ macro_cycle_engine.py | 149 +++++++++++ macro_cycle_pdf.py | 427 ++++++++++++++++++++++++++++++++ macro_cycle_ui.py | 370 ++++++++++++++++++++++++++++ 7 files changed, 2014 insertions(+), 3 deletions(-) create mode 100644 macro_cycle_agents.py create mode 100644 macro_cycle_data.py create mode 100644 macro_cycle_engine.py create mode 100644 macro_cycle_pdf.py create mode 100644 macro_cycle_ui.py diff --git a/README.md b/README.md index 1b7f4f2..2087e08 100644 --- a/README.md +++ b/README.md @@ -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模型全局可配置化** diff --git a/app.py b/app.py index 5f8abe4..4740011 100644 --- a/app.py +++ b/app.py @@ -276,6 +276,9 @@ def main(): """, 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: diff --git a/macro_cycle_agents.py b/macro_cycle_agents.py new file mode 100644 index 0000000..8661bb6 --- /dev/null +++ b/macro_cycle_agents.py @@ -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("初始化完成") diff --git a/macro_cycle_data.py b/macro_cycle_data.py new file mode 100644 index 0000000..6276091 --- /dev/null +++ b/macro_cycle_data.py @@ -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("制造业PMI(50为荣枯线):") + 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')}") diff --git a/macro_cycle_engine.py b/macro_cycle_engine.py new file mode 100644 index 0000000..ac9e635 --- /dev/null +++ b/macro_cycle_engine.py @@ -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)} 字符") + + # 阶段2:AI智能体分析 + 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("引擎初始化完成") diff --git a/macro_cycle_pdf.py b/macro_cycle_pdf.py new file mode 100644 index 0000000..b33a742 --- /dev/null +++ b/macro_cycle_pdf.py @@ -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'\1', text) + # 移除markdown斜体 *text* → text + text = re.sub(r'\*(.*?)\*', r'\1', 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', '
') + 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""" + + 生成时间: {timestamp}
+ 分析框架: 三维周期定位系统
+ AI分析师: 4位专业分析师协同研判
+ 分析维度: 康波长周期 · 美林中短周期 · 中国政策环境
+ 数据来源: AKShare宏观经济数据 +
+ """ + elements.append(Paragraph(info_text, styles['Normal'])) + elements.append(Spacer(1, 0.5*inch)) + + # 分析师团队 + team_text = """ + + AI分析师团队:
+ 康波周期分析师 · 美林时钟分析师 · 中国政策分析师 · 首席宏观策略师 +
+ """ + elements.append(Paragraph(team_text, styles['Normal'])) + elements.append(Spacer(1, 0.8*inch)) + + # 免责声明 + elements.append(Paragraph( + "本报告由AI系统自动生成,仅供学习研究参考,不构成投资建议。
" + "周期理论是认知框架而非精确预测工具。投资有风险,入市需谨慎。
", + 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( + "整合康波周期、美林投资时钟、中国政策三个维度,构建周期仪表盘,给出最终综合投资策略。", + 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( + "基于康德拉季耶夫长波理论(周金涛\"人生发财靠康波\"),判断当前处于第五轮信息技术康波的阶段位置。", + 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( + "基于经济增长与通胀两大维度,结合中国政策方向(第三维度),判断当前处于美林时钟的哪个象限。", + 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( + "深度分析货币政策、财政政策、产业政策、房地产政策,评估政策对周期的影响和投资机会。", + 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( + "--- 报告结束 ---
" + "本报告由宏观周期AI分析系统自动生成
" + "康波是罗盘,美林是航海图,政策是季风
" + "愿你在经济的海洋中,驶向属于自己的财富彼岸
", + 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}") diff --git a/macro_cycle_ui.py b/macro_cycle_ui.py new file mode 100644 index 0000000..e31737d --- /dev/null +++ b/macro_cycle_ui.py @@ -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(""" +
+

+ 🧭 宏观周期分析 +

+

+ 康波周期 × 美林投资时钟 × 中国政策分析 — AI驱动的宏观经济周期研判 +

+
+ """, 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(""" +
+

👔 首席宏观策略师 — 综合研判

+

+ 整合康波周期 + 美林投资时钟 + 中国政策三维分析,给出最终投资策略 +

+
+ """, 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(""" +
+

🌊 康波周期分析师 — 60年长周期定位

+

+ 基于康德拉季耶夫长波理论,判断当前处于第五轮信息技术康波的哪个阶段 +

+
+ """, 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(""" +
+

⏰ 美林投资时钟分析师 — 中短周期定位

+

+ 基于经济增长+通胀+政策三维度,判断当前处于美林时钟的哪个象限 +

+
+ """, 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(""" +
+

🏛️ 中国政策分析师 — 政策第三维度

+

+ 深度分析货币政策、财政政策、产业政策、房地产政策对周期和投资的影响 +

+
+ """, 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()