libfinance 0.0.6__tar.gz → 0.1.2__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.
- libfinance-0.1.2/PKG-INFO +170 -0
- libfinance-0.1.2/README.md +157 -0
- libfinance-0.1.2/VERSION +1 -0
- libfinance-0.1.2/libfinance/__init__.py +50 -0
- libfinance-0.1.2/libfinance/api/calendar.py +205 -0
- libfinance-0.1.2/libfinance/api/corporate_actions.py +120 -0
- libfinance-0.1.2/libfinance/api/exfactor.py +40 -0
- libfinance-0.1.2/libfinance/api/factors.py +85 -0
- libfinance-0.1.2/libfinance/api/financials.py +112 -0
- libfinance-0.1.2/libfinance/api/get_price.py +177 -0
- libfinance-0.1.2/libfinance/api/index_components.py +58 -0
- libfinance-0.1.2/libfinance/api/industry.py +61 -0
- libfinance-0.1.2/libfinance/api/instrument.py +132 -0
- libfinance-0.1.2/libfinance/api/live_quote.py +63 -0
- libfinance-0.1.2/libfinance/api/shares.py +80 -0
- libfinance-0.1.2/libfinance/api/theme.py +59 -0
- libfinance-0.1.2/libfinance/client.py +475 -0
- libfinance-0.1.2/libfinance/subscribe/__init__.py +0 -0
- libfinance-0.1.2/libfinance/subscribe/md_protocol.py +646 -0
- libfinance-0.1.2/libfinance/subscribe/quote_api.py +549 -0
- libfinance-0.1.2/libfinance/utils/cache.py +177 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/utils/utils.py +11 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/utils/validators.py +0 -35
- libfinance-0.1.2/libfinance.egg-info/PKG-INFO +170 -0
- libfinance-0.1.2/libfinance.egg-info/SOURCES.txt +40 -0
- libfinance-0.1.2/libfinance.egg-info/requires.txt +7 -0
- libfinance-0.1.2/pyproject.toml +15 -0
- libfinance-0.1.2/test/test_client_api_contract.py +425 -0
- libfinance-0.1.2/test/test_client_reconnect.py +102 -0
- libfinance-0.1.2/test/test_contract.py +40 -0
- libfinance-0.1.2/test/test_docs_contract.py +170 -0
- libfinance-0.1.2/test/test_rpc_contract.py +81 -0
- libfinance-0.1.2/test/test_subscribe_live.py +314 -0
- libfinance-0.1.2/test/test_version.py +23 -0
- libfinance-0.0.6/PKG-INFO +0 -83
- libfinance-0.0.6/README.md +0 -74
- libfinance-0.0.6/libfinance/__init__.py +0 -22
- libfinance-0.0.6/libfinance/api/calendar.py +0 -129
- libfinance-0.0.6/libfinance/api/concept_components.py +0 -84
- libfinance-0.0.6/libfinance/api/get_price.py +0 -269
- libfinance-0.0.6/libfinance/api/index_components.py +0 -69
- libfinance-0.0.6/libfinance/api/instrument.py +0 -216
- libfinance-0.0.6/libfinance/client.py +0 -166
- libfinance-0.0.6/libfinance.egg-info/PKG-INFO +0 -83
- libfinance-0.0.6/libfinance.egg-info/SOURCES.txt +0 -21
- libfinance-0.0.6/libfinance.egg-info/requires.txt +0 -3
- libfinance-0.0.6/pyproject.toml +0 -11
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/api/__init__.py +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/utils/__init__.py +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/utils/datetime_func.py +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance/utils/decorators.py +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance.egg-info/dependency_links.txt +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/libfinance.egg-info/top_level.txt +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/setup.cfg +0 -0
- {libfinance-0.0.6 → libfinance-0.1.2}/setup.py +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: libfinance
|
|
3
|
+
Version: 0.1.2
|
|
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
|
+
**面向量化研究与回测的 Python 金融数据接口 —— A 股与美股,同一套术语**
|
|
22
|
+
|
|
23
|
+
[](https://pypi.org/project/libfinance/)
|
|
24
|
+
[](https://libfinance.readthedocs.io/zh-cn/latest/)
|
|
25
|
+
[](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
|
+
`libfinance` 让 A 股与美股使用同一套术语:证券标识的写法相同,查询函数与参数名相同,返回的表结构也相同。两个市场的差别落在数据上,不落在调用方式上。
|
|
39
|
+
|
|
40
|
+
覆盖行情、证券信息、交易日历、公司行动、财务数据及行业、指数与概念数据,并支持实时行情订阅。查询结果便于直接用于 pandas 分析。
|
|
41
|
+
|
|
42
|
+
研究需要的不只是历史数字,还包括明确的证券身份、当时有效的信息,以及一致的价格口径。`libfinance` 把这三件事写进了数据设计:
|
|
43
|
+
|
|
44
|
+
- **统一的证券标识符** —— 用 `<trading_code>.<namespace>` 表达证券,例如 `600000.XSHG`、`000001.XSHE`、`AAPL.US`,区分不同市场的同名代码;结合历史时点解析代码,减少更名与代码复用带来的歧义。
|
|
45
|
+
- **point-in-time 机制 `as_of`** —— 按历史时点还原证券池,并选择当时已披露的财务版本,帮助避免未来信息和幸存者偏差。
|
|
46
|
+
- **高质量的复权因子 `exfactor`** —— 结合公司行动处理价格可比性,提供不复权、前复权和后复权行情;通过 `get_ex_factor` 查看单次及累计因子,让价格变化有据可查。
|
|
47
|
+
|
|
48
|
+
## 安装
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install libfinance
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
从源码安装:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/StateOfTheArt-quant/libfinance.git
|
|
58
|
+
cd libfinance/python
|
|
59
|
+
pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
C++ 客户端(函数名、参数与 Python 版逐一相同,见 [cpp/README.md](cpp/README.md)):
|
|
63
|
+
|
|
64
|
+
```cpp
|
|
65
|
+
#include <libfinance/libfinance.hpp>
|
|
66
|
+
|
|
67
|
+
auto bars = libfinance::get_price({"000001.XSHE", "600000.XSHG"}, "2024-03-01", "2024-03-06");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 快速开始
|
|
71
|
+
|
|
72
|
+
按[安装与连接说明](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/installation.html)配置服务后,即可查询:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from libfinance import instruments, get_price, get_ex_factor
|
|
76
|
+
|
|
77
|
+
# 查询历史时点对应的证券信息。
|
|
78
|
+
print(instruments("600000.XSHG", as_of="2024-03-01"))
|
|
79
|
+
|
|
80
|
+
# 显式选择不复权,查看历史原始行情。
|
|
81
|
+
print(get_price(
|
|
82
|
+
["000001.XSHE", "600000.XSHG"],
|
|
83
|
+
"2024-03-01", "2024-03-06", adjust_type="none",
|
|
84
|
+
))
|
|
85
|
+
|
|
86
|
+
# 查看公司行动对应的单次及累计复权因子。
|
|
87
|
+
print(get_ex_factor("600000.XSHG", "2023-01-01", "2024-12-31"))
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
一分钟看懂这几行取到了什么,见[快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html)。
|
|
91
|
+
|
|
92
|
+
## A 股与美股共用一套术语
|
|
93
|
+
|
|
94
|
+
统一体现在三个层面。
|
|
95
|
+
|
|
96
|
+
| 层面 | 统一的内容 | 例 |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| 证券标识 | 写法都是 `<trading_code>.<namespace>`;命名空间的粒度取决于该市场消除歧义所需的范围 | `600000.XSHG`、`AAPL.US` |
|
|
99
|
+
| 函数与参数 | 两个市场调用同一组函数,参数名相同,`as_of` 与 `adjust_type` 的含义一致 | `get_price`、`instruments`、`get_dividends` |
|
|
100
|
+
| 返回结构 | 列名与索引一致;某个市场不适用或未提供的字段取 `NaN`,不另设一张表 | 美股的 `turnover`、`limit_up`、`limit_down` |
|
|
101
|
+
|
|
102
|
+
需要显式指定市场的,只有不涉及具体证券的查询:交易日历、全市场目录、数据覆盖范围。按证券查询时,命名空间已经给出了市场信息,列表里也可以混合两个市场的代码。
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from libfinance import instruments, get_trading_dates
|
|
106
|
+
|
|
107
|
+
instruments(["000001.XSHE", "AAPL.US"]) # 命名空间已给出市场
|
|
108
|
+
get_trading_dates("2024-01-01", "2024-01-31", market="us") # 不涉及具体证券
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
统一的是术语和调用约定,数据本身的差异依然存在。下表的「市场」一列标出了每类数据实际覆盖的市场,逐个接口的情况见[查美股](https://libfinance.readthedocs.io/zh-cn/latest/howto/us_market.html)。
|
|
112
|
+
|
|
113
|
+
## 数据覆盖
|
|
114
|
+
|
|
115
|
+
| 数据 | 市场 | 主要函数 | 说明 |
|
|
116
|
+
| --- | --- | --- | --- |
|
|
117
|
+
| 交易日历 | CN · US | `get_trading_dates` | 交易日、区间取日、前后推 N 个交易日 |
|
|
118
|
+
| 证券主数据 | CN · US | `all_instruments` | 代码、名称、类型、上市与退市日期 |
|
|
119
|
+
| 日频行情 | CN · US | `get_price` | 开高低收、成交量额,可复权 |
|
|
120
|
+
| 复权因子 | CN · US | `get_ex_factor` | 逐除权日的单次及累计因子 |
|
|
121
|
+
| 股本结构 | CN | `get_shares` | 逐交易日的总股本与流通股本 |
|
|
122
|
+
| 分红 / 拆股 / 配股 | CN · US | `get_dividends` | 除权事件,价格跳空的来源 |
|
|
123
|
+
| 分拆 | US | `get_spinoffs` | A 股不产生这类事件 |
|
|
124
|
+
| 财务报表(PIT) | CN | `get_pit_financials_ex` | 按季度取,带修订历史 |
|
|
125
|
+
| 财务衍生指标 | CN、US | `get_financial_metrics` | 按交易日的财务衍生指标 |
|
|
126
|
+
| 因子 | CN | `get_factor_exposure`、`list_factor_libraries`、`list_factors` | qlib、alpha158、Barra CNE5 风格 / 行业因子与描述符 |
|
|
127
|
+
| 行业分类 | CN / US | `get_instrument_industry`、`get_industry_constituents`、`get_industry_weights` | 申万、GICS 等分类体系 |
|
|
128
|
+
| 指数成分与权重 | CN | `get_index_weights` | 任意交易日的成分权重 |
|
|
129
|
+
| 概念板块成分 | CN | `get_concept_weights` | THS 概念分类 |
|
|
130
|
+
| 实时行情 | CN | `QuoteApi` | 订阅推送 |
|
|
131
|
+
|
|
132
|
+
覆盖到哪一年、更新到哪一天,取决于你连的那个服务。**不要照抄文档里的日期**,用[数据新鲜度](https://libfinance.readthedocs.io/zh-cn/latest/data/freshness.html)里的两个函数自己查。
|
|
133
|
+
|
|
134
|
+
## 概念设计
|
|
135
|
+
|
|
136
|
+
| 主题 | 解决的问题 |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| [统一的证券标识符](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) | 区分市场、证券身份及历史代码,准确关联不同数据 |
|
|
139
|
+
| [point-in-time 机制 as_of](https://libfinance.readthedocs.io/zh-cn/latest/concepts/point_in_time.html) | 还原历史证券池与可见财报,避免未来信息和幸存者偏差 |
|
|
140
|
+
| [高质量的复权因子 exfactor](https://libfinance.readthedocs.io/zh-cn/latest/concepts/exfactor.html) | 理解公司行动对价格的影响,以及三种价格口径的计算和用途 |
|
|
141
|
+
|
|
142
|
+
## 文档与示例
|
|
143
|
+
|
|
144
|
+
| | |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) | 概念设计、数据说明、操作指南与 API 参考 |
|
|
147
|
+
| [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) | The same documentation tree in English |
|
|
148
|
+
| [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) | 按数据族排序的可运行示例(Python 与 C++ 一一对应),与 API 参考对照阅读 |
|
|
149
|
+
| [🧩 操作指南](https://libfinance.readthedocs.io/zh-cn/latest/howto/index.html) | 取行情面板、PIT 回测、订阅实时行情等成套做法 |
|
|
150
|
+
| [🩺 故障排查](https://libfinance.readthedocs.io/zh-cn/latest/howto/troubleshooting.html) | 按**症状**编排:看到什么现象,就从哪一行开始 |
|
|
151
|
+
|
|
152
|
+
API 参考按合约信息和交易日历、行情信息、基本面信息、行业和概念信息、公司行动信息、实时行情分组,包含参数说明和带打印结果的场景示例。
|
|
153
|
+
|
|
154
|
+
## 社区
|
|
155
|
+
|
|
156
|
+
问题与需求请提 [Issue](https://github.com/StateOfTheArt-quant/libfinance/issues)。关注公众号获取更新:
|
|
157
|
+
|
|
158
|
+
<div align="center">
|
|
159
|
+
<img alt="微信公众号二维码" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/code.png" width="600" height="220">
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
## 仓库结构
|
|
163
|
+
|
|
164
|
+
| 目录 | 内容 |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| `contract/` | 各语言客户端共同遵守的契约:公开函数(名称、参数顺序与默认值、返回)与它们调用的服务端函数 |
|
|
167
|
+
| `contract/conformance/` | 同一组调用分别经 Python 与 C++ 客户端发给同一个服务端,逐项比对答案 |
|
|
168
|
+
| `python/` | Python 客户端(PyPI 上的 `libfinance`) |
|
|
169
|
+
| `cpp/` | C++ 客户端 |
|
|
170
|
+
| `docs/` | 文档(中英双语) |
|
|
@@ -0,0 +1,157 @@
|
|
|
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
|
+
**面向量化研究与回测的 Python 金融数据接口 —— A 股与美股,同一套术语**
|
|
9
|
+
|
|
10
|
+
[](https://pypi.org/project/libfinance/)
|
|
11
|
+
[](https://libfinance.readthedocs.io/zh-cn/latest/)
|
|
12
|
+
[](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
|
+
`libfinance` 让 A 股与美股使用同一套术语:证券标识的写法相同,查询函数与参数名相同,返回的表结构也相同。两个市场的差别落在数据上,不落在调用方式上。
|
|
26
|
+
|
|
27
|
+
覆盖行情、证券信息、交易日历、公司行动、财务数据及行业、指数与概念数据,并支持实时行情订阅。查询结果便于直接用于 pandas 分析。
|
|
28
|
+
|
|
29
|
+
研究需要的不只是历史数字,还包括明确的证券身份、当时有效的信息,以及一致的价格口径。`libfinance` 把这三件事写进了数据设计:
|
|
30
|
+
|
|
31
|
+
- **统一的证券标识符** —— 用 `<trading_code>.<namespace>` 表达证券,例如 `600000.XSHG`、`000001.XSHE`、`AAPL.US`,区分不同市场的同名代码;结合历史时点解析代码,减少更名与代码复用带来的歧义。
|
|
32
|
+
- **point-in-time 机制 `as_of`** —— 按历史时点还原证券池,并选择当时已披露的财务版本,帮助避免未来信息和幸存者偏差。
|
|
33
|
+
- **高质量的复权因子 `exfactor`** —— 结合公司行动处理价格可比性,提供不复权、前复权和后复权行情;通过 `get_ex_factor` 查看单次及累计因子,让价格变化有据可查。
|
|
34
|
+
|
|
35
|
+
## 安装
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install libfinance
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
从源码安装:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/StateOfTheArt-quant/libfinance.git
|
|
45
|
+
cd libfinance/python
|
|
46
|
+
pip install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
C++ 客户端(函数名、参数与 Python 版逐一相同,见 [cpp/README.md](cpp/README.md)):
|
|
50
|
+
|
|
51
|
+
```cpp
|
|
52
|
+
#include <libfinance/libfinance.hpp>
|
|
53
|
+
|
|
54
|
+
auto bars = libfinance::get_price({"000001.XSHE", "600000.XSHG"}, "2024-03-01", "2024-03-06");
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 快速开始
|
|
58
|
+
|
|
59
|
+
按[安装与连接说明](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/installation.html)配置服务后,即可查询:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from libfinance import instruments, get_price, get_ex_factor
|
|
63
|
+
|
|
64
|
+
# 查询历史时点对应的证券信息。
|
|
65
|
+
print(instruments("600000.XSHG", as_of="2024-03-01"))
|
|
66
|
+
|
|
67
|
+
# 显式选择不复权,查看历史原始行情。
|
|
68
|
+
print(get_price(
|
|
69
|
+
["000001.XSHE", "600000.XSHG"],
|
|
70
|
+
"2024-03-01", "2024-03-06", adjust_type="none",
|
|
71
|
+
))
|
|
72
|
+
|
|
73
|
+
# 查看公司行动对应的单次及累计复权因子。
|
|
74
|
+
print(get_ex_factor("600000.XSHG", "2023-01-01", "2024-12-31"))
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
一分钟看懂这几行取到了什么,见[快速开始](https://libfinance.readthedocs.io/zh-cn/latest/getting_started/quickstart.html)。
|
|
78
|
+
|
|
79
|
+
## A 股与美股共用一套术语
|
|
80
|
+
|
|
81
|
+
统一体现在三个层面。
|
|
82
|
+
|
|
83
|
+
| 层面 | 统一的内容 | 例 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| 证券标识 | 写法都是 `<trading_code>.<namespace>`;命名空间的粒度取决于该市场消除歧义所需的范围 | `600000.XSHG`、`AAPL.US` |
|
|
86
|
+
| 函数与参数 | 两个市场调用同一组函数,参数名相同,`as_of` 与 `adjust_type` 的含义一致 | `get_price`、`instruments`、`get_dividends` |
|
|
87
|
+
| 返回结构 | 列名与索引一致;某个市场不适用或未提供的字段取 `NaN`,不另设一张表 | 美股的 `turnover`、`limit_up`、`limit_down` |
|
|
88
|
+
|
|
89
|
+
需要显式指定市场的,只有不涉及具体证券的查询:交易日历、全市场目录、数据覆盖范围。按证券查询时,命名空间已经给出了市场信息,列表里也可以混合两个市场的代码。
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from libfinance import instruments, get_trading_dates
|
|
93
|
+
|
|
94
|
+
instruments(["000001.XSHE", "AAPL.US"]) # 命名空间已给出市场
|
|
95
|
+
get_trading_dates("2024-01-01", "2024-01-31", market="us") # 不涉及具体证券
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
统一的是术语和调用约定,数据本身的差异依然存在。下表的「市场」一列标出了每类数据实际覆盖的市场,逐个接口的情况见[查美股](https://libfinance.readthedocs.io/zh-cn/latest/howto/us_market.html)。
|
|
99
|
+
|
|
100
|
+
## 数据覆盖
|
|
101
|
+
|
|
102
|
+
| 数据 | 市场 | 主要函数 | 说明 |
|
|
103
|
+
| --- | --- | --- | --- |
|
|
104
|
+
| 交易日历 | CN · US | `get_trading_dates` | 交易日、区间取日、前后推 N 个交易日 |
|
|
105
|
+
| 证券主数据 | CN · US | `all_instruments` | 代码、名称、类型、上市与退市日期 |
|
|
106
|
+
| 日频行情 | CN · US | `get_price` | 开高低收、成交量额,可复权 |
|
|
107
|
+
| 复权因子 | CN · US | `get_ex_factor` | 逐除权日的单次及累计因子 |
|
|
108
|
+
| 股本结构 | CN | `get_shares` | 逐交易日的总股本与流通股本 |
|
|
109
|
+
| 分红 / 拆股 / 配股 | CN · US | `get_dividends` | 除权事件,价格跳空的来源 |
|
|
110
|
+
| 分拆 | US | `get_spinoffs` | A 股不产生这类事件 |
|
|
111
|
+
| 财务报表(PIT) | CN | `get_pit_financials_ex` | 按季度取,带修订历史 |
|
|
112
|
+
| 财务衍生指标 | CN、US | `get_financial_metrics` | 按交易日的财务衍生指标 |
|
|
113
|
+
| 因子 | CN | `get_factor_exposure`、`list_factor_libraries`、`list_factors` | qlib、alpha158、Barra CNE5 风格 / 行业因子与描述符 |
|
|
114
|
+
| 行业分类 | CN / US | `get_instrument_industry`、`get_industry_constituents`、`get_industry_weights` | 申万、GICS 等分类体系 |
|
|
115
|
+
| 指数成分与权重 | CN | `get_index_weights` | 任意交易日的成分权重 |
|
|
116
|
+
| 概念板块成分 | CN | `get_concept_weights` | THS 概念分类 |
|
|
117
|
+
| 实时行情 | CN | `QuoteApi` | 订阅推送 |
|
|
118
|
+
|
|
119
|
+
覆盖到哪一年、更新到哪一天,取决于你连的那个服务。**不要照抄文档里的日期**,用[数据新鲜度](https://libfinance.readthedocs.io/zh-cn/latest/data/freshness.html)里的两个函数自己查。
|
|
120
|
+
|
|
121
|
+
## 概念设计
|
|
122
|
+
|
|
123
|
+
| 主题 | 解决的问题 |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| [统一的证券标识符](https://libfinance.readthedocs.io/zh-cn/latest/concepts/security_identifiers.html) | 区分市场、证券身份及历史代码,准确关联不同数据 |
|
|
126
|
+
| [point-in-time 机制 as_of](https://libfinance.readthedocs.io/zh-cn/latest/concepts/point_in_time.html) | 还原历史证券池与可见财报,避免未来信息和幸存者偏差 |
|
|
127
|
+
| [高质量的复权因子 exfactor](https://libfinance.readthedocs.io/zh-cn/latest/concepts/exfactor.html) | 理解公司行动对价格的影响,以及三种价格口径的计算和用途 |
|
|
128
|
+
|
|
129
|
+
## 文档与示例
|
|
130
|
+
|
|
131
|
+
| | |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| [📘 中文文档](https://libfinance.readthedocs.io/zh-cn/latest/) | 概念设计、数据说明、操作指南与 API 参考 |
|
|
134
|
+
| [📗 English documentation](https://libfinance.readthedocs.io/en/latest/) | The same documentation tree in English |
|
|
135
|
+
| [💻 示例代码](https://github.com/StateOfTheArt-quant/libfinance/tree/main/example) | 按数据族排序的可运行示例(Python 与 C++ 一一对应),与 API 参考对照阅读 |
|
|
136
|
+
| [🧩 操作指南](https://libfinance.readthedocs.io/zh-cn/latest/howto/index.html) | 取行情面板、PIT 回测、订阅实时行情等成套做法 |
|
|
137
|
+
| [🩺 故障排查](https://libfinance.readthedocs.io/zh-cn/latest/howto/troubleshooting.html) | 按**症状**编排:看到什么现象,就从哪一行开始 |
|
|
138
|
+
|
|
139
|
+
API 参考按合约信息和交易日历、行情信息、基本面信息、行业和概念信息、公司行动信息、实时行情分组,包含参数说明和带打印结果的场景示例。
|
|
140
|
+
|
|
141
|
+
## 社区
|
|
142
|
+
|
|
143
|
+
问题与需求请提 [Issue](https://github.com/StateOfTheArt-quant/libfinance/issues)。关注公众号获取更新:
|
|
144
|
+
|
|
145
|
+
<div align="center">
|
|
146
|
+
<img alt="微信公众号二维码" src="https://raw.githubusercontent.com/StateOfTheArt-quant/libfinance/main/docs/_shared/_static/img/code.png" width="600" height="220">
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
## 仓库结构
|
|
150
|
+
|
|
151
|
+
| 目录 | 内容 |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `contract/` | 各语言客户端共同遵守的契约:公开函数(名称、参数顺序与默认值、返回)与它们调用的服务端函数 |
|
|
154
|
+
| `contract/conformance/` | 同一组调用分别经 Python 与 C++ 客户端发给同一个服务端,逐项比对答案 |
|
|
155
|
+
| `python/` | Python 客户端(PyPI 上的 `libfinance`) |
|
|
156
|
+
| `cpp/` | C++ 客户端 |
|
|
157
|
+
| `docs/` | 文档(中英双语) |
|
libfinance-0.1.2/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.2
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .client import init_client
|
|
2
|
+
|
|
3
|
+
# 不再 import 时连接 RPC(服务 A);第一次调用 libfinance.api.* 会按 client.py 的
|
|
4
|
+
# _DEFAULT_HOST/_DEFAULT_PORT 懒自动连接。两种方式指到别的服务端:
|
|
5
|
+
#
|
|
6
|
+
# 1. 环境变量(本地调试推荐,不用改代码):
|
|
7
|
+
# export LIBFINANCE_HOST=127.0.0.1
|
|
8
|
+
# export LIBFINANCE_PORT=8080
|
|
9
|
+
# 必须在 `import libfinance` 之前 export —— 取值发生在 import 时。
|
|
10
|
+
#
|
|
11
|
+
# 2. 显式调用:
|
|
12
|
+
# from libfinance import init_client
|
|
13
|
+
# init_client(host="127.0.0.1", port=8080)
|
|
14
|
+
#
|
|
15
|
+
# 两者都不设时连的是内置默认 libfinance.tech:8080,那是**生产环境**。
|
|
16
|
+
# 这样 RPC 服务未就绪时,libfinance.subscribe 等子模块也可以独立使用。
|
|
17
|
+
|
|
18
|
+
__all__ = ["__version__", "init_client"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _version():
|
|
22
|
+
"""The repository's one version (VERSION at its root), which the C++ client shares.
|
|
23
|
+
|
|
24
|
+
From a checkout it is read from that file; an installed package carries it in its metadata."""
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
checkout = Path(__file__).resolve().parents[1] # python/ in a checkout
|
|
27
|
+
if (checkout / "pyproject.toml").is_file() and (checkout / "VERSION").is_file():
|
|
28
|
+
return (checkout / "VERSION").read_text().strip()
|
|
29
|
+
try:
|
|
30
|
+
from importlib.metadata import version
|
|
31
|
+
return version("libfinance")
|
|
32
|
+
except Exception: # noqa: BLE001 -- neither a checkout nor installed
|
|
33
|
+
return "0+unknown"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__version__ = _version()
|
|
37
|
+
#from libfinance.api import *
|
|
38
|
+
def __go():
|
|
39
|
+
import sys
|
|
40
|
+
import importlib
|
|
41
|
+
import pkgutil
|
|
42
|
+
|
|
43
|
+
# 3.4 引入 asyncio,3.5 引入 async/await 语法,3.6 引入 async generator
|
|
44
|
+
async_syntax_supported = sys.version_info[:2] >= (3, 6)
|
|
45
|
+
|
|
46
|
+
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__, "libfinance."):
|
|
47
|
+
if module_name.startswith("libfinance.api") and not is_pkg:
|
|
48
|
+
importlib.import_module(module_name)
|
|
49
|
+
|
|
50
|
+
__go()
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
r"""交易日历。
|
|
4
|
+
|
|
5
|
+
服务端只出\ **两条原语\ **——会话集合(\ ``get_trading_calendar``)与这份集合的\ **\ 权威区间**
|
|
6
|
+
(\ ``get_calendar_coverage``\ )。区间切片、前后推 n 个交易日、是否交易日、区间计数,全是
|
|
7
|
+
在一个有序数组上做 bisect,在这里本地算:一个场所几千个日期、几十 KB、更新极慢,拉一次
|
|
8
|
+
缓存一天,比每问一个日期就走一次 RPC 划算得多。
|
|
9
|
+
|
|
10
|
+
**为什么必须一起取区间。** release 有一个 ``confirmed_through``——没人发布过的日子,
|
|
11
|
+
任何据此推出的答案都是猜的。只拿会话集合而不校验区间,本地 bisect 会把"查询超出确认
|
|
12
|
+
范围"悄悄变成"那几天没有交易",回测不会察觉自己少了几天。区间也不能用
|
|
13
|
+
``sessions[0]`` / ``sessions[-1]`` 顶替:端点是自然日,而最后一个会话是它之前的最后一个
|
|
14
|
+
**交易日**\ ,中间隔着周末与假期。
|
|
15
|
+
|
|
16
|
+
两者在 ``_calendar()`` 里\ **一次取回并一起缓存**\ :分两次取、各自缓存,中间服务端切了一版
|
|
17
|
+
就会拿到一对来自不同 release 的数据——用旧区间去校验新会话,而且没有任何迹象。
|
|
18
|
+
|
|
19
|
+
``market`` 默认 ``"cn"``\ 。服务端的 calendar 命名空间同时绑了 CN 与 US,不传 market 时
|
|
20
|
+
它无从选路会直接报错;给个默认值让既有调用继续工作,要美股传 ``market="us"``\ 。
|
|
21
|
+
"""
|
|
22
|
+
import json
|
|
23
|
+
|
|
24
|
+
import pandas as pd
|
|
25
|
+
|
|
26
|
+
from libfinance.client import get_client
|
|
27
|
+
from libfinance.utils.decorators import export_as_api, ttl_cache
|
|
28
|
+
|
|
29
|
+
DEFAULT_MARKET = "cn"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CalendarCoverageError(ValueError):
|
|
33
|
+
"""查询落在 release 确认过的区间之外。
|
|
34
|
+
|
|
35
|
+
这不是"那天没有交易"——是没人发布过那一天,所以任何答案都是猜的。宁可报错,
|
|
36
|
+
也不要让调用方拿到一个悄悄变短的结果。
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _to_timestamp(d):
|
|
41
|
+
return pd.Timestamp(d).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@ttl_cache(24 * 3600)
|
|
45
|
+
def _calendar(market=DEFAULT_MARKET):
|
|
46
|
+
"""(会话集合, 区间下界, 区间上界)。两条 RPC 一次取回,绑在同一个缓存条目上。"""
|
|
47
|
+
client = get_client()
|
|
48
|
+
sessions = pd.to_datetime(json.loads(client.get_trading_calendar(market=market)))
|
|
49
|
+
window = client.get_calendar_coverage(market=market)
|
|
50
|
+
return (
|
|
51
|
+
sessions,
|
|
52
|
+
_to_timestamp(window["history_start"]),
|
|
53
|
+
_to_timestamp(window["confirmed_through"]),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _sessions(market, *dates):
|
|
58
|
+
"""取会话集合,并确认每个被问到的日期都落在 release 确认过的区间内。"""
|
|
59
|
+
sessions, lower, upper = _calendar(market)
|
|
60
|
+
for value in dates:
|
|
61
|
+
if value < lower or value > upper:
|
|
62
|
+
raise CalendarCoverageError(
|
|
63
|
+
"{} 的查询 {} 超出 release 确认范围 {}..{}".format(
|
|
64
|
+
market, value.date(), lower.date(), upper.date()
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
return sessions
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@export_as_api
|
|
71
|
+
@ttl_cache(24 * 3600)
|
|
72
|
+
def get_all_trading_dates(market=DEFAULT_MARKET):
|
|
73
|
+
r"""获取全部交易日。
|
|
74
|
+
|
|
75
|
+
:param market: 市场,cn(默认)或 us
|
|
76
|
+
|
|
77
|
+
:returns: pandas.DatetimeIndex,当前日历内全部交易日。
|
|
78
|
+
"""
|
|
79
|
+
return _calendar(market)[0]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@export_as_api
|
|
83
|
+
def get_calendar_coverage(market=DEFAULT_MARKET):
|
|
84
|
+
r"""获取日历的权威区间——本 release 确认到哪一天。
|
|
85
|
+
|
|
86
|
+
:param market: 市场,cn(默认)或 us
|
|
87
|
+
|
|
88
|
+
:returns: dict,包含 history_start(历史起点)和 confirmed_through(确认上界),值为 pandas.Timestamp。
|
|
89
|
+
"""
|
|
90
|
+
_, lower, upper = _calendar(market)
|
|
91
|
+
return {"history_start": lower, "confirmed_through": upper}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@export_as_api
|
|
95
|
+
def get_trading_dates(start_date, end_date, market=DEFAULT_MARKET):
|
|
96
|
+
r"""获取某个区间的交易日期
|
|
97
|
+
|
|
98
|
+
:param start_date: 开始日期
|
|
99
|
+
:param end_date: 结束日期
|
|
100
|
+
:param market: 市场,cn(默认)或 us
|
|
101
|
+
|
|
102
|
+
:returns: pandas.DatetimeIndex,包含起止日期之间的交易日(含两端)。
|
|
103
|
+
"""
|
|
104
|
+
start_date, end_date = _to_timestamp(start_date), _to_timestamp(end_date)
|
|
105
|
+
sessions = _sessions(market, start_date, end_date)
|
|
106
|
+
left = sessions.searchsorted(start_date)
|
|
107
|
+
right = sessions.searchsorted(end_date, side="right")
|
|
108
|
+
return sessions[left:right]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@export_as_api
|
|
112
|
+
def get_previous_trading_date(date, n=1, market=DEFAULT_MARKET):
|
|
113
|
+
r"""获取指定日期之前的第 n 个交易日
|
|
114
|
+
|
|
115
|
+
:param date: 指定日期
|
|
116
|
+
:param n: 第 n 个交易日
|
|
117
|
+
:param market: 市场,cn(默认)或 us
|
|
118
|
+
|
|
119
|
+
:returns: pandas.Timestamp,严格早于输入日期的第 n 个交易日。
|
|
120
|
+
"""
|
|
121
|
+
date = _to_timestamp(date)
|
|
122
|
+
sessions = _sessions(market, date)
|
|
123
|
+
pos = sessions.searchsorted(date)
|
|
124
|
+
if pos < n:
|
|
125
|
+
# 旧实现在这里返回 sessions[0]。那是个**错误答案**:调用方要的是"往前第 n 个",
|
|
126
|
+
# 拿到的却是"最早的那个",且无从分辨。宁可报错。
|
|
127
|
+
raise CalendarCoverageError(
|
|
128
|
+
"{} 之前没有第 {} 个交易日;release 的第一个交易日是 {}".format(
|
|
129
|
+
date.date(), n, sessions[0].date()
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
return sessions[pos - n]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@export_as_api
|
|
136
|
+
def get_next_trading_date(date, n=1, market=DEFAULT_MARKET):
|
|
137
|
+
r"""获取指定日期之后的第 n 个交易日
|
|
138
|
+
|
|
139
|
+
:param date: 指定日期
|
|
140
|
+
:param n: 第 n 个交易日
|
|
141
|
+
:param market: 市场,cn(默认)或 us
|
|
142
|
+
|
|
143
|
+
:returns: pandas.Timestamp,严格晚于输入日期的第 n 个交易日。
|
|
144
|
+
"""
|
|
145
|
+
date = _to_timestamp(date)
|
|
146
|
+
sessions = _sessions(market, date)
|
|
147
|
+
pos = sessions.searchsorted(date, side="right")
|
|
148
|
+
if pos + n > len(sessions):
|
|
149
|
+
# 同上:旧实现返回 sessions[-1],那是"日历到头了"而不是"往后第 n 个"。
|
|
150
|
+
raise CalendarCoverageError(
|
|
151
|
+
"{} 之后没有第 {} 个交易日;release 确认到 {}".format(
|
|
152
|
+
date.date(), n, _calendar(market)[2].date()
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
return sessions[pos + n - 1]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@export_as_api
|
|
159
|
+
def is_trading_date(date, market=DEFAULT_MARKET):
|
|
160
|
+
r"""判断指定日期是否为交易日
|
|
161
|
+
|
|
162
|
+
:param date: 指定日期
|
|
163
|
+
:param market: 市场,cn(默认)或 us
|
|
164
|
+
|
|
165
|
+
:returns: bool,交易日为 True,非交易日为 False;超出日历范围会报错。
|
|
166
|
+
"""
|
|
167
|
+
date = _to_timestamp(date)
|
|
168
|
+
sessions = _sessions(market, date)
|
|
169
|
+
pos = sessions.searchsorted(date)
|
|
170
|
+
return pos < len(sessions) and sessions[pos] == date
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@export_as_api
|
|
174
|
+
def get_n_trading_dates_until(date, n, market=DEFAULT_MARKET):
|
|
175
|
+
r"""获取截至指定日期(含)的最后 n 个交易日
|
|
176
|
+
|
|
177
|
+
:param date: 指定日期
|
|
178
|
+
:param n: 交易日个数
|
|
179
|
+
:param market: 市场,cn(默认)或 us
|
|
180
|
+
|
|
181
|
+
:returns: pandas.DatetimeIndex,截至该日的最近 n 个交易日;历史不足 n 个时返回已有日期。
|
|
182
|
+
"""
|
|
183
|
+
date = _to_timestamp(date)
|
|
184
|
+
sessions = _sessions(market, date)
|
|
185
|
+
pos = sessions.searchsorted(date, side="right")
|
|
186
|
+
if pos >= n:
|
|
187
|
+
return sessions[pos - n:pos]
|
|
188
|
+
return sessions[:pos]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@export_as_api
|
|
192
|
+
def count_trading_dates(start_date, end_date, market=DEFAULT_MARKET):
|
|
193
|
+
r"""统计区间内的交易日数量
|
|
194
|
+
|
|
195
|
+
:param start_date: 开始日期
|
|
196
|
+
:param end_date: 结束日期
|
|
197
|
+
:param market: 市场,cn(默认)或 us
|
|
198
|
+
|
|
199
|
+
:returns: int,区间内的交易日数量(含两端)。
|
|
200
|
+
"""
|
|
201
|
+
start_date, end_date = _to_timestamp(start_date), _to_timestamp(end_date)
|
|
202
|
+
sessions = _sessions(market, start_date, end_date)
|
|
203
|
+
return int(
|
|
204
|
+
sessions.searchsorted(end_date, side="right") - sessions.searchsorted(start_date)
|
|
205
|
+
)
|