hamuna-quant-cli 0.1.22__tar.gz → 0.1.23__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 (40) hide show
  1. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/PKG-INFO +1 -1
  2. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/__init__.py +1 -1
  3. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/qmt_market.py +30 -47
  4. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/PKG-INFO +1 -1
  5. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/pyproject.toml +1 -1
  6. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/MANIFEST.in +0 -0
  7. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/README.md +0 -0
  8. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/README.md +0 -0
  9. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/__main__.py +0 -0
  10. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/_market_fallback.py +0 -0
  11. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/_metrics_15.py +0 -0
  12. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/_test_akquant_parity.py +0 -0
  13. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/akquant_data_adapter.py +0 -0
  14. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/akquant_runner.py +0 -0
  15. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/akquant_schema_adapter.py +0 -0
  16. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/base_strategy.py +0 -0
  17. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/cross_sectional_helpers.py +0 -0
  18. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/__init__.py +0 -0
  19. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/loader.py +0 -0
  20. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/qmt_broker.py +0 -0
  21. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/runner.py +0 -0
  22. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/live/server_market_client.py +0 -0
  23. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/prebuilt_downloader.py +0 -0
  24. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/prebuilt_resolver.py +0 -0
  25. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/qmt_translator.py +0 -0
  26. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/__init__.py +0 -0
  27. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/backtest.py +0 -0
  28. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/cache.py +0 -0
  29. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/discipline.py +0 -0
  30. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/http_client.py +0 -0
  31. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/s3client.py +0 -0
  32. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/runtime/server_client.py +0 -0
  33. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli/scripts/server.json +0 -0
  34. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/SOURCES.txt +0 -0
  35. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/dependency_links.txt +0 -0
  36. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/entry_points.txt +0 -0
  37. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/requires.txt +0 -0
  38. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/hamuna_quant_cli.egg-info/top_level.txt +0 -0
  39. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/setup.cfg +0 -0
  40. {hamuna_quant_cli-0.1.22 → hamuna_quant_cli-0.1.23}/tests/test_live_safety.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hamuna-quant-cli
3
- Version: 0.1.22
3
+ Version: 0.1.23
4
4
  Summary: Hamuna A 股回测 + 实盘统一 CLI (akquant 0.3.x). 替代 v1 自建 driver + QMT-style 策略规范.
5
5
  Author-email: Hamuna Team <team@hamuna.example>
6
6
  License: MIT
