qka 2.4.2.dev2__py3-none-any.whl → 2.4.3.dev2__py3-none-any.whl
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.
- qka/__init__.py +3 -1
- qka/core/data.py +72 -7
- qka/skills/qka/references/data.md +36 -0
- {qka-2.4.2.dev2.dist-info → qka-2.4.3.dev2.dist-info}/METADATA +1 -1
- {qka-2.4.2.dev2.dist-info → qka-2.4.3.dev2.dist-info}/RECORD +8 -8
- {qka-2.4.2.dev2.dist-info → qka-2.4.3.dev2.dist-info}/WHEEL +0 -0
- {qka-2.4.2.dev2.dist-info → qka-2.4.3.dev2.dist-info}/entry_points.txt +0 -0
- {qka-2.4.2.dev2.dist-info → qka-2.4.3.dev2.dist-info}/licenses/LICENSE +0 -0
qka/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@ except PackageNotFoundError:
|
|
|
13
13
|
|
|
14
14
|
# 核心功能直接导入
|
|
15
15
|
from qka.core.simulate import Simulate
|
|
16
|
-
from qka.core.data import Data
|
|
16
|
+
from qka.core.data import Data, set_tickflow_api_key
|
|
17
17
|
from qka.core.accessor import DataAccessor
|
|
18
18
|
from qka.core.backtest import Backtest
|
|
19
19
|
from qka.core.strategy import Strategy
|
|
@@ -33,6 +33,8 @@ __all__ = [
|
|
|
33
33
|
'Analysis', 'Segment', 'AlphaBeta',
|
|
34
34
|
# 通达信数据源
|
|
35
35
|
'set_tdx_root', 'get_tdx_root_info',
|
|
36
|
+
# TickFlow 凭据(进程级设一次)
|
|
37
|
+
'set_tickflow_api_key',
|
|
36
38
|
# 子模块
|
|
37
39
|
'core', 'utils'
|
|
38
40
|
]
|
qka/core/data.py
CHANGED
|
@@ -48,6 +48,51 @@ def _callable_source(fn):
|
|
|
48
48
|
return None
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
# ── TickFlow 凭据(进程级,设一次即可)──────────────────────────
|
|
52
|
+
# 放在模块级而不是 `Data` 参数里:「用哪个凭据」是部署级配置,不该每构造一次
|
|
53
|
+
# Data 就传一遍。优先级:set_tickflow_api_key() > 环境变量 > 免费档。
|
|
54
|
+
_TICKFLOW_API_KEY: Optional[str] = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def set_tickflow_api_key(api_key: Optional[str]) -> None:
|
|
58
|
+
"""设置 TickFlow API key(进程级,设一次即可)。
|
|
59
|
+
|
|
60
|
+
设了之后所有 `Data(source='tickflow')` 都走完整服务
|
|
61
|
+
(https://api.tickflow.org);不设则走免费档
|
|
62
|
+
(https://free-api.tickflow.org),与既有行为完全一致。
|
|
63
|
+
|
|
64
|
+
优先级:本函数设的值 > 环境变量 ``TICKFLOW_API_KEY`` > 免费档。
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
api_key: 密钥;传 None 或空串表示清除,回到免费档。
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
>>> from qka import Data, set_tickflow_api_key
|
|
71
|
+
>>> set_tickflow_api_key('tk_xxx')
|
|
72
|
+
>>> Data(symbols=['600519.SH']).get() # 已走完整服务
|
|
73
|
+
"""
|
|
74
|
+
global _TICKFLOW_API_KEY
|
|
75
|
+
_TICKFLOW_API_KEY = api_key or None
|
|
76
|
+
# 已经建好的客户端按旧 key 建的,作废掉 —— 否则「先建了免费档客户端、
|
|
77
|
+
# 后设 key」这条时间线会静默继续走免费档,既看不出来又难查。
|
|
78
|
+
Data._reset_tickflow_clients()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_tickflow_api_key() -> Optional[str]:
|
|
82
|
+
"""当前生效的 TickFlow key:函数设的优先,其次环境变量,都没有则 None。"""
|
|
83
|
+
return _TICKFLOW_API_KEY or os.environ.get('TICKFLOW_API_KEY') or None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _key_fingerprint(api_key: Optional[str]) -> str:
|
|
87
|
+
"""key 的短摘要,用作客户端缓存的键。
|
|
88
|
+
|
|
89
|
+
不拿明文 key 当字典键 —— 免得它出现在内存转储或日志里。
|
|
90
|
+
"""
|
|
91
|
+
if not api_key:
|
|
92
|
+
return ''
|
|
93
|
+
return hashlib.sha1(api_key.encode('utf-8')).hexdigest()[:12]
|
|
94
|
+
|
|
95
|
+
|
|
51
96
|
# 当日日线数据「可能已经生成」的时刻(本地时间)。一天以它为界切成前后两个时段:
|
|
52
97
|
# 17:00 之前,数据源手里最新的一根还是上一交易日,当天这根根本还没生成;
|
|
53
98
|
# 17:00 之后,当天的已经出完了,要补也就这一次。
|
|
@@ -1662,24 +1707,44 @@ class Data():
|
|
|
1662
1707
|
|
|
1663
1708
|
# ── TickFlow 数据源 ────────────────────────────────────────
|
|
1664
1709
|
|
|
1665
|
-
|
|
1710
|
+
_tf_clients = {} # {key 摘要: 客户端} —— 进程级复用;按 key 分开存,不同 key 不互相串
|
|
1666
1711
|
_tf_client_lock = threading.Lock()
|
|
1667
1712
|
|
|
1713
|
+
@classmethod
|
|
1714
|
+
def _reset_tickflow_clients(cls):
|
|
1715
|
+
"""丢掉已建好的 tickflow 客户端,下次按当前 key 重建。
|
|
1716
|
+
|
|
1717
|
+
由 `set_tickflow_api_key()` 调用:客户端一旦建好就缓存住,不清的话
|
|
1718
|
+
「先建了免费档客户端、后设 key」会静默继续走免费档。
|
|
1719
|
+
"""
|
|
1720
|
+
with cls._tf_client_lock:
|
|
1721
|
+
cls._tf_clients.clear()
|
|
1722
|
+
|
|
1668
1723
|
@classmethod
|
|
1669
1724
|
def _tickflow_client(cls):
|
|
1670
|
-
"""惰性创建并复用 TickFlow
|
|
1671
|
-
|
|
1725
|
+
"""惰性创建并复用 TickFlow 客户端。
|
|
1726
|
+
|
|
1727
|
+
有 key 走完整服务(api.tickflow.org),没有就走免费档
|
|
1728
|
+
(free-api.tickflow.org)。key 是**建客户端这一刻**现取的,
|
|
1729
|
+
所以设 key 的时机不必早于 import(见 `set_tickflow_api_key`)。
|
|
1730
|
+
"""
|
|
1731
|
+
key = get_tickflow_api_key()
|
|
1732
|
+
cache_key = _key_fingerprint(key)
|
|
1733
|
+
client = cls._tf_clients.get(cache_key)
|
|
1734
|
+
if client is None:
|
|
1672
1735
|
with cls._tf_client_lock:
|
|
1673
|
-
|
|
1736
|
+
client = cls._tf_clients.get(cache_key)
|
|
1737
|
+
if client is None:
|
|
1674
1738
|
from tickflow import TickFlow
|
|
1675
|
-
#
|
|
1739
|
+
# free() 会往 stdout 打一段带 emoji 的「免费档」说明。
|
|
1676
1740
|
# stdout 被重定向到文件、且编码非 UTF-8 时(如打包版把后端输出
|
|
1677
1741
|
# 写入 GBK 日志),print emoji 会抛 UnicodeEncodeError 而中断下载,
|
|
1678
1742
|
# 故创建期间丢弃其标准输出。(redirect_stdout 改的是全局 sys.stdout,
|
|
1679
1743
|
# 并发首次创建会互相覆盖,故用锁串行化。)
|
|
1680
1744
|
with contextlib.redirect_stdout(io.StringIO()):
|
|
1681
|
-
|
|
1682
|
-
|
|
1745
|
+
client = TickFlow(api_key=key) if key else TickFlow.free()
|
|
1746
|
+
cls._tf_clients[cache_key] = client
|
|
1747
|
+
return client
|
|
1683
1748
|
|
|
1684
1749
|
@staticmethod
|
|
1685
1750
|
def _split_symbol(symbol: str):
|
|
@@ -106,6 +106,42 @@ datadir/factors/{因子名}/{symbol}.parquet # 单列,日期索引
|
|
|
106
106
|
|
|
107
107
|
**作用范围**:只作用于默认(`lazy=False`)路径;`lazy=True`(回测走的那条)行为不变。不传 `factor_cache` 时,一切跟没有这个功能一样:不读、不写、不建目录。
|
|
108
108
|
|
|
109
|
+
### TickFlow 凭据
|
|
110
|
+
|
|
111
|
+
TickFlow 有两个入口,qka 按「有没有 key」自动选:
|
|
112
|
+
|
|
113
|
+
| 有没有 key | 走的入口 | 域名 |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| 有 | 完整服务 | `https://api.tickflow.org` |
|
|
116
|
+
| 没有 | 免费档 | `https://free-api.tickflow.org` |
|
|
117
|
+
|
|
118
|
+
不设 key 时与旧版行为完全一致(免费档提供日线、标的元信息、交易所、池子查询、复权因子;实时行情与分钟线是完整服务的能力)。
|
|
119
|
+
|
|
120
|
+
设 key 的方式是**进程级、设一次即可** —— 不用每次构造 `Data` 都传:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from qka import Data, set_tickflow_api_key
|
|
124
|
+
|
|
125
|
+
set_tickflow_api_key('tk_xxx') # 设一次,之后所有 source='tickflow' 的取数都生效
|
|
126
|
+
data = Data(symbols=['600519.SH']) # 不用再传任何东西
|
|
127
|
+
data.get()
|
|
128
|
+
|
|
129
|
+
set_tickflow_api_key(None) # 清除,回到免费档
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
优先级:**`set_tickflow_api_key()` > 环境变量 `TICKFLOW_API_KEY` > 免费档**(显式盖过隐式)。
|
|
133
|
+
|
|
134
|
+
不想改代码的话,部署时设环境变量即可:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
export TICKFLOW_API_KEY=tk_xxx
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
两点实现细节,用的时候心里有数:
|
|
141
|
+
|
|
142
|
+
- 读 key 的时机是**建客户端那一刻**,不是 `import` 时 —— 所以设 key 不必早于 `import qka`。
|
|
143
|
+
- 换 key(或从免费档切到 key)时,已建好的客户端会**自动作废重建**,不会继续沿用旧入口。
|
|
144
|
+
|
|
109
145
|
### 通达信数据源
|
|
110
146
|
|
|
111
147
|
`source='tdx'` 走本机安装的「支持 TQ 策略」通达信客户端(在进程内 `import tqcenter`,由客户端与本机 `TdxW.exe` 通信)。前提与边界:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
qka/__init__.py,sha256=
|
|
1
|
+
qka/__init__.py,sha256=xFkw3C-0TzeNkr5hPtz-0ZWwLao3cihUAUCXSE8FO1c,1183
|
|
2
2
|
qka/cli.py,sha256=12ZkbSZmE7hSmz5_O67gOXVKROIdymCQevnNfEOApd8,466
|
|
3
3
|
qka/core/__init__.py,sha256=kVhvzSA915MXOk9axq9T-COlv3OeTPfv2avX58WxElE,578
|
|
4
4
|
qka/core/accessor.py,sha256=iEZrteVe8nqv3s5Va2l3Vz50N2S6X0IOElKq9Ik3Wno,2893
|
|
5
5
|
qka/core/analysis.py,sha256=EXCO4qhzd2av5Yb4jihcNji1V-VFPOceUHKtg-q8bLs,11142
|
|
6
6
|
qka/core/backtest.py,sha256=kzMAFbyGFvGE--Qypiot6wAp0jTiEsOPbaPd8Zs3o1M,13541
|
|
7
7
|
qka/core/broker.py,sha256=FxeHh9qZ9M6FNFLd8EXwztA4kmC9zZzkrXin2hdVFa4,9662
|
|
8
|
-
qka/core/data.py,sha256=
|
|
8
|
+
qka/core/data.py,sha256=j5QNO_LbgU84mxC5rSIhyeaB-bL9HgTZUy5AelBYnVY,89607
|
|
9
9
|
qka/core/indicator.py,sha256=OId8bgYFCzDgjPr27rb6zHYxkPYX0XrjlWylGSQ2KCU,6447
|
|
10
10
|
qka/core/report.py,sha256=TaZoxWk7ZIPLhA9Ss9UOmxWY2ymzKJRUnxSzmyPcBTI,22386
|
|
11
11
|
qka/core/simulate.py,sha256=bdThckUFj0Y3GyAj5ahLIGv3HetJFTbyxbEcX2SUKn0,2915
|
|
@@ -18,11 +18,11 @@ qka/skills/qka/SKILL.md,sha256=lddd_JvGZ0x4JBlz_IB1cd4ScHRZ30-IC9SWI9Tjbvw,2132
|
|
|
18
18
|
qka/skills/qka/references/analysis.md,sha256=GdFbK3fa8sFgvcxJ1xzkToF4QwsCFXf_EgKb9bbRgwo,3587
|
|
19
19
|
qka/skills/qka/references/backtest.md,sha256=ZXL58zpuYHAJglPNk52an4fP3i0Ggnpuf0pg0QlbPk4,4803
|
|
20
20
|
qka/skills/qka/references/broker.md,sha256=wr62v1asRM-wBdsADIsB406eXm_ENYcrwGMANQobaa0,1083
|
|
21
|
-
qka/skills/qka/references/data.md,sha256=
|
|
21
|
+
qka/skills/qka/references/data.md,sha256=6mL44eGOk_xXLqQ62Wmv1DFYcXn3kayYWYWMd8-hFOk,28857
|
|
22
22
|
qka/skills/qka/references/sizing.md,sha256=3SsX2ddQoHjE177dberW0Q7wYxW-M_2DG_-sV3CCo9A,656
|
|
23
23
|
qka/skills/qka/references/strategy.md,sha256=-6xa_oigTTj77Siity5bTC5MbdF3UKfld9imnevlAAc,4455
|
|
24
|
-
qka-2.4.
|
|
25
|
-
qka-2.4.
|
|
26
|
-
qka-2.4.
|
|
27
|
-
qka-2.4.
|
|
28
|
-
qka-2.4.
|
|
24
|
+
qka-2.4.3.dev2.dist-info/METADATA,sha256=bOyyD3-Bjjlh5EzzCUtfEWKg69KNpvzgWiGTBhMadto,7545
|
|
25
|
+
qka-2.4.3.dev2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
26
|
+
qka-2.4.3.dev2.dist-info/entry_points.txt,sha256=quG9zg-rOKKtbg-6FiXkoxkUUTMltMBD0hZ0QUnJ6RM,37
|
|
27
|
+
qka-2.4.3.dev2.dist-info/licenses/LICENSE,sha256=3iIG35SnJNF11yIzm3vxa2QUvy9SS5rktM3O1DL2vqM,1075
|
|
28
|
+
qka-2.4.3.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|