首次提交

This commit is contained in:
hc
2025-12-31 19:58:09 +08:00
commit 8b0eadc876
20 changed files with 5670 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
"""
MND-IA Core Module
==================
共享内核 - 系统数据中心和逻辑基石
"""
from .world_book import WorldBook, Narrative, MacroCycle, create_narrative_id
__all__ = [
'WorldBook',
'Narrative',
'MacroCycle',
'create_narrative_id'
]
__version__ = '1.0.0'
+155
View File
@@ -0,0 +1,155 @@
{
"_meta": {
"version": "4.0.0",
"description": "Agent专用资产映射表。包含资产代码、关键词触发器及宏观因子敏感度矩阵。",
"instruction": "当计算Trust Index时,使用sensitivity中的数值作为基础权重(x),结合Narrative强度(y)进行最终打分。"
},
"assets": {
"core_A500": {
"name": "中证A500",
"etfs": ["512050", "512020", "563360"],
"keywords": ["核心资产", "大盘", "指数增强", "国家队", "长线资金"],
"sensitivity": {
"liquidity_easing": 0.6,
"policy_support": 0.8,
"cpi_rebound": 0.5,
"risk_on": 0.9
}
},
"tech_hardware": {
"name": "半导体与硬科技",
"etfs": ["512480", "588000"],
"keywords": ["芯片", "光刻机", "集成电路", "卡脖子", "科创板"],
"sensitivity": {
"interest_rate_down": 0.9,
"policy_tech_self_reliance": 1.0,
"geopolitics_tension": 0.7,
"risk_on": 1.0
}
},
"tech_software": {
"name": "软件与数字经济",
"etfs": ["515230", "159869"],
"keywords": ["信创", "国产软件", "操作系统", "数据要素", "AI应用", "网络安全"],
"sensitivity": {
"policy_digital_economy": 1.0,
"govt_spending": 0.8,
"risk_on": 0.9,
"interest_rate_down": 0.7
}
},
"tech_infra": {
"name": "5G与新基建",
"etfs": ["515050", "515880"],
"keywords": ["5G", "6G", "光模块", "通信基站", "算力底座", "东数西算"],
"sensitivity": {
"policy_new_infra": 1.0,
"tech_cycle_up": 0.8,
"export_growth": 0.6
}
},
"finance_broker": {
"name": "券商/牛市旗手",
"etfs": ["512880", "512900"],
"keywords": ["成交量", "资本市场", "印花税", "T+0", "金融强国"],
"sensitivity": {
"market_volume_spike": 1.0,
"policy_capital_market": 1.0,
"liquidity_easing": 0.8
}
},
"finance_bank": {
"name": "银行/高股息",
"etfs": ["512800", "159887"],
"keywords": ["高股息", "中特估", "红利", "避险", "存款利率"],
"sensitivity": {
"interest_rate_down": -0.5,
"risk_off": 0.8,
"policy_soe_reform": 0.7
}
},
"new_energy_vehicle": {
"name": "新能源车与电池",
"etfs": ["515030", "159840"],
"keywords": ["电动车", "锂电池", "宁德时代", "汽车下乡", "碳中和"],
"sensitivity": {
"consumption_stimulus": 0.8,
"export_growth": 0.9,
"oil_price_up": 0.5
}
},
"consumption_staples": {
"name": "主要消费(白酒)",
"etfs": ["512690"],
"keywords": ["白酒", "内需", "CPI", "春节", "高端消费"],
"sensitivity": {
"cpi_rebound": 0.9,
"liquidity_easing": 0.6,
"foreign_inflow": 0.8
}
},
"healthcare": {
"name": "医药医疗",
"etfs": ["512010", "159898"],
"keywords": ["创新药", "医疗器械", "老龄化", "医保", "CXO"],
"sensitivity": {
"interest_rate_down": 0.8,
"policy_public_health": 0.7,
"demographic_trend": 0.5
}
},
"cross_border_tech": {
"name": "跨境科技(T+0)",
"etfs": ["513330", "513300", "513500"],
"keywords": ["港股", "美股", "纳斯达克", "中概股", "平台经济"],
"sensitivity": {
"fed_rate_cut": 0.9,
"currency_rmb_depreciation": 0.8,
"policy_platform_economy": 0.7
}
},
"agriculture": {
"name": "农业与粮食安全",
"etfs": ["159825"],
"keywords": ["粮食安全", "一号文件", "猪周期", "种业", "食品通胀"],
"sensitivity": {
"cpi_rebound": 0.8,
"policy_food_security": 1.0,
"geopolitics_tension": 0.6
}
},
"resources_gold": {
"name": "资源与黄金",
"etfs": ["518880", "512400"],
"keywords": ["黄金", "有色", "通胀", "避险", "美元下跌"],
"sensitivity": {
"dollar_index_down": 0.9,
"geopolitics_tension": 1.0,
"inflation_expectations": 0.8
}
},
"defense_low_altitude": {
"name": "军工与低空",
"etfs": ["512660"],
"keywords": ["低空经济", "国防", "军费", "无人机", "地缘"],
"sensitivity": {
"policy_low_altitude": 1.0,
"geopolitics_tension": 0.9,
"govt_spending": 0.7
}
}
},
"macro_factors_definition": {
"liquidity_easing": "央行降准降息,或市场资金利率下行",
"interest_rate_down": "无风险利率下行(利好成长股)",
"cpi_rebound": "通胀回升,消费复苏",
"risk_on": "市场情绪高涨,追逐高风险高收益",
"risk_off": "市场恐慌,资金流向避险资产",
"policy_tech_self_reliance": "政策强调自主可控、国产替代",
"geopolitics_tension": "外部冲突、制裁或地缘紧张",
"currency_rmb_depreciation": "人民币贬值(利好出口及跨境资产)",
"fed_rate_cut": "美联储降息(利好港股/美股/黄金)"
}
}
+219
View File
@@ -0,0 +1,219 @@
"""
配置管理模块
提供统一的配置加载和访问接口,支持大模型配置、系统配置等
"""
import json
import os
from pathlib import Path
from typing import Dict, Any, Optional
class Config:
"""配置管理类,单例模式"""
_instance = None
_config_data: Dict[str, Any] = {}
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not self._config_data:
self.load_config()
def load_config(self, config_path: Optional[str] = None):
"""
加载配置文件
Args:
config_path: 配置文件路径,默认为项目根目录下的 config.json
"""
if config_path is None:
# 获取项目根目录(core 目录的上级目录)
project_root = Path(__file__).parent.parent
config_path = project_root / "config.json"
if not os.path.exists(config_path):
raise FileNotFoundError(f"配置文件不存在: {config_path}")
with open(config_path, 'r', encoding='utf-8') as f:
self._config_data = json.load(f)
def get(self, key: str, default: Any = None) -> Any:
"""
获取配置项(支持点号分隔的多级key)
Args:
key: 配置项键,如 "llm.model_name""llm"
default: 默认值
Returns:
配置值
"""
keys = key.split('.')
value = self._config_data
for k in keys:
if isinstance(value, dict):
value = value.get(k)
if value is None:
return default
else:
return default
return value
@property
def llm_config(self) -> Dict[str, Any]:
"""获取大模型配置"""
return self.get('llm', {})
@property
def model_name(self) -> str:
"""获取模型名称"""
return self.get('llm.model_name', 'gpt-4')
@property
def api_base(self) -> str:
"""获取API地址"""
return self.get('llm.api_base', 'https://api.openai.com/v1')
@property
def api_key(self) -> str:
"""获取API Key"""
return self.get('llm.api_key', '')
@property
def temperature(self) -> float:
"""获取温度参数"""
return self.get('llm.temperature', 0.7)
@property
def max_tokens(self) -> int:
"""获取最大token数"""
return self.get('llm.max_tokens', 2000)
@property
def timeout(self) -> int:
"""获取超时时间"""
return self.get('llm.timeout', 60)
def update(self, key: str, value: Any):
"""
更新配置项
Args:
key: 配置项键,支持点号分隔的多级key
value: 新值
"""
keys = key.split('.')
config = self._config_data
for k in keys[:-1]:
if k not in config:
config[k] = {}
config = config[k]
config[keys[-1]] = value
def save_config(self, config_path: Optional[str] = None):
"""
保存配置到文件
Args:
config_path: 配置文件路径,默认为项目根目录下的 config.json
"""
if config_path is None:
project_root = Path(__file__).parent.parent
config_path = project_root / "config.json"
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(self._config_data, f, ensure_ascii=False, indent=2)
# 全局配置实例
config = Config()
def get_llm_client():
"""
获取配置好的LLM客户端(OpenAI SDK
Returns:
OpenAI客户端实例
"""
try:
from openai import OpenAI
client = OpenAI(
api_key=config.api_key,
base_url=config.api_base,
timeout=config.timeout
)
return client
except ImportError:
print("警告: openai 库未安装,无法创建LLM客户端")
return None
except Exception as e:
print(f"创建LLM客户端失败: {e}")
return None
def llm_call(messages: list, **kwargs) -> Optional[str]:
"""
统一的LLM调用接口
Args:
messages: 消息列表,格式为 [{"role": "user", "content": "..."}]
**kwargs: 其他参数(会覆盖配置文件中的默认值)
Returns:
LLM返回的文本内容,失败返回None
"""
client = get_llm_client()
if client is None:
return None
try:
# 合并配置和传入的参数
params = {
'model': config.model_name,
'temperature': config.temperature,
'max_tokens': config.max_tokens,
}
params.update(kwargs)
response = client.chat.completions.create(
messages=messages,
**params
)
return response.choices[0].message.content
except Exception as e:
print(f"LLM调用失败: {e}")
return None
if __name__ == "__main__":
# 测试配置加载
print("=== 配置管理模块测试 ===")
print(f"模型名称: {config.model_name}")
print(f"API地址: {config.api_base}")
print(f"API Key: {config.api_key[:10]}..." if config.api_key else "API Key: 未配置")
print(f"温度: {config.temperature}")
print(f"最大tokens: {config.max_tokens}")
print("\n完整LLM配置:")
print(json.dumps(config.llm_config, indent=2, ensure_ascii=False))
# 测试配置更新
print("\n测试配置更新...")
config.update('llm.temperature', 0.5)
print(f"更新后的温度: {config.temperature}")
print()
# 测试获取不存在的配置
print(f"\n获取不存在的配置: {config.get('nonexistent.key', 'default_value')}")
# 测试调用
respodse = llm_call([{"role": "user", "content": "你好,用100字介绍一下你自己。"}])
print(f"\nLLM调用结果:\n{respodse}")
+243
View File
@@ -0,0 +1,243 @@
{
"_comment": "宏观逻辑矩阵 - 定义宏观因子对各 ETF 板块的基础理论影响值",
"_version": "1.0.0",
"_last_updated": "2025-12-30",
"_scoring_rules": {
"range": "影响值范围: -10 (极度负面) 到 +10 (极度正面)",
"neutral": "0 表示无明显影响",
"interpretation": "数值越大表示正面影响越强,数值越小表示负面影响越强"
},
"macro_factors": {
"rate_cut": {
"description": "降准降息 - 货币宽松政策",
"impact": {
"tech_etf": 8,
"ai_etf": 8,
"semiconductor_etf": 7,
"new_energy_vehicle_etf": 7,
"solar_etf": 6,
"pharma_etf": 5,
"consumer_etf": 7,
"bank_etf": -5,
"insurance_etf": -4,
"broker_etf": 6,
"realestate_etf": 9,
"military_etf": 4,
"metal_etf": 5,
"coal_etf": 2
}
},
"rate_hike": {
"description": "加息收紧 - 货币紧缩政策",
"impact": {
"tech_etf": -7,
"ai_etf": -7,
"semiconductor_etf": -6,
"new_energy_vehicle_etf": -6,
"solar_etf": -5,
"pharma_etf": -3,
"consumer_etf": -6,
"bank_etf": 5,
"insurance_etf": 4,
"broker_etf": -4,
"realestate_etf": -9,
"military_etf": -2,
"metal_etf": -4,
"coal_etf": -1
}
},
"currency_depreciation": {
"description": "人民币贬值 - 有利出口型企业",
"impact": {
"tech_etf": 3,
"ai_etf": 1,
"semiconductor_etf": 2,
"new_energy_vehicle_etf": 5,
"solar_etf": 6,
"pharma_etf": 2,
"consumer_etf": -3,
"bank_etf": -2,
"insurance_etf": -1,
"broker_etf": -1,
"realestate_etf": -4,
"military_etf": 3,
"metal_etf": 4,
"coal_etf": 1
}
},
"currency_appreciation": {
"description": "人民币升值 - 有利进口型企业",
"impact": {
"tech_etf": -2,
"ai_etf": -1,
"semiconductor_etf": -1,
"new_energy_vehicle_etf": -4,
"solar_etf": -5,
"pharma_etf": -1,
"consumer_etf": 4,
"bank_etf": 3,
"insurance_etf": 2,
"broker_etf": 2,
"realestate_etf": 5,
"military_etf": -2,
"metal_etf": -3,
"coal_etf": -1
}
},
"fiscal_stimulus": {
"description": "财政刺激政策 - 基建、消费刺激",
"impact": {
"tech_etf": 6,
"ai_etf": 7,
"semiconductor_etf": 6,
"new_energy_vehicle_etf": 8,
"solar_etf": 7,
"pharma_etf": 4,
"consumer_etf": 9,
"bank_etf": 5,
"insurance_etf": 4,
"broker_etf": 7,
"realestate_etf": 8,
"military_etf": 6,
"metal_etf": 8,
"coal_etf": 6
}
},
"regulation_tightening": {
"description": "监管收紧 - 行业整顿",
"impact": {
"tech_etf": -6,
"ai_etf": -4,
"semiconductor_etf": -3,
"new_energy_vehicle_etf": -4,
"solar_etf": -3,
"pharma_etf": -7,
"consumer_etf": -5,
"bank_etf": -2,
"insurance_etf": -2,
"broker_etf": -5,
"realestate_etf": -8,
"military_etf": -1,
"metal_etf": -2,
"coal_etf": -3
}
},
"export_strong": {
"description": "出口数据强劲",
"impact": {
"tech_etf": 5,
"ai_etf": 3,
"semiconductor_etf": 4,
"new_energy_vehicle_etf": 7,
"solar_etf": 8,
"pharma_etf": 3,
"consumer_etf": 2,
"bank_etf": 3,
"insurance_etf": 2,
"broker_etf": 4,
"realestate_etf": 1,
"military_etf": 4,
"metal_etf": 6,
"coal_etf": 3
}
},
"pmi_expansion": {
"description": "PMI 扩张 (>50) - 制造业景气",
"impact": {
"tech_etf": 7,
"ai_etf": 6,
"semiconductor_etf": 7,
"new_energy_vehicle_etf": 8,
"solar_etf": 7,
"pharma_etf": 4,
"consumer_etf": 6,
"bank_etf": 5,
"insurance_etf": 4,
"broker_etf": 6,
"realestate_etf": 4,
"military_etf": 6,
"metal_etf": 8,
"coal_etf": 7
}
},
"oil_price_surge": {
"description": "原油价格大涨",
"impact": {
"tech_etf": -3,
"ai_etf": -2,
"semiconductor_etf": -2,
"new_energy_vehicle_etf": 5,
"solar_etf": 6,
"pharma_etf": -1,
"consumer_etf": -4,
"bank_etf": -1,
"insurance_etf": -1,
"broker_etf": 0,
"realestate_etf": -3,
"military_etf": -1,
"metal_etf": 3,
"coal_etf": 8
}
},
"us_tech_weakness": {
"description": "美国科技股大跌",
"impact": {
"tech_etf": -6,
"ai_etf": -7,
"semiconductor_etf": -8,
"new_energy_vehicle_etf": -4,
"solar_etf": -3,
"pharma_etf": -2,
"consumer_etf": -3,
"bank_etf": 2,
"insurance_etf": 1,
"broker_etf": -2,
"realestate_etf": 1,
"military_etf": 0,
"metal_etf": 0,
"coal_etf": 1
}
}
},
"etf_mapping": {
"tech_etf": ["515980", "159813"],
"ai_etf": ["515980", "159813"],
"semiconductor_etf": ["512480", "159995"],
"new_energy_vehicle_etf": ["515030", "159806"],
"solar_etf": ["515790", "159857"],
"pharma_etf": ["512010", "159938"],
"consumer_etf": ["159928", "510630"],
"bank_etf": ["510230"],
"insurance_etf": ["512880"],
"broker_etf": ["512000"],
"realestate_etf": ["512200", "159707"],
"military_etf": ["512660", "512810"],
"metal_etf": ["512400", "159881"],
"coal_etf": ["515220", "159678"]
},
"composite_scenarios": {
"bull_market_start": {
"description": "牛市启动期 - 货币宽松 + 政策利好",
"factors": ["rate_cut", "fiscal_stimulus"],
"multiplier": 1.2
},
"bear_market_bottom": {
"description": "熊市底部 - 政策转向前",
"factors": ["rate_hike", "regulation_tightening"],
"multiplier": 0.8
},
"economic_recovery": {
"description": "经济复苏期",
"factors": ["pmi_expansion", "export_strong", "fiscal_stimulus"],
"multiplier": 1.15
},
"risk_off": {
"description": "风险规避模式",
"factors": ["us_tech_weakness", "currency_depreciation"],
"multiplier": 0.9
}
}
}
+400
View File
@@ -0,0 +1,400 @@
"""
MND-IA Core: World Book (世界书)
====================================
这是系统的数据中心和逻辑基石,存储宏观状态、活跃叙事对象和历史经验。
所有 Agent 必须通过此模块访问和更新系统状态。
"""
import json
import os
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
from pathlib import Path
from copy import deepcopy
class Narrative:
"""单个叙事对象 (Narrative Object)"""
def __init__(
self,
id: str,
topic: str,
related_etfs: List[str],
lifecycle_stage: str = "incubation",
base_score: float = 50.0,
decay_factor: float = 0.95,
current_weight: float = None
):
self.id = id
self.topic = topic
self.related_etfs = related_etfs
self.lifecycle_stage = lifecycle_stage # incubation | fermentation | realization | decay
self.base_score = base_score
self.decay_factor = decay_factor
self.current_weight = current_weight if current_weight is not None else base_score
self.last_updated = datetime.now().strftime("%Y-%m-%d")
def decay(self) -> None:
"""应用时间衰减"""
self.current_weight *= self.decay_factor
self.last_updated = datetime.now().strftime("%Y-%m-%d")
def boost(self, new_score: float) -> None:
"""新闻强化叙事权重"""
# 使用加权平均,新信息占40%,历史占60%
self.current_weight = self.current_weight * 0.6 + new_score * 0.4
self.last_updated = datetime.now().strftime("%Y-%m-%d")
def update_stage(self, new_stage: str) -> None:
"""更新生命周期阶段"""
valid_stages = ["incubation", "fermentation", "realization", "decay"]
if new_stage in valid_stages:
self.lifecycle_stage = new_stage
self.last_updated = datetime.now().strftime("%Y-%m-%d")
def to_dict(self) -> Dict[str, Any]:
"""转换为字典格式"""
return {
"id": self.id,
"topic": self.topic,
"related_etfs": self.related_etfs,
"lifecycle_stage": self.lifecycle_stage,
"base_score": self.base_score,
"decay_factor": self.decay_factor,
"current_weight": round(self.current_weight, 2),
"last_updated": self.last_updated
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Narrative':
"""从字典创建对象"""
return cls(
id=data["id"],
topic=data["topic"],
related_etfs=data["related_etfs"],
lifecycle_stage=data.get("lifecycle_stage", "incubation"),
base_score=data.get("base_score", 50.0),
decay_factor=data.get("decay_factor", 0.95),
current_weight=data.get("current_weight")
)
class MacroCycle:
"""宏观周期状态"""
def __init__(
self,
status: str = "neutral", # upward | downward | neutral
liquidity: str = "neutral", # loose | neutral | tight
policy_wind: str = "wait_and_see" # stimulus | regulation | wait_and_see
):
self.status = status
self.liquidity = liquidity
self.policy_wind = policy_wind
def to_dict(self) -> Dict[str, str]:
return {
"status": self.status,
"liquidity": self.liquidity,
"policy_wind": self.policy_wind
}
@classmethod
def from_dict(cls, data: Dict[str, str]) -> 'MacroCycle':
return cls(
status=data.get("status", "neutral"),
liquidity=data.get("liquidity", "neutral"),
policy_wind=data.get("policy_wind", "wait_and_see")
)
class WorldBook:
"""
MCP World Book - 系统核心数据中心
======================================
动态更新的状态管理器,存储:
1. 宏观周期状态
2. 活跃叙事对象列表
3. 宏观因子影响矩阵快照
"""
def __init__(self, data_dir: str = "data"):
self.data_dir = Path(data_dir)
self.data_dir.mkdir(exist_ok=True)
self.world_book_path = self.data_dir / "world_book.json"
# 初始化数据结构
self.timestamp = datetime.now().isoformat()
self.macro_cycle = MacroCycle()
self.active_narratives: Dict[str, Narrative] = {}
self.static_matrix_snapshot: Dict[str, Dict[str, float]] = {}
# 新增: 宏观因子向量 (用于向量点积计算)
self.macro_factor_vector: Dict[str, float] = {}
# 尝试加载已有数据
self.load()
def load(self) -> bool:
"""从磁盘加载 World Book"""
if not self.world_book_path.exists():
print(f"[WorldBook] 未找到已有数据,初始化新的 World Book")
self._load_static_matrix()
return False
try:
with open(self.world_book_path, 'r', encoding='utf-8') as f:
data = json.load(f)
self.timestamp = data.get("timestamp", datetime.now().isoformat())
self.macro_cycle = MacroCycle.from_dict(data.get("macro_cycle", {}))
# 加载叙事对象
self.active_narratives = {}
for narrative_data in data.get("active_narratives", []):
narrative = Narrative.from_dict(narrative_data)
self.active_narratives[narrative.id] = narrative
# 加载矩阵快照
self.static_matrix_snapshot = data.get("static_matrix_snapshot", {})
# 加载宏观因子向量
self.macro_factor_vector = data.get("macro_factor_vector", {})
print(f"[WorldBook] 成功加载数据,包含 {len(self.active_narratives)} 个活跃叙事")
return True
except Exception as e:
print(f"[WorldBook] 加载数据失败: {e}")
self._load_static_matrix()
return False
def save(self) -> bool:
"""保存 World Book 到磁盘"""
try:
self.timestamp = datetime.now().isoformat()
data = {
"timestamp": self.timestamp,
"macro_cycle": self.macro_cycle.to_dict(),
"active_narratives": [
narrative.to_dict()
for narrative in self.active_narratives.values()
],
"static_matrix_snapshot": self.static_matrix_snapshot,
"macro_factor_vector": self.macro_factor_vector
}
with open(self.world_book_path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"[WorldBook] 成功保存数据到 {self.world_book_path}")
return True
except Exception as e:
print(f"[WorldBook] 保存数据失败: {e}")
return False
def _load_static_matrix(self) -> None:
"""加载静态宏观矩阵"""
matrix_path = Path("core") / "macro_matrix.json"
if matrix_path.exists():
try:
with open(matrix_path, 'r', encoding='utf-8') as f:
self.static_matrix_snapshot = json.load(f)
print(f"[WorldBook] 加载宏观矩阵成功")
except Exception as e:
print(f"[WorldBook] 加载宏观矩阵失败: {e}")
self.static_matrix_snapshot = {}
def add_narrative(self, narrative: Narrative) -> None:
"""添加新叙事"""
self.active_narratives[narrative.id] = narrative
print(f"[WorldBook] 添加新叙事: {narrative.topic} (ID: {narrative.id})")
def update_narrative(self, narrative_id: str, **kwargs) -> bool:
"""更新叙事属性"""
if narrative_id not in self.active_narratives:
print(f"[WorldBook] 叙事不存在: {narrative_id}")
return False
narrative = self.active_narratives[narrative_id]
if 'new_score' in kwargs:
narrative.boost(kwargs['new_score'])
if 'stage' in kwargs:
narrative.update_stage(kwargs['stage'])
return True
def decay_all_narratives(self) -> None:
"""对所有叙事应用时间衰减"""
for narrative in self.active_narratives.values():
narrative.decay()
print(f"[WorldBook] 对 {len(self.active_narratives)} 个叙事应用了时间衰减")
def remove_weak_narratives(self, threshold: float = 10.0) -> List[str]:
"""移除权重过低的叙事"""
to_remove = [
nid for nid, narrative in self.active_narratives.items()
if narrative.current_weight < threshold
]
for nid in to_remove:
topic = self.active_narratives[nid].topic
del self.active_narratives[nid]
print(f"[WorldBook] 移除衰退叙事: {topic} (ID: {nid})")
return to_remove
def get_narrative_by_topic(self, topic: str) -> Optional[Narrative]:
"""根据主题获取叙事"""
for narrative in self.active_narratives.values():
if narrative.topic == topic:
return narrative
return None
def get_narratives_by_etf(self, etf_code: str) -> List[Narrative]:
"""获取与特定 ETF 相关的所有叙事"""
return [
narrative for narrative in self.active_narratives.values()
if etf_code in narrative.related_etfs
]
def update_macro_cycle(self, **kwargs) -> None:
"""更新宏观周期状态"""
if 'status' in kwargs:
self.macro_cycle.status = kwargs['status']
if 'liquidity' in kwargs:
self.macro_cycle.liquidity = kwargs['liquidity']
if 'policy_wind' in kwargs:
self.macro_cycle.policy_wind = kwargs['policy_wind']
print(f"[WorldBook] 宏观周期更新: {self.macro_cycle.to_dict()}")
def update_macro_factor_vector(self, factor_updates: Dict[str, float]) -> None:
"""
更新宏观因子向量
Args:
factor_updates: 宏观因子及其强度,例如:
{
"interest_rate_down": 1.0, # 强烈降息预期
"geopolitics_tension": 0.5, # 中等地缘紧张
"policy_digital_economy": 1.0 # 数字经济政策头条
}
"""
self.macro_factor_vector.update(factor_updates)
print(f"[WorldBook] 宏观因子向量更新: {self.macro_factor_vector}")
def get_macro_factor_value(self, factor_name: str) -> float:
"""获取特定宏观因子的当前值"""
return self.macro_factor_vector.get(factor_name, 0.0)
def clear_macro_factor_vector(self) -> None:
"""清空宏观因子向量(通常在每日开盘前重置)"""
self.macro_factor_vector = {}
print("[WorldBook] 宏观因子向量已清空")
def get_top_narratives(self, top_n: int = 5) -> List[Narrative]:
"""获取权重最高的 N 个叙事"""
sorted_narratives = sorted(
self.active_narratives.values(),
key=lambda n: n.current_weight,
reverse=True
)
return sorted_narratives[:top_n]
def export_snapshot(self) -> Dict[str, Any]:
"""导出完整快照(供其他 Agent 读取)"""
return {
"timestamp": self.timestamp,
"macro_cycle": self.macro_cycle.to_dict(),
"macro_factor_vector": self.macro_factor_vector,
"active_narratives": [n.to_dict() for n in self.active_narratives.values()],
"static_matrix_snapshot": self.static_matrix_snapshot,
"summary": {
"total_narratives": len(self.active_narratives),
"top_3_topics": [n.topic for n in self.get_top_narratives(3)]
}
}
def __repr__(self) -> str:
return (
f"<WorldBook: {len(self.active_narratives)} narratives, "
f"macro={self.macro_cycle.status}, "
f"updated={self.timestamp}>"
)
# ==================== 工具函数 ====================
def create_narrative_id(topic: str, date: Optional[str] = None) -> str:
"""生成叙事 ID"""
if date is None:
date = datetime.now().strftime("%Y%m")
# 简化主题名称作为 ID 的一部分
topic_slug = topic.replace(" ", "_").replace("", "_").replace("", "_")
return f"narrative_{topic_slug}_{date}"
if __name__ == "__main__":
# 测试代码
print("=" * 50)
print("World Book 核心模块测试")
print("=" * 50)
# 创建 World Book 实例
wb = WorldBook(data_dir="data")
# 添加测试叙事
narrative1 = Narrative(
id=create_narrative_id("低空经济"),
topic="低空经济",
related_etfs=["512980", "159969"],
lifecycle_stage="fermentation",
base_score=85.0,
decay_factor=0.95
)
narrative2 = Narrative(
id=create_narrative_id("AI算力"),
topic="AI算力",
related_etfs=["515980", "159813"],
lifecycle_stage="realization",
base_score=92.0,
decay_factor=0.93
)
wb.add_narrative(narrative1)
wb.add_narrative(narrative2)
# 更新宏观周期
wb.update_macro_cycle(
status="upward",
liquidity="loose",
policy_wind="stimulus"
)
# 保存数据
wb.save()
# 测试导出快照
snapshot = wb.export_snapshot()
print("\n当前状态快照:")
print(json.dumps(snapshot, ensure_ascii=False, indent=2))
# 测试衰减
print("\n应用时间衰减...")
wb.decay_all_narratives()
# 测试获取 Top 叙事
top = wb.get_top_narratives(2)
print(f"\nTop 2 叙事:")
for n in top:
print(f" - {n.topic}: {n.current_weight:.2f}")
print("\n✅ World Book 核心模块测试完成")