@@ -12,4 +12,4 @@ server (13-key metrics schema). 全部走 akquant 0.3.x 引擎.
12
12
  """
13
13
  from __future__ import annotations
14
14
 
15
- __version__ = "0.1.22"
15
+ __version__ = "0.1.23"
@@ -177,18 +177,17 @@ def _make_market_gateway() -> Any:
177
177
  self._tick_callback(raw)
178
178
 
179
179
  def _emit_bar(self, raw: dict[str, Any]) -> None:
180
- # Round 18.63.15: ts 用真实墙钟 (max(now, last+1ns)) — 之前 Round
181
- # 18.63.3 用 max(now, last+period_ns) 造"假递增日期", SSE 每秒推同一根
182
- # 当日 bar (time=00:00, volume 变) 时每根 +1 天 → 策略日期跳到未来
183
- # (2026-10/11 月), %H:%M 恒为启动时刻 — 用户实测报告 (11:02 恒不变).
184
- # 修: ts = max(now_ns, last_ns + 1) — 唯一递增 (流式每秒 1 根时墙钟
185
- # 天然不同; 批量推送时 +1ns 防碰撞), 日期 = 当天, %H:%M 随墙钟走.
186
- # QMT 真实 bar 时间 (epoch ms) 仍在 bar.extra['qmt_time_ms'] 可取.
187
- now_ns = time.time_ns()
188
- last_ns = getattr(self, "_last_bar_ts_ns", 0)
189
- ts_ns = max(now_ns, last_ns + 1) if last_ns else now_ns
190
- self._last_bar_ts_ns = ts_ns
191
- bar_obj = _to_bar_obj(raw, ts_ns=ts_ns)
180
+ # Round 18.63.16: bar.timestamp 直接用 SSE 推送的 QMT 真实 time
181
+ # (epoch ms), 不再生成/估计任何时间戳. 用户明确要求: 直接显示 SSE
182
+ # 推送时间戳, 且必须是 QMT 内部正确时间戳而非 CLI 生成估计.
183
+ # SSE bar dict 的 'time' 来自 QMT get_market_data_ex 的 time 列
184
+ # (bridge 原样透传, 见 _sse_push_bars_to 的 dict(zip(cols, last))),
185
+ # 实测 time=1788418800000 → 2026-09-03 15:00:00 (CST), 非生成.
186
+ # 之前 Round 18.63.3/15 用 period_ns / max(now,last+1) 造墙钟 ts →
187
+ # 用户实测 ts=11:02 恒不变 / 日期跳未来 — 均因没直接用 QMT 时间.
188
+ # 注: live 引擎不设 _active_start_time_ns (只有回测设), 故 QMT 当日
189
+ # bar (time=本日 00:00) 不会被_预热过滤_拦掉; 引擎不再需要墙钟递增.
190
+ bar_obj = _to_bar_obj(raw)
192
191
  if self._feed is not None:
193
192
  self._feed.add_bar(bar_obj)
194
193
  if self._bar_callback:
@@ -645,48 +644,32 @@ def _parse_tick_timestamp_ns(tick: dict[str, Any]) -> int:
645
644
  return 0
646
645
 
647
646
 
648
- def _to_bar_obj(raw: dict[str, Any], ts_ns: int | None = None):
647
+ def _to_bar_obj(raw: dict[str, Any]):
649
648
  """raw bar dict → akquant Bar 构造.
650
649
 
