libfinance 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. libfinance-0.1.4/PKG-INFO +229 -0
  2. libfinance-0.1.4/README.md +216 -0
  3. libfinance-0.1.4/VERSION +1 -0
  4. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/exfactor.py +1 -1
  5. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/get_price.py +2 -2
  6. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/index_components.py +1 -1
  7. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/instrument.py +4 -4
  8. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/live_quote.py +7 -4
  9. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/shares.py +37 -1
  10. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/client.py +29 -7
  11. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/subscribe/md_protocol.py +71 -115
  12. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/subscribe/quote_api.py +14 -16
  13. libfinance-0.1.4/libfinance.egg-info/PKG-INFO +229 -0
  14. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_client_api_contract.py +37 -9
  15. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_client_reconnect.py +74 -0
  16. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_subscribe_live.py +25 -15
  17. libfinance-0.1.2/PKG-INFO +0 -170
  18. libfinance-0.1.2/README.md +0 -157
  19. libfinance-0.1.2/VERSION +0 -1
  20. libfinance-0.1.2/libfinance.egg-info/PKG-INFO +0 -170
  21. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/__init__.py +0 -0
  22. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/__init__.py +0 -0
  23. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/calendar.py +0 -0
  24. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/corporate_actions.py +0 -0
  25. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/factors.py +0 -0
  26. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/financials.py +0 -0
  27. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/industry.py +0 -0
  28. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/api/theme.py +0 -0
  29. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/subscribe/__init__.py +0 -0
  30. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/__init__.py +0 -0
  31. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/cache.py +0 -0
  32. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/datetime_func.py +0 -0
  33. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/decorators.py +0 -0
  34. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/utils.py +0 -0
  35. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance/utils/validators.py +0 -0
  36. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance.egg-info/SOURCES.txt +0 -0
  37. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance.egg-info/dependency_links.txt +0 -0
  38. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance.egg-info/requires.txt +0 -0
  39. {libfinance-0.1.2 → libfinance-0.1.4}/libfinance.egg-info/top_level.txt +0 -0
  40. {libfinance-0.1.2 → libfinance-0.1.4}/pyproject.toml +0 -0
  41. {libfinance-0.1.2 → libfinance-0.1.4}/setup.cfg +0 -0
  42. {libfinance-0.1.2 → libfinance-0.1.4}/setup.py +0 -0
  43. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_contract.py +0 -0
  44. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_docs_contract.py +0 -0
  45. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_rpc_contract.py +0 -0
  46. {libfinance-0.1.2 → libfinance-0.1.4}/test/test_version.py +0 -0
