hamuna-quant-cli 0.1.13__tar.gz → 0.1.15__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.
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/PKG-INFO +1 -1
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/__init__.py +1 -1
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/qmt_market.py +43 -4
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/cache.py +17 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/PKG-INFO +1 -1
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/pyproject.toml +1 -1
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/MANIFEST.in +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/README.md +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/README.md +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/__main__.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/_market_fallback.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/_metrics_15.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/_test_akquant_parity.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/akquant_data_adapter.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/akquant_runner.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/akquant_schema_adapter.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/base_strategy.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/cross_sectional_helpers.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/__init__.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/loader.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/qmt_broker.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/runner.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/server_market_client.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/prebuilt_downloader.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/prebuilt_resolver.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/qmt_translator.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/__init__.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/backtest.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/discipline.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/http_client.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/s3client.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/server_client.py +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/scripts/server.json +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/SOURCES.txt +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/dependency_links.txt +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/entry_points.txt +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/requires.txt +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/top_level.txt +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/setup.cfg +0 -0
- {hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/tests/test_live_safety.py +0 -0
|
@@ -177,7 +177,18 @@ 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
|
-
|
|
180
|
+
# Round 18.63.3: bar 时间戳按 period 真实递增 — wall-clock time_ns()
|
|
181
|
+
# 在批量推送 (SSE batch / warmup 20 根) 时几乎相同, live feed 按
|
|
182
|
+
# 时间戳去重/聚合 (同刻 bar 只保留一根) → 交付给策略的 bar 数远少于
|
|
183
|
+
# 推送数 → warmup_period (30) 永远攒不满 → on_bar 永不触发.
|
|
184
|
+
# 修: 每根 bar ts = max(prev + period_ns, wall-clock), 保证唯一递增且
|
|
185
|
+
# 晚于 session 启动 (第一个 bar 用墙钟, 天然 > active_start).
|
|
186
|
+
period_ns = _period_ns(self._period)
|
|
187
|
+
now_ns = time.time_ns()
|
|
188
|
+
last_ns = getattr(self, "_last_bar_ts_ns", 0)
|
|
189
|
+
ts_ns = max(now_ns, last_ns + period_ns) 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)
|
|
181
192
|
if self._feed is not None:
|
|
182
193
|
self._feed.add_bar(bar_obj)
|
|
183
194
|
if self._bar_callback:
|
|
@@ -594,6 +605,23 @@ def _unwrap_envelope(resp: dict[str, Any]) -> Any:
|
|
|
594
605
|
return resp.get("value", resp)
|
|
595
606
|
|
|
596
607
|
|
|
608
|
+
def _period_ns(period: str) -> int:
|
|
609
|
+
"""QMT period 字符串 → 单根 bar 的名义时长 (ns). 用于 _emit_bar 时间戳递增.
|
|
610
|
+
|
|
611
|
+
Round 18.63.3: live feed 按时间戳去重/聚合, 同刻多根 bar 只保留一根 →
|
|
612
|
+
批量推送攒不满 warmup_period → on_bar 永不触发. 修: bar ts 按 period 真实
|
|
613
|
+
递增, 保证每根唯一. 无法识别时退回 1 分钟 (保守, 避免未来戳).
|
|
614
|
+
"""
|
|
615
|
+
p = str(period or "").strip().lower()
|
|
616
|
+
table = {
|
|
617
|
+
"1m": 60, "5m": 300, "15m": 900, "30m": 1800, "60m": 3600,
|
|
618
|
+
"1h": 3600, "4h": 14400, "1d": 86400, "day": 86400, "1w": 604800,
|
|
619
|
+
"week": 604800, "1mo": 2592000, "month": 2592000,
|
|
620
|
+
}
|
|
621
|
+
seconds = table.get(p, 60)
|
|
622
|
+
return int(seconds * 1_000_000_000)
|
|
623
|
+
|
|
624
|
+
|
|
597
625
|
def _bar_signature(bar: dict[str, Any]) -> tuple:
|
|
598
626
|
"""bar 摘要 — 推 on_bar 去重用.
|
|
599
627
|
|
|
@@ -633,11 +661,22 @@ def _parse_tick_timestamp_ns(tick: dict[str, Any]) -> int:
|
|
|
633
661
|
return 0
|
|
634
662
|
|
|
635
663
|
|
|
636
|
-
def _to_bar_obj(raw: dict[str, Any]):
|
|
637
|
-
"""raw bar dict → akquant Bar 构造.
|
|
664
|
+
def _to_bar_obj(raw: dict[str, Any], ts_ns: int | None = None):
|
|
665
|
+
"""raw bar dict → akquant Bar 构造.
|
|
666
|
+
|
|
667
|
+
Round 18.63+ 推送时间戳修复: akquant live 引擎对 on_bar 有
|
|
668
|
+
``_active_start_time_ns`` 预热过滤 — warmup 期间 bar 不调用户 on_bar.
|
|
669
|
+
QMT 日线 bar 的 ``time`` 字段是当日 00:00, 永远早于盘中 session 启动
|
|
670
|
+
时间 → 全被当历史滤掉 → on_bar 永不触发 (Round 18.63 复现根因).
|
|
671
|
+
修: Bar.timestamp 用 wall-clock ns (或调用方传入的单调递增 ts_ns), 让
|
|
672
|
+
引擎当"实时新 bar"接收. raw 的 ``time`` 字段保留给指标对齐/日志 (CLI 侧
|
|
673
|
+
_sse_dispatch 里 sig 去重用).
|
|
674
|
+
"""
|
|
675
|
+
import time as _t
|
|
638
676
|
from akquant import Bar
|
|
677
|
+
ts = ts_ns if ts_ns is not None else _t.time_ns()
|
|
639
678
|
return Bar(
|
|
640
|
-
timestamp=
|
|
679
|
+
timestamp=ts,
|
|
641
680
|
open=float(raw.get("open") or 0.0),
|
|
642
681
|
high=float(raw.get("high") or 0.0),
|
|
643
682
|
low=float(raw.get("low") or 0.0),
|
|
@@ -50,6 +50,23 @@ def cache_key(params: dict[str, Any]) -> str:
|
|
|
50
50
|
return hashlib.sha256(raw.encode()).hexdigest()[:16]
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
def make_key(endpoint: str, params: dict[str, Any] | None = None) -> str:
|
|
54
|
+
"""Round 18.63+ 补: http_client.py:174 (qmt_market snapshot 路径) 调
|
|
55
|
+
cache.make_key(endpoint, params) 期望 (endpoint, params) 签名 — 0.1.13 之前
|
|
56
|
+
该方法不存在, 触发 AttributeError 让 live market broker 整个 SSE/snapshot
|
|
57
|
+
推送瘫痪. 实际语义 = endpoint + sorted params, 短小适合本地缓存键.
|
|
58
|
+
|
|
59
|
+
与 cache_key(params) 区别: cache_key 只 hash params (适配 multi-endpoint),
|
|
60
|
+
make_key 把 endpoint 当 prefix, 跟 0.1.13 之后的调用约定一致.
|
|
61
|
+
"""
|
|
62
|
+
ep = (endpoint or "").strip("/")
|
|
63
|
+
if not params:
|
|
64
|
+
return ep
|
|
65
|
+
items = sorted((k, str(v)) for k, v in params.items() if v is not None)
|
|
66
|
+
suffix = "&".join(f"{k}={v}" for k, v in items)
|
|
67
|
+
return f"{ep}?{suffix}" if suffix else ep
|
|
68
|
+
|
|
69
|
+
|
|
53
70
|
def is_fresh(path: Path, endpoint: str) -> bool:
|
|
54
71
|
if not path.exists():
|
|
55
72
|
return False
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hamuna-quant-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.15"
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/_test_akquant_parity.py
RENAMED
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/akquant_data_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/akquant_schema_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/cross_sectional_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/live/server_market_client.py
RENAMED
|
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
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli/runtime/server_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{hamuna_quant_cli-0.1.13 → hamuna_quant_cli-0.1.15}/hamuna_quant_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|