首次提交
This commit is contained in:
@@ -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'
|
||||
@@ -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
@@ -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}")
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 核心模块测试完成")
|
||||
Reference in New Issue
Block a user