Security 类型体系 — Equity / Fixed Income / Fund
RC 系统中所有可交易的证券统一存储在 securities 表中,通过 type 字段区分三大类,每类有独立的 1:1 子表承载专属属性。
| Equity(股票) | Fixed Income(债券) | Fund(基金) | |
|---|---|---|---|
| 你持有的 | 公司的一部分所有权 | 对发行方的债权 | 一篮子资产的份额 |
| 收益来源 | 股价上涨 + 股息 | 固定票息 + 到期还本 | 净值变动 + 分红 |
| 风险特征 | 高波动,无保本 | 信用风险 + 利率风险 | 取决于底层持仓 |
| 到期日 | 无 | 有明确到期日 | 开放式基金无 |
| 发行方 | 上市公司 | 政府 / 公司 | 基金公司 |
securities (主表)├── type = 'equity' → equities (1:1)├── type = 'fixed_income' → fixed_incomes (1:1)└── type = 'fund' → funds (1:1)主表 securities
Section titled “主表 securities”所有证券的通用标识和元信息:
| 字段 | 类型 | 说明 |
|---|---|---|
type | enum | equity | fund | fixed_income |
name | string | 证券名称 |
symbol | string | 交易代码(如 AAPL) |
normalized_symbol | string | 标准化后的 symbol(去特殊字符、大写) |
cusip | string(9) | CUSIP 标识 |
isin | string(12) | ISIN 标识 |
reference | string | 供应商侧唯一标识 |
source | enum | 数据来源(morningstar、brokerage、generic 等 47 种) |
exchange_id | int | FK → exchanges |
organization_id | int | 所属组织 |
三个 scope 方法:
Security::equities() → where type = 'equity'Security::fixedIncomes() → where type = 'fixed_income'Security::funds() → where type = 'fund'equities 表 — 股票专属属性
Section titled “equities 表 — 股票专属属性”| 字段 | 类型 | 说明 |
|---|---|---|
security_id | int | FK → securities.id |
sector_id | int | FK → sectors(11 个股票板块) |
category_id | int | FK → categories(风格类别) |
capitalization | enum | small | middle | large |
valuation | enum | value | blend | growth |
country | string(3) | 3 字母 ISO 国家代码 |
股票的核心分析维度:
- Sector → 来自 Morningstar GECS Sector 层,11 个板块(详见 Sector 分类)
- Category →
capitalization × valuation= 9 宫格 Style Box - Country → 用于判定 developed / emerging 市场
fixed_incomes 表 — 债券专属属性
Section titled “fixed_incomes 表 — 债券专属属性”| 字段 | 类型 | 说明 |
|---|---|---|
security_id | int | FK → securities.id |
sector_id | int | FK → sectors(6 个债券板块) |
category_id | int | FK → categories |
subtype | enum | bond | cd | mbs |
market | enum | developed | emerging |
quality | enum | aaa | aa | a | bbb | bb | b | below | unrated |
债券的分析维度:
- Subtype:bond(普通债券)、cd(大额存单)、mbs(抵押贷款支持证券)
- Quality:信用评级,直接影响风险分析和收益假设
- Market:发达国家 / 新兴市场
- Sector:不同于股票的板块体系(Government、Corporate、Securitized 等)
funds 表 — 基金专属属性
Section titled “funds 表 — 基金专属属性”| 字段 | 类型 | 说明 |
|---|---|---|
security_id | int | FK → securities.id |
subtype | enum | etf | open_end | closed_end | uit | money_market |
expense_ratio | float | 费率(%) |
基金不直接有 sector / category,而是通过 allocations 分配表”透视”底层持仓:
| 关联表 | 用途 |
|---|---|
allocations_by_asset_type | 大类资产分配(US/Non-US Equity、US/Non-US Bond、Cash…) |
allocations_by_sector | 行业板块分配(11 个股票板块各占 %) |
allocations_by_category | 风格类别分配 |
allocations_by_market | 发达 / 新兴市场分配 |
allocations_by_bond_quality | 债券信用评级分配 |
allocations_by_equity_style | 股票 9 宫格风格分配 |
fund_equity_portfolio | 股票持仓明细 |
fund_bond_portfolio | 债券持仓明细(duration、maturity) |
基金的设计核心是 “透视”(look-through):虽然基金本身是一个 Security,但通过 allocations 层层拆解到底层 equity/bond,从而穿透分析客户组合的真实风险暴露。
// 基金模型上的计算属性$fund->equity_percentage; // 底层股票占比$fund->bond_percentage; // 底层债券占比$fund->percentages_by_category_id; // 风格类别分布$fund->percentages_by_equity_style; // 9 宫格分布Fund Subtype 详解
Section titled “Fund Subtype 详解”Fund 的 subtype 区分的是法律结构和交易机制——同样是”一篮子资产”,不同 subtype 的申赎方式、定价频率、流动性完全不同。
enum FundSubtype: string{ case ETF = 'etf'; // 交易所交易基金 case OPEN_END = 'open_end'; // 开放式基金(共同基金) case CLOSED_END = 'closed_end'; // 封闭式基金 case UIT = 'uit'; // 单位投资信托 case MONEY_MARKET = 'money_market'; // 货币市场基金}| Subtype | 中文 | 交易方式 | 定价 | 份额可变? | 典型例子 |
|---|---|---|---|---|---|
| ETF | 交易所交易基金 | 交易所实时买卖,像股票一样 | 盘中实时市价 | 是(授权参与人创建/赎回) | SPY, QQQ |
| Open-End | 开放式基金 | 通过基金公司每日申赎 | 每日收盘后 NAV | 是 | VTSAX |
| Closed-End | 封闭式基金 | 交易所买卖 | 市价(可能溢价/折价于 NAV) | 否(固定份额) | 市政债 CEF |
| UIT | 单位投资信托 | 通过发行商申赎 | 基于底层资产估值 | 否(固定组合+到期日) | 固定收益 UIT |
| Money Market | 货币市场基金 | 通过基金公司每日申赎 | 稳定 $1 NAV | 是 | VMFXX |
为什么需要区分
Section titled “为什么需要区分”1. 申购/赎回机制不同
ETF 和 Closed-End 在交易所交易(有 bid/ask spread),Open-End 和 Money Market 是按 NAV 申赎。在 brokerage 集成中直接影响持仓匹配:
// Security::matchEquityFundMoneyMarketSecuritiesBySymbol()if ($discrete_type === 'money_market_fund') { $query->where(self::COLUMN_TYPE, SecurityType::FUND) ->whereHas('fund', fn ($q) => $q->where('subtype', FundSubtype::MONEY_MARKET));}2. 现金等价物判定
Money Market Fund 被视为现金等价物,在计算投资账户的现金头寸时被特殊对待:
} elseif ($position->security?->type === SecurityType::FUND && $position->security->fund?->subtype === FundSubtype::MONEY_MARKET) { $carry += $position->value; // 归入现金}3. 供应商数据映射
不同供应商对同一类基金的叫法不同,subtype 是统一抽象层。HoldingInterface 将供应商的 discrete type 映射到系统 subtype:
self::DISCRETE_TYPE_ETF → FundSubtype::ETFself::DISCRETE_TYPE_OPEN_END_FUND → FundSubtype::OPEN_ENDself::DISCRETE_TYPE_CLOSED_END_FUND → FundSubtype::CLOSED_ENDself::DISCRETE_TYPE_MONEY_MARKET_FUND → FundSubtype::MONEY_MARKETself::DISCRETE_TYPE_UIT → FundSubtype::UIT4. 费率差异
ETF 通常费率最低(被动指数),Open-End 主动管理基金费率较高,Money Market 费率极低。expense_ratio 字段配合 subtype 一起影响投资回报计算。
Sector 两套分类
Section titled “Sector 两套分类”同一张 sectors 表,通过 type 字段区分:
// SectorType enumcase EQUITY = 'equity'; // 11 个股票板块 (ID 1-12,含 Not Classified)case BOND = 'bond'; // 6 个债券板块 (ID 13-18)| Sector Type | ID 范围 | 板块 |
|---|---|---|
| equity | 1 | Basic Materials |
| equity | 2 | Consumer Cyclical |
| equity | 3 | Financial Services |
| equity | 4 | Real Estate |
| equity | 5 | Communication Services |
| equity | 6 | Energy |
| equity | 7 | Industrials |
| equity | 8 | Technology |
| equity | 9 | Consumer Defensive |
| equity | 10 | Health Care |
| equity | 11 | Utilities |
| equity | 12 | Not Classified |
| bond | 13 | Government |
| bond | 14 | Corporate |
| bond | 15 | Securitized |
| bond | 16 | Municipal |
| bond | 17 | Cash |
| bond | 18 | Others |
equities.sector_id 和 fixed_incomes.sector_id 指向同一个 sectors 表但不同的子集。
本地创建证券的默认值
Section titled “本地创建证券的默认值”Security::createLocal() 在通过 brokerage 集成或手动录入创建证券时,按类型填充默认属性:
| 类型 | 默认 Sector | 默认 Category | 其他默认值 |
|---|---|---|---|
| Equity | Not Classified (12) | Large Growth | capitalization=Large, valuation=Blend, country=USA |
| Fixed Income | Government (13) | Government | quality=AAA, market=Developed, subtype=入参 |
| Fund | 不适用 | Other | expense_ratio=0, allocations 按 S&P 500 近似分布填充 |
未知证券 fallback
Section titled “未知证券 fallback”系统定义了三个通用 symbol 用于无法识别的证券:
| Symbol | 类型 | 用途 |
|---|---|---|
!?E | equity | 无法识别的股票 |
!?F | fund | 无法识别的基金 |
!?B | bond | 无法识别的债券 |
Morningstar 数据来源
Section titled “Morningstar 数据来源”生产环境中,这三类证券的数据主要来自 Morningstar:
| 数据类型 | Morningstar 来源 | 本地 extractor / transformer |
|---|---|---|
| Equity 基本数据 | CompanyReference + SecurityReference | Equity\CompanyReference、Equity\SecurityReference |
| Equity sector + style | AssetClassification(Data Point 3007、3001) | Equity\AssetClassification |
| Equity 价格 | Price(Data Point 30003) | Equity\Price |
| Fund 数据 | DataWarehouse37 + AssetClassification30 + InvestmentVehicle | Fund\* extractors |
| Fund 价格 | Prices | Fund\Price |
迁移到 GEDF / Snowflake 后,Equity 数据来源变更详见 DEV-19911 Morningstar GECS 和
equity-data-migration-v1.md。
graph TD
S["securities<br/>type: equity | fund | fixed_income<br/>name, symbol, cusip, isin"]
E["equities<br/>sector_id (1-12)<br/>capitalization: small|middle|large<br/>valuation: value|blend|growth<br/>country"]
FI["fixed_incomes<br/>sector_id (13-18)<br/>subtype: bond|cd|mbs<br/>quality: aaa...below<br/>market: developed|emerging"]
F["funds<br/>subtype: etf|open_end|closed_end|uit|money_market<br/>expense_ratio"]
S -->|type=equity| E
S -->|type=fixed_income| FI
S -->|type=fund| F
F --> AAT["allocations_by_asset_type<br/>US/Non-US Equity/Bond/Cash %"]
F --> ASEC["allocations_by_sector<br/>11 个股票板块 %"]
F --> ACAT["allocations_by_category<br/>风格类别 %"]
F --> AMKT["allocations_by_market<br/>发达/新兴 %"]
F --> ABQ["allocations_by_bond_quality<br/>信用评级分布"]
F --> AES["allocations_by_equity_style<br/>9 宫格风格分布"]
F --> FEP["fund_equity_portfolio<br/>股票持仓明细"]
F --> FBP["fund_bond_portfolio<br/>债券持仓明细"]
E --> SEC_E["sectors (type=equity)<br/>11 板块"]
FI --> SEC_B["sectors (type=bond)<br/>6 板块"]
ASEC --> SEC_E