651
- Round 18.63+ 推送时间戳修复: akquant live 引擎对 on_bar 有
652
- ``_active_start_time_ns`` 预热过滤 — warmup 期间 bar 不调用户 on_bar.
653
- QMT 日线 bar 的 ``time`` 字段是当日 00:00, 永远早于盘中 session 启动
654
- 时间 → 全被当历史滤掉 → on_bar 永不触发 (Round 18.63 复现根因).
655
- 修: Bar.timestamp 用 wall-clock ns (或调用方传入的单调递增 ts_ns), 让
656
- 引擎当"实时新 bar"接收.
657
-
658
- Round 18.63.7 补充: 原始 QMT bar 的真实时间戳 ``raw['time']`` (epoch ms)
659
- 通过 Bar.extra={'qmt_time_ms'} 字段传给策略层 — 策略 on_bar 可读
660
- ``bar.extra.get('qmt_time_ms')`` 拿到 QMT 真实 bar 时间 (epoch ms).
661
- 注: raw['stime'] (YYYYMMDDhhmmss 字符串) **不放 extra** — akquant Bar
662
- 的 extra 字段是 f64 dict (Rust 侧冻结), 不接受 string. 如策略要 stime,
663
- 直接 qmt_time_ms // 1000 → datetime 转换.
664
-
665
- Round 18.63.8 修正: Bar.extra 是 f64 → string 写入会 TypeError.
666
- 修复: extra 只放数字 (qmt_time_ms). stime 通过 numeric qmt_time_ms 已足够
667
- 还原 (qmt_time_ms/1000 → epoch s → datetime → str).
650
+ Round 18.63.16 (最终版): Bar.timestamp **直接 = SSE 推送的 QMT 真实 time**
651
+ (epoch ms → ns). 用户明确要求: 显示 SSE 推送时间戳且必须是 QMT 内部正确
652
+ 时间戳, 不是 CLI 生成估计. SSE bar dict 的 'time' 来自 QMT
653
+ get_market_data_ex 的 time 列 (bridge _sse_push_bars_to 原样透传), 实测
654
+ time=1788418800000 → 2026-09-03 15:00:00 (CST) — QMT 真实时间, 非生成.
655
+
656
+ 不再做任何 wall-clock 合成 (移除 Round 18.63.3/9/15 的 ts_ns / period_ns /
657
+ max(now,last+1) fallback): live 引擎不设 _active_start_time_ns (只有回测
658
+ setattr), 故 QMT 当日 bar (time=本日 00:00 < 盘中启动) 不会被预热过滤拦掉,
659
+ 无需用墙钟时间戳"伪装"实时 bar. 引擎是否去重/触发由 QMT 真实时间决定,
660
+ 与显示一致.
661
+
662
+ raw['stime'] (YYYYMMDDhhmmss 字符串) 不放 extra — akquant Bar 的 extra
663
+ 是 f64 dict (Rust 侧冻结), 不收 string. 策略要 stime 可自行
664
+ qmt_time_ms // 1000 → datetime 转换.
668
665
  """
669
- import time as _t
670
666
  from akquant import Bar
671
- # Round 18.63.9: 让 Bar.timestamp 用 QMT 真实时间 (qmt_time_ms 转 ns) 而非
672
- # wall-clock ns. 副作用: QMT bar 时间可能早于 session 启动 → akquant live
673
- # 引擎 `_active_start_time_ns` 预热过滤会当历史 bar 滤掉 → warmup 永远攒
674
- # 不满 → on_bar 不触发. 修: 当 qmt_time_ms < 当前 wall-clock 时 (QMT bar
675
- # 在历史), 用 wall-clock + period_ns 偏移保持单调递增, 让 live feed 不丢
676
- # bar; 当 qmt_time_ms >= wall-clock 时 (盘中真推), 直接用 qmt_time_ms.
677
- # qmt_time_ms 仍进 extra — 策略可同时读 bar.timestamp 与 bar.extra 取
678
- # 不同时间. 详见策略 on_bar 的"qmt_stime" vs "cli_wall".
679
- wall_ns = _t.time_ns()
680
667
  qmt_ms = raw.get("time")
681
668
  if isinstance(qmt_ms, (int, float)) and qmt_ms > 0:
682
- qmt_ns = int(qmt_ms * 1_000_000) # ms → ns
683
- if qmt_ns >= wall_ns:
684
- ts = qmt_ns # 盘中真推: 直接用 QMT 时间
685
- else:
686
- # 历史 bar: fallback 到 wall-clock + period 偏移 (调用方传 ts_ns)
687
- ts = ts_ns if ts_ns is not None else wall_ns
669
+ ts = int(qmt_ms * 1_000_000) # QMT 真实 epoch ms → ns
688
670
  else:
689
- ts = ts_ns if ts_ns is not None else wall_ns
671
+ # 理论上 SSE/polling bar 恒带 time; 兜底用墙钟 (避免 Bar 构造崩溃).
672
+ ts = __import__("time").time_ns()
690
673
  # 把 QMT 真实时间塞 extra — Bar 构造时一次性传 (事后不可写, Rust 侧冻结).
691
674
  # extra 必须是 f64 dict, 跳过 None / 非数字字段 (Rust 侧拒收 string).
692
675
  extra: dict[str, float] = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hamuna-quant-cli
3
- Version: 0.1.22
3
+ Version: 0.1.23
4
4
  Summary: Hamuna A 股回测 + 实盘统一 CLI (akquant 0.3.x). 替代 v1 自建 driver + QMT-style 策略规范.
5
5
  Author-email: Hamuna Team <team@hamuna.example>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hamuna-quant-cli"
7
- version = "0.1.22"
7
+ version = "0.1.23"
8
8
  description = "Hamuna A 股回测 + 实盘统一 CLI (akquant 0.3.x). 替代 v1 自建 driver + QMT-style 策略规范."
9
9
  readme = "hamuna_quant_cli/README.md"
10
10
  requires-python = ">=3.10"