@@ -0,0 +1,229 @@
1
+ Metadata-Version: 2.4
2
+ Name: libfinance
3
+ Version: 0.1.4
4
+ Summary: libfinance is a modern finance API
5
+ Description-Content-Type: text/markdown
6
+ Requires-Dist: lz4
7
+ Requires-Dist: msgpack
8
+ Requires-Dist: pandas
9
+ Requires-Dist: numpy
10
+ Requires-Dist: pyarrow
11
+ Requires-Dist: six
12
+ Requires-Dist: python-dateutil
13
+
14
+ <div align="center">
15
+
16
+ <picture>
17
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/libfinance_logo_dark.svg">
18
+ <img alt="libfinance" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/libfinance_logo.svg" width="300">
19
+ </picture>
20
+
21
+ **面向量化研究与回测的金融数据接口 —— A 股与美股一套术语,Python 与 C++ 一套函数**
22
+
23
+ [![PyPI](https://img.shields.io/pypi/v/libfinance?style=flat-square&logo=pypi&logoColor=white&label=PyPI)](https://pypi.org/project/libfinance/)
24
+ [![docs zh-cn](https://img.shields.io/readthedocs/libfinance?style=flat-square&logo=readthedocs&logoColor=white&label=docs%20zh-cn)](https://libfinance.readthedocs.io/zh-cn/latest/)
25
+ [![docs en](https://img.shields.io/readthedocs/libfinance-en?style=flat-square&logo=readthedocs&logoColor=white&label=docs%20en)](https://libfinance.readthedocs.io/en/latest/)
26
+
27
+ [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) ·
28
+ [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) ·
29
+ [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) ·
30
+ [🚀 快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html) ·
31
+ [🧭 概念设计](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) ·
32
+ [📑 API 参考](https://libfinance.readthedocs.io/zh-cn/latest/reference/contracts.html)
33
+
34
+ </div>
35
+
36
+ ---
37
+
38
+ 量化研究的结论依赖历史数据,而历史数据有三类常见的失真:证券代码会更名、复用,不同市场之间还会重号;财务报表在披露后会被修订,回测若读取最新版本,就用上了当时无从获得的信息;分红、拆股等公司行动改变价格的可比性,复权口径不一致会直接扭曲收益。研究与生产又常常分别使用 Python 与 C++,两套接口的细微差别会让同一策略在迁移后得到不同的结果。
39
+
40
+ `libfinance` 是面向量化研究与回测的金融数据客户端,覆盖 A 股与美股,提供 Python 与 C++ 两种实现。它以统一的证券标识、按时点(point-in-time)的数据版本和逐事件计算的复权因子组织行情、证券目录、交易日历、公司行动、股本、财务、行业 / 指数 / 主题成分与日频因子等数据;两个市场、两种语言遵循同一份接口契约,调用方式一致,差异只来自数据本身。
41
+
42
+ 数据设计的四条约定:
43
+
44
+ - **统一的证券标识符** —— `<trading_code>.<namespace>`,如 `600000.XSHG`、`000001.XSHE`、`AAPL.US`。命名空间区分不同市场的同号代码,代码按历史时点解析,更名与代码复用不会串到别的证券。
45
+ - **point-in-time 机制 `as_of`** —— 按历史时点还原证券池、选取当时已披露的财务版本,避免未来信息与幸存者偏差。
46
+ - **高质量的复权因子 `exfactor`** —— 由公司行动逐事件计算,提供不复权、前复权、后复权三种口径;`get_ex_factor` 给出单次与累计因子,价格的每一次调整都可追溯。
47
+ - **Python 与 C++ 统一的函数设计** —— 两种客户端按同一份契约(`contract/contract.json`)实现,函数名、参数顺序与默认值、校验与报错、返回的列一一对应;同一组调用经两种客户端发给同一服务端逐项比对。
48
+
49
+ ## 安装
50
+
51
+ ```bash
52
+ pip install libfinance
53
+ ```
54
+
55
+ 从源码安装:
56
+
57
+ ```bash
58
+ git clone https://github.com/StateOfTheArt-quant/libfinance.git
59
+ cd libfinance/python
60
+ pip install -e .
61
+ ```
62
+
63
+ > [!TIP]
64
+ > **使用 C++?** C++ 客户端与 Python 版函数一一对应,通过 CMake `FetchContent` 引入项目,依赖 Apache Arrow C++。安装、构建与示例见 [cpp/README.md](https://github.com/StateOfTheArt-quant/libfinance/blob/main/cpp/README.md)。
65
+
66
+ ## 快速开始
67
+
68
+ 按[安装与连接说明](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/installation.html)配置服务后即可查询。以下输出均为真实运行结果,数据持续更新,行数与数值可能不同。
69
+
70
+ **证券目录** —— 两个市场在同一张表里,列相同:
71
+
72
+ ```python
73
+ from libfinance import all_instruments
74
+
75
+ stocks = all_instruments(type="stock")
76
+ stocks.set_index("order_book_id").loc[
77
+ ["600000.XSHG", "000001.XSHE", "AAPL.US", "NVDA.US"], ["market", "exchange", "name"]]
78
+ ```
79
+
80
+ ```text
81
+ market exchange name
82
+ order_book_id
83
+ 600000.XSHG CN XSHG 浦发银行
84
+ 000001.XSHE CN XSHE 平安银行
85
+ AAPL.US US XNAS Apple Inc. - Common Stock
86
+ NVDA.US US XNAS NVIDIA Corporation - Common Stock
87
+ ```
88
+
89
+ **交易日** —— 区间按自然日给,返回其中的交易日(美股传 `market="us"`):
90
+
91
+ ```python
92
+ from libfinance import get_trading_dates
93
+
94
+ get_trading_dates("2024-05-11", "2024-05-20")
95
+ ```
96
+
97
+ ```text
98
+ DatetimeIndex(['2024-05-13', '2024-05-14', '2024-05-15', '2024-05-16',
99
+ '2024-05-17', '2024-05-20'],
100
+ dtype='datetime64[us]', freq=None)
101
+ ```
102
+
103
+ **行情** —— 一次调用混查两个市场;美股没有涨跌停,`limit_up` 为 `NaN`,表结构不变:
104
+
105
+ ```python
106
+ from libfinance import get_price
107
+
108
+ get_price(["600000.XSHG", "AAPL.US"], "2024-03-01", "2024-03-05",
109
+ fields=["open", "close", "volume", "limit_up"], adjust_type="none")
110
+ ```
111
+
112
+ ```text
113
+ open close volume limit_up
114
+ order_book_id datetime
115
+ 600000.XSHG 2024-03-01 7.13 7.11 29431801 7.87
116
+ 2024-03-04 7.12 7.07 27855963 7.82
117
+ 2024-03-05 7.05 7.16 41756232 7.78
118
+ AAPL.US 2024-03-01 179.55 179.66 73563100 NaN
119
+ 2024-03-04 176.15 175.10 81510101 NaN
120
+ 2024-03-05 170.76 170.12 95132400 NaN
121
+ ```
122
+
123
+ `adjust_type="none"` 取当天的真实成交价;不传时默认前复权(`"pre"`),见[价格口径](https://libfinance.readthedocs.io/zh-cn/latest/data/price.html)。
124
+
125
+ **因子** —— 库名 `system/alpha158` 展开为 158 个因子,每个因子一列:
126
+
127
+ ```python
128
+ from libfinance import get_factor_exposure
129
+
130
+ f = get_factor_exposure(["600000.XSHG", "000001.XSHE"], "system/alpha158", "2026-09-07", "2026-09-10")
131
+ f.iloc[:, :6].rename(columns=lambda c: c.rsplit("/", 1)[1]).round(4) # 前 6 列,列名只留因子名
132
+ ```
133
+
134
+ ```text
135
+ KMID KLEN KMID2 KUP KUP2 KLOW
136
+ order_book_id date
137
+ 600000.XSHG 2026-09-07 -0.0212 0.0286 -0.7407 0.0032 0.1111 0.0042
138
+ 2026-09-08 0.0076 0.0141 0.5385 0.0065 0.4615 0.0000
139
+ 2026-09-09 -0.0022 0.0086 -0.2500 0.0043 0.5000 0.0022
140
+ 2026-09-10 0.0141 0.0184 0.7647 0.0011 0.0588 0.0033
141
+ 000001.XSHE 2026-09-07 -0.0143 0.0194 -0.7391 0.0008 0.0435 0.0042
142
+ 2026-09-08 0.0103 0.0137 0.7500 0.0026 0.1875 0.0009
143
+ 2026-09-09 -0.0051 0.0085 -0.6000 0.0026 0.3000 0.0009
144
+ 2026-09-10 0.0146 0.0171 0.8500 0.0009 0.0500 0.0017
145
+ ```
146
+
147
+ 逐步说明见[快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html)。
148
+
149
+ ## A 股与美股共用一套术语
150
+
151
+ 统一体现在三个层面。
152
+
153
+ | 层面 | 统一的内容 | 例 |
154
+ | --- | --- | --- |
155
+ | 证券标识 | 写法都是 `<trading_code>.<namespace>`;命名空间的粒度取决于该市场消除歧义所需的范围 | `600000.XSHG`、`AAPL.US` |
156
+ | 函数与参数 | 两个市场调用同一组函数,参数名相同,`as_of` 与 `adjust_type` 的含义一致 | `get_price`、`instruments`、`get_dividends` |
157
+ | 返回结构 | 列名与索引一致;某个市场不适用或未提供的字段取 `NaN`,不另设一张表 | 美股的 `turnover`、`limit_up`、`limit_down` |
158
+
159
+ 需要显式指定市场的,只有不涉及具体证券的查询:交易日历、全市场目录、数据覆盖范围。按证券查询时,命名空间已经给出了市场信息,列表里也可以混合两个市场的代码。
160
+
161
+ ```python
162
+ from libfinance import instruments, get_trading_dates
163
+
164
+ instruments(["000001.XSHE", "AAPL.US"]) # 命名空间已给出市场
165
+ get_trading_dates("2024-01-01", "2024-01-31", market="us") # 不涉及具体证券
166
+ ```
167
+
168
+ 统一的是术语和调用约定,数据本身的差异依然存在。下表的「市场」一列标出了每类数据实际覆盖的市场,逐个接口的情况见[查美股](https://libfinance.readthedocs.io/zh-cn/latest/howto/us_market.html)。
169
+
170
+ ## 数据覆盖
171
+
172
+ | 数据 | 市场 | 主要函数 | 说明 |
173
+ | --- | --- | --- | --- |
174
+ | 交易日历 | CN · US | `get_trading_dates` | 交易日、区间取日、前后推 N 个交易日 |
175
+ | 证券目录 | CN · US | `all_instruments`、`instruments` | 股票、指数、行业、主题;代码、名称、上市与退市日期 |
176
+ | 日频行情 | CN · US | `get_price` | 开高低收、成交量额、涨跌停价,可复权 |
177
+ | 复权因子 | CN · US | `get_ex_factor` | 逐除权日的单次及累计因子 |
178
+ | 股本 | CN · US | `get_shares` | 逐交易日的总股本与流通股本 |
179
+ | 换手率 | CN、US | `get_turnover_rate` | 逐交易日的换手率(未复权成交量 ÷ A 股自由流通股本或美股已发行股数) |
180
+ | 分红 / 拆股 / 配股 | CN · US | `get_dividends`、`get_splits`、`get_allotments` | 除权事件;配股只有 A 股 |
181
+ | 分拆 | US | `get_spinoffs` | A 股不产生这类事件 |
182
+ | 财务报表(PIT) | CN · US | `get_pit_financials_ex` | 按季度取,带修订历史 |
183
+ | 财务衍生指标 | CN · US | `get_financial_metrics` | 按交易日的财务衍生指标 |
184
+ | 行业分类 | CN · US | `get_instrument_industry`、`get_industry_constituents`、`get_industry_weights` | 申万、GICS 等分类体系 |
185
+ | 指数成分与权重 | CN · US | `get_index_constituents`、`get_index_weights` | 中证、标普等 |
186
+ | 主题成分与权重 | CN | `get_theme_constituents`、`get_theme_weights` | THS 主题 |
187
+ | 日频因子 | CN | `get_factor_exposure`、`list_factor_libraries`、`list_factors` | alpha158、qlib,Barra CNE5 风格 / 行业因子,CNE5 与 CNE6 描述符;见[因子数据](https://libfinance.readthedocs.io/zh-cn/latest/data/factors.html)与[因子字典](https://libfinance.readthedocs.io/zh-cn/latest/reference/factor_dictionary.html) |
188
+ | 实时行情 | CN | `get_last_quotes`、`QuoteApi` | 最新快照与订阅推送 |
189
+
190
+ 覆盖到哪一年、更新到哪一天,取决于你连的那个服务。**不要照抄文档里的日期**,用[数据新鲜度](https://libfinance.readthedocs.io/zh-cn/latest/data/freshness.html)里的两个函数自己查。
191
+
192
+ ## 概念设计
193
+
194
+ | 主题 | 解决的问题 |
195
+ | --- | --- |
196
+ | [统一的证券标识符](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) | 区分市场、证券身份及历史代码,准确关联不同数据 |
197
+ | [point-in-time 机制 as_of](https://libfinance.readthedocs.io/zh-cn/latest/concepts/point_in_time.html) | 还原历史证券池与可见财报,避免未来信息和幸存者偏差 |
198
+ | [高质量的复权因子 exfactor](https://libfinance.readthedocs.io/zh-cn/latest/concepts/exfactor.html) | 理解公司行动对价格的影响,以及三种价格口径的计算和用途 |
199
+ | [Python 与 C++ 统一的函数设计](https://libfinance.readthedocs.io/zh-cn/latest/concepts/python_cpp.html) | 一份契约约束两种客户端:函数、参数、报错与返回列一一对应,并逐项核对 |
200
+
201
+ ## 文档与示例
202
+
203
+ | | |
204
+ | --- | --- |
205
+ | [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) | 概念设计、数据说明、操作指南与 API 参考 |
206
+ | [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) | The same documentation tree in English |
207
+ | [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) | 按数据族排序的可运行示例(Python 与 C++ 一一对应),与 API 参考对照阅读 |
208
+ | [🧩 操作指南](https://libfinance.readthedocs.io/zh-cn/latest/howto/index.html) | 取行情面板、PIT 回测、订阅实时行情等成套做法 |
209
+ | [🩺 故障排查](https://libfinance.readthedocs.io/zh-cn/latest/howto/troubleshooting.html) | 按**症状**编排:看到什么现象,就从哪一行开始 |
210
+
211
+ API 参考按合约信息和交易日历、行情、基本面、行业与指数和主题、公司行动、实时行情、因子分组,每个函数附 Python 与 C++ 两种写法的示例及其真实输出。
212
+
213
+ ## 社区
214
+
215
+ 问题与需求请提 [Issue](https://github.com/StateOfTheArt-quant/libfinance/issues)。关注公众号获取更新:
216
+
217
+ <div align="center">
218
+ <img alt="微信公众号二维码" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/code.png" width="600" height="220">
219
+ </div>
220
+
221
+ ## 仓库结构
222
+
223
+ | 目录 | 内容 |
224
+ | --- | --- |
225
+ | `contract/` | 各语言客户端共同遵守的契约:公开函数(名称、参数顺序与默认值、返回)与它们调用的服务端函数 |
226
+ | `contract/conformance/` | 同一组调用分别经 Python 与 C++ 客户端发给同一个服务端,逐项比对答案 |
227
+ | `python/` | Python 客户端(PyPI 上的 `libfinance`) |
228
+ | `cpp/` | C++ 客户端 |
229
+ | `docs/` | 文档(中英双语) |
@@ -0,0 +1,216 @@
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/libfinance_logo_dark.svg">
5
+ <img alt="libfinance" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/libfinance_logo.svg" width="300">
6
+ </picture>
7
+
8
+ **面向量化研究与回测的金融数据接口 —— A 股与美股一套术语,Python 与 C++ 一套函数**
9
+
10
+ [![PyPI](https://img.shields.io/pypi/v/libfinance?style=flat-square&logo=pypi&logoColor=white&label=PyPI)](https://pypi.org/project/libfinance/)
11
+ [![docs zh-cn](https://img.shields.io/readthedocs/libfinance?style=flat-square&logo=readthedocs&logoColor=white&label=docs%20zh-cn)](https://libfinance.readthedocs.io/zh-cn/latest/)
12
+ [![docs en](https://img.shields.io/readthedocs/libfinance-en?style=flat-square&logo=readthedocs&logoColor=white&label=docs%20en)](https://libfinance.readthedocs.io/en/latest/)
13
+
14
+ [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) ·
15
+ [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) ·
16
+ [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) ·
17
+ [🚀 快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html) ·
18
+ [🧭 概念设计](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) ·
19
+ [📑 API 参考](https://libfinance.readthedocs.io/zh-cn/latest/reference/contracts.html)
20
+
21
+ </div>
22
+
23
+ ---
24
+
25
+ 量化研究的结论依赖历史数据,而历史数据有三类常见的失真:证券代码会更名、复用,不同市场之间还会重号;财务报表在披露后会被修订,回测若读取最新版本,就用上了当时无从获得的信息;分红、拆股等公司行动改变价格的可比性,复权口径不一致会直接扭曲收益。研究与生产又常常分别使用 Python 与 C++,两套接口的细微差别会让同一策略在迁移后得到不同的结果。
26
+
27
+ `libfinance` 是面向量化研究与回测的金融数据客户端,覆盖 A 股与美股,提供 Python 与 C++ 两种实现。它以统一的证券标识、按时点(point-in-time)的数据版本和逐事件计算的复权因子组织行情、证券目录、交易日历、公司行动、股本、财务、行业 / 指数 / 主题成分与日频因子等数据;两个市场、两种语言遵循同一份接口契约,调用方式一致,差异只来自数据本身。
28
+
29
+ 数据设计的四条约定:
30
+
31
+ - **统一的证券标识符** —— `<trading_code>.<namespace>`,如 `600000.XSHG`、`000001.XSHE`、`AAPL.US`。命名空间区分不同市场的同号代码,代码按历史时点解析,更名与代码复用不会串到别的证券。
32
+ - **point-in-time 机制 `as_of`** —— 按历史时点还原证券池、选取当时已披露的财务版本,避免未来信息与幸存者偏差。
33
+ - **高质量的复权因子 `exfactor`** —— 由公司行动逐事件计算,提供不复权、前复权、后复权三种口径;`get_ex_factor` 给出单次与累计因子,价格的每一次调整都可追溯。
34
+ - **Python 与 C++ 统一的函数设计** —— 两种客户端按同一份契约(`contract/contract.json`)实现,函数名、参数顺序与默认值、校验与报错、返回的列一一对应;同一组调用经两种客户端发给同一服务端逐项比对。
35
+
36
+ ## 安装
37
+
38
+ ```bash
39
+ pip install libfinance
40
+ ```
41
+
42
+ 从源码安装:
43
+
44
+ ```bash
45
+ git clone https://github.com/StateOfTheArt-quant/libfinance.git
46
+ cd libfinance/python
47
+ pip install -e .
48
+ ```
49
+
50
+ > [!TIP]
51
+ > **使用 C++?** C++ 客户端与 Python 版函数一一对应,通过 CMake `FetchContent` 引入项目,依赖 Apache Arrow C++。安装、构建与示例见 [cpp/README.md](https://github.com/StateOfTheArt-quant/libfinance/blob/main/cpp/README.md)。
52
+
53
+ ## 快速开始
54
+
55
+ 按[安装与连接说明](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/installation.html)配置服务后即可查询。以下输出均为真实运行结果,数据持续更新,行数与数值可能不同。
56
+
57
+ **证券目录** —— 两个市场在同一张表里,列相同:
58
+
59
+ ```python
60
+ from libfinance import all_instruments
61
+
62
+ stocks = all_instruments(type="stock")
63
+ stocks.set_index("order_book_id").loc[
64
+ ["600000.XSHG", "000001.XSHE", "AAPL.US", "NVDA.US"], ["market", "exchange", "name"]]
65
+ ```
66
+
67
+ ```text
68
+ market exchange name
69
+ order_book_id
70
+ 600000.XSHG CN XSHG 浦发银行
71
+ 000001.XSHE CN XSHE 平安银行
72
+ AAPL.US US XNAS Apple Inc. - Common Stock
73
+ NVDA.US US XNAS NVIDIA Corporation - Common Stock
74
+ ```
75
+
76
+ **交易日** —— 区间按自然日给,返回其中的交易日(美股传 `market="us"`):
77
+
78
+ ```python
79
+ from libfinance import get_trading_dates
80
+
81
+ get_trading_dates("2024-05-11", "2024-05-20")
82
+ ```
83
+
84
+ ```text
85
+ DatetimeIndex(['2024-05-13', '2024-05-14', '2024-05-15', '2024-05-16',
86
+ '2024-05-17', '2024-05-20'],
87
+ dtype='datetime64[us]', freq=None)
88
+ ```
89
+
90
+ **行情** —— 一次调用混查两个市场;美股没有涨跌停,`limit_up` 为 `NaN`,表结构不变:
91
+
92
+ ```python
93
+ from libfinance import get_price
94
+
95
+ get_price(["600000.XSHG", "AAPL.US"], "2024-03-01", "2024-03-05",
96
+ fields=["open", "close", "volume", "limit_up"], adjust_type="none")
97
+ ```
98
+
99
+ ```text
100
+ open close volume limit_up
101
+ order_book_id datetime
102
+ 600000.XSHG 2024-03-01 7.13 7.11 29431801 7.87
103
+ 2024-03-04 7.12 7.07 27855963 7.82
104
+ 2024-03-05 7.05 7.16 41756232 7.78
105
+ AAPL.US 2024-03-01 179.55 179.66 73563100 NaN
106
+ 2024-03-04 176.15 175.10 81510101 NaN
107
+ 2024-03-05 170.76 170.12 95132400 NaN
108
+ ```
109
+
110
+ `adjust_type="none"` 取当天的真实成交价;不传时默认前复权(`"pre"`),见[价格口径](https://libfinance.readthedocs.io/zh-cn/latest/data/price.html)。
111
+
112
+ **因子** —— 库名 `system/alpha158` 展开为 158 个因子,每个因子一列:
113
+
114
+ ```python
115
+ from libfinance import get_factor_exposure
116
+
117
+ f = get_factor_exposure(["600000.XSHG", "000001.XSHE"], "system/alpha158", "2026-09-07", "2026-09-10")
118
+ f.iloc[:, :6].rename(columns=lambda c: c.rsplit("/", 1)[1]).round(4) # 前 6 列,列名只留因子名
119
+ ```
120
+
121
+ ```text
122
+ KMID KLEN KMID2 KUP KUP2 KLOW
123
+ order_book_id date
124
+ 600000.XSHG 2026-09-07 -0.0212 0.0286 -0.7407 0.0032 0.1111 0.0042
125
+ 2026-09-08 0.0076 0.0141 0.5385 0.0065 0.4615 0.0000
126
+ 2026-09-09 -0.0022 0.0086 -0.2500 0.0043 0.5000 0.0022
127
+ 2026-09-10 0.0141 0.0184 0.7647 0.0011 0.0588 0.0033
128
+ 000001.XSHE 2026-09-07 -0.0143 0.0194 -0.7391 0.0008 0.0435 0.0042
129
+ 2026-09-08 0.0103 0.0137 0.7500 0.0026 0.1875 0.0009
130
+ 2026-09-09 -0.0051 0.0085 -0.6000 0.0026 0.3000 0.0009
131
+ 2026-09-10 0.0146 0.0171 0.8500 0.0009 0.0500 0.0017
132
+ ```
133
+
134
+ 逐步说明见[快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html)。
135
+
136
+ ## A 股与美股共用一套术语
137
+
138
+ 统一体现在三个层面。
139
+
140
+ | 层面 | 统一的内容 | 例 |
141
+ | --- | --- | --- |
142
+ | 证券标识 | 写法都是 `<trading_code>.<namespace>`;命名空间的粒度取决于该市场消除歧义所需的范围 | `600000.XSHG`、`AAPL.US` |
143
+ | 函数与参数 | 两个市场调用同一组函数,参数名相同,`as_of` 与 `adjust_type` 的含义一致 | `get_price`、`instruments`、`get_dividends` |
144
+ | 返回结构 | 列名与索引一致;某个市场不适用或未提供的字段取 `NaN`,不另设一张表 | 美股的 `turnover`、`limit_up`、`limit_down` |
145
+
146
+ 需要显式指定市场的,只有不涉及具体证券的查询:交易日历、全市场目录、数据覆盖范围。按证券查询时,命名空间已经给出了市场信息,列表里也可以混合两个市场的代码。
147
+
148
+ ```python
149
+ from libfinance import instruments, get_trading_dates
150
+
151
+ instruments(["000001.XSHE", "AAPL.US"]) # 命名空间已给出市场
152
+ get_trading_dates("2024-01-01", "2024-01-31", market="us") # 不涉及具体证券
153
+ ```
154
+
155
+ 统一的是术语和调用约定,数据本身的差异依然存在。下表的「市场」一列标出了每类数据实际覆盖的市场,逐个接口的情况见[查美股](https://libfinance.readthedocs.io/zh-cn/latest/howto/us_market.html)。
156
+
157
+ ## 数据覆盖
158
+
159
+ | 数据 | 市场 | 主要函数 | 说明 |
160
+ | --- | --- | --- | --- |
161
+ | 交易日历 | CN · US | `get_trading_dates` | 交易日、区间取日、前后推 N 个交易日 |
162
+ | 证券目录 | CN · US | `all_instruments`、`instruments` | 股票、指数、行业、主题;代码、名称、上市与退市日期 |
163
+ | 日频行情 | CN · US | `get_price` | 开高低收、成交量额、涨跌停价,可复权 |
164
+ | 复权因子 | CN · US | `get_ex_factor` | 逐除权日的单次及累计因子 |
165
+ | 股本 | CN · US | `get_shares` | 逐交易日的总股本与流通股本 |
166
+ | 换手率 | CN、US | `get_turnover_rate` | 逐交易日的换手率(未复权成交量 ÷ A 股自由流通股本或美股已发行股数) |
167
+ | 分红 / 拆股 / 配股 | CN · US | `get_dividends`、`get_splits`、`get_allotments` | 除权事件;配股只有 A 股 |
168
+ | 分拆 | US | `get_spinoffs` | A 股不产生这类事件 |
169
+ | 财务报表(PIT) | CN · US | `get_pit_financials_ex` | 按季度取,带修订历史 |
170
+ | 财务衍生指标 | CN · US | `get_financial_metrics` | 按交易日的财务衍生指标 |
171
+ | 行业分类 | CN · US | `get_instrument_industry`、`get_industry_constituents`、`get_industry_weights` | 申万、GICS 等分类体系 |
172
+ | 指数成分与权重 | CN · US | `get_index_constituents`、`get_index_weights` | 中证、标普等 |
173
+ | 主题成分与权重 | CN | `get_theme_constituents`、`get_theme_weights` | THS 主题 |
174
+ | 日频因子 | CN | `get_factor_exposure`、`list_factor_libraries`、`list_factors` | alpha158、qlib,Barra CNE5 风格 / 行业因子,CNE5 与 CNE6 描述符;见[因子数据](https://libfinance.readthedocs.io/zh-cn/latest/data/factors.html)与[因子字典](https://libfinance.readthedocs.io/zh-cn/latest/reference/factor_dictionary.html) |
175
+ | 实时行情 | CN | `get_last_quotes`、`QuoteApi` | 最新快照与订阅推送 |
176
+
177
+ 覆盖到哪一年、更新到哪一天,取决于你连的那个服务。**不要照抄文档里的日期**,用[数据新鲜度](https://libfinance.readthedocs.io/zh-cn/latest/data/freshness.html)里的两个函数自己查。
178
+
179
+ ## 概念设计
180
+
181
+ | 主题 | 解决的问题 |
182
+ | --- | --- |
183
+ | [统一的证券标识符](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) | 区分市场、证券身份及历史代码,准确关联不同数据 |
184
+ | [point-in-time 机制 as_of](https://libfinance.readthedocs.io/zh-cn/latest/concepts/point_in_time.html) | 还原历史证券池与可见财报,避免未来信息和幸存者偏差 |
185
+ | [高质量的复权因子 exfactor](https://libfinance.readthedocs.io/zh-cn/latest/concepts/exfactor.html) | 理解公司行动对价格的影响,以及三种价格口径的计算和用途 |
186
+ | [Python 与 C++ 统一的函数设计](https://libfinance.readthedocs.io/zh-cn/latest/concepts/python_cpp.html) | 一份契约约束两种客户端:函数、参数、报错与返回列一一对应,并逐项核对 |
187
+
188
+ ## 文档与示例
189
+
190
+ | | |
191
+ | --- | --- |
192
+ | [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) | 概念设计、数据说明、操作指南与 API 参考 |
193
+ | [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) | The same documentation tree in English |
194
+ | [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) | 按数据族排序的可运行示例(Python 与 C++ 一一对应),与 API 参考对照阅读 |
195
+ | [🧩 操作指南](https://libfinance.readthedocs.io/zh-cn/latest/howto/index.html) | 取行情面板、PIT 回测、订阅实时行情等成套做法 |
196
+ | [🩺 故障排查](https://libfinance.readthedocs.io/zh-cn/latest/howto/troubleshooting.html) | 按**症状**编排:看到什么现象,就从哪一行开始 |
197
+
198
+ API 参考按合约信息和交易日历、行情、基本面、行业与指数和主题、公司行动、实时行情、因子分组,每个函数附 Python 与 C++ 两种写法的示例及其真实输出。
199
+
200
+ ## 社区
201
+
202
+ 问题与需求请提 [Issue](https://github.com/StateOfTheArt-quant/libfinance/issues)。关注公众号获取更新:
203
+
204
+ <div align="center">
205
+ <img alt="微信公众号二维码" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/code.png" width="600" height="220">
206
+ </div>
207
+
208
+ ## 仓库结构
209
+
210
+ | 目录 | 内容 |
211
+ | --- | --- |
212
+ | `contract/` | 各语言客户端共同遵守的契约:公开函数(名称、参数顺序与默认值、返回)与它们调用的服务端函数 |
213
+ | `contract/conformance/` | 同一组调用分别经 Python 与 C++ 客户端发给同一个服务端,逐项比对答案 |
214
+ | `python/` | Python 客户端(PyPI 上的 `libfinance`) |
215
+ | `cpp/` | C++ 客户端 |
216
+ | `docs/` | 文档(中英双语) |
@@ -0,0 +1 @@
1
+ 0.1.4
@@ -22,7 +22,7 @@ def get_ex_factor(
22
22
  :param end_date: 结束除权日,含当日;省略则查询至数据截止日。
23
23
  代码按该日有效的身份解析,省略时按当前代码解析
24
24
  :returns: 以 ex_date 为 DatetimeIndex 的 DataFrame,包含 order_book_id、
25
- permanent_id、ex_factor、ex_cum_factor。ex_factor 是单个除权日因子,同日行动已合成;
25
+ ex_factor、ex_cum_factor。ex_factor 是单个除权日因子,同日行动已合成;
26
26
  ex_cum_factor 是从数据版本内该证券首个事件前以 1 为基准的累计因子。
27
27
  已覆盖证券在窗口内无记录时返回保留索引和列结构的空表。
28
28
 
@@ -129,7 +129,7 @@ def get_price(
129
129
  指数原样返回
130
130
  :param adjust_orig: 前复权的基准日;省略时为 ``end_date``\ :价格换算到查询区间最后一天的口径,
131
131
  区间之后的除权不影响结果(point-in-time)
132
- :returns: 以 ``(order_book_id, datetime)`` 为索引的 DataFrame,列为 ``permanent_id`` 与所选字段。
132
+ :returns: 以 ``(order_book_id, datetime)`` 为索引的 DataFrame,列为所选字段。
133
133
 
134
134
  复权规则:成交量随复权反向缩放,成交额 ``turnover`` 不受复权影响。
135
135
  """
@@ -167,7 +167,7 @@ def get_price(
167
167
 
168
168
 
169
169
  def _to_panel(frame):
170
- r"""daybar 的扁平表(\ ``order_book_id, permanent_id, session_date, 字段...``\ )还原成
170
+ r"""daybar 的扁平表(\ ``order_book_id, session_date, 字段...``\ )还原成
171
171
  ``(order_book_id, datetime)`` 索引。不认识的形状原样返回,让调用方看见真实的列。"""
172
172
  if not isinstance(frame, pd.DataFrame) or not {"order_book_id", "session_date"} <= set(frame.columns):
173
173
  return frame
@@ -50,7 +50,7 @@ def get_index_weights(order_book_id: str, as_of=None) -> pd.DataFrame:
50
50
 
51
51
  :param order_book_id: 指数代码,如 ``"000300.XSHG"``
52
52
  :param as_of: 那一天的事实;省略则取指数已确认的最新日期
53
- :returns: pandas.DataFrame,包含 order_book_id(成分证券)、permanent_id、weight、methodology、source(指数发布机构)、
53
+ :returns: pandas.DataFrame,包含 order_book_id(成分证券)、weight、methodology、source(指数发布机构)、
54
54
  basis(origin 数据源发布 / reconstructed 按编制方法重构)、date(权重所在的日子)、quality_flags。
55
55
  权重是月末快照:其余交易日取之前最近一期、按各成分的复权收益率漂移,date 为 as_of,quality_flags 带 DRIFTED。
56
56
  """
@@ -5,8 +5,8 @@ r"""证券目录:股票、指数、行业、主题在同一个 instrument 聚
5
5
  签名与列名取自后端 instrument 数据族(\ ``instrument.all_instruments`` /
6
6
  ``instrument.instruments``\ ),本模块只做参数检查、按数据版本缓存与结果的形状。
7
7
 
8
- * ``order_book_id`` 是代码(\ ``600000.XSHG``\ 、\ ``000300.XSHG``\ 、\ ``AAPL.US``\ ),
9
- ``permanent_id`` 是证券不随代码变化的身份,\ ``name`` 是名称。
8
+ * ``order_book_id`` 是代码(\ ``600000.XSHG``\ 、\ ``000300.XSHG``\ 、\ ``AAPL.US``\ ),也是客户端唯一的证券标识;
9
+ ``name`` 是名称。
10
10
  * ``type`` 取 ``stock`` / ``index`` / ``industry`` / ``theme``\ 。
11
11
  * ``source`` 是定义并编号证券的机构:股票的交易所(XSHG、XNAS)、指数的发布机构
12
12
  (CSI、SPDJI)、行业的分类体系(SW、GICS)、主题的 THS;\ ``exchange`` 只有股票有。
@@ -25,7 +25,7 @@ from libfinance.utils.validators import ensure_list_of_string
25
25
  VALID_TYPES = ("stock", "index", "industry", "theme")
26
26
 
27
27
  #: all_instruments 的列,按后端的顺序。
28
- COLUMNS = ("order_book_id", "permanent_id", "type", "market", "name", "exchange", "source")
28
+ COLUMNS = ("order_book_id", "type", "market", "name", "exchange", "source")
29
29
 
30
30
 
31
31
  class Instrument(object):
@@ -90,7 +90,7 @@ def all_instruments(
90
90
  :param as_of: 给出则为该日的历史视图;省略时各类型取各自的当前状态。某类型不覆盖的日期
91
91
  报 CoverageError 并写明类型,缩小 ``type`` 或 ``source`` 即可。
92
92
  :param cached: 是否使用按服务端数据版本更新的缓存;显式指定市场时直接查询。
93
- :returns: DataFrame,列为 ``order_book_id, permanent_id, type, market, name, exchange, source``\ 。
93
+ :returns: DataFrame,列为 ``order_book_id, type, market, name, exchange, source``\ 。
94
94
  """
95
95
  types = _normalize_types(type)
96
96
  sources = _optional_strings(source, "source")
@@ -8,8 +8,7 @@ from libfinance.subscribe.md_protocol import Quote
8
8
  Quote 的字段集与订阅路径统一(定义见 libfinance/subscribe/md_protocol.py,对齐 dynamics):
9
9
 
10
10
  data_time: int
11
- instrument_id: str exchange_id: str # 代码与交易所后缀,如 600000 / XSHG
12
- instrument_type: int # InstrumentType 枚举
11
+ order_book_id: str # 如 600000.XSHG(协议 v4 起唯一的标的字段)
13
12
  pre_close_price / pre_settlement_price / last_price / volume / turnover
14
13
  pre_open_interest / open_interest
15
14
  open_price / high_price / low_price / upper_limit_price / lower_limit_price
@@ -17,13 +16,16 @@ Quote 的字段集与订阅路径统一(定义见 libfinance/subscribe/md_prot
17
16
  total_bid_volume / total_ask_volume / total_trade_num
18
17
  bid_price / ask_price / bid_volume / ask_volume # 均为 list[float],10 档
19
18
  trading_phase_code: str
20
- order_book_id: str # 只读属性 = f"{instrument_id}.{exchange_id}"
21
19
 
22
20
  注意:本函数走 RPC(8080),与行情网关是两条独立通路,只是复用同一个 Quote 类型。
23
21
  服务端返回体的字段名须与上面一致;下面用 __dict__ 注入,多余的键会原样带上,
24
22
  缺失的键则在访问时才报 AttributeError。
25
23
  """
26
24
 
25
+ #: 协议 v4 之前的标的字段:order_book_id 已包含全部信息,旧服务端送来也丢掉。
26
+ _RETIRED = frozenset(("instrument_id", "exchange_id", "instrument_type"))
27
+
28
+
27
29
  def dict_to_quotes_ultrafast(raw_data) -> dict[str, Quote]:
28
30
  result = {}
29
31
  for k, v in raw_data.items():
@@ -39,7 +41,8 @@ def dict_to_quotes_ultrafast(raw_data) -> dict[str, Quote]:
39
41
 
40
42
  # 🧹 3. 是 dict 时快速清洗内部 None 值,防止下游量价计算报 TypeError
41
43
  # 字典推导式在 CPython 底层由 C 循环驱动,性能损耗 < 5%
42
- clean_v = {fk: fv for fk, fv in v.items() if fv is not None}
44
+ clean_v = {fk: fv for fk, fv in v.items() if fv is not None and fk not in _RETIRED}
45
+ clean_v.setdefault("order_book_id", k) # 键就是 order_book_id;旧服务端不带这个字段
43
46
 
44
47
  # 🚀 4. 绕过 __init__ 参数绑定,直接注入对象内存
45
48
  q = object.__new__(Quote)
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """股本:统一字段,CN 与 US 同一套(后端 shares 数据族的 get_shares_panel)。"""
3
+ """股本:统一字段,CN 与 US 同一套(后端 shares 数据族的 get_shares_panel);以及由它算出的日频换手率。"""
4
4
  from typing import List, Optional, Union
5
5
 
6
6
  import pandas as pd
@@ -71,6 +71,42 @@ def get_shares(
71
71
  return _indexed(frame)
72
72
 
73
73
 
74
+ @export_as_api
75
+ def get_turnover_rate(
76
+ order_book_ids: Union[str, List[str]],
77
+ start_date=None,
78
+ end_date=None,
79
+ ) -> pd.DataFrame:
80
+ r"""获取日频换手率。
81
+
82
+ A 股换手率 = 当日未复权成交量 ÷ 当日生效的自由流通股本(没有时用流通股本);
83
+ 美股换手率 = 当日未复权成交量 ÷ 当日已发行股数。结果是\ **小数**\ (0.01 即 1%)。
84
+ A 股结果与 factors-daybar 的因子(如 ``system/broker-daybar/TURN20``\ )读取的换手率同一口径。
85
+
86
+ :param order_book_ids: 单个代码或代码列表,如 ``"600000.XSHG"``、``"AAPL.US"``
87
+ :param start_date: 开始日期;只给一个日期时取那一天
88
+ :param end_date: 结束日期;两个都省略时各市场分别取最近两周内最后一个有行情的交易日
89
+
90
+ :returns: pandas.DataFrame,以 (order_book_id, date) 为索引,一列 ``turnover_rate``\ 。停牌日没有行;
91
+ 没有股本数据的证券或日子为 NaN。
92
+ """
93
+ order_book_ids = ensure_list_of_string(order_book_ids, "order_book_ids")
94
+ if not order_book_ids:
95
+ raise ValueError("order_book_ids: at least one order book id expected")
96
+ if start_date is not None:
97
+ start_date = to_date_str(start_date)
98
+ if end_date is not None:
99
+ end_date = to_date_str(end_date)
100
+ if start_date is not None and end_date is not None and start_date > end_date:
101
+ raise ValueError(
102
+ "invalid date range: [{!r}, {!r}]".format(start_date, end_date)
103
+ )
104
+ frame = get_client().get_turnover_rate(
105
+ order_book_ids=order_book_ids, start_date=start_date, end_date=end_date,
106
+ )
107
+ return _indexed(frame)
108
+
109
+
74
110
  def _indexed(frame):
75
111
  """服务端的扁平表(order_book_id, date, 字段...)-> (order_book_id, date) 索引;已带索引的原样返回。"""
76
112
  if not isinstance(frame, pd.DataFrame) or not {"order_book_id", "date"} <= set(frame.columns):