mirror of
https://ghfast.top/https://github.com/aeroxw/easy_tdx_max.git
synced 2026-09-12 22:44:22 +08:00
- ZIG 右侧突破回补策略:MyTT 新增 ZIG 之字转向(未来函数,含前视偏差警示); 波谷启动建仓挂硬止损(OCO)→ 见顶清仓记前高 → 右侧突破回补;路径依赖不实现 entry_exit_masks(向量化守护测试白名单);含寻优预设网格与 --strategy-file 独立文件 - 交易时段感知刷新:realtime/session.py(09:15~11:30:30 / 13:00~15:05)+ GET /market/session;看板 30/60/120s 轮询休市自动暂停(三态状态栏 + 开关持久化 + 手动刷新不受限);SSE/WS 既有会话语义不动 - 120 分钟 K 线:/bars?category=MIN_120(MAC 原生 Period.MINS×120 优先, 2×60M 相邻聚合兜底,标准客户端上限 400 根);前端周期选择器同步 - 逐 bar 衍生字段:/bars 与 /bars/index 附带 pre_close/change/change_pct/ amplitude_pct(pre_close≤0.01 兜底防除零) - 159 只核心龙头池:数据资产取自 Fork(东财全行业龙头名单,四组分层); universe=core 接入 screen scan / SignalScanner / StrengthRanker / market strength; GET /market/core-leaders + WebUI「龙头池」页(搜索/个股详情) - 多 Provider LLM 直连:easy_tdx.ai + /llm/*(DeepSeek/通义/智谱/Kimi/MiniMax/ OpenAI/Claude/Ollama/自定义,openai 兼容 + anthropic 原生双协议); 配置落盘 ~/.easy_tdx/llm.json(WebUI「AI 设置」页 ⇆ 手工编辑双向兼容, 文件>环境变量>预设;key 脱敏回显/CLEAR 清除);「AI 解读」后台任务化 (复用 task_runner,提交+轮询,不占 HTTP 连接);思考型模型空白正文防御 (reasoning_content 耗尽 max_tokens → 可操作报错;默认 16000); AI 解读历史页(自动归档 Prompt/正文/策略上下文 + 去回测带参引导) - WebUI 加固:SPA fallback 对未知 /api/* 返回 JSON 404(不再 200 HTML 伪装解析错); index.html 一律 Cache-Control: no-store(防缓存旧资源引用);路由兜底重定向; 全局风险提示常驻底栏 + 龙头池/AI 解读针对性免责声明 - 测试:新增 9 个单测文件共 59 例;黄金基线仅新增 zig_breakout 条目(其余零漂移); 全量 1448 例通过
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
"""MyTT.ZIG 之字转向指标单元测试(借鉴 Fork 移植,v1.29)。
|
|
|
|
覆盖:边界输入(空/单根/零阈值)、单调序列恒等、V 型反转拐点标定、
|
|
阈值两种写法(5 与 0.05)等价、输出形状与有限性。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from easy_tdx.MyTT import ZIG
|
|
|
|
|
|
def test_zig_empty_and_single():
|
|
assert ZIG(np.array([]), 10).size == 0
|
|
single = ZIG(np.array([42.0]), 10)
|
|
assert single.shape == (1,) and single[0] == 42.0
|
|
|
|
|
|
def test_zig_zero_threshold_returns_self():
|
|
s = np.array([1.0, 5.0, 2.0, 8.0])
|
|
assert np.array_equal(ZIG(s, 0), s)
|
|
|
|
|
|
def test_zig_monotonic_series_identity():
|
|
"""单调序列无拐点,ZIG 退化为自身(RD 保留 3 位小数)。"""
|
|
line = np.linspace(1.0, 2.0, 50)
|
|
assert np.allclose(ZIG(line, 10), line, atol=1e-3)
|
|
|
|
|
|
def test_zig_v_shape_trough():
|
|
"""V 型反转:谷底被标为拐点,前后两段各自线性插值。"""
|
|
v = np.concatenate([np.linspace(100.0, 80.0, 30), np.linspace(80.0, 120.0, 40)])
|
|
z = ZIG(v, 5)
|
|
assert z.shape == v.shape
|
|
assert np.isfinite(z).all()
|
|
assert abs(z[0] - 100) < 0.01
|
|
assert abs(z[-1] - 120) < 0.01
|
|
# 谷底(两个 80 中的后者,上升段起点)被精确对齐
|
|
assert abs(z.min() - 80) < 0.01
|
|
assert abs(z[30] - 80) < 0.01
|
|
# 拐点间线性:下降段任意点是两端点的线性插值
|
|
assert abs(z[15] - (100 + 80) / 2) < 0.01
|
|
|
|
|
|
def test_zig_threshold_forms_equivalent():
|
|
s = 100 + 10 * np.sin(np.arange(80) / 6.0)
|
|
assert np.allclose(ZIG(s, 5), ZIG(s, 0.05), atol=1e-9)
|
|
|
|
|
|
def test_zig_zigzag_alternating_peaks():
|
|
"""标准锯齿:每个预设峰谷都应成为拐点(ZIG 值在拐点处触及其价格)。"""
|
|
seg = [10.0, 13.0, 10.0, 13.0, 10.0, 13.0] # ±30% 摆动,阈值 10% 必转向
|
|
s = np.array(seg)
|
|
z = ZIG(s, 10)
|
|
for i, price in enumerate(seg):
|
|
assert abs(z[i] - price) < 0.01, f"锯齿序列每根都是拐点: idx={i}"
|
|
|
|
|
|
def test_zig_noisy_series_shape():
|
|
rng = np.random.default_rng(7)
|
|
s = 100 + np.cumsum(rng.normal(0, 1.5, 200))
|
|
z = ZIG(s, 12)
|
|
assert z.shape == s.shape
|
|
assert np.isfinite(z).all()
|
|
assert z.min() >= s.min() - 1e-3 and z.max() <= s.max() + 1e-3
|