qka 2.4.4.dev2__tar.gz → 2.4.5__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 (32) hide show
  1. {qka-2.4.4.dev2 → qka-2.4.5}/PKG-INFO +1 -1
  2. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/data.py +36 -6
  3. {qka-2.4.4.dev2 → qka-2.4.5}/.github/workflows/release.yml +0 -0
  4. {qka-2.4.4.dev2 → qka-2.4.5}/.gitignore +0 -0
  5. {qka-2.4.4.dev2 → qka-2.4.5}/.vscode/settings.json +0 -0
  6. {qka-2.4.4.dev2 → qka-2.4.5}/CHANGELOG.md +0 -0
  7. {qka-2.4.4.dev2 → qka-2.4.5}/LICENSE +0 -0
  8. {qka-2.4.4.dev2 → qka-2.4.5}/README.md +0 -0
  9. {qka-2.4.4.dev2 → qka-2.4.5}/pyproject.toml +0 -0
  10. {qka-2.4.4.dev2 → qka-2.4.5}/qka/__init__.py +0 -0
  11. {qka-2.4.4.dev2 → qka-2.4.5}/qka/cli.py +0 -0
  12. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/__init__.py +0 -0
  13. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/accessor.py +0 -0
  14. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/analysis.py +0 -0
  15. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/backtest.py +0 -0
  16. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/broker.py +0 -0
  17. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/indicator.py +0 -0
  18. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/report.py +0 -0
  19. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/simulate.py +0 -0
  20. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/sizing.py +0 -0
  21. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/strategy.py +0 -0
  22. {qka-2.4.4.dev2 → qka-2.4.5}/qka/core/tdx.py +0 -0
  23. {qka-2.4.4.dev2 → qka-2.4.5}/qka/utils/__init__.py +0 -0
  24. {qka-2.4.4.dev2 → qka-2.4.5}/qka/utils/logger.py +0 -0
  25. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/SKILL.md +0 -0
  26. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/analysis.md +0 -0
  27. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/backtest.md +0 -0
  28. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/broker.md +0 -0
  29. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/data.md +0 -0
  30. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/sizing.md +0 -0
  31. {qka-2.4.4.dev2 → qka-2.4.5}/skills/qka/references/strategy.md +0 -0
  32. {qka-2.4.4.dev2 → qka-2.4.5}/tools/generate_api_ref.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qka
3
- Version: 2.4.4.dev2
3
+ Version: 2.4.5
4
4
  Summary: QKA(快量化 / Quant Kit for A-shares)- 简洁易用的 A 股量化回测框架
5
5
  Project-URL: Home, https://github.com/zsrl/qka
6
6
  Project-URL: Repository, https://github.com/zsrl/qka
@@ -1248,10 +1248,20 @@ class Data():
1248
1248
  return self._compute_qka_factor_cols(df, qka_specs)
1249
1249
 
1250
1250
  def _compute_qka_factor_cols(self, df, qka_specs, symbols=None):
1251
- """在已合并的 DataFrame 上计算 qka 内置指标。"""
1251
+ """在已合并的 DataFrame 上计算 qka 内置指标。
1252
+
1253
+ 因子定义的末位可以放一个 dict,作为**这一个因子自己的选项**,
1254
+ 只作用于它的计算,不影响别人、也不影响原始 returns:
1255
+ ('qka.alpha', 250, {'max_abs_return': 0.5})
1256
+ 超限的那天在因子眼里记空 —— 含这一天的滚动窗口就凑不满样本,
1257
+ 因子自然算不出来(作废),原始行情和 returns 一个字不动。
1258
+ """
1252
1259
  for col_key, spec in qka_specs:
1253
1260
  fn_name = spec[0].split('.', 1)[1] if spec[0].startswith('qka.') else spec[0]
1254
1261
  args = list(spec[1:])
1262
+ # 末位 dict = 该因子的选项;不是 dict 就照旧当位置参数传下去
1263
+ opts = args.pop() if args and isinstance(args[-1], dict) else {}
1264
+ lim = opts.get('max_abs_return')
1255
1265
 
1256
1266
  try:
1257
1267
  fn = getattr(indicator, fn_name)
@@ -1262,8 +1272,15 @@ class Data():
1262
1272
  # 为每只股票计算
1263
1273
  for symbol in (symbols if symbols is not None else self.symbols):
1264
1274
  col = f'{symbol}|{col_key}'
1275
+ work = df
1276
+ if lim:
1277
+ # 净化副本:只把这只票和基准的涨降幅超限处记空,别的列原样
1278
+ work = df.copy()
1279
+ for c in (f'{symbol}|returns', 'benchmark|returns'):
1280
+ if c in work.columns:
1281
+ work[c] = work[c].where(work[c].abs() <= lim)
1265
1282
  try:
1266
- df[col] = fn(df, symbol, *args)
1283
+ df[col] = fn(work, symbol, *args)
1267
1284
  except ValueError as e:
1268
1285
  logger.warning(f"计算 {col_key} 失败: {e}")
1269
1286
  df[col] = np.nan
@@ -1407,14 +1424,27 @@ class Data():
1407
1424
 
1408
1425
  @staticmethod
1409
1426
  def _spec_payload(spec):
1410
- """把一份因子定义转成可稳定序列化的结构;认不出返回 None。"""
1427
+ """把一份因子定义转成可稳定序列化的结构;认不出返回 None。
1428
+
1429
+ 末位的 dict 是「该因子自己的选项」(如 max_abs_return),也要进指纹 ——
1430
+ 选项变了,算出来的值就不一样,缓存必须跟着失效。
1431
+ """
1411
1432
  if callable(spec):
1412
1433
  src = _callable_source(spec)
1413
1434
  return None if src is None else {'fn': src}
1414
1435
  if isinstance(spec, (list, tuple)):
1415
- if all(isinstance(x, (str, int, float, bool)) for x in spec):
1416
- return list(spec)
1417
- return None
1436
+ items = []
1437
+ for x in spec:
1438
+ if isinstance(x, dict):
1439
+ if not all(isinstance(k, str) and isinstance(v, (str, int, float, bool))
1440
+ for k, v in x.items()):
1441
+ return None
1442
+ items.append({k: x[k] for k in sorted(x)})
1443
+ elif isinstance(x, (str, int, float, bool)):
1444
+ items.append(x)
1445
+ else:
1446
+ return None
1447
+ return items
1418
1448
  return None
1419
1449
 
1420
1450
  def _factor_cache_path(self, name: str, symbol: str) -> Path:
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