qka 2.2.0__tar.gz → 2.2.1.dev2__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.
- {qka-2.2.0 → qka-2.2.1.dev2}/PKG-INFO +1 -1
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/backtest.py +9 -1
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/data.py +12 -5
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/backtest.md +2 -1
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/data.md +13 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/strategy.md +17 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/.github/workflows/release.yml +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/.gitignore +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/.vscode/settings.json +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/CHANGELOG.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/LICENSE +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/README.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/pyproject.toml +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/__init__.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/cli.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/__init__.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/accessor.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/analysis.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/broker.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/indicator.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/report.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/sizing.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/core/strategy.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/utils/__init__.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/qka/utils/logger.py +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/SKILL.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/analysis.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/broker.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/skills/qka/references/sizing.md +0 -0
- {qka-2.2.0 → qka-2.2.1.dev2}/tools/generate_api_ref.py +0 -0
|
@@ -79,7 +79,7 @@ class Backtest:
|
|
|
79
79
|
|
|
80
80
|
def run(self, cash: float = 100000.0,
|
|
81
81
|
start_date: str = None, end_date: str = None,
|
|
82
|
-
benchmark: Optional[str] = None):
|
|
82
|
+
benchmark: Optional[str] = None, warmup: int = 0):
|
|
83
83
|
"""
|
|
84
84
|
执行回测
|
|
85
85
|
|
|
@@ -95,6 +95,10 @@ class Backtest:
|
|
|
95
95
|
end_date: 回测截止日期 YYYY-MM-DD,None 表示数据最晚日期
|
|
96
96
|
benchmark: 基准代码,如 '000300.SH'(沪深300)。
|
|
97
97
|
如果提供,会下载基准数据用于对比。
|
|
98
|
+
warmup: 指标预热天数(默认 0)。自动多读取 warmup 个交易日的历史数据用于
|
|
99
|
+
计算指标,使策略从第一个交易日起即拿到有效指标值,无需手写
|
|
100
|
+
warmup guard 跳过前 N 根 bar。仅用于计算,on_bar 调用次数不变。
|
|
101
|
+
显式传入(>0)时覆盖 Data 构造时的 warmup 设定。
|
|
98
102
|
|
|
99
103
|
Returns:
|
|
100
104
|
None。回测结果保存在 self.results、self.metrics、self.trade_history 中。
|
|
@@ -105,6 +109,10 @@ class Backtest:
|
|
|
105
109
|
self.strategy.sizing = SizingAccessor(self.strategy.broker)
|
|
106
110
|
self.strategy._data = DataAccessor()
|
|
107
111
|
|
|
112
|
+
# 指标预热:run 显式传入时覆盖 Data 构造时的 warmup 设定
|
|
113
|
+
if warmup > 0:
|
|
114
|
+
self.data.warmup = warmup
|
|
115
|
+
|
|
108
116
|
# 获取数据
|
|
109
117
|
raw = self.data.get(lazy=True, start_date=start_date, end_date=end_date)
|
|
110
118
|
|
|
@@ -74,6 +74,7 @@ class Data():
|
|
|
74
74
|
datadir: Optional[Path] = None,
|
|
75
75
|
indicators: Optional[dict] = None,
|
|
76
76
|
extra_fields: Optional[List[str]] = None,
|
|
77
|
+
warmup: int = 0,
|
|
77
78
|
):
|
|
78
79
|
"""
|
|
79
80
|
初始化数据对象
|
|
@@ -92,7 +93,11 @@ class Data():
|
|
|
92
93
|
可选值见 BAOSTOCK_EXTRA_FIELDS。追加的列同样遵循 {symbol}|{field} 命名,
|
|
93
94
|
如 'sh.600000|peTTM'。注意:首次下载后缓存字段固定,变更 extra_fields
|
|
94
95
|
会自动检测列缺失并重新下载对应股票。
|
|
95
|
-
|
|
96
|
+
|
|
97
|
+
warmup: 指标预热天数(默认 0)。回测/取数时自动多读取 warmup 个交易日的历史数据
|
|
98
|
+
用于计算指标,使第 1 个交易日即可拿到有效指标值,无需在策略里手写
|
|
99
|
+
`if len(hist) < N: continue` 跳过前 N 根 bar。仅用于计算,不会增加 on_bar 调用次数。
|
|
100
|
+
|
|
96
101
|
**1. 字典(混搭 ta 函数和自定义因子):**
|
|
97
102
|
```python
|
|
98
103
|
{
|
|
@@ -119,6 +124,7 @@ class Data():
|
|
|
119
124
|
self.adjust = adjust
|
|
120
125
|
self.source = source
|
|
121
126
|
self.pool_size = pool_size
|
|
127
|
+
self.warmup = warmup
|
|
122
128
|
|
|
123
129
|
# extra_fields 白名单校验 + 去重
|
|
124
130
|
self.extra_fields = []
|
|
@@ -668,12 +674,13 @@ class Data():
|
|
|
668
674
|
return df
|
|
669
675
|
|
|
670
676
|
def _min_rows_for_indicators(self):
|
|
671
|
-
"""
|
|
677
|
+
"""计算所有指标所需的最小行数(含显式预热天数)。
|
|
672
678
|
|
|
673
|
-
|
|
679
|
+
遍历所有指标条目的整数参数,取最大值作为窗口上限的保守估计,
|
|
680
|
+
再与显式 warmup 取较大者。
|
|
674
681
|
"""
|
|
675
682
|
if not self._indicators or not isinstance(self._indicators, dict):
|
|
676
|
-
return
|
|
683
|
+
return self.warmup
|
|
677
684
|
max_window = 0
|
|
678
685
|
for spec in self._indicators.values():
|
|
679
686
|
if callable(spec) or not isinstance(spec, (list, tuple)):
|
|
@@ -686,7 +693,7 @@ class Data():
|
|
|
686
693
|
for v in rest[idx:]:
|
|
687
694
|
if isinstance(v, int):
|
|
688
695
|
max_window = max(max_window, v)
|
|
689
|
-
return max_window
|
|
696
|
+
return max(max_window, self.warmup)
|
|
690
697
|
|
|
691
698
|
def _get_from_baostock(
|
|
692
699
|
self, symbol: str,
|
|
@@ -19,7 +19,7 @@ bt = Backtest(data, strategy)
|
|
|
19
19
|
|
|
20
20
|
### run()
|
|
21
21
|
|
|
22
|
-
`run(cash=100000.0, start_date=None, end_date=None, benchmark=None)`
|
|
22
|
+
`run(cash=100000.0, start_date=None, end_date=None, benchmark=None, warmup=0)`
|
|
23
23
|
|
|
24
24
|
执行回测。注入 broker/sizing/data 后遍历每个交易日,调用 `strategy.on_bar(date)`。
|
|
25
25
|
|
|
@@ -29,6 +29,7 @@ bt = Backtest(data, strategy)
|
|
|
29
29
|
| `start_date` | `None` | 回测起始日期 `'YYYY-MM-DD'` |
|
|
30
30
|
| `end_date` | `None` | 回测截止日期 |
|
|
31
31
|
| `benchmark` | `None` | 基准指数代码,baostock 格式如 `'sh.000300'` |
|
|
32
|
+
| `warmup` | `0` | 指标预热天数。自动多读 `warmup` 天历史计算指标,使策略第 1 个 bar 起指标即有效(无需手写 warmup guard)。on_bar 调用次数不变;显式传入(>0)时覆盖 Data 的 warmup 设定 |
|
|
32
33
|
|
|
33
34
|
> 500 bar 以上自动分块迭代,避免一次性加载全量数据。
|
|
34
35
|
|
|
@@ -26,6 +26,19 @@ data = Data(
|
|
|
26
26
|
| `benchmark` | `str` | `None` | 基准指数代码,如 `'sh.000300'`。下载后在 `get()` 结果中追加 `benchmark|returns` 列 |
|
|
27
27
|
| `indicators` | `dict` | `None` | 预计算指标,见下方 |
|
|
28
28
|
| `extra_fields` | `list[str]` | `None` | baostock 扩展字段(选股/估值用),见下方 |
|
|
29
|
+
| `warmup` | `int` | `0` | 指标预热天数。回测/取数时自动多读 `warmup` 个交易日历史用于计算指标,使第 1 个交易日即拿到有效指标值(无需手写跳过前 N 根 bar)。仅用于计算,不增加回测 bar 数 |
|
|
30
|
+
|
|
31
|
+
> **warmup(指标预热)**:若指标/因子需要较长历史窗口(如动量排名需看前 200 天),设 `warmup=200`。
|
|
32
|
+
> qka 会在 `[start_date, end_date]` 之前额外多读 `warmup` 天数据用于计算指标,但返回和回测仍严格从
|
|
33
|
+
> `start_date` 起——策略第 1 个 bar 指标即有值,无需 `continue` 跳过前 N 根 bar。
|
|
34
|
+
>
|
|
35
|
+
> ```python
|
|
36
|
+
> data = Data(
|
|
37
|
+
> symbols=['sz.000001'],
|
|
38
|
+
> indicators={'mom200': lambda df: df['close'].pct_change(200)},
|
|
39
|
+
> warmup=200, # 自定义指标 qka 推断不出窗口,显式声明预热天数
|
|
40
|
+
> )
|
|
41
|
+
> ```
|
|
29
42
|
|
|
30
43
|
`get()` 返回的 DataFrame 除了 `open/high/low/close/volume/amount` 六大基本列外,还自动内置一列:
|
|
31
44
|
|
|
@@ -24,6 +24,7 @@ class MyStrategy(Strategy):
|
|
|
24
24
|
| `__init__` | **必须**调用 `super().__init__()`。不需要传任何参数 |
|
|
25
25
|
| `on_bar` 签名 | 只有 `self` 和 `date`。**没有** `get` 参数(旧版 API,已废弃) |
|
|
26
26
|
| `self.params` | **不存在**。不要写 `self.params.get('fast', 5)`,直接用实例属性 |
|
|
27
|
+
| 预热 guard | **不要**手写 `if len(hist) < N: continue` 跳过前 N 根 bar。改用 `Data(warmup=N)` 或 `bt.run(warmup=N)`,qka 自动多读历史计算指标 |
|
|
27
28
|
|
|
28
29
|
`Backtest.run()` 在执行时注入以下属性:
|
|
29
30
|
|
|
@@ -75,6 +76,22 @@ hist = self.history('close', 20) # 最近 20 天的收盘价
|
|
|
75
76
|
| 列 | 股票代码 |
|
|
76
77
|
| 异常 | 因子不存在时返回空 DataFrame(有索引无列),不抛异常 |
|
|
77
78
|
|
|
79
|
+
### 指标预热(warmup)
|
|
80
|
+
|
|
81
|
+
若策略用到的指标/因子需要较长历史窗口(如动量排名需看前 200 天数据),**不要**在 `on_bar` 里
|
|
82
|
+
手写 `if len(hist) < N: continue` 跳过前 N 根 bar。改用 `Data(warmup=N)` 或 `bt.run(warmup=N)`,
|
|
83
|
+
qka 自动在 `[start_date, end_date]` 之前多读 `warmup` 天数据用于计算指标,但回测仍从 `start_date`
|
|
84
|
+
首个交易日开始(`on_bar` 调用次数不变),指标自始有效:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
data = Data(symbols=[...], indicators={...}, warmup=200) # 构造时声明
|
|
88
|
+
# 或
|
|
89
|
+
bt.run(warmup=200) # 回测时声明(覆盖 Data 的设定)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
> 注意:qka 只能从 ta 指标的整数参数自动推断预热窗口;自定义 lambda 指标推断不到,
|
|
93
|
+
> 必须显式用 `warmup` 声明窗口天数,否则开头一段仍为 `NaN`。
|
|
94
|
+
|
|
78
95
|
### self.broker / self.sizing
|
|
79
96
|
|
|
80
97
|
由 `Backtest.run()` 注入(见上方注入表),通过 `self.broker.buy()` / `self.broker.sell()` 和 `self.sizing.percent()` 等方法使用。详见 [Broker](#broker) 和 [SizingAccessor](#sizingaccessor) 独立章节。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|