diff --git a/zhishi/.gitignore b/zhishi/.gitignore
new file mode 100644
index 0000000..a7698f3
--- /dev/null
+++ b/zhishi/.gitignore
@@ -0,0 +1,6 @@
+__pycache__/
+*.pyc
+.venv/
+.env
+.DS_Store
+*.log
diff --git a/zhishi/PARENT_NOTE.md b/zhishi/PARENT_NOTE.md
new file mode 100644
index 0000000..2469834
--- /dev/null
+++ b/zhishi/PARENT_NOTE.md
@@ -0,0 +1,3 @@
+## 姊妹投教产品(独立)
+
+仓库内 [`zhishi/`](./zhishi/) 为面向大陆 A股/港股通的投教产品 **知势**(独立品牌与契约,不互通账号计费)。详见 `zhishi/README.md`。
diff --git a/zhishi/README.md b/zhishi/README.md
new file mode 100644
index 0000000..c0cd67a
--- /dev/null
+++ b/zhishi/README.md
@@ -0,0 +1,37 @@
+# 知势 Zhishi — A股 / 港股通投教产品
+
+独立于 QuantRadar 的大陆投教产品:**复盘教练 + 课程框架自检**,不荐股。
+
+## 快速开始
+
+```bash
+cd zhishi
+python3 scripts/generate_fixtures.py # 生成 20 个教学案例日线
+python3 -m app # http://0.0.0.0:8787
+python3 -m unittest discover -s tests -v
+```
+
+环境变量见 [docs/DATA_SOURCES.md](docs/DATA_SOURCES.md)。默认 `ZHISHI_MODE=artifact`。
+
+## 文档
+
+| 文档 | 说明 |
+|------|------|
+| [docs/BRAND.md](docs/BRAND.md) | 品牌锁定 |
+| [docs/COMPLIANCE.md](docs/COMPLIANCE.md) | 禁荐股边界 |
+| [docs/TRUST_GATE.md](docs/TRUST_GATE.md) | 信任门控 |
+| [docs/WIREFRAMES.md](docs/WIREFRAMES.md) | 主路径线框 |
+| [docs/ENGINE_CONTRACT.md](docs/ENGINE_CONTRACT.md) | API 契约 |
+| [docs/DATA_SOURCES.md](docs/DATA_SOURCES.md) | 数据源授权 |
+| [docs/LICENSED_PARTNER.md](docs/LICENSED_PARTNER.md) | 持牌合作路径 |
+
+## 功能地图
+
+- H5:`/` 案例 → 自检 → 复盘本 → 错题本 → 港股通差异 → 会员定价
+- 小程序壳:[`miniprogram/`](miniprogram/)
+- SKU:免费 / ¥68 月 / ¥488 年 / ¥129 课包(mock 支付)
+- 法务:`/terms` `/privacy` `/disclaimer` `/methodology`
+
+## 拆仓说明
+
+本目录设计为**独立产品根**;可整体迁到单独 GitHub 仓库。勿与美股 QuantRadar 账号或订阅互通。
diff --git a/zhishi/app/__init__.py b/zhishi/app/__init__.py
new file mode 100644
index 0000000..d881e7d
--- /dev/null
+++ b/zhishi/app/__init__.py
@@ -0,0 +1,3 @@
+from __future__ import annotations
+
+# 知势应用包
diff --git a/zhishi/app/__main__.py b/zhishi/app/__main__.py
new file mode 100644
index 0000000..52f609b
--- /dev/null
+++ b/zhishi/app/__main__.py
@@ -0,0 +1,4 @@
+from app.server import main
+
+if __name__ == "__main__":
+ main()
diff --git a/zhishi/app/config.py b/zhishi/app/config.py
new file mode 100644
index 0000000..96e04b9
--- /dev/null
+++ b/zhishi/app/config.py
@@ -0,0 +1,31 @@
+"""知势 — 配置。默认 artifact,live 需显式开关 + token。"""
+from __future__ import annotations
+
+import os
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[1]
+FIXTURES = ROOT / "fixtures"
+CONTENT = ROOT / "content"
+
+HOST = os.environ.get("HOST", "0.0.0.0")
+PORT = int(os.environ.get("PORT", os.environ.get("ZHISHI_PORT", "8787")))
+MODE = os.environ.get("ZHISHI_MODE", "artifact").strip().lower()
+ALLOW_LIVE = os.environ.get("ZHISHI_ALLOW_LIVE", "0").strip() in {"1", "true", "yes"}
+TUSHARE_TOKEN = os.environ.get("TUSHARE_TOKEN", "").strip()
+SESSION_SECRET = os.environ.get("SESSION_SECRET", "zhishi-dev-secret-change-me")
+
+DISCLAIMER = "本产品为投资教育工具,不构成任何投资建议。市场有风险,决策须自负。"
+CONTRACT_VERSION = "1.0.0"
+
+# 知识付费 SKU(微信支付商品名须与此类目一致)
+SKUS = {
+ "free": {"name": "免费导读", "price_fen": 0, "period": None},
+ "monthly": {"name": "月度研习会员", "price_fen": 6800, "period": "month"},
+ "yearly": {"name": "年度研习会员", "price_fen": 48800, "period": "year"},
+ "course_traps": {"name": "课包·A股制度与行为陷阱", "price_fen": 12900, "period": None},
+}
+
+
+def live_eligible() -> bool:
+ return ALLOW_LIVE and bool(TUSHARE_TOKEN) and MODE == "live"
diff --git a/zhishi/app/engine/__init__.py b/zhishi/app/engine/__init__.py
new file mode 100644
index 0000000..e5684ef
--- /dev/null
+++ b/zhishi/app/engine/__init__.py
@@ -0,0 +1,10 @@
+from app.engine.data import load_bars, load_fixture
+from app.engine.score import analyze, fail_closed, posture_for
+
+__all__ = [
+ "analyze",
+ "fail_closed",
+ "load_bars",
+ "load_fixture",
+ "posture_for",
+]
diff --git a/zhishi/app/engine/data.py b/zhishi/app/engine/data.py
new file mode 100644
index 0000000..b470fd6
--- /dev/null
+++ b/zhishi/app/engine/data.py
@@ -0,0 +1,80 @@
+"""行情加载:默认 fixture;live 仅在授权后走 Tushare。"""
+from __future__ import annotations
+
+import json
+from pathlib import Path
+from typing import Any
+
+from app import config
+
+
+def _symbol_path(symbol: str) -> Path:
+ return config.FIXTURES / "ohlcv" / f"{symbol}.json"
+
+
+def load_fixture(symbol: str) -> dict[str, Any] | None:
+ path = _symbol_path(symbol)
+ if not path.is_file():
+ return None
+ with path.open(encoding="utf-8") as f:
+ return json.load(f)
+
+
+def load_bars(symbol: str, mode: str | None = None) -> dict[str, Any] | None:
+ mode = (mode or config.MODE).lower()
+ if mode == "live" and config.live_eligible():
+ live = _load_tushare(symbol)
+ if live is not None:
+ return live
+ # fail-closed:live 失败不静默编造
+ return None
+ return load_fixture(symbol)
+
+
+def _load_tushare(symbol: str) -> dict[str, Any] | None:
+ """可选依赖:未安装或失败则返回 None。"""
+ try:
+ import tushare as ts # type: ignore
+ except Exception:
+ return None
+ try:
+ pro = ts.pro_api(config.TUSHARE_TOKEN)
+ ts_code = _to_ts_code(symbol)
+ df = pro.daily(ts_code=ts_code, limit=120)
+ if df is None or df.empty:
+ return None
+ basic = pro.stock_basic(ts_code=ts_code, fields="ts_code,name,market,list_status")
+ name = str(basic.iloc[0]["name"]) if basic is not None and not basic.empty else symbol
+ bars = []
+ for _, row in df.sort_values("trade_date").iterrows():
+ bars.append(
+ {
+ "date": str(row["trade_date"]),
+ "open": float(row["open"]),
+ "high": float(row["high"]),
+ "low": float(row["low"]),
+ "close": float(row["close"]),
+ "volume": float(row["vol"]),
+ }
+ )
+ return {
+ "symbol": symbol,
+ "name": name,
+ "market": "A",
+ "is_st": "ST" in name.upper(),
+ "is_star_or_chinext": ts_code.startswith("688") or ts_code.startswith("300"),
+ "bars": bars,
+ "source": "tushare",
+ }
+ except Exception:
+ return None
+
+
+def _to_ts_code(symbol: str) -> str:
+ if symbol.startswith("6"):
+ return f"{symbol}.SH"
+ if symbol.startswith(("0", "3")):
+ return f"{symbol}.SZ"
+ if symbol.startswith(("4", "8")):
+ return f"{symbol}.BJ"
+ return f"{symbol}.SH"
diff --git a/zhishi/app/engine/score.py b/zhishi/app/engine/score.py
new file mode 100644
index 0000000..c62c545
--- /dev/null
+++ b/zhishi/app/engine/score.py
@@ -0,0 +1,230 @@
+"""A股制度门控 + 课程框架自检分(唯一 primary_score)。"""
+from __future__ import annotations
+
+from typing import Any
+
+from app.config import CONTRACT_VERSION, DISCLAIMER
+
+POSTURE_STRONG = "偏强学习态"
+POSTURE_NEUTRAL = "中性观察态"
+POSTURE_WEAK = "偏弱学习态"
+POSTURE_NODATA = "数据不足"
+
+
+def posture_for(score: int | None) -> str:
+ if score is None:
+ return POSTURE_NODATA
+ if score >= 70:
+ return POSTURE_STRONG
+ if score >= 40:
+ return POSTURE_NEUTRAL
+ return POSTURE_WEAK
+
+
+def fail_closed(symbol: str, error: str = "symbol_not_found") -> dict[str, Any]:
+ return {
+ "ok": False,
+ "contract_version": CONTRACT_VERSION,
+ "symbol": symbol,
+ "error": error,
+ "primary_score": None,
+ "posture": POSTURE_NODATA,
+ "gates": [],
+ "checklist": [],
+ "sample": False,
+ "degraded": False,
+ "warnings": [],
+ "disclaimer": DISCLAIMER,
+ }
+
+
+def analyze(payload: dict[str, Any]) -> dict[str, Any]:
+ """对已加载的 fixture/live payload 计算自检分。"""
+ bars = payload.get("bars") or []
+ if len(bars) < 20:
+ return fail_closed(str(payload.get("symbol", "")), "insufficient_bars")
+
+ closes = [float(b["close"]) for b in bars]
+ volumes = [float(b.get("volume") or 0) for b in bars]
+ highs = [float(b["high"]) for b in bars]
+ lows = [float(b["low"]) for b in bars]
+
+ last = closes[-1]
+ prev = closes[-2]
+ ma5 = sum(closes[-5:]) / 5
+ ma20 = sum(closes[-20:]) / 20
+ vol20 = sum(volumes[-20:]) / 20 or 1.0
+ vol_ratio = volumes[-1] / vol20
+
+ # 涨跌停近似:主板 10%,双创/科创 20%
+ limit_pct = 0.20 if payload.get("is_star_or_chinext") else 0.10
+ day_ret = (last - prev) / prev if prev else 0.0
+ near_limit = abs(day_ret) >= (limit_pct * 0.85)
+
+ is_st = bool(payload.get("is_st"))
+ market = payload.get("market") or "A"
+
+ gates = _build_gates(market=market, near_limit=near_limit, is_st=is_st, limit_pct=limit_pct)
+
+ checklist: list[dict[str, Any]] = []
+ # 1) 趋势结构 0-25
+ trend_score = 0
+ if last > ma20 > sum(closes[-60:]) / min(60, len(closes)) if len(closes) >= 60 else ma20:
+ trend_score = 22
+ reason = "收盘位于均线上方,教学上视为偏多结构(仅供框架练习)。"
+ elif last > ma20:
+ trend_score = 16
+ reason = "短中期均线偏多,但更长周期未确认。"
+ elif last > ma5:
+ trend_score = 10
+ reason = "仅短均线支撑,结构偏弱,适合作为观察教学案例。"
+ else:
+ trend_score = 4
+ reason = "价格位于主要均线下方,教学上归入偏弱结构。"
+ checklist.append(
+ {"id": "trend_structure", "title": "趋势结构(教学)", "score": trend_score, "max": 25, "reason": reason}
+ )
+
+ # 2) 量能配合 0-20
+ if 0.8 <= vol_ratio <= 1.8:
+ vol_score = 16
+ vol_reason = "量能处于常态区间,利于讨论「不追极端放量」。"
+ elif vol_ratio > 2.5:
+ vol_score = 6
+ vol_reason = "放量显著,教学重点:区分突破与接力风险。"
+ else:
+ vol_score = 10
+ vol_reason = "量能偏淡,强调流动性与滑点认知。"
+ checklist.append(
+ {"id": "volume_quality", "title": "量能质量(教学)", "score": vol_score, "max": 20, "reason": vol_reason}
+ )
+
+ # 3) 波动与涨跌停邻近 0-20
+ if near_limit:
+ lim_score = 4
+ lim_reason = f"接近约 {int(limit_pct*100)}% 涨跌停带,流动性与次日缺口是复盘重点。"
+ else:
+ range20 = (max(highs[-20:]) - min(lows[-20:])) / ma20 if ma20 else 0
+ lim_score = 16 if range20 < 0.25 else 10
+ lim_reason = "未贴涨跌停,可练习常规波动下的假设书写。"
+ checklist.append(
+ {
+ "id": "limit_proximity",
+ "title": "涨跌停邻近度(教学)",
+ "score": lim_score,
+ "max": 20,
+ "reason": lim_reason,
+ }
+ )
+
+ # 4) 制度风险项 0-20(ST / 次新简化)
+ if is_st:
+ inst_score = 2
+ inst_reason = "ST/*ST 标的:规则与退市风险教育优先于形态讨论。"
+ else:
+ inst_score = 16
+ inst_reason = "非 ST,制度风险项按常规教学权重计分。"
+ checklist.append(
+ {
+ "id": "institutional_risk",
+ "title": "制度风险(教学)",
+ "score": inst_score,
+ "max": 20,
+ "reason": inst_reason,
+ }
+ )
+
+ # 5) 复盘完备度占位 0-15(引擎侧给基准,用户写入假设后由复盘本加分在产品层)
+ review_score = 12
+ checklist.append(
+ {
+ "id": "review_ready",
+ "title": "复盘完备度(基准)",
+ "score": review_score,
+ "max": 15,
+ "reason": "写入「假设/失效条件」后,复盘本才算完成一次学习闭环。",
+ }
+ )
+
+ raw = sum(i["score"] for i in checklist)
+ primary = int(round(raw / sum(i["max"] for i in checklist) * 100))
+ # 门控惩罚:近涨跌停或 ST 额外下调,避免「高分+危险制度」
+ if near_limit:
+ primary = max(0, primary - 8)
+ if is_st:
+ primary = max(0, primary - 15)
+
+ return {
+ "ok": True,
+ "contract_version": CONTRACT_VERSION,
+ "symbol": payload.get("symbol"),
+ "name": payload.get("name") or payload.get("symbol"),
+ "market": market,
+ "primary_score": primary,
+ "posture": posture_for(primary),
+ "gates": gates,
+ "checklist": checklist,
+ "institutional_context": {
+ "near_limit": near_limit,
+ "is_st": is_st,
+ "is_star_or_chinext": bool(payload.get("is_star_or_chinext")),
+ "day_return_pct": round(day_ret * 100, 2),
+ "limit_band_pct": int(limit_pct * 100),
+ },
+ "sample": bool(payload.get("sample")),
+ "degraded": False,
+ "warnings": list(payload.get("warnings") or []),
+ "sources": [
+ {
+ "name": payload.get("source") or "fixture",
+ "role": "ohlcv",
+ "status": "ok",
+ }
+ ],
+ "as_of": bars[-1].get("date"),
+ "disclaimer": DISCLAIMER,
+ }
+
+
+def _build_gates(*, market: str, near_limit: bool, is_st: bool, limit_pct: float) -> list[dict[str, Any]]:
+ if market == "HKCONNECT":
+ return [
+ {
+ "id": "hkconnect_quota",
+ "title": "港股通额度与时段",
+ "passed": True,
+ "teaching": "港股通有交易时段与额度约束,教学自检需单独记住与 A 股差异。",
+ },
+ {
+ "id": "hkconnect_fx",
+ "title": "汇率与价差感知",
+ "passed": True,
+ "teaching": "报价与结算涉及汇率;复盘时记录汇率假设是否影响结论。",
+ },
+ {
+ "id": "t_plus_hk",
+ "title": "交收习惯差异",
+ "passed": True,
+ "teaching": "勿用 A 股 T+1 直觉硬套;以课程港股通篇为准。",
+ },
+ ]
+ return [
+ {
+ "id": "t1_settlement",
+ "title": "T+1 交收",
+ "passed": True,
+ "teaching": "当日成交的股票通常下一交易日才可了结,持有期与隔夜缺口必须进入假设。",
+ },
+ {
+ "id": "limit_liquidity",
+ "title": "涨跌停流动性",
+ "passed": not near_limit,
+ "teaching": f"接近约 {int(limit_pct*100)}% 涨跌停时,排队与打开风险优先于形态美丑。",
+ },
+ {
+ "id": "st_rules",
+ "title": "ST 与风险警示",
+ "passed": not is_st,
+ "teaching": "ST 标的以规则与退市教育为主,不作走势预测练习题。",
+ },
+ ]
diff --git a/zhishi/app/server.py b/zhishi/app/server.py
new file mode 100644
index 0000000..5f44893
--- /dev/null
+++ b/zhishi/app/server.py
@@ -0,0 +1,386 @@
+"""知势 HTTP 壳:stdlib,无强制第三方依赖。绑定 0.0.0.0:$PORT。"""
+from __future__ import annotations
+
+import json
+import re
+import secrets
+import time
+import urllib.parse
+from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
+from pathlib import Path
+from typing import Any
+
+from app import config
+from app.engine import analyze, fail_closed, load_bars
+
+STATIC = Path(__file__).resolve().parent / "static"
+CONTENT = config.CONTENT
+
+# 内存会话 / 复盘本 / 错题(MVP;生产换 DB)
+SESSIONS: dict[str, dict[str, Any]] = {}
+REVIEWS: dict[str, list[dict[str, Any]]] = {}
+DRILLS: dict[str, list[dict[str, Any]]] = {}
+REMINDERS: dict[str, list[dict[str, Any]]] = {}
+
+SYMBOL_RE = re.compile(r"^\d{6}$")
+HK_RE = re.compile(r"^\d{5}$")
+
+
+def _json_bytes(data: Any, code: int = 200) -> tuple[int, bytes, str]:
+ body = json.dumps(data, ensure_ascii=False).encode("utf-8")
+ return code, body, "application/json; charset=utf-8"
+
+
+def _read_json_file(path: Path) -> Any:
+ with path.open(encoding="utf-8") as f:
+ return json.load(f)
+
+
+def health() -> dict[str, Any]:
+ return {
+ "service": "zhishi",
+ "ok": True,
+ "contract_version": config.CONTRACT_VERSION,
+ "mode_default": config.MODE,
+ "data_path": "fixtures" if not config.live_eligible() else "tushare",
+ "live_eligible": config.live_eligible(),
+ "disclaimer": config.DISCLAIMER,
+ }
+
+
+def do_analyze(symbol: str, market: str = "A", mode: str | None = None, as_of: str | None = None) -> dict[str, Any]:
+ symbol = symbol.strip()
+ market = (market or "A").upper()
+ if market == "A" and not SYMBOL_RE.match(symbol):
+ return fail_closed(symbol, "invalid_symbol")
+ if market == "HKCONNECT" and not (HK_RE.match(symbol) or SYMBOL_RE.match(symbol)):
+ return fail_closed(symbol, "invalid_symbol")
+
+ payload = load_bars(symbol, mode=mode)
+ if payload is None:
+ # 港股通教学:尝试 hk fixture
+ if market == "HKCONNECT":
+ payload = load_bars(symbol, mode="artifact")
+ if payload is None:
+ return fail_closed(symbol, "symbol_not_found")
+
+ if market == "HKCONNECT":
+ payload = dict(payload)
+ payload["market"] = "HKCONNECT"
+
+ result = analyze(payload)
+ if as_of and result.get("ok"):
+ result["requested_as_of"] = as_of
+ return result
+
+
+class Handler(BaseHTTPRequestHandler):
+ server_version = "Zhishi/1.0"
+
+ def log_message(self, fmt: str, *args: Any) -> None:
+ # quieter default
+ sys_stderr = __import__("sys").stderr
+ sys_stderr.write("%s - %s\n" % (self.address_string(), fmt % args))
+
+ def _cors(self) -> None:
+ self.send_header("Access-Control-Allow-Origin", "*")
+ self.send_header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Session")
+ self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
+
+ def _send(self, code: int, body: bytes, content_type: str) -> None:
+ self.send_response(code)
+ self._cors()
+ self.send_header("Content-Type", content_type)
+ self.send_header("Content-Length", str(len(body)))
+ self.send_header("Cache-Control", "no-store")
+ self.end_headers()
+ self.wfile.write(body)
+
+ def do_OPTIONS(self) -> None: # noqa: N802
+ self.send_response(204)
+ self._cors()
+ self.end_headers()
+
+ def do_GET(self) -> None: # noqa: N802
+ parsed = urllib.parse.urlparse(self.path)
+ path = parsed.path
+ qs = urllib.parse.parse_qs(parsed.query)
+
+ if path == "/health":
+ code, body, ct = _json_bytes(health())
+ return self._send(code, body, ct)
+
+ if path == "/api/skus":
+ code, body, ct = _json_bytes({"ok": True, "skus": config.SKUS, "disclaimer": config.DISCLAIMER})
+ return self._send(code, body, ct)
+
+ if path == "/api/lessons":
+ return self._send(*_json_bytes({"ok": True, "lessons": _list_lessons()}))
+
+ if path.startswith("/api/lessons/"):
+ lid = path.rsplit("/", 1)[-1]
+ lesson = _load_lesson(lid)
+ if lesson is None:
+ return self._send(*_json_bytes({"ok": False, "error": "not_found"}, 404))
+ return self._send(*_json_bytes({"ok": True, "lesson": lesson}))
+
+ if path == "/api/cases":
+ idx = CONTENT / "cases" / "index.json"
+ cases = _read_json_file(idx) if idx.is_file() else []
+ free_only = qs.get("free", ["0"])[0] == "1"
+ if free_only:
+ cases = [c for c in cases if c.get("free_demo")]
+ return self._send(*_json_bytes({"ok": True, "cases": cases}))
+
+ if path == "/api/analyze":
+ symbol = (qs.get("symbol") or qs.get("ticker") or [""])[0]
+ market = (qs.get("market") or ["A"])[0]
+ mode = (qs.get("mode") or [None])[0]
+ as_of = (qs.get("as_of") or [None])[0]
+ result = do_analyze(symbol, market=market, mode=mode, as_of=as_of)
+ code = 200 if result.get("ok") else (400 if result.get("error") == "invalid_symbol" else 404)
+ return self._send(*_json_bytes(result, code))
+
+ if path == "/api/sample":
+ # 固定免费 Demo:600519
+ result = do_analyze("600519", mode="artifact")
+ result["sample"] = True
+ return self._send(*_json_bytes(result))
+
+ if path == "/api/hkconnect/checklist":
+ return self._send(*_json_bytes({"ok": True, "items": _hk_checklist_diff()}))
+
+ if path == "/api/me/reviews":
+ sid = self.headers.get("X-Session") or ""
+ return self._send(*_json_bytes({"ok": True, "reviews": REVIEWS.get(sid, [])}))
+
+ if path == "/api/me/drills":
+ sid = self.headers.get("X-Session") or ""
+ return self._send(*_json_bytes({"ok": True, "drills": DRILLS.get(sid, [])}))
+
+ if path == "/api/me/reminders":
+ sid = self.headers.get("X-Session") or ""
+ return self._send(*_json_bytes({"ok": True, "reminders": REMINDERS.get(sid, [])}))
+
+ # static / pages
+ if path == "/" or path == "/index.html":
+ return self._file(STATIC / "index.html", "text/html; charset=utf-8")
+ if path == "/app.css":
+ return self._file(STATIC / "app.css", "text/css; charset=utf-8")
+ if path == "/app.js":
+ return self._file(STATIC / "app.js", "application/javascript; charset=utf-8")
+ if path == "/terms":
+ return self._file(STATIC / "terms.html", "text/html; charset=utf-8")
+ if path == "/privacy":
+ return self._file(STATIC / "privacy.html", "text/html; charset=utf-8")
+ if path == "/disclaimer":
+ return self._file(STATIC / "disclaimer.html", "text/html; charset=utf-8")
+ if path == "/methodology":
+ return self._file(STATIC / "methodology.html", "text/html; charset=utf-8")
+ if path == "/pricing":
+ return self._file(STATIC / "pricing.html", "text/html; charset=utf-8")
+
+ self._send(*_json_bytes({"ok": False, "error": "not_found"}, 404))
+
+ def do_POST(self) -> None: # noqa: N802
+ parsed = urllib.parse.urlparse(self.path)
+ path = parsed.path
+ length = int(self.headers.get("Content-Length") or 0)
+ raw = self.rfile.read(length) if length else b"{}"
+ try:
+ data = json.loads(raw.decode("utf-8") or "{}")
+ except json.JSONDecodeError:
+ return self._send(*_json_bytes({"ok": False, "error": "invalid_json"}, 400))
+
+ if path == "/api/session":
+ sid = secrets.token_urlsafe(16)
+ plan = data.get("plan") or "free"
+ SESSIONS[sid] = {"plan": plan, "created": time.time()}
+ REVIEWS.setdefault(sid, [])
+ DRILLS.setdefault(sid, [])
+ REMINDERS.setdefault(sid, [])
+ return self._send(*_json_bytes({"ok": True, "session": sid, "plan": plan}))
+
+ if path == "/api/analyze":
+ symbol = str(data.get("symbol") or "")
+ market = str(data.get("market") or "A")
+ mode = (data.get("context") or {}).get("mode")
+ as_of = (data.get("context") or {}).get("as_of")
+ result = do_analyze(symbol, market=market, mode=mode, as_of=as_of)
+ code = 200 if result.get("ok") else (400 if result.get("error") == "invalid_symbol" else 404)
+ return self._send(*_json_bytes(result, code))
+
+ if path == "/api/reviews":
+ sid = self.headers.get("X-Session") or ""
+ if sid not in SESSIONS:
+ return self._send(*_json_bytes({"ok": False, "error": "login_required"}, 401))
+ entry = {
+ "id": secrets.token_hex(6),
+ "symbol": data.get("symbol"),
+ "name": data.get("name"),
+ "primary_score": data.get("primary_score"),
+ "posture": data.get("posture"),
+ "hypothesis": (data.get("hypothesis") or "").strip(),
+ "invalidation": (data.get("invalidation") or "").strip(),
+ "created_at": time.time(),
+ }
+ if not entry["hypothesis"] or not entry["invalidation"]:
+ return self._send(*_json_bytes({"ok": False, "error": "hypothesis_and_invalidation_required"}, 400))
+ REVIEWS.setdefault(sid, []).insert(0, entry)
+ # 自动创建次日复盘提醒
+ REMINDERS.setdefault(sid, []).append(
+ {
+ "id": secrets.token_hex(4),
+ "review_id": entry["id"],
+ "symbol": entry["symbol"],
+ "due_at": time.time() + 86400,
+ "kind": "next_day_review",
+ "done": False,
+ }
+ )
+ return self._send(*_json_bytes({"ok": True, "review": entry}))
+
+ if path == "/api/drills":
+ sid = self.headers.get("X-Session") or ""
+ if sid not in SESSIONS:
+ return self._send(*_json_bytes({"ok": False, "error": "login_required"}, 401))
+ item = {
+ "id": secrets.token_hex(6),
+ "prompt": data.get("prompt"),
+ "user_answer": data.get("user_answer"),
+ "correct": bool(data.get("correct")),
+ "explanation": data.get("explanation"),
+ "created_at": time.time(),
+ }
+ DRILLS.setdefault(sid, []).insert(0, item)
+ return self._send(*_json_bytes({"ok": True, "drill": item}))
+
+ if path == "/api/pay/mock_checkout":
+ # 微信小程序支付占位:返回 mock prepay 信息,生产换真实统一下单
+ sku_id = str(data.get("sku") or "")
+ sku = config.SKUS.get(sku_id)
+ if not sku:
+ return self._send(*_json_bytes({"ok": False, "error": "unknown_sku"}, 400))
+ if sku["price_fen"] <= 0:
+ return self._send(*_json_bytes({"ok": True, "sku": sku_id, "paid": True, "mock": True}))
+ return self._send(
+ *_json_bytes(
+ {
+ "ok": True,
+ "mock": True,
+ "sku": sku_id,
+ "name": sku["name"],
+ "price_fen": sku["price_fen"],
+ "prepay_id": f"mock_prepay_{sku_id}",
+ "message": "生产环境替换为微信统一下单;商品名必须为知识付费课包/研习会员。",
+ }
+ )
+ )
+
+ if path == "/api/reminders/complete":
+ sid = self.headers.get("X-Session") or ""
+ rid = data.get("id")
+ for r in REMINDERS.get(sid, []):
+ if r.get("id") == rid:
+ r["done"] = True
+ return self._send(*_json_bytes({"ok": True, "reminder": r}))
+ return self._send(*_json_bytes({"ok": False, "error": "not_found"}, 404))
+
+ self._send(*_json_bytes({"ok": False, "error": "not_found"}, 404))
+
+ def _file(self, path: Path, content_type: str) -> None:
+ if not path.is_file():
+ return self._send(*_json_bytes({"ok": False, "error": "not_found"}, 404))
+ body = path.read_bytes()
+ self._send(200, body, content_type)
+
+
+def _list_lessons() -> list[dict[str, Any]]:
+ lessons_dir = CONTENT / "lessons"
+ out = []
+ if not lessons_dir.is_dir():
+ return out
+ for p in sorted(lessons_dir.glob("*.md")):
+ meta = _parse_lesson_meta(p)
+ out.append(meta)
+ # hkconnect lessons
+ hk = CONTENT / "hkconnect"
+ if hk.is_dir():
+ for p in sorted(hk.glob("*.md")):
+ meta = _parse_lesson_meta(p)
+ meta["track"] = "hkconnect"
+ out.append(meta)
+ return out
+
+
+def _parse_lesson_meta(path: Path) -> dict[str, Any]:
+ text = path.read_text(encoding="utf-8")
+ title = path.stem
+ for line in text.splitlines():
+ if line.startswith("# "):
+ title = line[2:].strip()
+ break
+ return {
+ "id": path.stem,
+ "title": title,
+ "path": str(path.relative_to(CONTENT)),
+ "free": path.stem.startswith(("01-", "02-", "03-")),
+ }
+
+
+def _load_lesson(lesson_id: str) -> dict[str, Any] | None:
+ for folder in (CONTENT / "lessons", CONTENT / "hkconnect"):
+ path = folder / f"{lesson_id}.md"
+ if path.is_file():
+ return {
+ "id": lesson_id,
+ "title": _parse_lesson_meta(path)["title"],
+ "markdown": path.read_text(encoding="utf-8"),
+ "track": "hkconnect" if folder.name == "hkconnect" else "a",
+ }
+ return None
+
+
+def _hk_checklist_diff() -> list[dict[str, str]]:
+ return [
+ {
+ "id": "session",
+ "a_share": "连续竞价为主,有集合竞价",
+ "hkconnect": "需同时关注港股通开通时段与额度状态",
+ "teaching": "先确认「今天能不能通过港股通交易」,再谈形态。",
+ },
+ {
+ "id": "settlement",
+ "a_share": "T+1 股票交收直觉强",
+ "hkconnect": "交收与资金可用节奏不同,勿混用",
+ "teaching": "复盘本单独标注市场:A 或 港股通。",
+ },
+ {
+ "id": "fx",
+ "a_share": "人民币计价",
+ "hkconnect": "汇率影响真实盈亏体感",
+ "teaching": "假设里写清汇率是否纳入判断。",
+ },
+ {
+ "id": "limits",
+ "a_share": "涨跌停制度显著影响行为",
+ "hkconnect": "无 A 股式涨跌停,波动叙事不同",
+ "teaching": "不要把涨停板战术迁移到港股通标的。",
+ },
+ {
+ "id": "spread",
+ "a_share": "流动性分层看板块",
+ "hkconnect": "价差与深度可能更差",
+ "teaching": "自检增加「价差可接受吗」一项。",
+ },
+ ]
+
+
+def main() -> None:
+ server = ThreadingHTTPServer((config.HOST, config.PORT), Handler)
+ print(f"知势 listening on http://{config.HOST}:{config.PORT}", flush=True)
+ server.serve_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/zhishi/app/static/app.css b/zhishi/app/static/app.css
new file mode 100644
index 0000000..5192a7c
--- /dev/null
+++ b/zhishi/app/static/app.css
@@ -0,0 +1,166 @@
+:root {
+ --ink: #1a3a3a;
+ --accent: #b86e2c;
+ --paper0: #f7f3eb;
+ --paper1: #e8efea;
+ --line: rgba(26, 58, 58, 0.14);
+ --muted: rgba(26, 58, 58, 0.68);
+ --danger: #8b3a3a;
+ --radius: 4px;
+ --font-display: "Noto Serif SC", "Songti SC", serif;
+ --font-body: "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
+}
+
+* { box-sizing: border-box; }
+html, body {
+ margin: 0;
+ min-height: 100%;
+ color: var(--ink);
+ font-family: var(--font-body);
+ background:
+ radial-gradient(1200px 600px at 10% -10%, #dfece4 0%, transparent 55%),
+ radial-gradient(900px 500px at 100% 0%, #f0e2cf 0%, transparent 50%),
+ linear-gradient(180deg, var(--paper0), var(--paper1));
+}
+a { color: var(--accent); text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+.wrap {
+ width: min(920px, calc(100% - 2rem));
+ margin: 0 auto;
+ padding: 1.25rem 0 4rem;
+}
+
+.topbar {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 1rem;
+ margin-bottom: 2rem;
+ animation: rise 0.7s ease both;
+}
+.brand {
+ font-family: var(--font-display);
+ font-size: clamp(1.8rem, 4vw, 2.4rem);
+ letter-spacing: 0.08em;
+ margin: 0;
+}
+.brand span { color: var(--accent); }
+.nav { display: flex; flex-wrap: wrap; gap: 0.85rem; font-size: 0.92rem; }
+
+.hero {
+ margin-bottom: 2rem;
+ animation: rise 0.8s ease 0.05s both;
+}
+.hero h2 {
+ font-family: var(--font-display);
+ font-weight: 600;
+ font-size: clamp(1.35rem, 3vw, 1.85rem);
+ margin: 0 0 0.55rem;
+ max-width: 18em;
+}
+.hero p {
+ margin: 0;
+ color: var(--muted);
+ max-width: 36em;
+ line-height: 1.65;
+}
+
+.panel {
+ border-top: 1px solid var(--line);
+ padding: 1.25rem 0;
+ animation: rise 0.75s ease both;
+}
+.panel h3 {
+ font-family: var(--font-display);
+ font-size: 1.15rem;
+ margin: 0 0 0.75rem;
+}
+
+.row { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
+input[type="text"], textarea {
+ border: 1px solid var(--line);
+ background: rgba(255,255,255,0.55);
+ color: var(--ink);
+ border-radius: var(--radius);
+ padding: 0.65rem 0.75rem;
+ font: inherit;
+ min-width: min(100%, 220px);
+}
+textarea { width: 100%; min-height: 72px; resize: vertical; }
+button, .btn {
+ appearance: none;
+ border: 1px solid var(--ink);
+ background: var(--ink);
+ color: #f7f3eb;
+ border-radius: var(--radius);
+ padding: 0.65rem 1rem;
+ font: inherit;
+ cursor: pointer;
+ transition: transform 0.2s ease, background 0.2s ease;
+}
+button.secondary, .btn.secondary {
+ background: transparent;
+ color: var(--ink);
+}
+button:hover { transform: translateY(-1px); }
+
+.score-block {
+ display: grid;
+ gap: 0.35rem;
+ margin: 1rem 0 1.25rem;
+}
+.score-num {
+ font-family: var(--font-display);
+ font-size: 3.2rem;
+ line-height: 1;
+}
+.posture {
+ font-size: 1.15rem;
+ color: var(--accent);
+ letter-spacing: 0.04em;
+}
+
+.list { list-style: none; padding: 0; margin: 0; }
+.list li {
+ padding: 0.85rem 0;
+ border-bottom: 1px solid var(--line);
+}
+.list li:first-child { border-top: 1px solid var(--line); }
+.muted { color: var(--muted); font-size: 0.92rem; line-height: 1.55; }
+.tag {
+ display: inline-block;
+ font-size: 0.78rem;
+ border: 1px solid var(--line);
+ padding: 0.1rem 0.4rem;
+ margin-right: 0.35rem;
+}
+
+.disclaimer {
+ position: sticky;
+ bottom: 0;
+ margin-top: 2rem;
+ padding: 0.75rem 0;
+ border-top: 1px solid var(--line);
+ background: linear-gradient(180deg, transparent, var(--paper1) 30%);
+ font-size: 0.82rem;
+ color: var(--muted);
+ animation: fade 1s ease both;
+}
+
+.hidden { display: none !important; }
+.error { color: var(--danger); }
+
+@keyframes rise {
+ from { opacity: 0; transform: translateY(10px); }
+ to { opacity: 1; transform: none; }
+}
+@keyframes fade {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@media (max-width: 640px) {
+ .topbar { flex-direction: column; align-items: flex-start; }
+ .score-num { font-size: 2.6rem; }
+}
diff --git a/zhishi/app/static/app.js b/zhishi/app/static/app.js
new file mode 100644
index 0000000..89a35ec
--- /dev/null
+++ b/zhishi/app/static/app.js
@@ -0,0 +1,207 @@
+(() => {
+ const state = {
+ session: localStorage.getItem("zhishi_session") || "",
+ lastResult: null,
+ };
+
+ const $ = (id) => document.getElementById(id);
+
+ async function api(path, opts = {}) {
+ const headers = Object.assign({ "Content-Type": "application/json" }, opts.headers || {});
+ if (state.session) headers["X-Session"] = state.session;
+ const res = await fetch(path, { ...opts, headers });
+ return res.json();
+ }
+
+ async function ensureSession() {
+ if (state.session) return state.session;
+ const data = await api("/api/session", { method: "POST", body: "{}" });
+ state.session = data.session;
+ localStorage.setItem("zhishi_session", state.session);
+ return state.session;
+ }
+
+ function renderAnalyze(result) {
+ const err = $("analyze-error");
+ const box = $("result");
+ if (!result.ok) {
+ err.textContent = `无法自检:${result.error || "数据不足"}(fail-closed,不编造分数)`;
+ err.classList.remove("hidden");
+ box.classList.add("hidden");
+ state.lastResult = null;
+ return;
+ }
+ err.classList.add("hidden");
+ box.classList.remove("hidden");
+ state.lastResult = result;
+ $("score").textContent = String(result.primary_score);
+ $("posture").textContent = result.posture;
+ $("meta").textContent = `${result.symbol} ${result.name || ""} · as_of ${result.as_of || "—"} · ${result.market}`;
+ $("gates").innerHTML = (result.gates || [])
+ .map(
+ (g) =>
+ `
${g.passed ? "通过" : "关注"}${g.title}${g.teaching}
`
+ )
+ .join("");
+ $("checklist").innerHTML = (result.checklist || [])
+ .map(
+ (c) =>
+ `${c.title} · ${c.score}/${c.max}${c.reason}
`
+ )
+ .join("");
+ }
+
+ async function loadCases() {
+ const data = await api("/api/cases?free=0");
+ const free = (data.cases || []).filter((c) => c.free_demo);
+ const rest = (data.cases || []).filter((c) => !c.free_demo).slice(0, 5);
+ const all = free.concat(rest);
+ $("case-list").innerHTML = all
+ .map(
+ (c) =>
+ `${c.summary}
`
+ )
+ .join("");
+ document.querySelectorAll(".case-btn").forEach((btn) => {
+ btn.addEventListener("click", async () => {
+ $("symbol").value = btn.dataset.symbol;
+ const result = await api(`/api/analyze?symbol=${btn.dataset.symbol}&market=A&mode=artifact`);
+ renderAnalyze(result);
+ location.hash = "#check";
+ });
+ });
+ }
+
+ async function loadLessons() {
+ const data = await api("/api/lessons");
+ $("lesson-list").innerHTML = (data.lessons || [])
+ .map(
+ (l) =>
+ `${l.track === "hkconnect" ? "[港股通] " : ""}${l.title}`
+ )
+ .join("");
+ document.querySelectorAll(".lesson-link").forEach((a) => {
+ a.addEventListener("click", async (e) => {
+ e.preventDefault();
+ const lesson = await api(`/api/lessons/${a.dataset.id}`);
+ if (!lesson.ok) return;
+ $("lesson-view").classList.remove("hidden");
+ $("lesson-title").textContent = lesson.lesson.title;
+ $("lesson-body").textContent = lesson.lesson.markdown;
+ });
+ });
+ $("lesson-close").addEventListener("click", () => $("lesson-view").classList.add("hidden"));
+ }
+
+ async function refreshReviews() {
+ await ensureSession();
+ const data = await api("/api/me/reviews");
+ const items = data.reviews || [];
+ $("review-list").innerHTML = items.length
+ ? items
+ .map(
+ (r) =>
+ `${r.symbol} ${r.name || ""} · ${r.posture} · 分 ${r.primary_score}假设:${r.hypothesis}
失效:${r.invalidation}
`
+ )
+ .join("")
+ : `尚无记录。完成一次自检并写入假设。`;
+ const rem = await api("/api/me/reminders");
+ const reminders = rem.reminders || [];
+ $("reminder-list").innerHTML = reminders.length
+ ? reminders
+ .map(
+ (r) =>
+ `${r.done ? "已完成" : "待复盘"} · ${r.symbol} · ${r.kind} `
+ )
+ .join("")
+ : `写入复盘本后会自动生成次日提醒。`;
+ document.querySelectorAll(".rem-done").forEach((btn) => {
+ btn.addEventListener("click", async () => {
+ await api("/api/reminders/complete", { method: "POST", body: JSON.stringify({ id: btn.dataset.id }) });
+ refreshReviews();
+ });
+ });
+ }
+
+ const DRILL = {
+ prompt: "A 股当日买入的股票,通常最早何时可以卖出?",
+ options: {
+ a: "当日随时可卖",
+ b: "下一交易日(T+1)",
+ c: "一周后",
+ },
+ answer: "b",
+ explanation: "A 股股票实行 T+1:当日买入,下一交易日才能卖出。这是复盘必须写入的持有期约束。",
+ };
+
+ function setupDrill() {
+ $("drill-q").textContent = `${DRILL.prompt}\nA. ${DRILL.options.a}\nB. ${DRILL.options.b}\nC. ${DRILL.options.c}`;
+ document.querySelectorAll(".drill-ans").forEach((btn) => {
+ btn.addEventListener("click", async () => {
+ await ensureSession();
+ const correct = btn.dataset.answer === DRILL.answer;
+ $("drill-feedback").textContent = correct ? "正确。" + DRILL.explanation : "未答对。" + DRILL.explanation;
+ if (!correct) {
+ await api("/api/drills", {
+ method: "POST",
+ body: JSON.stringify({
+ prompt: DRILL.prompt,
+ user_answer: btn.dataset.answer,
+ correct: false,
+ explanation: DRILL.explanation,
+ }),
+ });
+ const drills = await api("/api/me/drills");
+ $("drill-list").innerHTML = (drills.drills || [])
+ .map((d) => `${d.prompt} → 你的答案 ${d.user_answer}`)
+ .join("");
+ }
+ });
+ });
+ }
+
+ async function loadHk() {
+ const data = await api("/api/hkconnect/checklist");
+ $("hk-list").innerHTML = (data.items || [])
+ .map(
+ (i) =>
+ `${i.id}A股:${i.a_share}
港股通:${i.hkconnect}
教学:${i.teaching}
`
+ )
+ .join("");
+ }
+
+ $("btn-analyze").addEventListener("click", async () => {
+ const symbol = $("symbol").value.trim();
+ const market = $("market").value;
+ const result = await api(`/api/analyze?symbol=${encodeURIComponent(symbol)}&market=${market}`);
+ renderAnalyze(result);
+ });
+
+ $("btn-sample").addEventListener("click", async () => {
+ const result = await api("/api/sample");
+ $("symbol").value = result.symbol || "600519";
+ renderAnalyze(result);
+ });
+
+ $("btn-save-review").addEventListener("click", async () => {
+ await ensureSession();
+ if (!state.lastResult) return;
+ const payload = {
+ symbol: state.lastResult.symbol,
+ name: state.lastResult.name,
+ primary_score: state.lastResult.primary_score,
+ posture: state.lastResult.posture,
+ hypothesis: $("hypothesis").value,
+ invalidation: $("invalidation").value,
+ };
+ const res = await api("/api/reviews", { method: "POST", body: JSON.stringify(payload) });
+ $("review-msg").textContent = res.ok ? "已写入,并创建次日复盘提醒。" : res.error || "失败";
+ if (res.ok) {
+ $("hypothesis").value = "";
+ $("invalidation").value = "";
+ refreshReviews();
+ }
+ });
+
+ Promise.all([ensureSession(), loadCases(), loadLessons(), loadHk(), refreshReviews()]).then(setupDrill);
+})();
diff --git a/zhishi/app/static/disclaimer.html b/zhishi/app/static/disclaimer.html
new file mode 100644
index 0000000..0e00d86
--- /dev/null
+++ b/zhishi/app/static/disclaimer.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ 免责声明 — 知势
+
+
+
+
+
← 知势
+
免责声明
+
+
本产品为投资教育工具,不构成任何投资建议。
+
框架自检分与学习姿态(偏强/中性/偏弱学习态)仅用于课程练习,不是买入、卖出、持有或目标价建议。
+
历史案例经过教学简化,不代表未来表现。你应独立判断并自行承担投资风险。
+
未取得证券投资咨询许可前,知势不会提供个股买卖时机或选股推荐服务。
+
+
+
+
diff --git a/zhishi/app/static/index.html b/zhishi/app/static/index.html
new file mode 100644
index 0000000..3a66241
--- /dev/null
+++ b/zhishi/app/static/index.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+ 知势 — 复盘研习
+
+
+
+
+
+
+
+
+
+
+ 复盘每一笔,而不是追每一笔
+ 课程框架自检 + 假设/失效条件。面向 A 股与港股通的投资教育工具,不提供个股买卖建议。
+
+
+
+
+
+
+
+ 框架自检
+
+
+
+
+
+
+
+
+
+
制度门控
+
+
检查项
+
+
写入复盘本
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 错题本 / 小测
+ 答错会进入错题本。题目只考规则认知,不考「买哪只」。
+
+
+
+
+
+
+
+
+
+
+
+
+
本产品为投资教育工具,不构成任何投资建议。市场有风险,决策须自负。 · 免责声明 · 用户协议 · 隐私政策
+
+
+
+
diff --git a/zhishi/app/static/methodology.html b/zhishi/app/static/methodology.html
new file mode 100644
index 0000000..175d3cb
--- /dev/null
+++ b/zhishi/app/static/methodology.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ 方法说明 — 知势
+
+
+
+
+
← 知势
+
方法说明
+
+
知势只展示 一个 主分数 primary_score(课程框架自检分),并映射到唯一学习姿态。
+
评分项包括:趋势结构(教学)、量能质量、涨跌停邻近度、制度风险、复盘完备度基准。A 股门控强调 T+1、涨跌停流动性与 ST。
+
无数据或假代码时 fail-closed:不给分、不编故事。本页说明的是投资教育方法,不构成投资建议。
+
完整契约见仓库 docs/ENGINE_CONTRACT.md 与 docs/TRUST_GATE.md。
+
+
+
+
diff --git a/zhishi/app/static/pricing.html b/zhishi/app/static/pricing.html
new file mode 100644
index 0000000..fedaefe
--- /dev/null
+++ b/zhishi/app/static/pricing.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ 研习会员 — 知势
+
+
+
+
+
← 知势
+
研习会员
+
知识付费 SKU。商品名不含荐股/投顾字样。微信支付在小程序端接入;H5 提供 mock 下单联调。
+
+
+
本产品为投资教育工具,不构成任何投资建议。 · 用户协议 · 隐私
+
+
+
+
diff --git a/zhishi/app/static/privacy.html b/zhishi/app/static/privacy.html
new file mode 100644
index 0000000..a896a7f
--- /dev/null
+++ b/zhishi/app/static/privacy.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 隐私政策 — 知势
+
+
+
+
+
← 知势
+
隐私政策
+
+
我们仅收集提供教育服务所必需的信息。
+
1. 会话标识、复盘本与错题本内容存储于服务端(MVP 可为内存/数据库)。
+
2. 支付由微信支付等合规通道处理;我们不存储完整银行卡信息。
+
3. 不会出售你的复盘内容;不会用「晒单收益榜」公开你的假设原文。
+
4. 你可请求导出或删除个人复盘数据(联系运营邮箱,上线后公示)。
+
+
本产品为投资教育工具,不构成任何投资建议。
+
+
+
diff --git a/zhishi/app/static/terms.html b/zhishi/app/static/terms.html
new file mode 100644
index 0000000..a2dcb08
--- /dev/null
+++ b/zhishi/app/static/terms.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ 用户协议 — 知势
+
+
+
+
+
← 知势
+
用户协议
+
+
欢迎使用「知势」投资教育产品。使用本服务即表示你同意本协议。
+
1. 服务性质:本产品提供投资知识课程、历史案例复盘与课程框架自检工具,不提供证券投资咨询、不荐股、不代客理财。
+
2. 知识付费:会员与课包费用用于解锁教育功能,不构成任何收益承诺。
+
3. 账户:你应妥善保管会话与账号;不得利用本服务从事违法违规活动。
+
4. 内容:课程与案例仅供学习;市场有风险,决策须自负。
+
5. 变更:我们可能更新本协议;重大变更将在产品内提示。
+
+
本产品为投资教育工具,不构成任何投资建议。
+
+
+
diff --git a/zhishi/content/cases/000001.json b/zhishi/content/cases/000001.json
new file mode 100644
index 0000000..18961a2
--- /dev/null
+++ b/zhishi/content/cases/000001.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-000001",
+ "symbol": "000001",
+ "name": "平安银行",
+ "title": "平安银行(000001)· 银行股·低波动",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行股·低波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/000002.json b/zhishi/content/cases/000002.json
new file mode 100644
index 0000000..5706d5b
--- /dev/null
+++ b/zhishi/content/cases/000002.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-000002",
+ "symbol": "000002",
+ "name": "万科A",
+ "title": "万科A(000002)· 地产·制度风险讨论",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:地产·制度风险讨论。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/000568.json b/zhishi/content/cases/000568.json
new file mode 100644
index 0000000..99af474
--- /dev/null
+++ b/zhishi/content/cases/000568.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-000568",
+ "symbol": "000568",
+ "name": "泸州老窖",
+ "title": "泸州老窖(000568)· 白酒·教学案例",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒·教学案例。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/000725.json b/zhishi/content/cases/000725.json
new file mode 100644
index 0000000..4409a88
--- /dev/null
+++ b/zhishi/content/cases/000725.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-000725",
+ "symbol": "000725",
+ "name": "京东方A",
+ "title": "京东方A(000725)· 制造·贴近跌停带演示",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:制造·贴近跌停带演示。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/000858.json b/zhishi/content/cases/000858.json
new file mode 100644
index 0000000..8d461f6
--- /dev/null
+++ b/zhishi/content/cases/000858.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-000858",
+ "symbol": "000858",
+ "name": "五粮液",
+ "title": "五粮液(000858)· 白酒·回调复盘",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒·回调复盘。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/002415.json b/zhishi/content/cases/002415.json
new file mode 100644
index 0000000..aa977f5
--- /dev/null
+++ b/zhishi/content/cases/002415.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-002415",
+ "symbol": "002415",
+ "name": "海康威视",
+ "title": "海康威视(002415)· 制造·量能常态",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:制造·量能常态。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/002594.json b/zhishi/content/cases/002594.json
new file mode 100644
index 0000000..d177b2f
--- /dev/null
+++ b/zhishi/content/cases/002594.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-002594",
+ "symbol": "002594",
+ "name": "比亚迪",
+ "title": "比亚迪(002594)· 新能源·放量讨论",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:新能源·放量讨论。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/300059.json b/zhishi/content/cases/300059.json
new file mode 100644
index 0000000..880b2a5
--- /dev/null
+++ b/zhishi/content/cases/300059.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-300059",
+ "symbol": "300059",
+ "name": "东方财富",
+ "title": "东方财富(300059)· 券商互联·弹性",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:券商互联·弹性。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/300750.json b/zhishi/content/cases/300750.json
new file mode 100644
index 0000000..e883bf4
--- /dev/null
+++ b/zhishi/content/cases/300750.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-300750",
+ "symbol": "300750",
+ "name": "宁德时代",
+ "title": "宁德时代(300750)· 创业板·弹性",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:创业板·弹性。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600000.json b/zhishi/content/cases/600000.json
new file mode 100644
index 0000000..f068cc0
--- /dev/null
+++ b/zhishi/content/cases/600000.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600000",
+ "symbol": "600000",
+ "name": "浦发银行",
+ "title": "浦发银行(600000)· 银行·T+1持有期",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行·T+1持有期。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600030.json b/zhishi/content/cases/600030.json
new file mode 100644
index 0000000..f638acd
--- /dev/null
+++ b/zhishi/content/cases/600030.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600030",
+ "symbol": "600030",
+ "name": "中信证券",
+ "title": "中信证券(600030)· 券商·周期教学",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:券商·周期教学。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600036.json b/zhishi/content/cases/600036.json
new file mode 100644
index 0000000..b6196dd
--- /dev/null
+++ b/zhishi/content/cases/600036.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600036",
+ "symbol": "600036",
+ "name": "招商银行",
+ "title": "招商银行(600036)· 银行·趋势教学",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行·趋势教学。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600276.json b/zhishi/content/cases/600276.json
new file mode 100644
index 0000000..42f8836
--- /dev/null
+++ b/zhishi/content/cases/600276.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600276",
+ "symbol": "600276",
+ "name": "恒瑞医药",
+ "title": "恒瑞医药(600276)· 医药·中性观察",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:医药·中性观察。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600519.json b/zhishi/content/cases/600519.json
new file mode 100644
index 0000000..df4b99f
--- /dev/null
+++ b/zhishi/content/cases/600519.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600519",
+ "symbol": "600519",
+ "name": "贵州茅台",
+ "title": "贵州茅台(600519)· 白酒龙头·常态波动",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒龙头·常态波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/600900.json b/zhishi/content/cases/600900.json
new file mode 100644
index 0000000..3ad916c
--- /dev/null
+++ b/zhishi/content/cases/600900.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-600900",
+ "symbol": "600900",
+ "name": "长江电力",
+ "title": "长江电力(600900)· 公用事业·低波动",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:公用事业·低波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/601012.json b/zhishi/content/cases/601012.json
new file mode 100644
index 0000000..d709d5c
--- /dev/null
+++ b/zhishi/content/cases/601012.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-601012",
+ "symbol": "601012",
+ "name": "隆基绿能",
+ "title": "隆基绿能(601012)· 光伏·弱势结构",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:光伏·弱势结构。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/601318.json b/zhishi/content/cases/601318.json
new file mode 100644
index 0000000..c99cf73
--- /dev/null
+++ b/zhishi/content/cases/601318.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-601318",
+ "symbol": "601318",
+ "name": "中国平安",
+ "title": "中国平安(601318)· 保险·均值回归",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:保险·均值回归。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/601398.json b/zhishi/content/cases/601398.json
new file mode 100644
index 0000000..5317526
--- /dev/null
+++ b/zhishi/content/cases/601398.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-601398",
+ "symbol": "601398",
+ "name": "工商银行",
+ "title": "工商银行(601398)· 大行·复盘四问",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:大行·复盘四问。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/601888.json b/zhishi/content/cases/601888.json
new file mode 100644
index 0000000..a681712
--- /dev/null
+++ b/zhishi/content/cases/601888.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-601888",
+ "symbol": "601888",
+ "name": "中国中免",
+ "title": "中国中免(601888)· 消费·趋势破裂",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:消费·趋势破裂。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/688981.json b/zhishi/content/cases/688981.json
new file mode 100644
index 0000000..937e352
--- /dev/null
+++ b/zhishi/content/cases/688981.json
@@ -0,0 +1,10 @@
+{
+ "id": "case-688981",
+ "symbol": "688981",
+ "name": "中芯国际",
+ "title": "中芯国际(688981)· 科创板·制度差异",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:科创板·制度差异。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+}
\ No newline at end of file
diff --git a/zhishi/content/cases/index.json b/zhishi/content/cases/index.json
new file mode 100644
index 0000000..f6488a3
--- /dev/null
+++ b/zhishi/content/cases/index.json
@@ -0,0 +1,202 @@
+[
+ {
+ "id": "case-600519",
+ "symbol": "600519",
+ "name": "贵州茅台",
+ "title": "贵州茅台(600519)· 白酒龙头·常态波动",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒龙头·常态波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-000001",
+ "symbol": "000001",
+ "name": "平安银行",
+ "title": "平安银行(000001)· 银行股·低波动",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行股·低波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-300750",
+ "symbol": "300750",
+ "name": "宁德时代",
+ "title": "宁德时代(300750)· 创业板·弹性",
+ "as_of": "20240420",
+ "free_demo": true,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:创业板·弹性。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-688981",
+ "symbol": "688981",
+ "name": "中芯国际",
+ "title": "中芯国际(688981)· 科创板·制度差异",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:科创板·制度差异。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-600036",
+ "symbol": "600036",
+ "name": "招商银行",
+ "title": "招商银行(600036)· 银行·趋势教学",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行·趋势教学。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-601318",
+ "symbol": "601318",
+ "name": "中国平安",
+ "title": "中国平安(601318)· 保险·均值回归",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:保险·均值回归。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-000858",
+ "symbol": "000858",
+ "name": "五粮液",
+ "title": "五粮液(000858)· 白酒·回调复盘",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒·回调复盘。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-002594",
+ "symbol": "002594",
+ "name": "比亚迪",
+ "title": "比亚迪(002594)· 新能源·放量讨论",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:新能源·放量讨论。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-601012",
+ "symbol": "601012",
+ "name": "隆基绿能",
+ "title": "隆基绿能(601012)· 光伏·弱势结构",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:光伏·弱势结构。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-600276",
+ "symbol": "600276",
+ "name": "恒瑞医药",
+ "title": "恒瑞医药(600276)· 医药·中性观察",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:医药·中性观察。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-000568",
+ "symbol": "000568",
+ "name": "泸州老窖",
+ "title": "泸州老窖(000568)· 白酒·教学案例",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:白酒·教学案例。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-002415",
+ "symbol": "002415",
+ "name": "海康威视",
+ "title": "海康威视(002415)· 制造·量能常态",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:制造·量能常态。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-600900",
+ "symbol": "600900",
+ "name": "长江电力",
+ "title": "长江电力(600900)· 公用事业·低波动",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:公用事业·低波动。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-601888",
+ "symbol": "601888",
+ "name": "中国中免",
+ "title": "中国中免(601888)· 消费·趋势破裂",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:消费·趋势破裂。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-300059",
+ "symbol": "300059",
+ "name": "东方财富",
+ "title": "东方财富(300059)· 券商互联·弹性",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:券商互联·弹性。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-600030",
+ "symbol": "600030",
+ "name": "中信证券",
+ "title": "中信证券(600030)· 券商·周期教学",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:券商·周期教学。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-000725",
+ "symbol": "000725",
+ "name": "京东方A",
+ "title": "京东方A(000725)· 制造·贴近跌停带演示",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:制造·贴近跌停带演示。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-601398",
+ "symbol": "601398",
+ "name": "工商银行",
+ "title": "工商银行(601398)· 大行·复盘四问",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:大行·复盘四问。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-600000",
+ "symbol": "600000",
+ "name": "浦发银行",
+ "title": "浦发银行(600000)· 银行·T+1持有期",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:银行·T+1持有期。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ },
+ {
+ "id": "case-000002",
+ "symbol": "000002",
+ "name": "万科A",
+ "title": "万科A(000002)· 地产·制度风险讨论",
+ "as_of": "20240420",
+ "free_demo": false,
+ "summary": "历史日线教学样本,用于练习框架自检与复盘四问。标签:地产·制度风险讨论。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。"
+ }
+]
\ No newline at end of file
diff --git a/zhishi/content/hkconnect/hk-01-session-quota.md b/zhishi/content/hkconnect/hk-01-session-quota.md
new file mode 100644
index 0000000..6d94f25
--- /dev/null
+++ b/zhishi/content/hkconnect/hk-01-session-quota.md
@@ -0,0 +1,18 @@
+# 港股通:时段与额度
+
+> 年度课包 · 港股通轨道
+
+## 与 A 股的第一差异
+
+通过港股通交易,需同时满足:**开通权限、交易时段、额度状态**。
+形态再「好看」,若当日无法交易,复盘应记为流程失败而非策略失败。
+
+## 自检增加项
+
+- 今天是否处于可交易窗口?
+- 额度是否可能影响成交预期?
+- 我是否误用了 A 股涨停板战术?
+
+## 练习
+
+用市场切换到「港股通」跑一次教学自检,对比门控文案差异。
diff --git a/zhishi/content/hkconnect/hk-02-fx-spread.md b/zhishi/content/hkconnect/hk-02-fx-spread.md
new file mode 100644
index 0000000..bccb35f
--- /dev/null
+++ b/zhishi/content/hkconnect/hk-02-fx-spread.md
@@ -0,0 +1,15 @@
+# 港股通:汇率与价差
+
+> 年度课包 · 港股通轨道
+
+## 汇率
+
+盈亏体感可能被汇率放大或对冲。假设中应写明:是否纳入汇率判断。
+
+## 价差
+
+部分标的买卖价差更大。自检增加:「当前价差是否可接受?」
+
+## 交收直觉
+
+不要把 A 股 T+1 的肌肉记忆直接套用;以券商与交易所披露的交收规则为准,并在复盘本标注市场类型。
diff --git a/zhishi/content/lessons/01-t1-liquidity.md b/zhishi/content/lessons/01-t1-liquidity.md
new file mode 100644
index 0000000..76a63aa
--- /dev/null
+++ b/zhishi/content/lessons/01-t1-liquidity.md
@@ -0,0 +1,20 @@
+# T+1 与流动性
+
+> 免费导读 · A股制度篇
+
+## 学什么
+
+A 股股票通常实行 **T+1**:当日买入,下一交易日才能卖出。
+这意味着你的「假设」必须包含隔夜缺口与持有期,而不能假设盘中随时离场。
+
+## 复盘四问(结合 T+1)
+
+1. 我计划持有多久?是否跨越至少一个交易日?
+2. 若次日低开,我的失效条件是否已写清?
+3. 流动性是否足够让我按教学计划退出(而非情绪退出)?
+4. 我是否在用「当日可卖」的错觉做决策?
+
+## 练习
+
+打开任意教学案例,在复盘本写下:**持有期假设**与**次日失效条件**。
+本课不教你买哪只股票。
diff --git a/zhishi/content/lessons/02-limit-traps.md b/zhishi/content/lessons/02-limit-traps.md
new file mode 100644
index 0000000..892388d
--- /dev/null
+++ b/zhishi/content/lessons/02-limit-traps.md
@@ -0,0 +1,22 @@
+# 涨跌停行为陷阱
+
+> 免费导读 · A股行为篇
+
+## 学什么
+
+涨跌停会改变微观结构:排队、打开、封单与次日溢价/折价预期。
+接近涨跌停时,**流动性与规则**往往比 K 线形态更重要。
+
+## 常见陷阱(教学)
+
+- 把「封板」当成确定性收益
+- 在跌停附近抄底却未写失效条件
+- 忽略不同板块涨跌幅限制差异(主板约 10%,双创/科创约 20% 等,以交易所规则为准)
+
+## 自检提示
+
+知势在「涨跌停邻近度」检查项会扣分或提示关注——这是教学权重,不是买卖信号。
+
+## 练习
+
+选一个「贴近跌停带」的教学案例,只回答:若打开/封死,我的假设分别是什么?
diff --git a/zhishi/content/lessons/03-review-four.md b/zhishi/content/lessons/03-review-four.md
new file mode 100644
index 0000000..4ef724a
--- /dev/null
+++ b/zhishi/content/lessons/03-review-four.md
@@ -0,0 +1,18 @@
+# 复盘四问
+
+> 免费导读 · 方法篇
+
+## 四问
+
+1. **我看到了什么事实?**(价格、量能、制度标记,而非传闻)
+2. **我的假设是什么?**(可证伪的一句话)
+3. **什么情况下假设失效?**(必须可观察)
+4. **我学到了哪条规则?**(T+1、涨跌停、ST…)
+
+## 为什么只要一个分数
+
+多分数会让人挑对自己有利的指标。知势只保留 `primary_score` 与一个学习姿态,逼你完成叙事一致的复盘。
+
+## 练习
+
+完成一次框架自检 → 强制填写假设与失效条件 → 等待次日提醒再回看。
diff --git a/zhishi/docs/BRAND.md b/zhishi/docs/BRAND.md
new file mode 100644
index 0000000..2050d0a
--- /dev/null
+++ b/zhishi/docs/BRAND.md
@@ -0,0 +1,30 @@
+# 知势 — 品牌锁定
+
+> 版本:1.0.0 · 状态:锁定 · 2026-08-10
+
+## 品牌名
+
+| 项 | 值 |
+|----|-----|
+| 中文名 | **知势** |
+| 英文/域名候选 | zhishi.app / zhishi.edu(待注册) |
+| 一句话 | 帮你用可复用的检查清单复盘每一笔交易,而不是再给你一个荐股 App |
+
+## 禁用字样(未持牌)
+
+对外账号、小程序名称、商标、应用商店标题 **禁止** 使用:
+
+- 证券、投资顾问、投顾、荐股、稳赚、必涨、内幕、跟单
+
+允许:研习、复盘、投教、课程、框架自检、学习态
+
+## 视觉方向(MVP)
+
+- 气质:冷静、纸面研习室,非行情终端
+- 主色:墨青 `#1A3A3A`;强调:琥珀墨 `#B86E2C`;纸底渐变 `#F7F3EB → #E8EFEA`
+- 字体:标题用「思源宋体 / Noto Serif SC」;正文「思源黑体 / Noto Sans SC」
+- 禁止:紫靛渐变、多阴影卡片墙、仪表盘首屏
+
+## 与 QuantRadar
+
+完全独立品牌与账号体系;仅借鉴 Trust Gate / 单一主结论方法,不互通订阅。
diff --git a/zhishi/docs/COMPLIANCE.md b/zhishi/docs/COMPLIANCE.md
new file mode 100644
index 0000000..2cb2611
--- /dev/null
+++ b/zhishi/docs/COMPLIANCE.md
@@ -0,0 +1,57 @@
+# 知势 — 合规白皮书(禁荐股边界)
+
+> 版本:1.0.0 · 适用:未持有中国证监会证券投资咨询许可的运营主体
+
+## 1. 法律定性
+
+向投资者销售或提供具备下列一项或多项功能的软件并直接/间接收费,属于证券投资咨询业务,须经证监会许可:
+
+1. 对具体证券品种提供投资分析意见,或预测价格走势
+2. 提供具体证券品种选择建议
+3. 提供具体证券品种买卖时机建议
+4. 其他证券投资分析、预测或建议
+
+**知势 MVP 定位**:投资教育工具 + 知识付费,**不构成**上述荐股软件。
+
+## 2. 允许 vs 禁止
+
+| 允许 | 禁止 |
+|------|------|
+| 通用方法论课程、制度规则释义 | 「建议买入/卖出 XXX」「目标价」「明日必涨」 |
+| 历史案例复盘(标注历史、教学) | 持续性个股荐股服务、直播带票 |
+| 用户自填检查清单 + 机械「课程框架自检分」 | 将自检分包装成投资建议 |
+| 公开行情事实 + 规则释义 | 账号/商标使用未许可「证券」「投资顾问」字样 |
+| 模拟盘、错题本、能力测评 | 承诺收益、跟单、代客理财话术 |
+| 微信支付知识付费(课包/会员) | 按「荐股软件」「稳赚系统」卖点收费 |
+
+## 3. 产品输出词表(强制)
+
+| 字段 | 允许值 | 禁止值 |
+|------|--------|--------|
+| `posture` | 偏强学习态 / 中性观察态 / 偏弱学习态 / 数据不足 | 买入、卖出、加仓、减仓、Buy、Sell |
+| 页面主分 | `primary_score`(框架自检分) | 多分数互掐、Composite 并列 |
+| CTA | 写入复盘本、学习下一项检查 | 一键跟单、立即买入 |
+
+全站固定条:「本产品为投资教育工具,不构成任何投资建议。市场有风险,决策须自负。」
+
+## 4. 营销与类目
+
+- 微信小程序类目:教育 / 在线教育 / 知识付费(以微信当期类目为准)
+- 获客内容:复盘拆解、制度科普;**禁止**带票与收益承诺
+- 自 2026-09-30《金融产品网络营销管理办法》起,不做金融产品营销话术,不做未许可金融字样蹭流量
+
+## 5. 数据与用户
+
+- 教学演示可用延迟/日线公开数据;商用生产须有授权(见 [DATA_SOURCES.md](./DATA_SOURCES.md))
+- 用户复盘本为用户私有数据;不对外展示「晒单收益」排行榜
+
+## 6. 升级路径(持牌后)
+
+仅在与持牌证券投资咨询机构或券商投教/投顾达成书面合作后,方可评估「建议类」能力;无牌 **不开**。详见 [LICENSED_PARTNER.md](./LICENSED_PARTNER.md)。
+
+## 7. 抽检清单(上线前)
+
+- [ ] 全站无「买入/卖出/目标价/稳赚/必涨」
+- [ ] 假代码 / 无数据 fail-closed
+- [ ] 用户协议、隐私政策、「不构成投资建议」可访问
+- [ ] 小程序类目与支付商品名为课包/研习会员,非荐股
diff --git a/zhishi/docs/DATA_SOURCES.md b/zhishi/docs/DATA_SOURCES.md
new file mode 100644
index 0000000..598998f
--- /dev/null
+++ b/zhishi/docs/DATA_SOURCES.md
@@ -0,0 +1,39 @@
+# 知势 — A股日线数据源与授权边界
+
+> 版本:1.0.0 · 结论:MVP 默认 **fixture/artifact**;live 仅在配置授权密钥后启用。
+
+## 选定方案
+
+| 优先级 | 源 | 用途 | 授权边界 |
+|--------|-----|------|----------|
+| **默认** | 内置 `fixtures/` 日线 JSON | Demo、CI、无网教学 | 自有合成/公开教学样本,可商用展示 |
+| **可选 live** | **Tushare Pro** | 日线 OHLCV、基础信息、ST 标记 | 需积分/付费权限;**仅服务端**;禁止把原始行情转售或对外宣称「交易所官方」 |
+| **开发备选** | AKShare | 本地研发探测 | 聚合第三方公开接口,**生产商用风险高**;未获书面授权不得作为付费卖点数据层 |
+
+**MVP 锁定**:`ZHISHI_MODE=artifact`(默认)。`live` 仅当 `TUSHARE_TOKEN` 存在且 `ZHISHI_ALLOW_LIVE=1`。
+
+## 为何不用 Yahoo/Polygon 作 A股主源
+
+- A股代码、复权、涨跌停、ST、停牌语义与美股源不匹配
+- 大陆用户与合规叙事需要可说明的境内数据路径
+
+## 港股通
+
+- P2:教学案例用 fixture;规则课不依赖实时报价
+- live:Tushare 港股通成分与日线(同样需权限)
+
+## 禁止
+
+- 未授权源当付费产品「实时行情」卖点
+- 浏览器直出第三方 raw feed / API key
+- 把延迟数据标成「实时 Level-2」
+
+## 运行时开关
+
+```bash
+ZHISHI_MODE=artifact # artifact | live
+ZHISHI_ALLOW_LIVE=0 # 显式打开才允许 live
+TUSHARE_TOKEN= # 仅服务端
+```
+
+`/health` 必须暴露:`data_path`、`mode_default`、`live_eligible`(布尔,不含 token)。
diff --git a/zhishi/docs/ENGINE_CONTRACT.md b/zhishi/docs/ENGINE_CONTRACT.md
new file mode 100644
index 0000000..71a135f
--- /dev/null
+++ b/zhishi/docs/ENGINE_CONTRACT.md
@@ -0,0 +1,92 @@
+# ENGINE_CONTRACT — 知势自检引擎契约
+
+> 版本:`1.0.0`
+> 壳职责:请求规范化 + 展示;引擎产出唯一 `primary_score` 与教学 `posture`。
+
+## 1. 请求
+
+```json
+{
+ "contract_version": "1.0.0",
+ "symbol": "600519",
+ "market": "A",
+ "context": {
+ "mode": "artifact",
+ "as_of": "2024-06-14",
+ "request_id": "optional"
+ }
+}
+```
+
+| 字段 | 必需 | 说明 |
+|------|------|------|
+| `symbol` | 是 | A股 6 位数字;港股通阶段可为 5 位 |
+| `market` | 否 | `A`(默认)\| `HKCONNECT` |
+| `context.mode` | 否 | `artifact` \| `live` |
+| `context.as_of` | 否 | 教学复盘锚定日 |
+
+非法代码 → HTTP 400。
+
+## 2. 成功响应
+
+```json
+{
+ "ok": true,
+ "contract_version": "1.0.0",
+ "symbol": "600519",
+ "name": "贵州茅台",
+ "market": "A",
+ "primary_score": 62,
+ "posture": "中性观察态",
+ "gates": [
+ {
+ "id": "t1_settlement",
+ "title": "T+1 交收",
+ "passed": true,
+ "teaching": "当日买入不可卖出,教学自检需计入持有期约束。"
+ }
+ ],
+ "checklist": [
+ {
+ "id": "trend_structure",
+ "title": "趋势结构(教学)",
+ "score": 14,
+ "max": 20,
+ "reason": "…"
+ }
+ ],
+ "institutional_context": {
+ "near_limit": false,
+ "is_st": false,
+ "is_star_or_chinext": false
+ },
+ "sample": false,
+ "degraded": false,
+ "warnings": [],
+ "sources": [{"name": "fixture", "role": "ohlcv", "status": "ok"}],
+ "disclaimer": "本结果为课程框架自检,不构成投资建议。"
+}
+```
+
+## 3. Fail-closed
+
+```json
+{
+ "ok": false,
+ "error": "symbol_not_found",
+ "primary_score": null,
+ "posture": "数据不足",
+ "disclaimer": "本结果为课程框架自检,不构成投资建议。"
+}
+```
+
+无数据时 **不得** 编造分数或叙事。
+
+## 4. posture 枚举(唯一允许)
+
+- `偏强学习态` — score ≥ 70
+- `中性观察态` — 40 ≤ score < 70
+- `偏弱学习态` — score < 40
+- `数据不足` — fail-closed
+
+禁止映射为买卖词。
diff --git a/zhishi/docs/LICENSED_PARTNER.md b/zhishi/docs/LICENSED_PARTNER.md
new file mode 100644
index 0000000..457821f
--- /dev/null
+++ b/zhishi/docs/LICENSED_PARTNER.md
@@ -0,0 +1,32 @@
+# 持牌合作路径(P3)
+
+> 无证监会证券投资咨询许可前,**不开**建议类能力。
+
+## 目标
+
+与持牌证券投资咨询机构或券商投教/投顾团队联运,在合规前提下扩展能力与分发。
+
+## 合作形态(优先顺序)
+
+1. **投教内容联运**:知势提供复盘课包与工具;对方提供合规审核与流量
+2. **白标 H5**:券商 App 内嵌知势教育模块,品牌可共存,输出仍为教学姿态
+3. **持牌投顾接入(后置)**:仅在书面协议与合规审核流程就绪后,由持牌主体对外承担「建议」责任;知势侧技术隔离,默认关闭
+
+## 准入清单
+
+- [ ] 对方牌照与业务范围核验
+- [ ] 内容审核与留痕机制
+- [ ] 用户适当性与风险揭示由持牌方负责
+- [ ] 知势合同中明确:未授权不得宣传为荐股软件
+- [ ] 技术开关:`FEATURE_ADVICE=0` 默认;持牌租户单独开启且审计
+
+## 明确不做
+
+- 未持牌主体「挂靠」话术对外荐股
+- 用教育会员包装成投顾订阅
+- 直播间带票导流至未审核私域
+
+## 商业条款草案(非法律意见)
+
+- 收入分成或 SaaS 年费 + 按活跃学员
+- 合规罚则与下架权归属持牌方与知势双签
diff --git a/zhishi/docs/REPO.md b/zhishi/docs/REPO.md
new file mode 100644
index 0000000..8185921
--- /dev/null
+++ b/zhishi/docs/REPO.md
@@ -0,0 +1,5 @@
+# 知势 — 与父仓关系
+
+本目录是独立产品,借 QuantRadar 的 Trust Gate 方法,不共享品牌/账号/计费。
+
+后续可 `git subtree split` 或复制到 `Alexaliao001/zhishi` 独立仓库。
diff --git a/zhishi/docs/TRUST_GATE.md b/zhishi/docs/TRUST_GATE.md
new file mode 100644
index 0000000..c23ff7c
--- /dev/null
+++ b/zhishi/docs/TRUST_GATE.md
@@ -0,0 +1,30 @@
+# 知势 — Trust Gate(中文版)
+
+> 借鉴 QuantRadar Trust Gate 哲学,语义改为投教;违反 = 禁止推付费。
+
+## 铁律
+
+| ID | 规则 |
+|----|------|
+| ZG-1 | 页面上 **最多 1 个** 主分数,字段名 `primary_score`(框架自检分)。禁止同时展示多个综合分。 |
+| ZG-2 | `posture` 与标题/CTA 文案 **一致**。不允许「偏弱学习态」旁放「抓紧上车」。 |
+| ZG-3 | **禁止** 无出处 testimonials;禁止硬编码假用户数/假胜率。早期用「Beta · 教学案例」。 |
+| ZG-4 | 定价文案全站一致(¥68/月 · ¥488/年)。 |
+| ZG-5 | Demo 案例走预缓存 artifact,**不扣额度、不打 live 行情**。 |
+| ZG-6 | 无数据 / 假代码 **fail-closed**:不给分、不编叙事。 |
+| ZG-7 | 输出仅用教学姿态词;禁止买卖指令与目标价。 |
+| ZG-8 | 品牌图自托管;禁止外链 CDN 冒充本站。 |
+| ZG-9 | 收款前:用户协议 / 隐私 / 不构成投资建议 三页可访问。 |
+| ZG-10 | 产品登录不得依赖第三方「荐股」账号体系;会话自有。 |
+
+## 档位
+
+| 档 | 定位 |
+|----|------|
+| 访客 / 免费 | 规则短课 + 3 个 Demo 案例 |
+| 月度研习 | 无限自检 + 复盘本 + 提醒 |
+| 年度 | 同上 + 港股通课包 + 错题本 |
+
+## 战略一句话
+
+对外卖 **可审计的课程框架自检 + 单一学习姿态 + methodology**;不卖荐股幻觉。
diff --git a/zhishi/docs/WIREFRAMES.md b/zhishi/docs/WIREFRAMES.md
new file mode 100644
index 0000000..782537f
--- /dev/null
+++ b/zhishi/docs/WIREFRAMES.md
@@ -0,0 +1,75 @@
+# 知势 — 信息架构与主路径线框
+
+## 信息架构
+
+```text
+首页
+├── 今日教学案例(免费 Demo)
+├── 规则短课(3 课免费导读)
+├── 单票框架自检(会员)
+├── 我的复盘本
+├── 错题本 / 模拟(年度)
+├── 港股通规则课(年度)
+├── 研习会员定价
+└── 协议与免责
+```
+
+## 主路径(自检 → 复盘)一屏一职
+
+```text
+[1 输入] 代码 600519 或点「今日案例」
+ ↓
+[2 上下文] 制度条:是否近涨跌停 / ST / 注册制次新 / T+1 提示
+ ↓
+[3 主结论] 唯一 primary_score + posture(教学词)
+ ↓
+[4 展开] 各检查项:得分理由 +「为什么在 A 股重要」
+ ↓
+[5 强制出口] 输入「我的假设 / 失效条件」→ 写入复盘本
+ ↓
+[6 提醒] 次日/次周复盘结果回顾(教育闭环,非荐股推送)
+```
+
+## 线框(H5 / 小程序共用)
+
+### 首页
+
+```text
+┌────────────────────────────────┐
+│ 知势 研习会员 │
+│ 复盘每一笔,而不是追每一笔 │
+│ │
+│ [今日教学案例:贵州茅台 2024-…] │
+│ [开始框架自检] │
+│ │
+│ 短课 · T+1 与流动性 │
+│ 短课 · 涨跌停行为陷阱 │
+│ 短课 · 复盘四问 │
+│ ─ 本产品为投资教育工具… ─ │
+└────────────────────────────────┘
+```
+
+### 自检结果
+
+```text
+┌────────────────────────────────┐
+│ 600519 贵州茅台 · 教学自检 │
+│ │
+│ 框架自检分 62 │
+│ 中性观察态 │
+│ │
+│ ▸ T+1 当日不可卖出 — 已计入 │
+│ ▸ 近涨跌停流动性 — 扣分释义… │
+│ ▸ 趋势结构教学项 — … │
+│ │
+│ 我的假设 ________________ │
+│ 失效条件 ________________ │
+│ [写入复盘本] │
+│ ─ 不构成投资建议 ─ │
+└────────────────────────────────┘
+```
+
+## 不做
+
+- 首屏行情看板、多指标卡片墙、全市场选股器
+- 浮动「热股」「必看」贴纸
diff --git a/zhishi/fixtures/ohlcv/000001.json b/zhishi/fixtures/ohlcv/000001.json
new file mode 100644
index 0000000..286b83a
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/000001.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "000001",
+ "name": "平安银行",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 11.5,
+ "high": 11.88,
+ "low": 11.49,
+ "close": 11.76,
+ "volume": 986718.39
+ },
+ {
+ "date": "20240102",
+ "open": 11.76,
+ "high": 12.06,
+ "low": 11.69,
+ "close": 11.97,
+ "volume": 1477900.21
+ },
+ {
+ "date": "20240103",
+ "open": 11.97,
+ "high": 12.13,
+ "low": 11.9,
+ "close": 12.06,
+ "volume": 1148442.31
+ },
+ {
+ "date": "20240104",
+ "open": 12.06,
+ "high": 12.11,
+ "low": 11.96,
+ "close": 12.05,
+ "volume": 2988603.04
+ },
+ {
+ "date": "20240105",
+ "open": 12.05,
+ "high": 12.39,
+ "low": 12.0,
+ "close": 12.33,
+ "volume": 1390129.63
+ },
+ {
+ "date": "20240106",
+ "open": 12.33,
+ "high": 12.33,
+ "low": 12.04,
+ "close": 12.1,
+ "volume": 1500623.28
+ },
+ {
+ "date": "20240107",
+ "open": 12.1,
+ "high": 12.21,
+ "low": 12.0,
+ "close": 12.06,
+ "volume": 2033122.79
+ },
+ {
+ "date": "20240108",
+ "open": 12.06,
+ "high": 12.07,
+ "low": 11.91,
+ "close": 11.95,
+ "volume": 1100734.26
+ },
+ {
+ "date": "20240109",
+ "open": 11.95,
+ "high": 12.11,
+ "low": 11.87,
+ "close": 11.99,
+ "volume": 1200055.69
+ },
+ {
+ "date": "20240110",
+ "open": 11.99,
+ "high": 12.33,
+ "low": 11.9,
+ "close": 12.23,
+ "volume": 2794506.03
+ },
+ {
+ "date": "20240111",
+ "open": 12.23,
+ "high": 12.5,
+ "low": 12.18,
+ "close": 12.4,
+ "volume": 2958148.46
+ },
+ {
+ "date": "20240112",
+ "open": 12.4,
+ "high": 12.71,
+ "low": 12.31,
+ "close": 12.69,
+ "volume": 2373331.98
+ },
+ {
+ "date": "20240113",
+ "open": 12.69,
+ "high": 12.77,
+ "low": 12.63,
+ "close": 12.7,
+ "volume": 2834630.56
+ },
+ {
+ "date": "20240114",
+ "open": 12.7,
+ "high": 12.84,
+ "low": 12.66,
+ "close": 12.73,
+ "volume": 2742272.02
+ },
+ {
+ "date": "20240115",
+ "open": 12.73,
+ "high": 13.05,
+ "low": 12.66,
+ "close": 12.99,
+ "volume": 2824726.97
+ },
+ {
+ "date": "20240116",
+ "open": 12.99,
+ "high": 13.22,
+ "low": 12.97,
+ "close": 13.16,
+ "volume": 1514267.94
+ },
+ {
+ "date": "20240117",
+ "open": 13.16,
+ "high": 13.33,
+ "low": 13.04,
+ "close": 13.31,
+ "volume": 1389902.53
+ },
+ {
+ "date": "20240118",
+ "open": 13.31,
+ "high": 13.63,
+ "low": 13.18,
+ "close": 13.59,
+ "volume": 2353652.77
+ },
+ {
+ "date": "20240119",
+ "open": 13.59,
+ "high": 13.7,
+ "low": 13.5,
+ "close": 13.63,
+ "volume": 2093478.37
+ },
+ {
+ "date": "20240120",
+ "open": 13.63,
+ "high": 13.65,
+ "low": 13.47,
+ "close": 13.54,
+ "volume": 2855139.59
+ },
+ {
+ "date": "20240201",
+ "open": 13.54,
+ "high": 13.66,
+ "low": 13.43,
+ "close": 13.65,
+ "volume": 2397088.43
+ },
+ {
+ "date": "20240202",
+ "open": 13.65,
+ "high": 13.96,
+ "low": 13.55,
+ "close": 13.94,
+ "volume": 929269.57
+ },
+ {
+ "date": "20240203",
+ "open": 13.94,
+ "high": 14.11,
+ "low": 13.91,
+ "close": 14.07,
+ "volume": 2726080.58
+ },
+ {
+ "date": "20240204",
+ "open": 14.07,
+ "high": 14.14,
+ "low": 13.74,
+ "close": 13.85,
+ "volume": 1338630.35
+ },
+ {
+ "date": "20240205",
+ "open": 13.85,
+ "high": 13.98,
+ "low": 13.65,
+ "close": 13.71,
+ "volume": 2377314.42
+ },
+ {
+ "date": "20240206",
+ "open": 13.71,
+ "high": 13.76,
+ "low": 13.43,
+ "close": 13.45,
+ "volume": 2280083.97
+ },
+ {
+ "date": "20240207",
+ "open": 13.45,
+ "high": 13.58,
+ "low": 13.23,
+ "close": 13.24,
+ "volume": 2404731.72
+ },
+ {
+ "date": "20240208",
+ "open": 13.24,
+ "high": 13.27,
+ "low": 12.88,
+ "close": 12.98,
+ "volume": 1145660.24
+ },
+ {
+ "date": "20240209",
+ "open": 12.98,
+ "high": 13.07,
+ "low": 12.78,
+ "close": 12.83,
+ "volume": 894954.19
+ },
+ {
+ "date": "20240210",
+ "open": 12.83,
+ "high": 13.17,
+ "low": 12.83,
+ "close": 13.15,
+ "volume": 1557242.21
+ },
+ {
+ "date": "20240211",
+ "open": 13.15,
+ "high": 13.35,
+ "low": 13.13,
+ "close": 13.25,
+ "volume": 1541870.3
+ },
+ {
+ "date": "20240212",
+ "open": 13.25,
+ "high": 13.31,
+ "low": 12.9,
+ "close": 13.0,
+ "volume": 2427882.66
+ },
+ {
+ "date": "20240213",
+ "open": 13.0,
+ "high": 13.37,
+ "low": 12.89,
+ "close": 13.27,
+ "volume": 2351759.31
+ },
+ {
+ "date": "20240214",
+ "open": 13.27,
+ "high": 13.31,
+ "low": 13.18,
+ "close": 13.28,
+ "volume": 1495873.04
+ },
+ {
+ "date": "20240215",
+ "open": 13.28,
+ "high": 13.34,
+ "low": 12.97,
+ "close": 13.08,
+ "volume": 1080580.22
+ },
+ {
+ "date": "20240216",
+ "open": 13.08,
+ "high": 13.21,
+ "low": 13.01,
+ "close": 13.16,
+ "volume": 1116424.82
+ },
+ {
+ "date": "20240217",
+ "open": 13.16,
+ "high": 13.5,
+ "low": 13.08,
+ "close": 13.47,
+ "volume": 1723462.2
+ },
+ {
+ "date": "20240218",
+ "open": 13.47,
+ "high": 13.54,
+ "low": 13.19,
+ "close": 13.21,
+ "volume": 924918.19
+ },
+ {
+ "date": "20240219",
+ "open": 13.21,
+ "high": 13.23,
+ "low": 12.95,
+ "close": 12.97,
+ "volume": 2197166.53
+ },
+ {
+ "date": "20240220",
+ "open": 12.97,
+ "high": 13.13,
+ "low": 12.84,
+ "close": 13.0,
+ "volume": 2987955.51
+ },
+ {
+ "date": "20240301",
+ "open": 13.0,
+ "high": 13.06,
+ "low": 12.85,
+ "close": 12.88,
+ "volume": 2100722.16
+ },
+ {
+ "date": "20240302",
+ "open": 12.88,
+ "high": 13.09,
+ "low": 12.79,
+ "close": 12.98,
+ "volume": 1364540.43
+ },
+ {
+ "date": "20240303",
+ "open": 12.98,
+ "high": 13.05,
+ "low": 12.97,
+ "close": 12.97,
+ "volume": 878098.71
+ },
+ {
+ "date": "20240304",
+ "open": 12.97,
+ "high": 12.98,
+ "low": 12.86,
+ "close": 12.95,
+ "volume": 1329904.13
+ },
+ {
+ "date": "20240305",
+ "open": 12.95,
+ "high": 12.97,
+ "low": 12.72,
+ "close": 12.75,
+ "volume": 1278178.0
+ },
+ {
+ "date": "20240306",
+ "open": 12.75,
+ "high": 12.85,
+ "low": 12.71,
+ "close": 12.79,
+ "volume": 2211869.27
+ },
+ {
+ "date": "20240307",
+ "open": 12.79,
+ "high": 12.91,
+ "low": 12.54,
+ "close": 12.66,
+ "volume": 2403648.3
+ },
+ {
+ "date": "20240308",
+ "open": 12.66,
+ "high": 12.72,
+ "low": 12.58,
+ "close": 12.65,
+ "volume": 912716.44
+ },
+ {
+ "date": "20240309",
+ "open": 12.65,
+ "high": 12.72,
+ "low": 12.61,
+ "close": 12.64,
+ "volume": 1006330.93
+ },
+ {
+ "date": "20240310",
+ "open": 12.64,
+ "high": 12.89,
+ "low": 12.57,
+ "close": 12.84,
+ "volume": 2827190.76
+ },
+ {
+ "date": "20240311",
+ "open": 12.84,
+ "high": 12.97,
+ "low": 12.71,
+ "close": 12.94,
+ "volume": 1618898.76
+ },
+ {
+ "date": "20240312",
+ "open": 12.94,
+ "high": 13.03,
+ "low": 12.68,
+ "close": 12.69,
+ "volume": 1473029.19
+ },
+ {
+ "date": "20240313",
+ "open": 12.69,
+ "high": 13.0,
+ "low": 12.69,
+ "close": 12.92,
+ "volume": 1793131.61
+ },
+ {
+ "date": "20240314",
+ "open": 12.92,
+ "high": 12.98,
+ "low": 12.87,
+ "close": 12.9,
+ "volume": 2095239.14
+ },
+ {
+ "date": "20240315",
+ "open": 12.9,
+ "high": 12.93,
+ "low": 12.63,
+ "close": 12.68,
+ "volume": 2857594.95
+ },
+ {
+ "date": "20240316",
+ "open": 12.68,
+ "high": 12.78,
+ "low": 12.45,
+ "close": 12.47,
+ "volume": 2057416.03
+ },
+ {
+ "date": "20240317",
+ "open": 12.47,
+ "high": 12.53,
+ "low": 12.35,
+ "close": 12.44,
+ "volume": 1669093.63
+ },
+ {
+ "date": "20240318",
+ "open": 12.44,
+ "high": 12.46,
+ "low": 12.25,
+ "close": 12.26,
+ "volume": 2670155.92
+ },
+ {
+ "date": "20240319",
+ "open": 12.26,
+ "high": 12.49,
+ "low": 12.18,
+ "close": 12.37,
+ "volume": 854271.3
+ },
+ {
+ "date": "20240320",
+ "open": 12.37,
+ "high": 12.59,
+ "low": 12.28,
+ "close": 12.49,
+ "volume": 1895488.94
+ },
+ {
+ "date": "20240401",
+ "open": 12.49,
+ "high": 12.55,
+ "low": 12.34,
+ "close": 12.44,
+ "volume": 1391673.49
+ },
+ {
+ "date": "20240402",
+ "open": 12.44,
+ "high": 12.55,
+ "low": 12.32,
+ "close": 12.49,
+ "volume": 2569569.95
+ },
+ {
+ "date": "20240403",
+ "open": 12.49,
+ "high": 12.87,
+ "low": 12.45,
+ "close": 12.76,
+ "volume": 1309580.19
+ },
+ {
+ "date": "20240404",
+ "open": 12.76,
+ "high": 12.82,
+ "low": 12.71,
+ "close": 12.79,
+ "volume": 2294108.47
+ },
+ {
+ "date": "20240405",
+ "open": 12.79,
+ "high": 13.13,
+ "low": 12.68,
+ "close": 13.06,
+ "volume": 1011084.08
+ },
+ {
+ "date": "20240406",
+ "open": 13.06,
+ "high": 13.19,
+ "low": 12.99,
+ "close": 13.01,
+ "volume": 1716889.7
+ },
+ {
+ "date": "20240407",
+ "open": 13.01,
+ "high": 13.02,
+ "low": 12.67,
+ "close": 12.79,
+ "volume": 2975001.46
+ },
+ {
+ "date": "20240408",
+ "open": 12.79,
+ "high": 12.92,
+ "low": 12.75,
+ "close": 12.9,
+ "volume": 1309739.22
+ },
+ {
+ "date": "20240409",
+ "open": 12.9,
+ "high": 13.12,
+ "low": 12.85,
+ "close": 13.03,
+ "volume": 1952788.49
+ },
+ {
+ "date": "20240410",
+ "open": 13.03,
+ "high": 13.1,
+ "low": 12.72,
+ "close": 12.84,
+ "volume": 2462710.07
+ },
+ {
+ "date": "20240411",
+ "open": 12.84,
+ "high": 12.91,
+ "low": 12.55,
+ "close": 12.64,
+ "volume": 1365973.14
+ },
+ {
+ "date": "20240412",
+ "open": 12.64,
+ "high": 12.95,
+ "low": 12.55,
+ "close": 12.89,
+ "volume": 1689159.46
+ },
+ {
+ "date": "20240413",
+ "open": 12.89,
+ "high": 13.32,
+ "low": 12.82,
+ "close": 13.21,
+ "volume": 1118483.05
+ },
+ {
+ "date": "20240414",
+ "open": 13.21,
+ "high": 13.22,
+ "low": 13.13,
+ "close": 13.21,
+ "volume": 2739998.54
+ },
+ {
+ "date": "20240415",
+ "open": 13.21,
+ "high": 13.28,
+ "low": 12.99,
+ "close": 13.05,
+ "volume": 1690812.29
+ },
+ {
+ "date": "20240416",
+ "open": 13.05,
+ "high": 13.33,
+ "low": 12.96,
+ "close": 13.21,
+ "volume": 1839498.19
+ },
+ {
+ "date": "20240417",
+ "open": 13.21,
+ "high": 13.56,
+ "low": 13.11,
+ "close": 13.52,
+ "volume": 2248667.06
+ },
+ {
+ "date": "20240418",
+ "open": 13.52,
+ "high": 13.83,
+ "low": 13.49,
+ "close": 13.71,
+ "volume": 2166747.86
+ },
+ {
+ "date": "20240419",
+ "open": 13.71,
+ "high": 13.8,
+ "low": 13.55,
+ "close": 13.69,
+ "volume": 2196627.86
+ },
+ {
+ "date": "20240420",
+ "open": 13.69,
+ "high": 13.75,
+ "low": 13.32,
+ "close": 13.42,
+ "volume": 2743086.06
+ }
+ ],
+ "source": "fixture",
+ "sample": true,
+ "teaching_tag": "银行股·低波动"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/000002.json b/zhishi/fixtures/ohlcv/000002.json
new file mode 100644
index 0000000..8a98126
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/000002.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "000002",
+ "name": "万科A",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 8.0,
+ "high": 8.22,
+ "low": 7.94,
+ "close": 8.17,
+ "volume": 2790155.72
+ },
+ {
+ "date": "20240102",
+ "open": 8.17,
+ "high": 8.22,
+ "low": 8.02,
+ "close": 8.1,
+ "volume": 2718686.82
+ },
+ {
+ "date": "20240103",
+ "open": 8.1,
+ "high": 8.16,
+ "low": 8.06,
+ "close": 8.15,
+ "volume": 2986443.63
+ },
+ {
+ "date": "20240104",
+ "open": 8.15,
+ "high": 8.17,
+ "low": 7.94,
+ "close": 8.02,
+ "volume": 1788681.66
+ },
+ {
+ "date": "20240105",
+ "open": 8.02,
+ "high": 8.05,
+ "low": 7.86,
+ "close": 7.93,
+ "volume": 1538251.38
+ },
+ {
+ "date": "20240106",
+ "open": 7.93,
+ "high": 7.98,
+ "low": 7.86,
+ "close": 7.93,
+ "volume": 1882649.89
+ },
+ {
+ "date": "20240107",
+ "open": 7.93,
+ "high": 7.97,
+ "low": 7.8,
+ "close": 7.8,
+ "volume": 1007954.94
+ },
+ {
+ "date": "20240108",
+ "open": 7.8,
+ "high": 7.85,
+ "low": 7.69,
+ "close": 7.71,
+ "volume": 2318549.58
+ },
+ {
+ "date": "20240109",
+ "open": 7.71,
+ "high": 7.72,
+ "low": 7.61,
+ "close": 7.61,
+ "volume": 2352724.17
+ },
+ {
+ "date": "20240110",
+ "open": 7.61,
+ "high": 7.77,
+ "low": 7.59,
+ "close": 7.75,
+ "volume": 828556.19
+ },
+ {
+ "date": "20240111",
+ "open": 7.75,
+ "high": 7.85,
+ "low": 7.74,
+ "close": 7.82,
+ "volume": 2223121.83
+ },
+ {
+ "date": "20240112",
+ "open": 7.82,
+ "high": 7.91,
+ "low": 7.81,
+ "close": 7.88,
+ "volume": 2205075.46
+ },
+ {
+ "date": "20240113",
+ "open": 7.88,
+ "high": 7.95,
+ "low": 7.87,
+ "close": 7.92,
+ "volume": 2843435.28
+ },
+ {
+ "date": "20240114",
+ "open": 7.92,
+ "high": 8.12,
+ "low": 7.84,
+ "close": 8.07,
+ "volume": 2076795.28
+ },
+ {
+ "date": "20240115",
+ "open": 8.07,
+ "high": 8.08,
+ "low": 7.98,
+ "close": 8.03,
+ "volume": 1942874.18
+ },
+ {
+ "date": "20240116",
+ "open": 8.03,
+ "high": 8.11,
+ "low": 7.96,
+ "close": 8.03,
+ "volume": 1052629.18
+ },
+ {
+ "date": "20240117",
+ "open": 8.03,
+ "high": 8.19,
+ "low": 7.98,
+ "close": 8.19,
+ "volume": 1493718.8
+ },
+ {
+ "date": "20240118",
+ "open": 8.19,
+ "high": 8.37,
+ "low": 8.14,
+ "close": 8.29,
+ "volume": 2478420.29
+ },
+ {
+ "date": "20240119",
+ "open": 8.29,
+ "high": 8.35,
+ "low": 8.14,
+ "close": 8.15,
+ "volume": 1801492.05
+ },
+ {
+ "date": "20240120",
+ "open": 8.15,
+ "high": 8.15,
+ "low": 8.05,
+ "close": 8.11,
+ "volume": 1005177.66
+ },
+ {
+ "date": "20240201",
+ "open": 8.11,
+ "high": 8.11,
+ "low": 7.99,
+ "close": 8.04,
+ "volume": 1462219.69
+ },
+ {
+ "date": "20240202",
+ "open": 8.04,
+ "high": 8.04,
+ "low": 7.88,
+ "close": 7.89,
+ "volume": 1914608.46
+ },
+ {
+ "date": "20240203",
+ "open": 7.89,
+ "high": 7.9,
+ "low": 7.69,
+ "close": 7.74,
+ "volume": 1960056.59
+ },
+ {
+ "date": "20240204",
+ "open": 7.74,
+ "high": 7.76,
+ "low": 7.62,
+ "close": 7.63,
+ "volume": 1405089.69
+ },
+ {
+ "date": "20240205",
+ "open": 7.63,
+ "high": 7.65,
+ "low": 7.6,
+ "close": 7.61,
+ "volume": 1298067.57
+ },
+ {
+ "date": "20240206",
+ "open": 7.61,
+ "high": 7.66,
+ "low": 7.5,
+ "close": 7.56,
+ "volume": 2225532.41
+ },
+ {
+ "date": "20240207",
+ "open": 7.56,
+ "high": 7.57,
+ "low": 7.55,
+ "close": 7.57,
+ "volume": 2195253.66
+ },
+ {
+ "date": "20240208",
+ "open": 7.57,
+ "high": 7.63,
+ "low": 7.48,
+ "close": 7.55,
+ "volume": 1452261.2
+ },
+ {
+ "date": "20240209",
+ "open": 7.55,
+ "high": 7.57,
+ "low": 7.47,
+ "close": 7.52,
+ "volume": 1017090.63
+ },
+ {
+ "date": "20240210",
+ "open": 7.52,
+ "high": 7.59,
+ "low": 7.44,
+ "close": 7.47,
+ "volume": 2933850.55
+ },
+ {
+ "date": "20240211",
+ "open": 7.47,
+ "high": 7.53,
+ "low": 7.42,
+ "close": 7.45,
+ "volume": 1018621.09
+ },
+ {
+ "date": "20240212",
+ "open": 7.45,
+ "high": 7.51,
+ "low": 7.38,
+ "close": 7.5,
+ "volume": 2341989.36
+ },
+ {
+ "date": "20240213",
+ "open": 7.5,
+ "high": 7.59,
+ "low": 7.46,
+ "close": 7.52,
+ "volume": 2926740.03
+ },
+ {
+ "date": "20240214",
+ "open": 7.52,
+ "high": 7.63,
+ "low": 7.5,
+ "close": 7.62,
+ "volume": 2661153.4
+ },
+ {
+ "date": "20240215",
+ "open": 7.62,
+ "high": 7.69,
+ "low": 7.5,
+ "close": 7.5,
+ "volume": 2449364.27
+ },
+ {
+ "date": "20240216",
+ "open": 7.5,
+ "high": 7.59,
+ "low": 7.45,
+ "close": 7.56,
+ "volume": 2080974.99
+ },
+ {
+ "date": "20240217",
+ "open": 7.56,
+ "high": 7.58,
+ "low": 7.52,
+ "close": 7.53,
+ "volume": 2241092.99
+ },
+ {
+ "date": "20240218",
+ "open": 7.53,
+ "high": 7.7,
+ "low": 7.46,
+ "close": 7.68,
+ "volume": 1674093.18
+ },
+ {
+ "date": "20240219",
+ "open": 7.68,
+ "high": 7.74,
+ "low": 7.54,
+ "close": 7.61,
+ "volume": 1001749.55
+ },
+ {
+ "date": "20240220",
+ "open": 7.61,
+ "high": 7.78,
+ "low": 7.55,
+ "close": 7.76,
+ "volume": 1444452.35
+ },
+ {
+ "date": "20240301",
+ "open": 7.76,
+ "high": 7.97,
+ "low": 7.74,
+ "close": 7.95,
+ "volume": 915244.98
+ },
+ {
+ "date": "20240302",
+ "open": 7.95,
+ "high": 7.95,
+ "low": 7.77,
+ "close": 7.84,
+ "volume": 844399.88
+ },
+ {
+ "date": "20240303",
+ "open": 7.84,
+ "high": 7.85,
+ "low": 7.71,
+ "close": 7.72,
+ "volume": 2506317.83
+ },
+ {
+ "date": "20240304",
+ "open": 7.72,
+ "high": 7.77,
+ "low": 7.54,
+ "close": 7.57,
+ "volume": 1122643.82
+ },
+ {
+ "date": "20240305",
+ "open": 7.57,
+ "high": 7.61,
+ "low": 7.48,
+ "close": 7.5,
+ "volume": 1660554.66
+ },
+ {
+ "date": "20240306",
+ "open": 7.5,
+ "high": 7.54,
+ "low": 7.42,
+ "close": 7.48,
+ "volume": 1439353.35
+ },
+ {
+ "date": "20240307",
+ "open": 7.48,
+ "high": 7.59,
+ "low": 7.45,
+ "close": 7.53,
+ "volume": 2481141.9
+ },
+ {
+ "date": "20240308",
+ "open": 7.53,
+ "high": 7.57,
+ "low": 7.38,
+ "close": 7.41,
+ "volume": 1076417.98
+ },
+ {
+ "date": "20240309",
+ "open": 7.41,
+ "high": 7.55,
+ "low": 7.37,
+ "close": 7.48,
+ "volume": 1577757.96
+ },
+ {
+ "date": "20240310",
+ "open": 7.48,
+ "high": 7.71,
+ "low": 7.43,
+ "close": 7.64,
+ "volume": 2034752.94
+ },
+ {
+ "date": "20240311",
+ "open": 7.64,
+ "high": 7.76,
+ "low": 7.58,
+ "close": 7.7,
+ "volume": 1985574.56
+ },
+ {
+ "date": "20240312",
+ "open": 7.7,
+ "high": 7.87,
+ "low": 7.65,
+ "close": 7.81,
+ "volume": 1963955.57
+ },
+ {
+ "date": "20240313",
+ "open": 7.81,
+ "high": 7.83,
+ "low": 7.74,
+ "close": 7.78,
+ "volume": 1475505.88
+ },
+ {
+ "date": "20240314",
+ "open": 7.78,
+ "high": 7.81,
+ "low": 7.71,
+ "close": 7.79,
+ "volume": 1083439.02
+ },
+ {
+ "date": "20240315",
+ "open": 7.79,
+ "high": 7.99,
+ "low": 7.72,
+ "close": 7.95,
+ "volume": 2739753.52
+ },
+ {
+ "date": "20240316",
+ "open": 7.95,
+ "high": 7.97,
+ "low": 7.77,
+ "close": 7.85,
+ "volume": 2255366.91
+ },
+ {
+ "date": "20240317",
+ "open": 7.85,
+ "high": 7.87,
+ "low": 7.71,
+ "close": 7.72,
+ "volume": 1469295.49
+ },
+ {
+ "date": "20240318",
+ "open": 7.72,
+ "high": 7.72,
+ "low": 7.59,
+ "close": 7.59,
+ "volume": 1839576.07
+ },
+ {
+ "date": "20240319",
+ "open": 7.59,
+ "high": 7.72,
+ "low": 7.54,
+ "close": 7.68,
+ "volume": 2238518.36
+ },
+ {
+ "date": "20240320",
+ "open": 7.68,
+ "high": 7.74,
+ "low": 7.54,
+ "close": 7.58,
+ "volume": 1721542.21
+ },
+ {
+ "date": "20240401",
+ "open": 7.58,
+ "high": 7.79,
+ "low": 7.53,
+ "close": 7.75,
+ "volume": 2510307.68
+ },
+ {
+ "date": "20240402",
+ "open": 7.75,
+ "high": 7.78,
+ "low": 7.74,
+ "close": 7.77,
+ "volume": 1437161.57
+ },
+ {
+ "date": "20240403",
+ "open": 7.77,
+ "high": 7.8,
+ "low": 7.67,
+ "close": 7.68,
+ "volume": 2492014.64
+ },
+ {
+ "date": "20240404",
+ "open": 7.68,
+ "high": 7.84,
+ "low": 7.67,
+ "close": 7.79,
+ "volume": 1278312.25
+ },
+ {
+ "date": "20240405",
+ "open": 7.79,
+ "high": 8.02,
+ "low": 7.73,
+ "close": 7.95,
+ "volume": 2712052.09
+ },
+ {
+ "date": "20240406",
+ "open": 7.95,
+ "high": 7.97,
+ "low": 7.83,
+ "close": 7.86,
+ "volume": 1841342.44
+ },
+ {
+ "date": "20240407",
+ "open": 7.86,
+ "high": 7.88,
+ "low": 7.77,
+ "close": 7.84,
+ "volume": 1204293.72
+ },
+ {
+ "date": "20240408",
+ "open": 7.84,
+ "high": 7.95,
+ "low": 7.82,
+ "close": 7.88,
+ "volume": 1537516.24
+ },
+ {
+ "date": "20240409",
+ "open": 7.88,
+ "high": 7.9,
+ "low": 7.79,
+ "close": 7.86,
+ "volume": 2732700.04
+ },
+ {
+ "date": "20240410",
+ "open": 7.86,
+ "high": 7.86,
+ "low": 7.7,
+ "close": 7.75,
+ "volume": 1909216.3
+ },
+ {
+ "date": "20240411",
+ "open": 7.75,
+ "high": 7.81,
+ "low": 7.54,
+ "close": 7.6,
+ "volume": 2037645.34
+ },
+ {
+ "date": "20240412",
+ "open": 7.6,
+ "high": 7.62,
+ "low": 7.42,
+ "close": 7.48,
+ "volume": 2306892.39
+ },
+ {
+ "date": "20240413",
+ "open": 7.48,
+ "high": 7.55,
+ "low": 7.48,
+ "close": 7.48,
+ "volume": 2304401.93
+ },
+ {
+ "date": "20240414",
+ "open": 7.48,
+ "high": 7.68,
+ "low": 7.48,
+ "close": 7.61,
+ "volume": 2349226.19
+ },
+ {
+ "date": "20240415",
+ "open": 7.61,
+ "high": 7.7,
+ "low": 7.6,
+ "close": 7.65,
+ "volume": 2918822.17
+ },
+ {
+ "date": "20240416",
+ "open": 7.65,
+ "high": 7.84,
+ "low": 7.61,
+ "close": 7.83,
+ "volume": 1978845.33
+ },
+ {
+ "date": "20240417",
+ "open": 7.83,
+ "high": 7.86,
+ "low": 7.82,
+ "close": 7.83,
+ "volume": 2406841.0
+ },
+ {
+ "date": "20240418",
+ "open": 7.83,
+ "high": 7.89,
+ "low": 7.79,
+ "close": 7.86,
+ "volume": 1428730.06
+ },
+ {
+ "date": "20240419",
+ "open": 7.86,
+ "high": 8.08,
+ "low": 7.84,
+ "close": 8.02,
+ "volume": 1476023.11
+ },
+ {
+ "date": "20240420",
+ "open": 8.02,
+ "high": 8.1,
+ "low": 7.95,
+ "close": 8.05,
+ "volume": 2842468.03
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "地产·制度风险讨论"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/000568.json b/zhishi/fixtures/ohlcv/000568.json
new file mode 100644
index 0000000..0b8c2b7
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/000568.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "000568",
+ "name": "泸州老窖",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 160,
+ "high": 160.95,
+ "low": 158.52,
+ "close": 160.06,
+ "volume": 1824430.15
+ },
+ {
+ "date": "20240102",
+ "open": 160.06,
+ "high": 161.46,
+ "low": 159.76,
+ "close": 160.51,
+ "volume": 1926199.01
+ },
+ {
+ "date": "20240103",
+ "open": 160.51,
+ "high": 163.14,
+ "low": 160.36,
+ "close": 161.85,
+ "volume": 1467482.78
+ },
+ {
+ "date": "20240104",
+ "open": 161.85,
+ "high": 163.16,
+ "low": 158.17,
+ "close": 159.28,
+ "volume": 892136.74
+ },
+ {
+ "date": "20240105",
+ "open": 159.28,
+ "high": 164.7,
+ "low": 158.23,
+ "close": 163.13,
+ "volume": 2154237.95
+ },
+ {
+ "date": "20240106",
+ "open": 163.13,
+ "high": 163.16,
+ "low": 160.17,
+ "close": 161.02,
+ "volume": 931012.43
+ },
+ {
+ "date": "20240107",
+ "open": 161.02,
+ "high": 161.41,
+ "low": 159.13,
+ "close": 159.18,
+ "volume": 1820655.81
+ },
+ {
+ "date": "20240108",
+ "open": 159.18,
+ "high": 160.52,
+ "low": 158.33,
+ "close": 159.15,
+ "volume": 2208641.76
+ },
+ {
+ "date": "20240109",
+ "open": 159.15,
+ "high": 160.61,
+ "low": 158.43,
+ "close": 159.55,
+ "volume": 1411958.38
+ },
+ {
+ "date": "20240110",
+ "open": 159.55,
+ "high": 165.15,
+ "low": 158.21,
+ "close": 163.52,
+ "volume": 2357181.17
+ },
+ {
+ "date": "20240111",
+ "open": 163.52,
+ "high": 163.9,
+ "low": 162.1,
+ "close": 162.57,
+ "volume": 954491.7
+ },
+ {
+ "date": "20240112",
+ "open": 162.57,
+ "high": 165.59,
+ "low": 161.2,
+ "close": 164.93,
+ "volume": 1650329.77
+ },
+ {
+ "date": "20240113",
+ "open": 164.93,
+ "high": 170.17,
+ "low": 164.93,
+ "close": 168.74,
+ "volume": 1261378.31
+ },
+ {
+ "date": "20240114",
+ "open": 168.74,
+ "high": 173.08,
+ "low": 167.08,
+ "close": 172.28,
+ "volume": 1674333.65
+ },
+ {
+ "date": "20240115",
+ "open": 172.28,
+ "high": 173.36,
+ "low": 168.08,
+ "close": 169.4,
+ "volume": 1393506.29
+ },
+ {
+ "date": "20240116",
+ "open": 169.4,
+ "high": 169.96,
+ "low": 165.07,
+ "close": 166.67,
+ "volume": 2467689.14
+ },
+ {
+ "date": "20240117",
+ "open": 166.67,
+ "high": 167.08,
+ "low": 164.06,
+ "close": 164.22,
+ "volume": 931765.49
+ },
+ {
+ "date": "20240118",
+ "open": 164.22,
+ "high": 167.13,
+ "low": 163.31,
+ "close": 166.83,
+ "volume": 1784334.73
+ },
+ {
+ "date": "20240119",
+ "open": 166.83,
+ "high": 168.05,
+ "low": 164.71,
+ "close": 164.92,
+ "volume": 2216173.27
+ },
+ {
+ "date": "20240120",
+ "open": 164.92,
+ "high": 165.62,
+ "low": 162.14,
+ "close": 162.49,
+ "volume": 1393548.95
+ },
+ {
+ "date": "20240201",
+ "open": 162.49,
+ "high": 167.68,
+ "low": 162.0,
+ "close": 166.34,
+ "volume": 2746703.25
+ },
+ {
+ "date": "20240202",
+ "open": 166.34,
+ "high": 167.0,
+ "low": 163.18,
+ "close": 164.59,
+ "volume": 2212038.44
+ },
+ {
+ "date": "20240203",
+ "open": 164.59,
+ "high": 166.22,
+ "low": 161.7,
+ "close": 162.04,
+ "volume": 1368210.63
+ },
+ {
+ "date": "20240204",
+ "open": 162.04,
+ "high": 164.98,
+ "low": 161.56,
+ "close": 164.44,
+ "volume": 961476.82
+ },
+ {
+ "date": "20240205",
+ "open": 164.44,
+ "high": 165.39,
+ "low": 161.42,
+ "close": 161.81,
+ "volume": 2122824.46
+ },
+ {
+ "date": "20240206",
+ "open": 161.81,
+ "high": 162.55,
+ "low": 159.74,
+ "close": 161.28,
+ "volume": 1864193.97
+ },
+ {
+ "date": "20240207",
+ "open": 161.28,
+ "high": 163.63,
+ "low": 160.99,
+ "close": 162.23,
+ "volume": 1139097.7
+ },
+ {
+ "date": "20240208",
+ "open": 162.23,
+ "high": 166.97,
+ "low": 161.82,
+ "close": 165.62,
+ "volume": 1217561.47
+ },
+ {
+ "date": "20240209",
+ "open": 165.62,
+ "high": 169.39,
+ "low": 165.29,
+ "close": 167.81,
+ "volume": 2890298.88
+ },
+ {
+ "date": "20240210",
+ "open": 167.81,
+ "high": 172.15,
+ "low": 167.11,
+ "close": 171.12,
+ "volume": 1028447.3
+ },
+ {
+ "date": "20240211",
+ "open": 171.12,
+ "high": 172.77,
+ "low": 167.59,
+ "close": 168.0,
+ "volume": 2350074.81
+ },
+ {
+ "date": "20240212",
+ "open": 168.0,
+ "high": 169.38,
+ "low": 165.58,
+ "close": 166.58,
+ "volume": 1445557.76
+ },
+ {
+ "date": "20240213",
+ "open": 166.58,
+ "high": 167.78,
+ "low": 164.45,
+ "close": 164.56,
+ "volume": 1302471.94
+ },
+ {
+ "date": "20240214",
+ "open": 164.56,
+ "high": 166.82,
+ "low": 163.55,
+ "close": 165.41,
+ "volume": 1416482.66
+ },
+ {
+ "date": "20240215",
+ "open": 165.41,
+ "high": 169.28,
+ "low": 165.39,
+ "close": 168.93,
+ "volume": 1392226.64
+ },
+ {
+ "date": "20240216",
+ "open": 168.93,
+ "high": 169.04,
+ "low": 168.63,
+ "close": 168.94,
+ "volume": 1611327.81
+ },
+ {
+ "date": "20240217",
+ "open": 168.94,
+ "high": 170.14,
+ "low": 168.33,
+ "close": 169.91,
+ "volume": 2760068.51
+ },
+ {
+ "date": "20240218",
+ "open": 169.91,
+ "high": 175.16,
+ "low": 168.74,
+ "close": 174.01,
+ "volume": 2085768.59
+ },
+ {
+ "date": "20240219",
+ "open": 174.01,
+ "high": 174.07,
+ "low": 171.6,
+ "close": 171.63,
+ "volume": 2802467.4
+ },
+ {
+ "date": "20240220",
+ "open": 171.63,
+ "high": 175.28,
+ "low": 171.59,
+ "close": 173.61,
+ "volume": 2199605.95
+ },
+ {
+ "date": "20240301",
+ "open": 173.61,
+ "high": 175.18,
+ "low": 173.06,
+ "close": 173.91,
+ "volume": 2998586.78
+ },
+ {
+ "date": "20240302",
+ "open": 173.91,
+ "high": 174.86,
+ "low": 169.76,
+ "close": 171.02,
+ "volume": 2780430.94
+ },
+ {
+ "date": "20240303",
+ "open": 171.02,
+ "high": 174.49,
+ "low": 169.66,
+ "close": 173.27,
+ "volume": 2813005.68
+ },
+ {
+ "date": "20240304",
+ "open": 173.27,
+ "high": 174.46,
+ "low": 170.99,
+ "close": 172.55,
+ "volume": 2716422.77
+ },
+ {
+ "date": "20240305",
+ "open": 172.55,
+ "high": 173.91,
+ "low": 170.85,
+ "close": 172.34,
+ "volume": 2060176.5
+ },
+ {
+ "date": "20240306",
+ "open": 172.34,
+ "high": 174.4,
+ "low": 171.33,
+ "close": 173.74,
+ "volume": 2139507.18
+ },
+ {
+ "date": "20240307",
+ "open": 173.74,
+ "high": 174.85,
+ "low": 169.19,
+ "close": 170.89,
+ "volume": 2735542.02
+ },
+ {
+ "date": "20240308",
+ "open": 170.89,
+ "high": 173.74,
+ "low": 169.63,
+ "close": 173.07,
+ "volume": 2078096.33
+ },
+ {
+ "date": "20240309",
+ "open": 173.07,
+ "high": 174.52,
+ "low": 172.9,
+ "close": 173.04,
+ "volume": 2450462.39
+ },
+ {
+ "date": "20240310",
+ "open": 173.04,
+ "high": 174.08,
+ "low": 168.99,
+ "close": 169.81,
+ "volume": 1306487.62
+ },
+ {
+ "date": "20240311",
+ "open": 169.81,
+ "high": 172.61,
+ "low": 168.77,
+ "close": 171.75,
+ "volume": 2825021.4
+ },
+ {
+ "date": "20240312",
+ "open": 171.75,
+ "high": 171.77,
+ "low": 169.78,
+ "close": 170.29,
+ "volume": 2291901.35
+ },
+ {
+ "date": "20240313",
+ "open": 170.29,
+ "high": 170.58,
+ "low": 166.91,
+ "close": 168.44,
+ "volume": 2251978.01
+ },
+ {
+ "date": "20240314",
+ "open": 168.44,
+ "high": 169.94,
+ "low": 167.87,
+ "close": 168.42,
+ "volume": 2264977.94
+ },
+ {
+ "date": "20240315",
+ "open": 168.42,
+ "high": 169.15,
+ "low": 165.21,
+ "close": 166.56,
+ "volume": 2811286.64
+ },
+ {
+ "date": "20240316",
+ "open": 166.56,
+ "high": 170.48,
+ "low": 165.59,
+ "close": 169.82,
+ "volume": 1496271.06
+ },
+ {
+ "date": "20240317",
+ "open": 169.82,
+ "high": 170.67,
+ "low": 166.07,
+ "close": 167.47,
+ "volume": 2667184.67
+ },
+ {
+ "date": "20240318",
+ "open": 167.47,
+ "high": 171.09,
+ "low": 167.0,
+ "close": 169.48,
+ "volume": 1172083.6
+ },
+ {
+ "date": "20240319",
+ "open": 169.48,
+ "high": 169.99,
+ "low": 169.12,
+ "close": 169.53,
+ "volume": 1710766.56
+ },
+ {
+ "date": "20240320",
+ "open": 169.53,
+ "high": 171.75,
+ "low": 168.99,
+ "close": 170.91,
+ "volume": 2646060.51
+ },
+ {
+ "date": "20240401",
+ "open": 170.91,
+ "high": 175.84,
+ "low": 170.78,
+ "close": 175.04,
+ "volume": 869268.71
+ },
+ {
+ "date": "20240402",
+ "open": 175.04,
+ "high": 178.49,
+ "low": 173.8,
+ "close": 178.42,
+ "volume": 2055280.31
+ },
+ {
+ "date": "20240403",
+ "open": 178.42,
+ "high": 179.83,
+ "low": 177.3,
+ "close": 177.33,
+ "volume": 1098938.55
+ },
+ {
+ "date": "20240404",
+ "open": 177.33,
+ "high": 177.46,
+ "low": 175.86,
+ "close": 177.41,
+ "volume": 1322299.82
+ },
+ {
+ "date": "20240405",
+ "open": 177.41,
+ "high": 177.5,
+ "low": 173.89,
+ "close": 174.99,
+ "volume": 1782257.69
+ },
+ {
+ "date": "20240406",
+ "open": 174.99,
+ "high": 177.61,
+ "low": 173.58,
+ "close": 176.45,
+ "volume": 2908613.43
+ },
+ {
+ "date": "20240407",
+ "open": 176.45,
+ "high": 178.71,
+ "low": 175.61,
+ "close": 178.36,
+ "volume": 1193109.41
+ },
+ {
+ "date": "20240408",
+ "open": 178.36,
+ "high": 179.2,
+ "low": 173.63,
+ "close": 174.88,
+ "volume": 1194017.38
+ },
+ {
+ "date": "20240409",
+ "open": 174.88,
+ "high": 175.48,
+ "low": 172.31,
+ "close": 173.52,
+ "volume": 1944930.48
+ },
+ {
+ "date": "20240410",
+ "open": 173.52,
+ "high": 176.17,
+ "low": 172.84,
+ "close": 174.85,
+ "volume": 2542250.92
+ },
+ {
+ "date": "20240411",
+ "open": 174.85,
+ "high": 178.64,
+ "low": 173.22,
+ "close": 178.48,
+ "volume": 2389229.79
+ },
+ {
+ "date": "20240412",
+ "open": 178.48,
+ "high": 179.29,
+ "low": 174.86,
+ "close": 175.96,
+ "volume": 2801923.79
+ },
+ {
+ "date": "20240413",
+ "open": 175.96,
+ "high": 176.96,
+ "low": 173.88,
+ "close": 175.42,
+ "volume": 2552887.93
+ },
+ {
+ "date": "20240414",
+ "open": 175.42,
+ "high": 180.2,
+ "low": 174.28,
+ "close": 179.37,
+ "volume": 1250767.6
+ },
+ {
+ "date": "20240415",
+ "open": 179.37,
+ "high": 183.09,
+ "low": 178.22,
+ "close": 181.61,
+ "volume": 2378856.3
+ },
+ {
+ "date": "20240416",
+ "open": 181.61,
+ "high": 183.24,
+ "low": 177.95,
+ "close": 179.72,
+ "volume": 2950188.75
+ },
+ {
+ "date": "20240417",
+ "open": 179.72,
+ "high": 181.89,
+ "low": 179.14,
+ "close": 180.47,
+ "volume": 2801977.38
+ },
+ {
+ "date": "20240418",
+ "open": 180.47,
+ "high": 184.45,
+ "low": 180.32,
+ "close": 183.81,
+ "volume": 1769982.62
+ },
+ {
+ "date": "20240419",
+ "open": 183.81,
+ "high": 186.1,
+ "low": 182.91,
+ "close": 184.68,
+ "volume": 862502.8
+ },
+ {
+ "date": "20240420",
+ "open": 184.68,
+ "high": 187.83,
+ "low": 183.2,
+ "close": 187.71,
+ "volume": 1180371.88
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "白酒·教学案例"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/000725.json b/zhishi/fixtures/ohlcv/000725.json
new file mode 100644
index 0000000..30b12d4
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/000725.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "000725",
+ "name": "京东方A",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 3.8,
+ "high": 3.84,
+ "low": 3.76,
+ "close": 3.81,
+ "volume": 1437175.83
+ },
+ {
+ "date": "20240102",
+ "open": 3.81,
+ "high": 3.9,
+ "low": 3.79,
+ "close": 3.87,
+ "volume": 1042356.51
+ },
+ {
+ "date": "20240103",
+ "open": 3.87,
+ "high": 3.88,
+ "low": 3.77,
+ "close": 3.8,
+ "volume": 1355244.29
+ },
+ {
+ "date": "20240104",
+ "open": 3.8,
+ "high": 3.82,
+ "low": 3.76,
+ "close": 3.81,
+ "volume": 2879426.61
+ },
+ {
+ "date": "20240105",
+ "open": 3.81,
+ "high": 3.84,
+ "low": 3.8,
+ "close": 3.8,
+ "volume": 2587739.8
+ },
+ {
+ "date": "20240106",
+ "open": 3.8,
+ "high": 3.88,
+ "low": 3.77,
+ "close": 3.87,
+ "volume": 2029562.11
+ },
+ {
+ "date": "20240107",
+ "open": 3.87,
+ "high": 3.97,
+ "low": 3.85,
+ "close": 3.96,
+ "volume": 2741403.43
+ },
+ {
+ "date": "20240108",
+ "open": 3.96,
+ "high": 4.01,
+ "low": 3.96,
+ "close": 4.0,
+ "volume": 2867507.3
+ },
+ {
+ "date": "20240109",
+ "open": 4.0,
+ "high": 4.04,
+ "low": 3.99,
+ "close": 4.0,
+ "volume": 2586849.35
+ },
+ {
+ "date": "20240110",
+ "open": 4.0,
+ "high": 4.1,
+ "low": 4.0,
+ "close": 4.07,
+ "volume": 1618824.25
+ },
+ {
+ "date": "20240111",
+ "open": 4.07,
+ "high": 4.1,
+ "low": 3.98,
+ "close": 4.0,
+ "volume": 2910911.48
+ },
+ {
+ "date": "20240112",
+ "open": 4.0,
+ "high": 4.03,
+ "low": 3.95,
+ "close": 3.98,
+ "volume": 1325682.44
+ },
+ {
+ "date": "20240113",
+ "open": 3.98,
+ "high": 4.04,
+ "low": 3.96,
+ "close": 4.0,
+ "volume": 1591357.2
+ },
+ {
+ "date": "20240114",
+ "open": 4.0,
+ "high": 4.03,
+ "low": 3.96,
+ "close": 3.97,
+ "volume": 2128572.15
+ },
+ {
+ "date": "20240115",
+ "open": 3.97,
+ "high": 4.01,
+ "low": 3.97,
+ "close": 3.99,
+ "volume": 2248843.3
+ },
+ {
+ "date": "20240116",
+ "open": 3.99,
+ "high": 4.09,
+ "low": 3.98,
+ "close": 4.08,
+ "volume": 2799889.67
+ },
+ {
+ "date": "20240117",
+ "open": 4.08,
+ "high": 4.11,
+ "low": 4.08,
+ "close": 4.1,
+ "volume": 2457192.79
+ },
+ {
+ "date": "20240118",
+ "open": 4.1,
+ "high": 4.12,
+ "low": 4.07,
+ "close": 4.08,
+ "volume": 2192824.38
+ },
+ {
+ "date": "20240119",
+ "open": 4.08,
+ "high": 4.15,
+ "low": 4.08,
+ "close": 4.13,
+ "volume": 2970939.16
+ },
+ {
+ "date": "20240120",
+ "open": 4.13,
+ "high": 4.22,
+ "low": 4.11,
+ "close": 4.22,
+ "volume": 2309196.32
+ },
+ {
+ "date": "20240201",
+ "open": 4.22,
+ "high": 4.25,
+ "low": 4.17,
+ "close": 4.21,
+ "volume": 2098322.44
+ },
+ {
+ "date": "20240202",
+ "open": 4.21,
+ "high": 4.22,
+ "low": 4.19,
+ "close": 4.2,
+ "volume": 1131763.27
+ },
+ {
+ "date": "20240203",
+ "open": 4.2,
+ "high": 4.21,
+ "low": 4.11,
+ "close": 4.14,
+ "volume": 1981351.52
+ },
+ {
+ "date": "20240204",
+ "open": 4.14,
+ "high": 4.25,
+ "low": 4.11,
+ "close": 4.21,
+ "volume": 908774.45
+ },
+ {
+ "date": "20240205",
+ "open": 4.21,
+ "high": 4.3,
+ "low": 4.17,
+ "close": 4.3,
+ "volume": 2645675.78
+ },
+ {
+ "date": "20240206",
+ "open": 4.3,
+ "high": 4.36,
+ "low": 4.3,
+ "close": 4.34,
+ "volume": 987337.62
+ },
+ {
+ "date": "20240207",
+ "open": 4.34,
+ "high": 4.39,
+ "low": 4.32,
+ "close": 4.38,
+ "volume": 1383499.67
+ },
+ {
+ "date": "20240208",
+ "open": 4.38,
+ "high": 4.39,
+ "low": 4.29,
+ "close": 4.32,
+ "volume": 1870990.22
+ },
+ {
+ "date": "20240209",
+ "open": 4.32,
+ "high": 4.34,
+ "low": 4.29,
+ "close": 4.31,
+ "volume": 1934468.9
+ },
+ {
+ "date": "20240210",
+ "open": 4.31,
+ "high": 4.35,
+ "low": 4.28,
+ "close": 4.31,
+ "volume": 1303934.52
+ },
+ {
+ "date": "20240211",
+ "open": 4.31,
+ "high": 4.32,
+ "low": 4.27,
+ "close": 4.29,
+ "volume": 862431.62
+ },
+ {
+ "date": "20240212",
+ "open": 4.29,
+ "high": 4.37,
+ "low": 4.27,
+ "close": 4.35,
+ "volume": 2765560.41
+ },
+ {
+ "date": "20240213",
+ "open": 4.35,
+ "high": 4.37,
+ "low": 4.28,
+ "close": 4.32,
+ "volume": 2022891.43
+ },
+ {
+ "date": "20240214",
+ "open": 4.32,
+ "high": 4.37,
+ "low": 4.28,
+ "close": 4.36,
+ "volume": 2460521.3
+ },
+ {
+ "date": "20240215",
+ "open": 4.36,
+ "high": 4.37,
+ "low": 4.3,
+ "close": 4.33,
+ "volume": 1940999.83
+ },
+ {
+ "date": "20240216",
+ "open": 4.33,
+ "high": 4.35,
+ "low": 4.3,
+ "close": 4.34,
+ "volume": 2348683.41
+ },
+ {
+ "date": "20240217",
+ "open": 4.34,
+ "high": 4.43,
+ "low": 4.32,
+ "close": 4.41,
+ "volume": 1909366.49
+ },
+ {
+ "date": "20240218",
+ "open": 4.41,
+ "high": 4.45,
+ "low": 4.41,
+ "close": 4.42,
+ "volume": 1379540.13
+ },
+ {
+ "date": "20240219",
+ "open": 4.42,
+ "high": 4.57,
+ "low": 4.4,
+ "close": 4.53,
+ "volume": 2454351.45
+ },
+ {
+ "date": "20240220",
+ "open": 4.53,
+ "high": 4.54,
+ "low": 4.46,
+ "close": 4.48,
+ "volume": 2338448.74
+ },
+ {
+ "date": "20240301",
+ "open": 4.48,
+ "high": 4.51,
+ "low": 4.36,
+ "close": 4.4,
+ "volume": 2146966.53
+ },
+ {
+ "date": "20240302",
+ "open": 4.4,
+ "high": 4.51,
+ "low": 4.36,
+ "close": 4.51,
+ "volume": 2642275.34
+ },
+ {
+ "date": "20240303",
+ "open": 4.51,
+ "high": 4.53,
+ "low": 4.39,
+ "close": 4.42,
+ "volume": 1288515.87
+ },
+ {
+ "date": "20240304",
+ "open": 4.42,
+ "high": 4.5,
+ "low": 4.39,
+ "close": 4.47,
+ "volume": 1741838.52
+ },
+ {
+ "date": "20240305",
+ "open": 4.47,
+ "high": 4.49,
+ "low": 4.38,
+ "close": 4.39,
+ "volume": 1985142.59
+ },
+ {
+ "date": "20240306",
+ "open": 4.39,
+ "high": 4.4,
+ "low": 4.33,
+ "close": 4.35,
+ "volume": 2603088.63
+ },
+ {
+ "date": "20240307",
+ "open": 4.35,
+ "high": 4.48,
+ "low": 4.35,
+ "close": 4.46,
+ "volume": 2450349.95
+ },
+ {
+ "date": "20240308",
+ "open": 4.46,
+ "high": 4.49,
+ "low": 4.4,
+ "close": 4.44,
+ "volume": 873756.51
+ },
+ {
+ "date": "20240309",
+ "open": 4.44,
+ "high": 4.51,
+ "low": 4.42,
+ "close": 4.49,
+ "volume": 1535343.96
+ },
+ {
+ "date": "20240310",
+ "open": 4.49,
+ "high": 4.52,
+ "low": 4.47,
+ "close": 4.51,
+ "volume": 1423280.67
+ },
+ {
+ "date": "20240311",
+ "open": 4.51,
+ "high": 4.52,
+ "low": 4.42,
+ "close": 4.45,
+ "volume": 1483137.82
+ },
+ {
+ "date": "20240312",
+ "open": 4.45,
+ "high": 4.46,
+ "low": 4.39,
+ "close": 4.4,
+ "volume": 2965863.74
+ },
+ {
+ "date": "20240313",
+ "open": 4.4,
+ "high": 4.47,
+ "low": 4.39,
+ "close": 4.47,
+ "volume": 1758965.59
+ },
+ {
+ "date": "20240314",
+ "open": 4.47,
+ "high": 4.5,
+ "low": 4.44,
+ "close": 4.48,
+ "volume": 2472283.5
+ },
+ {
+ "date": "20240315",
+ "open": 4.48,
+ "high": 4.51,
+ "low": 4.42,
+ "close": 4.42,
+ "volume": 1976541.53
+ },
+ {
+ "date": "20240316",
+ "open": 4.42,
+ "high": 4.46,
+ "low": 4.36,
+ "close": 4.4,
+ "volume": 2904722.9
+ },
+ {
+ "date": "20240317",
+ "open": 4.4,
+ "high": 4.43,
+ "low": 4.38,
+ "close": 4.39,
+ "volume": 2365567.3
+ },
+ {
+ "date": "20240318",
+ "open": 4.39,
+ "high": 4.48,
+ "low": 4.38,
+ "close": 4.46,
+ "volume": 2467751.06
+ },
+ {
+ "date": "20240319",
+ "open": 4.46,
+ "high": 4.56,
+ "low": 4.44,
+ "close": 4.52,
+ "volume": 1333723.5
+ },
+ {
+ "date": "20240320",
+ "open": 4.52,
+ "high": 4.53,
+ "low": 4.48,
+ "close": 4.48,
+ "volume": 1069335.0
+ },
+ {
+ "date": "20240401",
+ "open": 4.48,
+ "high": 4.51,
+ "low": 4.44,
+ "close": 4.49,
+ "volume": 1632075.81
+ },
+ {
+ "date": "20240402",
+ "open": 4.49,
+ "high": 4.53,
+ "low": 4.43,
+ "close": 4.43,
+ "volume": 1547494.78
+ },
+ {
+ "date": "20240403",
+ "open": 4.43,
+ "high": 4.51,
+ "low": 4.39,
+ "close": 4.5,
+ "volume": 2435692.76
+ },
+ {
+ "date": "20240404",
+ "open": 4.5,
+ "high": 4.54,
+ "low": 4.43,
+ "close": 4.47,
+ "volume": 1930788.63
+ },
+ {
+ "date": "20240405",
+ "open": 4.47,
+ "high": 4.47,
+ "low": 4.37,
+ "close": 4.41,
+ "volume": 2753513.79
+ },
+ {
+ "date": "20240406",
+ "open": 4.41,
+ "high": 4.49,
+ "low": 4.37,
+ "close": 4.45,
+ "volume": 1321685.38
+ },
+ {
+ "date": "20240407",
+ "open": 4.45,
+ "high": 4.49,
+ "low": 4.37,
+ "close": 4.4,
+ "volume": 1759562.16
+ },
+ {
+ "date": "20240408",
+ "open": 4.4,
+ "high": 4.41,
+ "low": 4.35,
+ "close": 4.37,
+ "volume": 2799772.4
+ },
+ {
+ "date": "20240409",
+ "open": 4.37,
+ "high": 4.38,
+ "low": 4.32,
+ "close": 4.32,
+ "volume": 2051561.58
+ },
+ {
+ "date": "20240410",
+ "open": 4.32,
+ "high": 4.35,
+ "low": 4.23,
+ "close": 4.25,
+ "volume": 1730971.36
+ },
+ {
+ "date": "20240411",
+ "open": 4.25,
+ "high": 4.26,
+ "low": 4.18,
+ "close": 4.21,
+ "volume": 2869654.47
+ },
+ {
+ "date": "20240412",
+ "open": 4.21,
+ "high": 4.28,
+ "low": 4.2,
+ "close": 4.27,
+ "volume": 1598080.03
+ },
+ {
+ "date": "20240413",
+ "open": 4.27,
+ "high": 4.39,
+ "low": 4.26,
+ "close": 4.35,
+ "volume": 2193516.37
+ },
+ {
+ "date": "20240414",
+ "open": 4.35,
+ "high": 4.37,
+ "low": 4.33,
+ "close": 4.34,
+ "volume": 2387464.43
+ },
+ {
+ "date": "20240415",
+ "open": 4.34,
+ "high": 4.45,
+ "low": 4.32,
+ "close": 4.41,
+ "volume": 1771770.62
+ },
+ {
+ "date": "20240416",
+ "open": 4.41,
+ "high": 4.45,
+ "low": 4.37,
+ "close": 4.45,
+ "volume": 2489568.73
+ },
+ {
+ "date": "20240417",
+ "open": 4.45,
+ "high": 4.47,
+ "low": 4.38,
+ "close": 4.4,
+ "volume": 2674172.6
+ },
+ {
+ "date": "20240418",
+ "open": 4.4,
+ "high": 4.46,
+ "low": 4.36,
+ "close": 4.45,
+ "volume": 2845799.49
+ },
+ {
+ "date": "20240419",
+ "open": 4.45,
+ "high": 4.56,
+ "low": 4.43,
+ "close": 4.54,
+ "volume": 1694340.08
+ },
+ {
+ "date": "20240420",
+ "open": 4.54,
+ "high": 4.56,
+ "low": 4.08,
+ "close": 4.12,
+ "volume": 3614160.5
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "制造·贴近跌停带演示"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/000858.json b/zhishi/fixtures/ohlcv/000858.json
new file mode 100644
index 0000000..ef68860
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/000858.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "000858",
+ "name": "五粮液",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 140,
+ "high": 140.21,
+ "low": 138.33,
+ "close": 139.24,
+ "volume": 959359.83
+ },
+ {
+ "date": "20240102",
+ "open": 139.24,
+ "high": 140.32,
+ "low": 139.16,
+ "close": 139.81,
+ "volume": 1916358.61
+ },
+ {
+ "date": "20240103",
+ "open": 139.81,
+ "high": 140.42,
+ "low": 137.16,
+ "close": 137.25,
+ "volume": 999568.63
+ },
+ {
+ "date": "20240104",
+ "open": 137.25,
+ "high": 138.39,
+ "low": 136.96,
+ "close": 137.13,
+ "volume": 1291125.72
+ },
+ {
+ "date": "20240105",
+ "open": 137.13,
+ "high": 139.57,
+ "low": 136.34,
+ "close": 138.26,
+ "volume": 1672697.04
+ },
+ {
+ "date": "20240106",
+ "open": 138.26,
+ "high": 141.63,
+ "low": 137.07,
+ "close": 141.57,
+ "volume": 1437140.43
+ },
+ {
+ "date": "20240107",
+ "open": 141.57,
+ "high": 141.73,
+ "low": 139.22,
+ "close": 139.66,
+ "volume": 2595477.99
+ },
+ {
+ "date": "20240108",
+ "open": 139.66,
+ "high": 140.47,
+ "low": 137.12,
+ "close": 138.0,
+ "volume": 1619274.59
+ },
+ {
+ "date": "20240109",
+ "open": 138.0,
+ "high": 138.73,
+ "low": 137.92,
+ "close": 138.64,
+ "volume": 1253109.17
+ },
+ {
+ "date": "20240110",
+ "open": 138.64,
+ "high": 140.71,
+ "low": 138.2,
+ "close": 140.11,
+ "volume": 2088236.1
+ },
+ {
+ "date": "20240111",
+ "open": 140.11,
+ "high": 140.59,
+ "low": 139.0,
+ "close": 140.17,
+ "volume": 2337787.75
+ },
+ {
+ "date": "20240112",
+ "open": 140.17,
+ "high": 140.97,
+ "low": 138.17,
+ "close": 138.9,
+ "volume": 2725302.49
+ },
+ {
+ "date": "20240113",
+ "open": 138.9,
+ "high": 141.09,
+ "low": 137.54,
+ "close": 140.68,
+ "volume": 1059744.71
+ },
+ {
+ "date": "20240114",
+ "open": 140.68,
+ "high": 141.75,
+ "low": 140.3,
+ "close": 140.52,
+ "volume": 1875718.82
+ },
+ {
+ "date": "20240115",
+ "open": 140.52,
+ "high": 141.46,
+ "low": 136.9,
+ "close": 137.96,
+ "volume": 2060657.07
+ },
+ {
+ "date": "20240116",
+ "open": 137.96,
+ "high": 141.07,
+ "low": 137.0,
+ "close": 140.63,
+ "volume": 2107613.73
+ },
+ {
+ "date": "20240117",
+ "open": 140.63,
+ "high": 142.13,
+ "low": 139.45,
+ "close": 141.49,
+ "volume": 2878298.41
+ },
+ {
+ "date": "20240118",
+ "open": 141.49,
+ "high": 142.62,
+ "low": 141.4,
+ "close": 141.68,
+ "volume": 2343282.45
+ },
+ {
+ "date": "20240119",
+ "open": 141.68,
+ "high": 144.39,
+ "low": 140.51,
+ "close": 142.97,
+ "volume": 1426110.17
+ },
+ {
+ "date": "20240120",
+ "open": 142.97,
+ "high": 143.93,
+ "low": 142.56,
+ "close": 142.59,
+ "volume": 1815729.63
+ },
+ {
+ "date": "20240201",
+ "open": 142.59,
+ "high": 142.76,
+ "low": 140.74,
+ "close": 140.82,
+ "volume": 2490112.57
+ },
+ {
+ "date": "20240202",
+ "open": 140.82,
+ "high": 141.17,
+ "low": 138.28,
+ "close": 138.82,
+ "volume": 2717128.34
+ },
+ {
+ "date": "20240203",
+ "open": 138.82,
+ "high": 139.45,
+ "low": 135.8,
+ "close": 136.55,
+ "volume": 2743444.42
+ },
+ {
+ "date": "20240204",
+ "open": 136.55,
+ "high": 140.05,
+ "low": 136.17,
+ "close": 138.85,
+ "volume": 1713652.34
+ },
+ {
+ "date": "20240205",
+ "open": 138.85,
+ "high": 140.08,
+ "low": 136.99,
+ "close": 138.32,
+ "volume": 1132025.99
+ },
+ {
+ "date": "20240206",
+ "open": 138.32,
+ "high": 138.64,
+ "low": 136.33,
+ "close": 136.65,
+ "volume": 1866918.01
+ },
+ {
+ "date": "20240207",
+ "open": 136.65,
+ "high": 137.9,
+ "low": 136.64,
+ "close": 137.54,
+ "volume": 1721682.3
+ },
+ {
+ "date": "20240208",
+ "open": 137.54,
+ "high": 138.32,
+ "low": 135.76,
+ "close": 137.07,
+ "volume": 2319086.05
+ },
+ {
+ "date": "20240209",
+ "open": 137.07,
+ "high": 138.36,
+ "low": 136.14,
+ "close": 137.51,
+ "volume": 918784.37
+ },
+ {
+ "date": "20240210",
+ "open": 137.51,
+ "high": 141.42,
+ "low": 136.31,
+ "close": 140.33,
+ "volume": 2555320.87
+ },
+ {
+ "date": "20240211",
+ "open": 140.33,
+ "high": 140.89,
+ "low": 139.85,
+ "close": 140.0,
+ "volume": 2195437.04
+ },
+ {
+ "date": "20240212",
+ "open": 140.0,
+ "high": 140.09,
+ "low": 137.3,
+ "close": 137.59,
+ "volume": 1157067.01
+ },
+ {
+ "date": "20240213",
+ "open": 137.59,
+ "high": 137.66,
+ "low": 136.94,
+ "close": 136.94,
+ "volume": 1132782.85
+ },
+ {
+ "date": "20240214",
+ "open": 136.94,
+ "high": 137.44,
+ "low": 134.79,
+ "close": 134.83,
+ "volume": 2723531.23
+ },
+ {
+ "date": "20240215",
+ "open": 134.83,
+ "high": 136.06,
+ "low": 134.49,
+ "close": 135.86,
+ "volume": 1564257.0
+ },
+ {
+ "date": "20240216",
+ "open": 135.86,
+ "high": 136.03,
+ "low": 134.22,
+ "close": 135.37,
+ "volume": 2984825.99
+ },
+ {
+ "date": "20240217",
+ "open": 135.37,
+ "high": 136.15,
+ "low": 135.25,
+ "close": 135.5,
+ "volume": 1024812.76
+ },
+ {
+ "date": "20240218",
+ "open": 135.5,
+ "high": 135.86,
+ "low": 133.76,
+ "close": 134.88,
+ "volume": 1155164.94
+ },
+ {
+ "date": "20240219",
+ "open": 134.88,
+ "high": 136.16,
+ "low": 131.62,
+ "close": 132.32,
+ "volume": 1122525.59
+ },
+ {
+ "date": "20240220",
+ "open": 132.32,
+ "high": 132.94,
+ "low": 131.62,
+ "close": 132.91,
+ "volume": 2952702.73
+ },
+ {
+ "date": "20240301",
+ "open": 132.91,
+ "high": 136.36,
+ "low": 132.56,
+ "close": 135.41,
+ "volume": 1606739.54
+ },
+ {
+ "date": "20240302",
+ "open": 135.41,
+ "high": 136.46,
+ "low": 133.01,
+ "close": 133.72,
+ "volume": 2513920.76
+ },
+ {
+ "date": "20240303",
+ "open": 133.72,
+ "high": 134.02,
+ "low": 131.95,
+ "close": 133.03,
+ "volume": 2966837.31
+ },
+ {
+ "date": "20240304",
+ "open": 133.03,
+ "high": 136.57,
+ "low": 131.94,
+ "close": 135.48,
+ "volume": 2427720.64
+ },
+ {
+ "date": "20240305",
+ "open": 135.48,
+ "high": 136.18,
+ "low": 133.67,
+ "close": 134.15,
+ "volume": 863756.33
+ },
+ {
+ "date": "20240306",
+ "open": 134.15,
+ "high": 134.52,
+ "low": 131.29,
+ "close": 131.63,
+ "volume": 2323548.27
+ },
+ {
+ "date": "20240307",
+ "open": 131.63,
+ "high": 135.27,
+ "low": 130.4,
+ "close": 134.67,
+ "volume": 2973683.73
+ },
+ {
+ "date": "20240308",
+ "open": 134.67,
+ "high": 138.26,
+ "low": 134.37,
+ "close": 137.76,
+ "volume": 1299060.82
+ },
+ {
+ "date": "20240309",
+ "open": 137.76,
+ "high": 138.04,
+ "low": 135.38,
+ "close": 136.23,
+ "volume": 2780678.34
+ },
+ {
+ "date": "20240310",
+ "open": 136.23,
+ "high": 139.32,
+ "low": 135.34,
+ "close": 138.65,
+ "volume": 2559216.24
+ },
+ {
+ "date": "20240311",
+ "open": 138.65,
+ "high": 139.57,
+ "low": 135.17,
+ "close": 136.41,
+ "volume": 2521066.35
+ },
+ {
+ "date": "20240312",
+ "open": 136.41,
+ "high": 138.95,
+ "low": 136.17,
+ "close": 138.29,
+ "volume": 2536097.95
+ },
+ {
+ "date": "20240313",
+ "open": 138.29,
+ "high": 139.39,
+ "low": 136.25,
+ "close": 137.59,
+ "volume": 1670844.69
+ },
+ {
+ "date": "20240314",
+ "open": 137.59,
+ "high": 138.89,
+ "low": 136.33,
+ "close": 137.32,
+ "volume": 1174008.05
+ },
+ {
+ "date": "20240315",
+ "open": 137.32,
+ "high": 137.53,
+ "low": 134.14,
+ "close": 135.36,
+ "volume": 2574304.36
+ },
+ {
+ "date": "20240316",
+ "open": 135.36,
+ "high": 136.48,
+ "low": 132.24,
+ "close": 133.54,
+ "volume": 2245990.24
+ },
+ {
+ "date": "20240317",
+ "open": 133.54,
+ "high": 134.28,
+ "low": 132.81,
+ "close": 132.98,
+ "volume": 831334.46
+ },
+ {
+ "date": "20240318",
+ "open": 132.98,
+ "high": 137.01,
+ "low": 132.28,
+ "close": 136.13,
+ "volume": 2853974.57
+ },
+ {
+ "date": "20240319",
+ "open": 136.13,
+ "high": 137.32,
+ "low": 134.94,
+ "close": 136.06,
+ "volume": 1264293.14
+ },
+ {
+ "date": "20240320",
+ "open": 136.06,
+ "high": 136.46,
+ "low": 134.56,
+ "close": 134.89,
+ "volume": 2090161.77
+ },
+ {
+ "date": "20240401",
+ "open": 134.89,
+ "high": 135.45,
+ "low": 133.59,
+ "close": 133.76,
+ "volume": 2802037.52
+ },
+ {
+ "date": "20240402",
+ "open": 133.76,
+ "high": 134.37,
+ "low": 132.44,
+ "close": 133.22,
+ "volume": 2789452.9
+ },
+ {
+ "date": "20240403",
+ "open": 133.22,
+ "high": 134.44,
+ "low": 132.41,
+ "close": 133.07,
+ "volume": 1970014.92
+ },
+ {
+ "date": "20240404",
+ "open": 133.07,
+ "high": 133.57,
+ "low": 132.49,
+ "close": 133.55,
+ "volume": 1202837.35
+ },
+ {
+ "date": "20240405",
+ "open": 133.55,
+ "high": 134.61,
+ "low": 130.67,
+ "close": 130.9,
+ "volume": 1841684.45
+ },
+ {
+ "date": "20240406",
+ "open": 130.9,
+ "high": 133.29,
+ "low": 130.47,
+ "close": 132.55,
+ "volume": 1940367.17
+ },
+ {
+ "date": "20240407",
+ "open": 132.55,
+ "high": 134.26,
+ "low": 132.41,
+ "close": 133.22,
+ "volume": 2032651.49
+ },
+ {
+ "date": "20240408",
+ "open": 133.22,
+ "high": 133.58,
+ "low": 131.02,
+ "close": 132.04,
+ "volume": 1916970.78
+ },
+ {
+ "date": "20240409",
+ "open": 132.04,
+ "high": 133.75,
+ "low": 130.84,
+ "close": 132.74,
+ "volume": 1775146.47
+ },
+ {
+ "date": "20240410",
+ "open": 132.74,
+ "high": 134.42,
+ "low": 132.06,
+ "close": 133.74,
+ "volume": 2324008.21
+ },
+ {
+ "date": "20240411",
+ "open": 133.74,
+ "high": 134.5,
+ "low": 133.1,
+ "close": 133.79,
+ "volume": 2871302.48
+ },
+ {
+ "date": "20240412",
+ "open": 133.79,
+ "high": 136.51,
+ "low": 132.53,
+ "close": 135.32,
+ "volume": 1371103.05
+ },
+ {
+ "date": "20240413",
+ "open": 135.32,
+ "high": 137.31,
+ "low": 134.19,
+ "close": 136.02,
+ "volume": 1101695.76
+ },
+ {
+ "date": "20240414",
+ "open": 136.02,
+ "high": 136.63,
+ "low": 133.95,
+ "close": 134.05,
+ "volume": 1329405.27
+ },
+ {
+ "date": "20240415",
+ "open": 134.05,
+ "high": 134.95,
+ "low": 130.77,
+ "close": 131.81,
+ "volume": 2773458.15
+ },
+ {
+ "date": "20240416",
+ "open": 131.81,
+ "high": 132.75,
+ "low": 129.23,
+ "close": 130.09,
+ "volume": 1114553.8
+ },
+ {
+ "date": "20240417",
+ "open": 130.09,
+ "high": 133.94,
+ "low": 129.8,
+ "close": 132.65,
+ "volume": 2895509.08
+ },
+ {
+ "date": "20240418",
+ "open": 132.65,
+ "high": 133.3,
+ "low": 131.07,
+ "close": 132.38,
+ "volume": 2631378.27
+ },
+ {
+ "date": "20240419",
+ "open": 132.38,
+ "high": 132.95,
+ "low": 130.02,
+ "close": 130.69,
+ "volume": 1546055.52
+ },
+ {
+ "date": "20240420",
+ "open": 130.69,
+ "high": 131.11,
+ "low": 128.3,
+ "close": 129.23,
+ "volume": 842862.44
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "白酒·回调复盘"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/002415.json b/zhishi/fixtures/ohlcv/002415.json
new file mode 100644
index 0000000..2ec3cac
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/002415.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "002415",
+ "name": "海康威视",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 30,
+ "high": 30.24,
+ "low": 29.8,
+ "close": 30.04,
+ "volume": 1113720.78
+ },
+ {
+ "date": "20240102",
+ "open": 30.04,
+ "high": 30.15,
+ "low": 29.37,
+ "close": 29.45,
+ "volume": 2582765.71
+ },
+ {
+ "date": "20240103",
+ "open": 29.45,
+ "high": 29.96,
+ "low": 29.29,
+ "close": 29.78,
+ "volume": 2254906.39
+ },
+ {
+ "date": "20240104",
+ "open": 29.78,
+ "high": 29.91,
+ "low": 29.33,
+ "close": 29.38,
+ "volume": 2793140.56
+ },
+ {
+ "date": "20240105",
+ "open": 29.38,
+ "high": 29.62,
+ "low": 28.85,
+ "close": 28.87,
+ "volume": 2311280.11
+ },
+ {
+ "date": "20240106",
+ "open": 28.87,
+ "high": 28.99,
+ "low": 28.49,
+ "close": 28.73,
+ "volume": 840929.46
+ },
+ {
+ "date": "20240107",
+ "open": 28.73,
+ "high": 28.99,
+ "low": 28.09,
+ "close": 28.23,
+ "volume": 1000151.58
+ },
+ {
+ "date": "20240108",
+ "open": 28.23,
+ "high": 29.2,
+ "low": 28.2,
+ "close": 28.92,
+ "volume": 1731054.55
+ },
+ {
+ "date": "20240109",
+ "open": 28.92,
+ "high": 29.01,
+ "low": 28.34,
+ "close": 28.52,
+ "volume": 1159753.08
+ },
+ {
+ "date": "20240110",
+ "open": 28.52,
+ "high": 28.86,
+ "low": 28.47,
+ "close": 28.85,
+ "volume": 2594534.83
+ },
+ {
+ "date": "20240111",
+ "open": 28.85,
+ "high": 28.97,
+ "low": 28.62,
+ "close": 28.79,
+ "volume": 1848890.14
+ },
+ {
+ "date": "20240112",
+ "open": 28.79,
+ "high": 28.8,
+ "low": 28.5,
+ "close": 28.71,
+ "volume": 2928409.54
+ },
+ {
+ "date": "20240113",
+ "open": 28.71,
+ "high": 29.59,
+ "low": 28.61,
+ "close": 29.4,
+ "volume": 1598882.82
+ },
+ {
+ "date": "20240114",
+ "open": 29.4,
+ "high": 29.92,
+ "low": 29.36,
+ "close": 29.72,
+ "volume": 1316939.34
+ },
+ {
+ "date": "20240115",
+ "open": 29.72,
+ "high": 29.87,
+ "low": 29.37,
+ "close": 29.61,
+ "volume": 1900026.67
+ },
+ {
+ "date": "20240116",
+ "open": 29.61,
+ "high": 29.86,
+ "low": 28.93,
+ "close": 29.06,
+ "volume": 1941794.07
+ },
+ {
+ "date": "20240117",
+ "open": 29.06,
+ "high": 29.18,
+ "low": 28.66,
+ "close": 28.77,
+ "volume": 2498220.87
+ },
+ {
+ "date": "20240118",
+ "open": 28.77,
+ "high": 28.93,
+ "low": 28.28,
+ "close": 28.33,
+ "volume": 2330970.19
+ },
+ {
+ "date": "20240119",
+ "open": 28.33,
+ "high": 28.4,
+ "low": 27.71,
+ "close": 27.81,
+ "volume": 2201245.2
+ },
+ {
+ "date": "20240120",
+ "open": 27.81,
+ "high": 27.93,
+ "low": 27.26,
+ "close": 27.32,
+ "volume": 1420170.75
+ },
+ {
+ "date": "20240201",
+ "open": 27.32,
+ "high": 27.62,
+ "low": 27.18,
+ "close": 27.35,
+ "volume": 2902962.13
+ },
+ {
+ "date": "20240202",
+ "open": 27.35,
+ "high": 27.61,
+ "low": 26.92,
+ "close": 27.01,
+ "volume": 1216311.02
+ },
+ {
+ "date": "20240203",
+ "open": 27.01,
+ "high": 27.63,
+ "low": 27.01,
+ "close": 27.38,
+ "volume": 1390158.91
+ },
+ {
+ "date": "20240204",
+ "open": 27.38,
+ "high": 27.88,
+ "low": 27.32,
+ "close": 27.79,
+ "volume": 818985.68
+ },
+ {
+ "date": "20240205",
+ "open": 27.79,
+ "high": 27.96,
+ "low": 27.01,
+ "close": 27.28,
+ "volume": 2996689.3
+ },
+ {
+ "date": "20240206",
+ "open": 27.28,
+ "high": 27.36,
+ "low": 27.19,
+ "close": 27.35,
+ "volume": 2532284.7
+ },
+ {
+ "date": "20240207",
+ "open": 27.35,
+ "high": 28.01,
+ "low": 27.29,
+ "close": 27.83,
+ "volume": 1959921.57
+ },
+ {
+ "date": "20240208",
+ "open": 27.83,
+ "high": 28.05,
+ "low": 27.76,
+ "close": 27.87,
+ "volume": 2882690.31
+ },
+ {
+ "date": "20240209",
+ "open": 27.87,
+ "high": 28.48,
+ "low": 27.79,
+ "close": 28.44,
+ "volume": 2720973.12
+ },
+ {
+ "date": "20240210",
+ "open": 28.44,
+ "high": 28.7,
+ "low": 28.08,
+ "close": 28.22,
+ "volume": 2331137.07
+ },
+ {
+ "date": "20240211",
+ "open": 28.22,
+ "high": 28.61,
+ "low": 28.14,
+ "close": 28.55,
+ "volume": 1360871.52
+ },
+ {
+ "date": "20240212",
+ "open": 28.55,
+ "high": 29.06,
+ "low": 28.52,
+ "close": 28.86,
+ "volume": 2750161.45
+ },
+ {
+ "date": "20240213",
+ "open": 28.86,
+ "high": 28.93,
+ "low": 28.7,
+ "close": 28.83,
+ "volume": 2954850.6
+ },
+ {
+ "date": "20240214",
+ "open": 28.83,
+ "high": 29.16,
+ "low": 28.56,
+ "close": 28.98,
+ "volume": 2916372.94
+ },
+ {
+ "date": "20240215",
+ "open": 28.98,
+ "high": 29.51,
+ "low": 28.81,
+ "close": 29.39,
+ "volume": 2782115.46
+ },
+ {
+ "date": "20240216",
+ "open": 29.39,
+ "high": 30.02,
+ "low": 29.29,
+ "close": 29.85,
+ "volume": 1610634.24
+ },
+ {
+ "date": "20240217",
+ "open": 29.85,
+ "high": 30.41,
+ "low": 29.84,
+ "close": 30.24,
+ "volume": 2362288.9
+ },
+ {
+ "date": "20240218",
+ "open": 30.24,
+ "high": 31.11,
+ "low": 29.97,
+ "close": 30.86,
+ "volume": 2803122.56
+ },
+ {
+ "date": "20240219",
+ "open": 30.86,
+ "high": 31.23,
+ "low": 30.75,
+ "close": 30.99,
+ "volume": 1016246.36
+ },
+ {
+ "date": "20240220",
+ "open": 30.99,
+ "high": 31.09,
+ "low": 30.57,
+ "close": 30.86,
+ "volume": 2316047.58
+ },
+ {
+ "date": "20240301",
+ "open": 30.86,
+ "high": 31.19,
+ "low": 30.82,
+ "close": 31.0,
+ "volume": 1975360.81
+ },
+ {
+ "date": "20240302",
+ "open": 31.0,
+ "high": 31.48,
+ "low": 30.92,
+ "close": 31.35,
+ "volume": 1695141.08
+ },
+ {
+ "date": "20240303",
+ "open": 31.35,
+ "high": 31.57,
+ "low": 31.14,
+ "close": 31.18,
+ "volume": 999182.47
+ },
+ {
+ "date": "20240304",
+ "open": 31.18,
+ "high": 31.4,
+ "low": 30.76,
+ "close": 31.0,
+ "volume": 2250664.95
+ },
+ {
+ "date": "20240305",
+ "open": 31.0,
+ "high": 31.8,
+ "low": 30.99,
+ "close": 31.68,
+ "volume": 1873210.19
+ },
+ {
+ "date": "20240306",
+ "open": 31.68,
+ "high": 31.74,
+ "low": 31.47,
+ "close": 31.68,
+ "volume": 1550783.12
+ },
+ {
+ "date": "20240307",
+ "open": 31.68,
+ "high": 31.78,
+ "low": 31.09,
+ "close": 31.39,
+ "volume": 816993.72
+ },
+ {
+ "date": "20240308",
+ "open": 31.39,
+ "high": 31.47,
+ "low": 31.21,
+ "close": 31.27,
+ "volume": 1751399.9
+ },
+ {
+ "date": "20240309",
+ "open": 31.27,
+ "high": 31.56,
+ "low": 30.8,
+ "close": 30.95,
+ "volume": 2335807.12
+ },
+ {
+ "date": "20240310",
+ "open": 30.95,
+ "high": 31.1,
+ "low": 30.37,
+ "close": 30.56,
+ "volume": 2654330.12
+ },
+ {
+ "date": "20240311",
+ "open": 30.56,
+ "high": 30.7,
+ "low": 30.03,
+ "close": 30.29,
+ "volume": 2629674.02
+ },
+ {
+ "date": "20240312",
+ "open": 30.29,
+ "high": 30.46,
+ "low": 29.77,
+ "close": 30.0,
+ "volume": 1669638.44
+ },
+ {
+ "date": "20240313",
+ "open": 30.0,
+ "high": 30.51,
+ "low": 29.7,
+ "close": 30.31,
+ "volume": 2018539.69
+ },
+ {
+ "date": "20240314",
+ "open": 30.31,
+ "high": 30.74,
+ "low": 30.08,
+ "close": 30.63,
+ "volume": 1508982.11
+ },
+ {
+ "date": "20240315",
+ "open": 30.63,
+ "high": 30.82,
+ "low": 30.53,
+ "close": 30.7,
+ "volume": 1099006.31
+ },
+ {
+ "date": "20240316",
+ "open": 30.7,
+ "high": 30.87,
+ "low": 30.33,
+ "close": 30.4,
+ "volume": 901002.94
+ },
+ {
+ "date": "20240317",
+ "open": 30.4,
+ "high": 30.98,
+ "low": 30.12,
+ "close": 30.89,
+ "volume": 2117339.06
+ },
+ {
+ "date": "20240318",
+ "open": 30.89,
+ "high": 31.16,
+ "low": 30.54,
+ "close": 30.82,
+ "volume": 1506127.85
+ },
+ {
+ "date": "20240319",
+ "open": 30.82,
+ "high": 31.01,
+ "low": 30.12,
+ "close": 30.37,
+ "volume": 2138706.2
+ },
+ {
+ "date": "20240320",
+ "open": 30.37,
+ "high": 30.97,
+ "low": 30.19,
+ "close": 30.84,
+ "volume": 1379037.32
+ },
+ {
+ "date": "20240401",
+ "open": 30.84,
+ "high": 30.96,
+ "low": 30.67,
+ "close": 30.79,
+ "volume": 1679013.52
+ },
+ {
+ "date": "20240402",
+ "open": 30.79,
+ "high": 31.34,
+ "low": 30.72,
+ "close": 31.29,
+ "volume": 1360280.18
+ },
+ {
+ "date": "20240403",
+ "open": 31.29,
+ "high": 32.2,
+ "low": 31.27,
+ "close": 32.03,
+ "volume": 2637869.88
+ },
+ {
+ "date": "20240404",
+ "open": 32.03,
+ "high": 32.92,
+ "low": 31.92,
+ "close": 32.65,
+ "volume": 2416227.08
+ },
+ {
+ "date": "20240405",
+ "open": 32.65,
+ "high": 32.69,
+ "low": 32.16,
+ "close": 32.45,
+ "volume": 2632681.54
+ },
+ {
+ "date": "20240406",
+ "open": 32.45,
+ "high": 32.73,
+ "low": 32.1,
+ "close": 32.1,
+ "volume": 1478511.2
+ },
+ {
+ "date": "20240407",
+ "open": 32.1,
+ "high": 32.16,
+ "low": 31.43,
+ "close": 31.48,
+ "volume": 2374824.55
+ },
+ {
+ "date": "20240408",
+ "open": 31.48,
+ "high": 31.54,
+ "low": 31.21,
+ "close": 31.27,
+ "volume": 1486316.41
+ },
+ {
+ "date": "20240409",
+ "open": 31.27,
+ "high": 32.05,
+ "low": 31.24,
+ "close": 31.86,
+ "volume": 2306986.43
+ },
+ {
+ "date": "20240410",
+ "open": 31.86,
+ "high": 32.14,
+ "low": 31.69,
+ "close": 31.99,
+ "volume": 2233291.51
+ },
+ {
+ "date": "20240411",
+ "open": 31.99,
+ "high": 32.67,
+ "low": 31.79,
+ "close": 32.5,
+ "volume": 1828040.15
+ },
+ {
+ "date": "20240412",
+ "open": 32.5,
+ "high": 32.91,
+ "low": 32.37,
+ "close": 32.78,
+ "volume": 1936646.18
+ },
+ {
+ "date": "20240413",
+ "open": 32.78,
+ "high": 33.27,
+ "low": 32.48,
+ "close": 33.18,
+ "volume": 1881401.11
+ },
+ {
+ "date": "20240414",
+ "open": 33.18,
+ "high": 34.03,
+ "low": 32.86,
+ "close": 33.79,
+ "volume": 2301393.14
+ },
+ {
+ "date": "20240415",
+ "open": 33.79,
+ "high": 33.93,
+ "low": 33.56,
+ "close": 33.77,
+ "volume": 2458515.22
+ },
+ {
+ "date": "20240416",
+ "open": 33.77,
+ "high": 34.41,
+ "low": 33.75,
+ "close": 34.37,
+ "volume": 1037914.91
+ },
+ {
+ "date": "20240417",
+ "open": 34.37,
+ "high": 34.39,
+ "low": 33.81,
+ "close": 33.81,
+ "volume": 1348952.61
+ },
+ {
+ "date": "20240418",
+ "open": 33.81,
+ "high": 34.04,
+ "low": 33.1,
+ "close": 33.31,
+ "volume": 2924444.71
+ },
+ {
+ "date": "20240419",
+ "open": 33.31,
+ "high": 34.33,
+ "low": 32.99,
+ "close": 34.08,
+ "volume": 861748.02
+ },
+ {
+ "date": "20240420",
+ "open": 34.08,
+ "high": 34.4,
+ "low": 33.59,
+ "close": 33.75,
+ "volume": 1254499.71
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "制造·量能常态"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/002594.json b/zhishi/fixtures/ohlcv/002594.json
new file mode 100644
index 0000000..efd9511
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/002594.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "002594",
+ "name": "比亚迪",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 220,
+ "high": 222.12,
+ "low": 217.57,
+ "close": 217.84,
+ "volume": 2350597.23
+ },
+ {
+ "date": "20240102",
+ "open": 217.84,
+ "high": 218.38,
+ "low": 212.18,
+ "close": 214.32,
+ "volume": 1260674.79
+ },
+ {
+ "date": "20240103",
+ "open": 214.32,
+ "high": 217.22,
+ "low": 213.35,
+ "close": 216.23,
+ "volume": 1888961.93
+ },
+ {
+ "date": "20240104",
+ "open": 216.23,
+ "high": 218.02,
+ "low": 213.58,
+ "close": 213.77,
+ "volume": 1315202.51
+ },
+ {
+ "date": "20240105",
+ "open": 213.77,
+ "high": 214.34,
+ "low": 208.83,
+ "close": 209.69,
+ "volume": 2784541.46
+ },
+ {
+ "date": "20240106",
+ "open": 209.69,
+ "high": 209.93,
+ "low": 208.53,
+ "close": 209.07,
+ "volume": 2981525.27
+ },
+ {
+ "date": "20240107",
+ "open": 209.07,
+ "high": 210.37,
+ "low": 204.71,
+ "close": 205.48,
+ "volume": 2253854.98
+ },
+ {
+ "date": "20240108",
+ "open": 205.48,
+ "high": 206.91,
+ "low": 203.49,
+ "close": 204.5,
+ "volume": 2229387.0
+ },
+ {
+ "date": "20240109",
+ "open": 204.5,
+ "high": 209.92,
+ "low": 204.21,
+ "close": 208.71,
+ "volume": 941621.69
+ },
+ {
+ "date": "20240110",
+ "open": 208.71,
+ "high": 214.46,
+ "low": 208.3,
+ "close": 213.42,
+ "volume": 2881297.51
+ },
+ {
+ "date": "20240111",
+ "open": 213.42,
+ "high": 216.28,
+ "low": 211.54,
+ "close": 214.71,
+ "volume": 1428437.11
+ },
+ {
+ "date": "20240112",
+ "open": 214.71,
+ "high": 216.6,
+ "low": 213.58,
+ "close": 213.86,
+ "volume": 2481449.66
+ },
+ {
+ "date": "20240113",
+ "open": 213.86,
+ "high": 215.34,
+ "low": 209.05,
+ "close": 210.53,
+ "volume": 2889999.41
+ },
+ {
+ "date": "20240114",
+ "open": 210.53,
+ "high": 215.39,
+ "low": 210.11,
+ "close": 214.31,
+ "volume": 1130351.71
+ },
+ {
+ "date": "20240115",
+ "open": 214.31,
+ "high": 216.22,
+ "low": 214.15,
+ "close": 215.12,
+ "volume": 2787085.39
+ },
+ {
+ "date": "20240116",
+ "open": 215.12,
+ "high": 217.24,
+ "low": 214.65,
+ "close": 215.73,
+ "volume": 1336549.82
+ },
+ {
+ "date": "20240117",
+ "open": 215.73,
+ "high": 216.47,
+ "low": 210.97,
+ "close": 211.53,
+ "volume": 1731484.09
+ },
+ {
+ "date": "20240118",
+ "open": 211.53,
+ "high": 213.3,
+ "low": 209.01,
+ "close": 210.89,
+ "volume": 1185552.18
+ },
+ {
+ "date": "20240119",
+ "open": 210.89,
+ "high": 211.24,
+ "low": 209.04,
+ "close": 210.43,
+ "volume": 2944660.16
+ },
+ {
+ "date": "20240120",
+ "open": 210.43,
+ "high": 212.04,
+ "low": 207.51,
+ "close": 208.13,
+ "volume": 829078.78
+ },
+ {
+ "date": "20240201",
+ "open": 208.13,
+ "high": 211.85,
+ "low": 207.78,
+ "close": 211.13,
+ "volume": 1758336.06
+ },
+ {
+ "date": "20240202",
+ "open": 211.13,
+ "high": 211.99,
+ "low": 208.18,
+ "close": 209.11,
+ "volume": 1719515.4
+ },
+ {
+ "date": "20240203",
+ "open": 209.11,
+ "high": 211.07,
+ "low": 208.91,
+ "close": 210.46,
+ "volume": 987562.92
+ },
+ {
+ "date": "20240204",
+ "open": 210.46,
+ "high": 211.56,
+ "low": 206.52,
+ "close": 207.26,
+ "volume": 2576939.61
+ },
+ {
+ "date": "20240205",
+ "open": 207.26,
+ "high": 209.3,
+ "low": 205.23,
+ "close": 207.83,
+ "volume": 938542.59
+ },
+ {
+ "date": "20240206",
+ "open": 207.83,
+ "high": 208.12,
+ "low": 203.04,
+ "close": 203.83,
+ "volume": 2062076.35
+ },
+ {
+ "date": "20240207",
+ "open": 203.83,
+ "high": 207.3,
+ "low": 201.86,
+ "close": 206.57,
+ "volume": 806468.4
+ },
+ {
+ "date": "20240208",
+ "open": 206.57,
+ "high": 210.65,
+ "low": 204.77,
+ "close": 210.21,
+ "volume": 872867.22
+ },
+ {
+ "date": "20240209",
+ "open": 210.21,
+ "high": 216.77,
+ "low": 208.13,
+ "close": 215.14,
+ "volume": 2076017.36
+ },
+ {
+ "date": "20240210",
+ "open": 215.14,
+ "high": 217.22,
+ "low": 211.62,
+ "close": 212.56,
+ "volume": 983380.57
+ },
+ {
+ "date": "20240211",
+ "open": 212.56,
+ "high": 215.16,
+ "low": 211.55,
+ "close": 214.1,
+ "volume": 1139942.85
+ },
+ {
+ "date": "20240212",
+ "open": 214.1,
+ "high": 215.34,
+ "low": 210.03,
+ "close": 210.99,
+ "volume": 1078194.1
+ },
+ {
+ "date": "20240213",
+ "open": 210.99,
+ "high": 212.52,
+ "low": 209.43,
+ "close": 210.94,
+ "volume": 1836855.88
+ },
+ {
+ "date": "20240214",
+ "open": 210.94,
+ "high": 211.7,
+ "low": 209.99,
+ "close": 210.46,
+ "volume": 1234515.11
+ },
+ {
+ "date": "20240215",
+ "open": 210.46,
+ "high": 210.7,
+ "low": 208.93,
+ "close": 210.48,
+ "volume": 2358306.47
+ },
+ {
+ "date": "20240216",
+ "open": 210.48,
+ "high": 212.11,
+ "low": 209.71,
+ "close": 212.06,
+ "volume": 1751324.24
+ },
+ {
+ "date": "20240217",
+ "open": 212.06,
+ "high": 214.11,
+ "low": 207.13,
+ "close": 208.71,
+ "volume": 1905681.72
+ },
+ {
+ "date": "20240218",
+ "open": 208.71,
+ "high": 211.58,
+ "low": 208.23,
+ "close": 211.16,
+ "volume": 1956629.85
+ },
+ {
+ "date": "20240219",
+ "open": 211.16,
+ "high": 215.39,
+ "low": 211.14,
+ "close": 214.0,
+ "volume": 2148971.38
+ },
+ {
+ "date": "20240220",
+ "open": 214.0,
+ "high": 220.1,
+ "low": 212.02,
+ "close": 218.48,
+ "volume": 2959808.14
+ },
+ {
+ "date": "20240301",
+ "open": 218.48,
+ "high": 219.12,
+ "low": 215.12,
+ "close": 216.31,
+ "volume": 2948967.64
+ },
+ {
+ "date": "20240302",
+ "open": 216.31,
+ "high": 218.34,
+ "low": 213.74,
+ "close": 215.57,
+ "volume": 1935803.16
+ },
+ {
+ "date": "20240303",
+ "open": 215.57,
+ "high": 219.41,
+ "low": 213.89,
+ "close": 217.33,
+ "volume": 1450819.43
+ },
+ {
+ "date": "20240304",
+ "open": 217.33,
+ "high": 221.68,
+ "low": 216.52,
+ "close": 221.25,
+ "volume": 2908883.82
+ },
+ {
+ "date": "20240305",
+ "open": 221.25,
+ "high": 225.96,
+ "low": 220.61,
+ "close": 225.26,
+ "volume": 2148673.57
+ },
+ {
+ "date": "20240306",
+ "open": 225.26,
+ "high": 230.86,
+ "low": 223.15,
+ "close": 229.3,
+ "volume": 2401672.39
+ },
+ {
+ "date": "20240307",
+ "open": 229.3,
+ "high": 234.59,
+ "low": 228.47,
+ "close": 233.18,
+ "volume": 1740503.29
+ },
+ {
+ "date": "20240308",
+ "open": 233.18,
+ "high": 234.89,
+ "low": 231.23,
+ "close": 233.66,
+ "volume": 1391460.51
+ },
+ {
+ "date": "20240309",
+ "open": 233.66,
+ "high": 235.37,
+ "low": 229.08,
+ "close": 229.71,
+ "volume": 1723417.85
+ },
+ {
+ "date": "20240310",
+ "open": 229.71,
+ "high": 231.61,
+ "low": 225.7,
+ "close": 226.32,
+ "volume": 1441621.74
+ },
+ {
+ "date": "20240311",
+ "open": 226.32,
+ "high": 231.15,
+ "low": 225.69,
+ "close": 229.99,
+ "volume": 2754474.54
+ },
+ {
+ "date": "20240312",
+ "open": 229.99,
+ "high": 230.82,
+ "low": 227.43,
+ "close": 229.65,
+ "volume": 2538357.81
+ },
+ {
+ "date": "20240313",
+ "open": 229.65,
+ "high": 233.36,
+ "low": 227.78,
+ "close": 232.78,
+ "volume": 2112517.8
+ },
+ {
+ "date": "20240314",
+ "open": 232.78,
+ "high": 237.69,
+ "low": 230.96,
+ "close": 236.81,
+ "volume": 2545563.2
+ },
+ {
+ "date": "20240315",
+ "open": 236.81,
+ "high": 238.36,
+ "low": 234.37,
+ "close": 236.21,
+ "volume": 2984782.44
+ },
+ {
+ "date": "20240316",
+ "open": 236.21,
+ "high": 243.17,
+ "low": 235.89,
+ "close": 241.27,
+ "volume": 2142628.87
+ },
+ {
+ "date": "20240317",
+ "open": 241.27,
+ "high": 244.1,
+ "low": 240.16,
+ "close": 243.88,
+ "volume": 2711166.41
+ },
+ {
+ "date": "20240318",
+ "open": 243.88,
+ "high": 251.25,
+ "low": 243.66,
+ "close": 248.94,
+ "volume": 2135590.29
+ },
+ {
+ "date": "20240319",
+ "open": 248.94,
+ "high": 255.31,
+ "low": 248.15,
+ "close": 253.65,
+ "volume": 885164.52
+ },
+ {
+ "date": "20240320",
+ "open": 253.65,
+ "high": 261.31,
+ "low": 252.0,
+ "close": 259.08,
+ "volume": 1605749.36
+ },
+ {
+ "date": "20240401",
+ "open": 259.08,
+ "high": 265.71,
+ "low": 257.2,
+ "close": 263.56,
+ "volume": 2119422.34
+ },
+ {
+ "date": "20240402",
+ "open": 263.56,
+ "high": 264.34,
+ "low": 261.14,
+ "close": 262.07,
+ "volume": 1518940.7
+ },
+ {
+ "date": "20240403",
+ "open": 262.07,
+ "high": 263.26,
+ "low": 260.18,
+ "close": 262.97,
+ "volume": 1565702.59
+ },
+ {
+ "date": "20240404",
+ "open": 262.97,
+ "high": 263.64,
+ "low": 258.59,
+ "close": 259.6,
+ "volume": 1748695.88
+ },
+ {
+ "date": "20240405",
+ "open": 259.6,
+ "high": 263.8,
+ "low": 259.02,
+ "close": 263.54,
+ "volume": 1444947.96
+ },
+ {
+ "date": "20240406",
+ "open": 263.54,
+ "high": 265.52,
+ "low": 260.08,
+ "close": 260.37,
+ "volume": 911930.21
+ },
+ {
+ "date": "20240407",
+ "open": 260.37,
+ "high": 263.6,
+ "low": 258.22,
+ "close": 261.67,
+ "volume": 2030851.53
+ },
+ {
+ "date": "20240408",
+ "open": 261.67,
+ "high": 263.98,
+ "low": 258.37,
+ "close": 260.29,
+ "volume": 1853557.28
+ },
+ {
+ "date": "20240409",
+ "open": 260.29,
+ "high": 264.12,
+ "low": 257.69,
+ "close": 261.67,
+ "volume": 2848740.5
+ },
+ {
+ "date": "20240410",
+ "open": 261.67,
+ "high": 262.53,
+ "low": 256.95,
+ "close": 258.0,
+ "volume": 1171714.69
+ },
+ {
+ "date": "20240411",
+ "open": 258.0,
+ "high": 261.85,
+ "low": 255.71,
+ "close": 261.69,
+ "volume": 2088233.64
+ },
+ {
+ "date": "20240412",
+ "open": 261.69,
+ "high": 264.78,
+ "low": 259.24,
+ "close": 263.68,
+ "volume": 2072358.39
+ },
+ {
+ "date": "20240413",
+ "open": 263.68,
+ "high": 271.53,
+ "low": 261.86,
+ "close": 269.05,
+ "volume": 2963403.06
+ },
+ {
+ "date": "20240414",
+ "open": 269.05,
+ "high": 270.58,
+ "low": 266.78,
+ "close": 269.59,
+ "volume": 1961577.38
+ },
+ {
+ "date": "20240415",
+ "open": 269.59,
+ "high": 271.43,
+ "low": 266.67,
+ "close": 267.95,
+ "volume": 1081357.21
+ },
+ {
+ "date": "20240416",
+ "open": 267.95,
+ "high": 274.06,
+ "low": 265.35,
+ "close": 272.69,
+ "volume": 1974054.95
+ },
+ {
+ "date": "20240417",
+ "open": 272.69,
+ "high": 279.54,
+ "low": 272.1,
+ "close": 278.73,
+ "volume": 1958313.65
+ },
+ {
+ "date": "20240418",
+ "open": 278.73,
+ "high": 285.11,
+ "low": 276.93,
+ "close": 282.78,
+ "volume": 1073384.23
+ },
+ {
+ "date": "20240419",
+ "open": 282.78,
+ "high": 282.88,
+ "low": 281.09,
+ "close": 282.14,
+ "volume": 2878447.7
+ },
+ {
+ "date": "20240420",
+ "open": 282.14,
+ "high": 284.11,
+ "low": 279.15,
+ "close": 280.9,
+ "volume": 1115098.34
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "新能源·放量讨论"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/300059.json b/zhishi/fixtures/ohlcv/300059.json
new file mode 100644
index 0000000..881ed5e
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/300059.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "300059",
+ "name": "东方财富",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": true,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 14,
+ "high": 14.33,
+ "low": 13.9,
+ "close": 14.33,
+ "volume": 1147627.99
+ },
+ {
+ "date": "20240102",
+ "open": 14.33,
+ "high": 14.68,
+ "low": 14.2,
+ "close": 14.68,
+ "volume": 2298971.46
+ },
+ {
+ "date": "20240103",
+ "open": 14.68,
+ "high": 15.1,
+ "low": 14.64,
+ "close": 14.95,
+ "volume": 1543771.07
+ },
+ {
+ "date": "20240104",
+ "open": 14.95,
+ "high": 15.17,
+ "low": 14.91,
+ "close": 15.13,
+ "volume": 1302941.4
+ },
+ {
+ "date": "20240105",
+ "open": 15.13,
+ "high": 15.54,
+ "low": 15.01,
+ "close": 15.41,
+ "volume": 1291460.66
+ },
+ {
+ "date": "20240106",
+ "open": 15.41,
+ "high": 15.82,
+ "low": 15.37,
+ "close": 15.74,
+ "volume": 1802180.98
+ },
+ {
+ "date": "20240107",
+ "open": 15.74,
+ "high": 15.75,
+ "low": 15.64,
+ "close": 15.72,
+ "volume": 1591921.79
+ },
+ {
+ "date": "20240108",
+ "open": 15.72,
+ "high": 15.96,
+ "low": 15.62,
+ "close": 15.81,
+ "volume": 1691220.94
+ },
+ {
+ "date": "20240109",
+ "open": 15.81,
+ "high": 16.27,
+ "low": 15.74,
+ "close": 16.11,
+ "volume": 2879054.58
+ },
+ {
+ "date": "20240110",
+ "open": 16.11,
+ "high": 16.13,
+ "low": 15.78,
+ "close": 15.8,
+ "volume": 2863742.54
+ },
+ {
+ "date": "20240111",
+ "open": 15.8,
+ "high": 16.09,
+ "low": 15.76,
+ "close": 15.98,
+ "volume": 1888967.16
+ },
+ {
+ "date": "20240112",
+ "open": 15.98,
+ "high": 16.31,
+ "low": 15.96,
+ "close": 16.3,
+ "volume": 904315.57
+ },
+ {
+ "date": "20240113",
+ "open": 16.3,
+ "high": 16.45,
+ "low": 16.21,
+ "close": 16.31,
+ "volume": 1683210.51
+ },
+ {
+ "date": "20240114",
+ "open": 16.31,
+ "high": 16.39,
+ "low": 16.16,
+ "close": 16.36,
+ "volume": 1578363.1
+ },
+ {
+ "date": "20240115",
+ "open": 16.36,
+ "high": 16.41,
+ "low": 16.07,
+ "close": 16.2,
+ "volume": 1500188.64
+ },
+ {
+ "date": "20240116",
+ "open": 16.2,
+ "high": 16.59,
+ "low": 16.13,
+ "close": 16.54,
+ "volume": 963242.1
+ },
+ {
+ "date": "20240117",
+ "open": 16.54,
+ "high": 17.02,
+ "low": 16.46,
+ "close": 16.88,
+ "volume": 1053881.26
+ },
+ {
+ "date": "20240118",
+ "open": 16.88,
+ "high": 16.98,
+ "low": 16.74,
+ "close": 16.92,
+ "volume": 2841562.93
+ },
+ {
+ "date": "20240119",
+ "open": 16.92,
+ "high": 17.19,
+ "low": 16.91,
+ "close": 17.14,
+ "volume": 2766668.0
+ },
+ {
+ "date": "20240120",
+ "open": 17.14,
+ "high": 17.56,
+ "low": 17.06,
+ "close": 17.53,
+ "volume": 1858135.69
+ },
+ {
+ "date": "20240201",
+ "open": 17.53,
+ "high": 17.96,
+ "low": 17.52,
+ "close": 17.95,
+ "volume": 2656246.69
+ },
+ {
+ "date": "20240202",
+ "open": 17.95,
+ "high": 18.13,
+ "low": 17.81,
+ "close": 18.05,
+ "volume": 2105349.03
+ },
+ {
+ "date": "20240203",
+ "open": 18.05,
+ "high": 18.3,
+ "low": 18.04,
+ "close": 18.25,
+ "volume": 819635.42
+ },
+ {
+ "date": "20240204",
+ "open": 18.25,
+ "high": 18.37,
+ "low": 18.09,
+ "close": 18.16,
+ "volume": 1564121.52
+ },
+ {
+ "date": "20240205",
+ "open": 18.16,
+ "high": 18.43,
+ "low": 18.05,
+ "close": 18.3,
+ "volume": 1485824.23
+ },
+ {
+ "date": "20240206",
+ "open": 18.3,
+ "high": 18.76,
+ "low": 18.14,
+ "close": 18.61,
+ "volume": 2763674.37
+ },
+ {
+ "date": "20240207",
+ "open": 18.61,
+ "high": 18.74,
+ "low": 18.19,
+ "close": 18.25,
+ "volume": 1654579.16
+ },
+ {
+ "date": "20240208",
+ "open": 18.25,
+ "high": 18.34,
+ "low": 18.21,
+ "close": 18.32,
+ "volume": 2969770.28
+ },
+ {
+ "date": "20240209",
+ "open": 18.32,
+ "high": 18.48,
+ "low": 18.1,
+ "close": 18.22,
+ "volume": 1492595.84
+ },
+ {
+ "date": "20240210",
+ "open": 18.22,
+ "high": 18.33,
+ "low": 17.99,
+ "close": 18.12,
+ "volume": 1548078.64
+ },
+ {
+ "date": "20240211",
+ "open": 18.12,
+ "high": 18.15,
+ "low": 17.65,
+ "close": 17.8,
+ "volume": 2403493.03
+ },
+ {
+ "date": "20240212",
+ "open": 17.8,
+ "high": 17.95,
+ "low": 17.43,
+ "close": 17.54,
+ "volume": 1536579.45
+ },
+ {
+ "date": "20240213",
+ "open": 17.54,
+ "high": 17.91,
+ "low": 17.52,
+ "close": 17.89,
+ "volume": 1555930.95
+ },
+ {
+ "date": "20240214",
+ "open": 17.89,
+ "high": 18.23,
+ "low": 17.8,
+ "close": 18.13,
+ "volume": 2794840.86
+ },
+ {
+ "date": "20240215",
+ "open": 18.13,
+ "high": 18.27,
+ "low": 18.08,
+ "close": 18.08,
+ "volume": 2522480.88
+ },
+ {
+ "date": "20240216",
+ "open": 18.08,
+ "high": 18.2,
+ "low": 17.7,
+ "close": 17.85,
+ "volume": 2242655.16
+ },
+ {
+ "date": "20240217",
+ "open": 17.85,
+ "high": 18.06,
+ "low": 17.72,
+ "close": 17.96,
+ "volume": 1611318.78
+ },
+ {
+ "date": "20240218",
+ "open": 17.96,
+ "high": 18.06,
+ "low": 17.69,
+ "close": 17.79,
+ "volume": 1055729.4
+ },
+ {
+ "date": "20240219",
+ "open": 17.79,
+ "high": 17.94,
+ "low": 17.76,
+ "close": 17.86,
+ "volume": 2356649.8
+ },
+ {
+ "date": "20240220",
+ "open": 17.86,
+ "high": 18.19,
+ "low": 17.7,
+ "close": 18.12,
+ "volume": 2971979.58
+ },
+ {
+ "date": "20240301",
+ "open": 18.12,
+ "high": 18.38,
+ "low": 18.07,
+ "close": 18.3,
+ "volume": 1085820.32
+ },
+ {
+ "date": "20240302",
+ "open": 18.3,
+ "high": 18.48,
+ "low": 18.15,
+ "close": 18.16,
+ "volume": 2815704.3
+ },
+ {
+ "date": "20240303",
+ "open": 18.16,
+ "high": 18.51,
+ "low": 18.14,
+ "close": 18.37,
+ "volume": 2221456.06
+ },
+ {
+ "date": "20240304",
+ "open": 18.37,
+ "high": 18.49,
+ "low": 18.02,
+ "close": 18.17,
+ "volume": 2387259.12
+ },
+ {
+ "date": "20240305",
+ "open": 18.17,
+ "high": 18.4,
+ "low": 18.13,
+ "close": 18.24,
+ "volume": 1145518.51
+ },
+ {
+ "date": "20240306",
+ "open": 18.24,
+ "high": 18.6,
+ "low": 18.17,
+ "close": 18.59,
+ "volume": 1723772.11
+ },
+ {
+ "date": "20240307",
+ "open": 18.59,
+ "high": 19.02,
+ "low": 18.48,
+ "close": 18.95,
+ "volume": 1902823.83
+ },
+ {
+ "date": "20240308",
+ "open": 18.95,
+ "high": 19.07,
+ "low": 18.86,
+ "close": 18.98,
+ "volume": 2111909.01
+ },
+ {
+ "date": "20240309",
+ "open": 18.98,
+ "high": 19.06,
+ "low": 18.79,
+ "close": 18.97,
+ "volume": 2948164.63
+ },
+ {
+ "date": "20240310",
+ "open": 18.97,
+ "high": 19.15,
+ "low": 18.8,
+ "close": 18.8,
+ "volume": 1531482.48
+ },
+ {
+ "date": "20240311",
+ "open": 18.8,
+ "high": 19.22,
+ "low": 18.68,
+ "close": 19.19,
+ "volume": 2987006.34
+ },
+ {
+ "date": "20240312",
+ "open": 19.19,
+ "high": 19.42,
+ "low": 19.18,
+ "close": 19.33,
+ "volume": 1792293.41
+ },
+ {
+ "date": "20240313",
+ "open": 19.33,
+ "high": 19.5,
+ "low": 19.26,
+ "close": 19.35,
+ "volume": 2572627.87
+ },
+ {
+ "date": "20240314",
+ "open": 19.35,
+ "high": 19.47,
+ "low": 19.17,
+ "close": 19.31,
+ "volume": 1165353.73
+ },
+ {
+ "date": "20240315",
+ "open": 19.31,
+ "high": 19.85,
+ "low": 19.22,
+ "close": 19.76,
+ "volume": 2939711.65
+ },
+ {
+ "date": "20240316",
+ "open": 19.76,
+ "high": 19.97,
+ "low": 19.71,
+ "close": 19.87,
+ "volume": 1284075.32
+ },
+ {
+ "date": "20240317",
+ "open": 19.87,
+ "high": 20.25,
+ "low": 19.74,
+ "close": 20.15,
+ "volume": 2329900.35
+ },
+ {
+ "date": "20240318",
+ "open": 20.15,
+ "high": 20.43,
+ "low": 19.98,
+ "close": 20.37,
+ "volume": 1789529.84
+ },
+ {
+ "date": "20240319",
+ "open": 20.37,
+ "high": 20.54,
+ "low": 19.94,
+ "close": 20.12,
+ "volume": 1065108.02
+ },
+ {
+ "date": "20240320",
+ "open": 20.12,
+ "high": 20.66,
+ "low": 20.07,
+ "close": 20.52,
+ "volume": 2065316.82
+ },
+ {
+ "date": "20240401",
+ "open": 20.52,
+ "high": 20.99,
+ "low": 20.38,
+ "close": 20.96,
+ "volume": 1328970.43
+ },
+ {
+ "date": "20240402",
+ "open": 20.96,
+ "high": 21.16,
+ "low": 20.48,
+ "close": 20.68,
+ "volume": 2241270.23
+ },
+ {
+ "date": "20240403",
+ "open": 20.68,
+ "high": 21.09,
+ "low": 20.59,
+ "close": 21.01,
+ "volume": 2153045.97
+ },
+ {
+ "date": "20240404",
+ "open": 21.01,
+ "high": 21.51,
+ "low": 20.91,
+ "close": 21.36,
+ "volume": 2180838.22
+ },
+ {
+ "date": "20240405",
+ "open": 21.36,
+ "high": 21.53,
+ "low": 21.13,
+ "close": 21.32,
+ "volume": 2502131.54
+ },
+ {
+ "date": "20240406",
+ "open": 21.32,
+ "high": 21.4,
+ "low": 20.99,
+ "close": 21.2,
+ "volume": 1632039.9
+ },
+ {
+ "date": "20240407",
+ "open": 21.2,
+ "high": 21.43,
+ "low": 21.17,
+ "close": 21.41,
+ "volume": 1296316.71
+ },
+ {
+ "date": "20240408",
+ "open": 21.41,
+ "high": 21.68,
+ "low": 21.27,
+ "close": 21.63,
+ "volume": 960080.07
+ },
+ {
+ "date": "20240409",
+ "open": 21.63,
+ "high": 22.02,
+ "low": 21.57,
+ "close": 21.87,
+ "volume": 1325395.29
+ },
+ {
+ "date": "20240410",
+ "open": 21.87,
+ "high": 21.98,
+ "low": 21.64,
+ "close": 21.68,
+ "volume": 1315727.87
+ },
+ {
+ "date": "20240411",
+ "open": 21.68,
+ "high": 22.24,
+ "low": 21.64,
+ "close": 22.03,
+ "volume": 1942865.64
+ },
+ {
+ "date": "20240412",
+ "open": 22.03,
+ "high": 22.45,
+ "low": 21.91,
+ "close": 22.24,
+ "volume": 1968826.59
+ },
+ {
+ "date": "20240413",
+ "open": 22.24,
+ "high": 22.75,
+ "low": 22.08,
+ "close": 22.57,
+ "volume": 2169602.86
+ },
+ {
+ "date": "20240414",
+ "open": 22.57,
+ "high": 22.95,
+ "low": 22.4,
+ "close": 22.94,
+ "volume": 1289117.52
+ },
+ {
+ "date": "20240415",
+ "open": 22.94,
+ "high": 23.03,
+ "low": 22.73,
+ "close": 22.85,
+ "volume": 2098161.87
+ },
+ {
+ "date": "20240416",
+ "open": 22.85,
+ "high": 23.07,
+ "low": 22.77,
+ "close": 22.99,
+ "volume": 2243164.97
+ },
+ {
+ "date": "20240417",
+ "open": 22.99,
+ "high": 23.59,
+ "low": 22.99,
+ "close": 23.5,
+ "volume": 2678157.13
+ },
+ {
+ "date": "20240418",
+ "open": 23.5,
+ "high": 24.17,
+ "low": 23.35,
+ "close": 23.97,
+ "volume": 1718024.72
+ },
+ {
+ "date": "20240419",
+ "open": 23.97,
+ "high": 24.19,
+ "low": 23.45,
+ "close": 23.56,
+ "volume": 1069660.71
+ },
+ {
+ "date": "20240420",
+ "open": 23.56,
+ "high": 23.76,
+ "low": 23.47,
+ "close": 23.75,
+ "volume": 2127146.38
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "券商互联·弹性"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/300750.json b/zhishi/fixtures/ohlcv/300750.json
new file mode 100644
index 0000000..89bb45f
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/300750.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "300750",
+ "name": "宁德时代",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": true,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 180,
+ "high": 180.98,
+ "low": 177.67,
+ "close": 178.33,
+ "volume": 2128624.08
+ },
+ {
+ "date": "20240102",
+ "open": 178.33,
+ "high": 179.9,
+ "low": 178.3,
+ "close": 179.78,
+ "volume": 2642431.98
+ },
+ {
+ "date": "20240103",
+ "open": 179.78,
+ "high": 180.2,
+ "low": 176.51,
+ "close": 178.28,
+ "volume": 1834579.72
+ },
+ {
+ "date": "20240104",
+ "open": 178.28,
+ "high": 182.29,
+ "low": 177.15,
+ "close": 181.43,
+ "volume": 1131356.13
+ },
+ {
+ "date": "20240105",
+ "open": 181.43,
+ "high": 184.57,
+ "low": 180.48,
+ "close": 182.98,
+ "volume": 2430754.08
+ },
+ {
+ "date": "20240106",
+ "open": 182.98,
+ "high": 184.97,
+ "low": 181.6,
+ "close": 184.85,
+ "volume": 2100419.08
+ },
+ {
+ "date": "20240107",
+ "open": 184.85,
+ "high": 184.91,
+ "low": 182.07,
+ "close": 183.66,
+ "volume": 1840048.0
+ },
+ {
+ "date": "20240108",
+ "open": 183.66,
+ "high": 187.56,
+ "low": 182.35,
+ "close": 185.93,
+ "volume": 2826417.07
+ },
+ {
+ "date": "20240109",
+ "open": 185.93,
+ "high": 187.42,
+ "low": 184.69,
+ "close": 185.52,
+ "volume": 2858290.79
+ },
+ {
+ "date": "20240110",
+ "open": 185.52,
+ "high": 189.33,
+ "low": 185.26,
+ "close": 189.14,
+ "volume": 1277371.27
+ },
+ {
+ "date": "20240111",
+ "open": 189.14,
+ "high": 194.42,
+ "low": 187.96,
+ "close": 193.58,
+ "volume": 1462257.64
+ },
+ {
+ "date": "20240112",
+ "open": 193.58,
+ "high": 194.87,
+ "low": 192.9,
+ "close": 194.12,
+ "volume": 2087163.04
+ },
+ {
+ "date": "20240113",
+ "open": 194.12,
+ "high": 197.11,
+ "low": 192.8,
+ "close": 195.35,
+ "volume": 2843680.32
+ },
+ {
+ "date": "20240114",
+ "open": 195.35,
+ "high": 200.94,
+ "low": 194.03,
+ "close": 198.97,
+ "volume": 1158819.17
+ },
+ {
+ "date": "20240115",
+ "open": 198.97,
+ "high": 204.65,
+ "low": 197.17,
+ "close": 202.69,
+ "volume": 2052036.51
+ },
+ {
+ "date": "20240116",
+ "open": 202.69,
+ "high": 205.58,
+ "low": 201.01,
+ "close": 205.15,
+ "volume": 2061771.18
+ },
+ {
+ "date": "20240117",
+ "open": 205.15,
+ "high": 205.28,
+ "low": 201.94,
+ "close": 203.68,
+ "volume": 2977573.23
+ },
+ {
+ "date": "20240118",
+ "open": 203.68,
+ "high": 205.31,
+ "low": 199.59,
+ "close": 200.42,
+ "volume": 1131683.82
+ },
+ {
+ "date": "20240119",
+ "open": 200.42,
+ "high": 201.96,
+ "low": 197.32,
+ "close": 199.06,
+ "volume": 897218.13
+ },
+ {
+ "date": "20240120",
+ "open": 199.06,
+ "high": 200.67,
+ "low": 197.63,
+ "close": 200.58,
+ "volume": 1528099.12
+ },
+ {
+ "date": "20240201",
+ "open": 200.58,
+ "high": 206.53,
+ "low": 199.57,
+ "close": 204.52,
+ "volume": 2996719.68
+ },
+ {
+ "date": "20240202",
+ "open": 204.52,
+ "high": 204.68,
+ "low": 202.06,
+ "close": 203.28,
+ "volume": 869031.08
+ },
+ {
+ "date": "20240203",
+ "open": 203.28,
+ "high": 204.11,
+ "low": 199.79,
+ "close": 201.02,
+ "volume": 1143637.78
+ },
+ {
+ "date": "20240204",
+ "open": 201.02,
+ "high": 202.77,
+ "low": 196.76,
+ "close": 197.38,
+ "volume": 2909050.74
+ },
+ {
+ "date": "20240205",
+ "open": 197.38,
+ "high": 202.16,
+ "low": 196.48,
+ "close": 201.4,
+ "volume": 1944160.57
+ },
+ {
+ "date": "20240206",
+ "open": 201.4,
+ "high": 204.42,
+ "low": 200.27,
+ "close": 203.21,
+ "volume": 2164277.5
+ },
+ {
+ "date": "20240207",
+ "open": 203.21,
+ "high": 208.8,
+ "low": 202.33,
+ "close": 207.75,
+ "volume": 2384684.75
+ },
+ {
+ "date": "20240208",
+ "open": 207.75,
+ "high": 208.37,
+ "low": 203.8,
+ "close": 205.81,
+ "volume": 1946480.05
+ },
+ {
+ "date": "20240209",
+ "open": 205.81,
+ "high": 206.8,
+ "low": 204.96,
+ "close": 206.78,
+ "volume": 2075923.47
+ },
+ {
+ "date": "20240210",
+ "open": 206.78,
+ "high": 208.05,
+ "low": 201.54,
+ "close": 202.83,
+ "volume": 932177.12
+ },
+ {
+ "date": "20240211",
+ "open": 202.83,
+ "high": 205.45,
+ "low": 201.45,
+ "close": 204.5,
+ "volume": 1575669.36
+ },
+ {
+ "date": "20240212",
+ "open": 204.5,
+ "high": 208.44,
+ "low": 204.45,
+ "close": 206.91,
+ "volume": 933268.97
+ },
+ {
+ "date": "20240213",
+ "open": 206.91,
+ "high": 211.08,
+ "low": 206.39,
+ "close": 209.07,
+ "volume": 1803886.69
+ },
+ {
+ "date": "20240214",
+ "open": 209.07,
+ "high": 211.14,
+ "low": 208.31,
+ "close": 210.46,
+ "volume": 1487875.45
+ },
+ {
+ "date": "20240215",
+ "open": 210.46,
+ "high": 211.72,
+ "low": 209.12,
+ "close": 209.75,
+ "volume": 1629752.75
+ },
+ {
+ "date": "20240216",
+ "open": 209.75,
+ "high": 212.9,
+ "low": 208.56,
+ "close": 212.84,
+ "volume": 2417381.0
+ },
+ {
+ "date": "20240217",
+ "open": 212.84,
+ "high": 213.32,
+ "low": 209.86,
+ "close": 211.56,
+ "volume": 1325129.39
+ },
+ {
+ "date": "20240218",
+ "open": 211.56,
+ "high": 212.48,
+ "low": 207.65,
+ "close": 209.11,
+ "volume": 1024051.72
+ },
+ {
+ "date": "20240219",
+ "open": 209.11,
+ "high": 209.81,
+ "low": 206.22,
+ "close": 207.96,
+ "volume": 1764547.61
+ },
+ {
+ "date": "20240220",
+ "open": 207.96,
+ "high": 212.16,
+ "low": 207.26,
+ "close": 211.8,
+ "volume": 2230511.23
+ },
+ {
+ "date": "20240301",
+ "open": 211.8,
+ "high": 216.98,
+ "low": 211.33,
+ "close": 216.0,
+ "volume": 1066022.51
+ },
+ {
+ "date": "20240302",
+ "open": 216.0,
+ "high": 217.24,
+ "low": 214.26,
+ "close": 216.83,
+ "volume": 2644648.03
+ },
+ {
+ "date": "20240303",
+ "open": 216.83,
+ "high": 217.43,
+ "low": 212.55,
+ "close": 214.28,
+ "volume": 2212261.96
+ },
+ {
+ "date": "20240304",
+ "open": 214.28,
+ "high": 218.53,
+ "low": 214.01,
+ "close": 217.77,
+ "volume": 1442274.36
+ },
+ {
+ "date": "20240305",
+ "open": 217.77,
+ "high": 221.8,
+ "low": 217.02,
+ "close": 221.2,
+ "volume": 1717192.53
+ },
+ {
+ "date": "20240306",
+ "open": 221.2,
+ "high": 222.1,
+ "low": 218.92,
+ "close": 220.95,
+ "volume": 1143195.29
+ },
+ {
+ "date": "20240307",
+ "open": 220.95,
+ "high": 223.04,
+ "low": 214.67,
+ "close": 216.58,
+ "volume": 2971210.04
+ },
+ {
+ "date": "20240308",
+ "open": 216.58,
+ "high": 218.64,
+ "low": 214.47,
+ "close": 216.48,
+ "volume": 1288599.62
+ },
+ {
+ "date": "20240309",
+ "open": 216.48,
+ "high": 221.25,
+ "low": 215.05,
+ "close": 219.41,
+ "volume": 1941832.95
+ },
+ {
+ "date": "20240310",
+ "open": 219.41,
+ "high": 220.16,
+ "low": 217.38,
+ "close": 217.88,
+ "volume": 949748.77
+ },
+ {
+ "date": "20240311",
+ "open": 217.88,
+ "high": 219.92,
+ "low": 216.11,
+ "close": 219.29,
+ "volume": 899168.98
+ },
+ {
+ "date": "20240312",
+ "open": 219.29,
+ "high": 225.38,
+ "low": 217.27,
+ "close": 223.82,
+ "volume": 2772447.76
+ },
+ {
+ "date": "20240313",
+ "open": 223.82,
+ "high": 229.73,
+ "low": 223.8,
+ "close": 228.41,
+ "volume": 2439656.19
+ },
+ {
+ "date": "20240314",
+ "open": 228.41,
+ "high": 229.09,
+ "low": 224.11,
+ "close": 225.61,
+ "volume": 1954921.1
+ },
+ {
+ "date": "20240315",
+ "open": 225.61,
+ "high": 227.73,
+ "low": 223.92,
+ "close": 225.3,
+ "volume": 1550975.85
+ },
+ {
+ "date": "20240316",
+ "open": 225.3,
+ "high": 227.24,
+ "low": 222.28,
+ "close": 223.35,
+ "volume": 2521115.25
+ },
+ {
+ "date": "20240317",
+ "open": 223.35,
+ "high": 223.79,
+ "low": 221.23,
+ "close": 222.42,
+ "volume": 2596983.86
+ },
+ {
+ "date": "20240318",
+ "open": 222.42,
+ "high": 224.18,
+ "low": 217.66,
+ "close": 219.69,
+ "volume": 2573312.29
+ },
+ {
+ "date": "20240319",
+ "open": 219.69,
+ "high": 223.45,
+ "low": 218.3,
+ "close": 223.43,
+ "volume": 2697620.05
+ },
+ {
+ "date": "20240320",
+ "open": 223.43,
+ "high": 224.04,
+ "low": 218.88,
+ "close": 219.47,
+ "volume": 1959985.59
+ },
+ {
+ "date": "20240401",
+ "open": 219.47,
+ "high": 220.5,
+ "low": 217.55,
+ "close": 219.25,
+ "volume": 803979.03
+ },
+ {
+ "date": "20240402",
+ "open": 219.25,
+ "high": 219.53,
+ "low": 215.14,
+ "close": 215.41,
+ "volume": 950516.71
+ },
+ {
+ "date": "20240403",
+ "open": 215.41,
+ "high": 222.43,
+ "low": 215.22,
+ "close": 220.55,
+ "volume": 1904664.01
+ },
+ {
+ "date": "20240404",
+ "open": 220.55,
+ "high": 221.24,
+ "low": 218.5,
+ "close": 219.27,
+ "volume": 2223209.95
+ },
+ {
+ "date": "20240405",
+ "open": 219.27,
+ "high": 221.47,
+ "low": 218.85,
+ "close": 220.68,
+ "volume": 1523307.87
+ },
+ {
+ "date": "20240406",
+ "open": 220.68,
+ "high": 221.9,
+ "low": 215.93,
+ "close": 217.49,
+ "volume": 1636523.74
+ },
+ {
+ "date": "20240407",
+ "open": 217.49,
+ "high": 217.88,
+ "low": 213.13,
+ "close": 213.92,
+ "volume": 2129756.71
+ },
+ {
+ "date": "20240408",
+ "open": 213.92,
+ "high": 218.01,
+ "low": 212.21,
+ "close": 217.18,
+ "volume": 2170438.32
+ },
+ {
+ "date": "20240409",
+ "open": 217.18,
+ "high": 217.99,
+ "low": 215.98,
+ "close": 217.05,
+ "volume": 2346337.45
+ },
+ {
+ "date": "20240410",
+ "open": 217.05,
+ "high": 218.56,
+ "low": 215.82,
+ "close": 216.82,
+ "volume": 1339183.25
+ },
+ {
+ "date": "20240411",
+ "open": 216.82,
+ "high": 219.23,
+ "low": 216.67,
+ "close": 217.71,
+ "volume": 1734754.8
+ },
+ {
+ "date": "20240412",
+ "open": 217.71,
+ "high": 219.63,
+ "low": 215.49,
+ "close": 217.53,
+ "volume": 1623318.53
+ },
+ {
+ "date": "20240413",
+ "open": 217.53,
+ "high": 223.72,
+ "low": 216.96,
+ "close": 221.97,
+ "volume": 1821115.07
+ },
+ {
+ "date": "20240414",
+ "open": 221.97,
+ "high": 223.77,
+ "low": 217.31,
+ "close": 218.76,
+ "volume": 2752155.7
+ },
+ {
+ "date": "20240415",
+ "open": 218.76,
+ "high": 223.67,
+ "low": 217.15,
+ "close": 222.19,
+ "volume": 2040456.7
+ },
+ {
+ "date": "20240416",
+ "open": 222.19,
+ "high": 223.49,
+ "low": 218.76,
+ "close": 218.77,
+ "volume": 1115740.39
+ },
+ {
+ "date": "20240417",
+ "open": 218.77,
+ "high": 222.12,
+ "low": 218.57,
+ "close": 222.02,
+ "volume": 1018459.1
+ },
+ {
+ "date": "20240418",
+ "open": 222.02,
+ "high": 226.78,
+ "low": 221.97,
+ "close": 226.38,
+ "volume": 2651378.26
+ },
+ {
+ "date": "20240419",
+ "open": 226.38,
+ "high": 228.29,
+ "low": 221.58,
+ "close": 223.08,
+ "volume": 2639600.29
+ },
+ {
+ "date": "20240420",
+ "open": 223.08,
+ "high": 229.5,
+ "low": 221.3,
+ "close": 228.18,
+ "volume": 879792.39
+ }
+ ],
+ "source": "fixture",
+ "sample": true,
+ "teaching_tag": "创业板·弹性"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600000.json b/zhishi/fixtures/ohlcv/600000.json
new file mode 100644
index 0000000..ed6acde
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600000.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600000",
+ "name": "浦发银行",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 7.5,
+ "high": 7.64,
+ "low": 7.46,
+ "close": 7.58,
+ "volume": 1925281.75
+ },
+ {
+ "date": "20240102",
+ "open": 7.58,
+ "high": 7.65,
+ "low": 7.54,
+ "close": 7.56,
+ "volume": 1126171.55
+ },
+ {
+ "date": "20240103",
+ "open": 7.56,
+ "high": 7.58,
+ "low": 7.47,
+ "close": 7.5,
+ "volume": 1389403.86
+ },
+ {
+ "date": "20240104",
+ "open": 7.5,
+ "high": 7.52,
+ "low": 7.36,
+ "close": 7.39,
+ "volume": 2052328.03
+ },
+ {
+ "date": "20240105",
+ "open": 7.39,
+ "high": 7.39,
+ "low": 7.29,
+ "close": 7.3,
+ "volume": 1993373.71
+ },
+ {
+ "date": "20240106",
+ "open": 7.3,
+ "high": 7.36,
+ "low": 7.23,
+ "close": 7.29,
+ "volume": 1711762.7
+ },
+ {
+ "date": "20240107",
+ "open": 7.29,
+ "high": 7.34,
+ "low": 7.12,
+ "close": 7.17,
+ "volume": 1671339.33
+ },
+ {
+ "date": "20240108",
+ "open": 7.17,
+ "high": 7.26,
+ "low": 7.11,
+ "close": 7.24,
+ "volume": 2634375.11
+ },
+ {
+ "date": "20240109",
+ "open": 7.24,
+ "high": 7.43,
+ "low": 7.23,
+ "close": 7.36,
+ "volume": 1999554.25
+ },
+ {
+ "date": "20240110",
+ "open": 7.36,
+ "high": 7.51,
+ "low": 7.33,
+ "close": 7.45,
+ "volume": 1104795.71
+ },
+ {
+ "date": "20240111",
+ "open": 7.45,
+ "high": 7.52,
+ "low": 7.4,
+ "close": 7.51,
+ "volume": 815300.78
+ },
+ {
+ "date": "20240112",
+ "open": 7.51,
+ "high": 7.55,
+ "low": 7.5,
+ "close": 7.51,
+ "volume": 1856425.52
+ },
+ {
+ "date": "20240113",
+ "open": 7.51,
+ "high": 7.56,
+ "low": 7.45,
+ "close": 7.53,
+ "volume": 2705354.37
+ },
+ {
+ "date": "20240114",
+ "open": 7.53,
+ "high": 7.7,
+ "low": 7.53,
+ "close": 7.68,
+ "volume": 1628545.6
+ },
+ {
+ "date": "20240115",
+ "open": 7.68,
+ "high": 7.74,
+ "low": 7.55,
+ "close": 7.57,
+ "volume": 1082443.2
+ },
+ {
+ "date": "20240116",
+ "open": 7.57,
+ "high": 7.6,
+ "low": 7.46,
+ "close": 7.52,
+ "volume": 1814287.76
+ },
+ {
+ "date": "20240117",
+ "open": 7.52,
+ "high": 7.57,
+ "low": 7.46,
+ "close": 7.47,
+ "volume": 1260253.34
+ },
+ {
+ "date": "20240118",
+ "open": 7.47,
+ "high": 7.61,
+ "low": 7.46,
+ "close": 7.55,
+ "volume": 946229.46
+ },
+ {
+ "date": "20240119",
+ "open": 7.55,
+ "high": 7.62,
+ "low": 7.55,
+ "close": 7.57,
+ "volume": 1760907.4
+ },
+ {
+ "date": "20240120",
+ "open": 7.57,
+ "high": 7.58,
+ "low": 7.5,
+ "close": 7.51,
+ "volume": 1428849.32
+ },
+ {
+ "date": "20240201",
+ "open": 7.51,
+ "high": 7.53,
+ "low": 7.47,
+ "close": 7.52,
+ "volume": 2733260.58
+ },
+ {
+ "date": "20240202",
+ "open": 7.52,
+ "high": 7.61,
+ "low": 7.47,
+ "close": 7.6,
+ "volume": 2194508.98
+ },
+ {
+ "date": "20240203",
+ "open": 7.6,
+ "high": 7.63,
+ "low": 7.4,
+ "close": 7.45,
+ "volume": 2890311.27
+ },
+ {
+ "date": "20240204",
+ "open": 7.45,
+ "high": 7.66,
+ "low": 7.41,
+ "close": 7.61,
+ "volume": 2908631.29
+ },
+ {
+ "date": "20240205",
+ "open": 7.61,
+ "high": 7.65,
+ "low": 7.53,
+ "close": 7.53,
+ "volume": 2504111.81
+ },
+ {
+ "date": "20240206",
+ "open": 7.53,
+ "high": 7.62,
+ "low": 7.52,
+ "close": 7.6,
+ "volume": 1952192.38
+ },
+ {
+ "date": "20240207",
+ "open": 7.6,
+ "high": 7.72,
+ "low": 7.58,
+ "close": 7.71,
+ "volume": 1928065.63
+ },
+ {
+ "date": "20240208",
+ "open": 7.71,
+ "high": 7.78,
+ "low": 7.59,
+ "close": 7.65,
+ "volume": 2901884.49
+ },
+ {
+ "date": "20240209",
+ "open": 7.65,
+ "high": 7.77,
+ "low": 7.62,
+ "close": 7.71,
+ "volume": 1910364.28
+ },
+ {
+ "date": "20240210",
+ "open": 7.71,
+ "high": 7.75,
+ "low": 7.7,
+ "close": 7.71,
+ "volume": 2669290.38
+ },
+ {
+ "date": "20240211",
+ "open": 7.71,
+ "high": 7.74,
+ "low": 7.54,
+ "close": 7.61,
+ "volume": 1928499.36
+ },
+ {
+ "date": "20240212",
+ "open": 7.61,
+ "high": 7.77,
+ "low": 7.57,
+ "close": 7.75,
+ "volume": 1634353.09
+ },
+ {
+ "date": "20240213",
+ "open": 7.75,
+ "high": 7.78,
+ "low": 7.68,
+ "close": 7.71,
+ "volume": 2651884.22
+ },
+ {
+ "date": "20240214",
+ "open": 7.71,
+ "high": 7.9,
+ "low": 7.66,
+ "close": 7.89,
+ "volume": 1963450.2
+ },
+ {
+ "date": "20240215",
+ "open": 7.89,
+ "high": 7.9,
+ "low": 7.85,
+ "close": 7.88,
+ "volume": 1497400.09
+ },
+ {
+ "date": "20240216",
+ "open": 7.88,
+ "high": 7.93,
+ "low": 7.83,
+ "close": 7.86,
+ "volume": 1450702.39
+ },
+ {
+ "date": "20240217",
+ "open": 7.86,
+ "high": 7.93,
+ "low": 7.76,
+ "close": 7.8,
+ "volume": 2940324.05
+ },
+ {
+ "date": "20240218",
+ "open": 7.8,
+ "high": 7.85,
+ "low": 7.65,
+ "close": 7.7,
+ "volume": 2361755.44
+ },
+ {
+ "date": "20240219",
+ "open": 7.7,
+ "high": 7.79,
+ "low": 7.65,
+ "close": 7.72,
+ "volume": 902618.05
+ },
+ {
+ "date": "20240220",
+ "open": 7.72,
+ "high": 7.85,
+ "low": 7.7,
+ "close": 7.8,
+ "volume": 2407433.35
+ },
+ {
+ "date": "20240301",
+ "open": 7.8,
+ "high": 7.96,
+ "low": 7.79,
+ "close": 7.94,
+ "volume": 1436092.78
+ },
+ {
+ "date": "20240302",
+ "open": 7.94,
+ "high": 8.03,
+ "low": 7.94,
+ "close": 7.99,
+ "volume": 1789240.34
+ },
+ {
+ "date": "20240303",
+ "open": 7.99,
+ "high": 8.08,
+ "low": 7.97,
+ "close": 8.03,
+ "volume": 2527619.65
+ },
+ {
+ "date": "20240304",
+ "open": 8.03,
+ "high": 8.14,
+ "low": 8.0,
+ "close": 8.11,
+ "volume": 2835715.99
+ },
+ {
+ "date": "20240305",
+ "open": 8.11,
+ "high": 8.15,
+ "low": 8.01,
+ "close": 8.03,
+ "volume": 2083167.1
+ },
+ {
+ "date": "20240306",
+ "open": 8.03,
+ "high": 8.17,
+ "low": 8.02,
+ "close": 8.16,
+ "volume": 940297.69
+ },
+ {
+ "date": "20240307",
+ "open": 8.16,
+ "high": 8.2,
+ "low": 8.0,
+ "close": 8.04,
+ "volume": 2880103.82
+ },
+ {
+ "date": "20240308",
+ "open": 8.04,
+ "high": 8.09,
+ "low": 8.04,
+ "close": 8.05,
+ "volume": 1295885.67
+ },
+ {
+ "date": "20240309",
+ "open": 8.05,
+ "high": 8.07,
+ "low": 7.93,
+ "close": 8.0,
+ "volume": 1717390.26
+ },
+ {
+ "date": "20240310",
+ "open": 8.0,
+ "high": 8.04,
+ "low": 7.87,
+ "close": 7.89,
+ "volume": 1209397.86
+ },
+ {
+ "date": "20240311",
+ "open": 7.89,
+ "high": 7.95,
+ "low": 7.83,
+ "close": 7.94,
+ "volume": 1765375.91
+ },
+ {
+ "date": "20240312",
+ "open": 7.94,
+ "high": 8.0,
+ "low": 7.73,
+ "close": 7.81,
+ "volume": 2424743.67
+ },
+ {
+ "date": "20240313",
+ "open": 7.81,
+ "high": 8.02,
+ "low": 7.79,
+ "close": 7.95,
+ "volume": 1869840.41
+ },
+ {
+ "date": "20240314",
+ "open": 7.95,
+ "high": 8.09,
+ "low": 7.87,
+ "close": 8.05,
+ "volume": 1731185.17
+ },
+ {
+ "date": "20240315",
+ "open": 8.05,
+ "high": 8.06,
+ "low": 7.87,
+ "close": 7.9,
+ "volume": 841619.56
+ },
+ {
+ "date": "20240316",
+ "open": 7.9,
+ "high": 8.04,
+ "low": 7.83,
+ "close": 7.96,
+ "volume": 2970743.05
+ },
+ {
+ "date": "20240317",
+ "open": 7.96,
+ "high": 7.97,
+ "low": 7.88,
+ "close": 7.89,
+ "volume": 2847781.65
+ },
+ {
+ "date": "20240318",
+ "open": 7.89,
+ "high": 7.9,
+ "low": 7.69,
+ "close": 7.74,
+ "volume": 2885021.21
+ },
+ {
+ "date": "20240319",
+ "open": 7.74,
+ "high": 7.78,
+ "low": 7.74,
+ "close": 7.77,
+ "volume": 2602936.08
+ },
+ {
+ "date": "20240320",
+ "open": 7.77,
+ "high": 7.88,
+ "low": 7.7,
+ "close": 7.86,
+ "volume": 1418712.68
+ },
+ {
+ "date": "20240401",
+ "open": 7.86,
+ "high": 7.93,
+ "low": 7.75,
+ "close": 7.75,
+ "volume": 1598225.86
+ },
+ {
+ "date": "20240402",
+ "open": 7.75,
+ "high": 7.8,
+ "low": 7.62,
+ "close": 7.66,
+ "volume": 1354535.71
+ },
+ {
+ "date": "20240403",
+ "open": 7.66,
+ "high": 7.73,
+ "low": 7.59,
+ "close": 7.72,
+ "volume": 2523609.43
+ },
+ {
+ "date": "20240404",
+ "open": 7.72,
+ "high": 7.77,
+ "low": 7.62,
+ "close": 7.64,
+ "volume": 2064602.62
+ },
+ {
+ "date": "20240405",
+ "open": 7.64,
+ "high": 7.66,
+ "low": 7.56,
+ "close": 7.6,
+ "volume": 957570.0
+ },
+ {
+ "date": "20240406",
+ "open": 7.6,
+ "high": 7.85,
+ "low": 7.58,
+ "close": 7.79,
+ "volume": 2117289.03
+ },
+ {
+ "date": "20240407",
+ "open": 7.79,
+ "high": 7.8,
+ "low": 7.66,
+ "close": 7.69,
+ "volume": 2375241.87
+ },
+ {
+ "date": "20240408",
+ "open": 7.69,
+ "high": 7.76,
+ "low": 7.54,
+ "close": 7.56,
+ "volume": 1161334.1
+ },
+ {
+ "date": "20240409",
+ "open": 7.56,
+ "high": 7.64,
+ "low": 7.53,
+ "close": 7.58,
+ "volume": 1981032.64
+ },
+ {
+ "date": "20240410",
+ "open": 7.58,
+ "high": 7.8,
+ "low": 7.55,
+ "close": 7.76,
+ "volume": 1216357.28
+ },
+ {
+ "date": "20240411",
+ "open": 7.76,
+ "high": 7.84,
+ "low": 7.72,
+ "close": 7.79,
+ "volume": 1225903.54
+ },
+ {
+ "date": "20240412",
+ "open": 7.79,
+ "high": 7.86,
+ "low": 7.58,
+ "close": 7.64,
+ "volume": 2658514.13
+ },
+ {
+ "date": "20240413",
+ "open": 7.64,
+ "high": 7.81,
+ "low": 7.62,
+ "close": 7.77,
+ "volume": 2919773.48
+ },
+ {
+ "date": "20240414",
+ "open": 7.77,
+ "high": 7.94,
+ "low": 7.72,
+ "close": 7.93,
+ "volume": 1900863.59
+ },
+ {
+ "date": "20240415",
+ "open": 7.93,
+ "high": 7.98,
+ "low": 7.73,
+ "close": 7.78,
+ "volume": 1782422.03
+ },
+ {
+ "date": "20240416",
+ "open": 7.78,
+ "high": 7.85,
+ "low": 7.66,
+ "close": 7.71,
+ "volume": 1412999.35
+ },
+ {
+ "date": "20240417",
+ "open": 7.71,
+ "high": 7.9,
+ "low": 7.68,
+ "close": 7.83,
+ "volume": 2061626.44
+ },
+ {
+ "date": "20240418",
+ "open": 7.83,
+ "high": 7.84,
+ "low": 7.64,
+ "close": 7.71,
+ "volume": 2900671.15
+ },
+ {
+ "date": "20240419",
+ "open": 7.71,
+ "high": 7.89,
+ "low": 7.65,
+ "close": 7.88,
+ "volume": 1663291.33
+ },
+ {
+ "date": "20240420",
+ "open": 7.88,
+ "high": 7.95,
+ "low": 7.79,
+ "close": 7.79,
+ "volume": 978710.65
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "银行·T+1持有期"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600030.json b/zhishi/fixtures/ohlcv/600030.json
new file mode 100644
index 0000000..3fc166e
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600030.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600030",
+ "name": "中信证券",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 20,
+ "high": 20.1,
+ "low": 19.84,
+ "close": 19.93,
+ "volume": 1782870.36
+ },
+ {
+ "date": "20240102",
+ "open": 19.93,
+ "high": 20.06,
+ "low": 19.84,
+ "close": 19.89,
+ "volume": 2196991.03
+ },
+ {
+ "date": "20240103",
+ "open": 19.89,
+ "high": 19.95,
+ "low": 19.44,
+ "close": 19.51,
+ "volume": 1112291.14
+ },
+ {
+ "date": "20240104",
+ "open": 19.51,
+ "high": 19.83,
+ "low": 19.35,
+ "close": 19.77,
+ "volume": 2903651.08
+ },
+ {
+ "date": "20240105",
+ "open": 19.77,
+ "high": 19.94,
+ "low": 19.44,
+ "close": 19.6,
+ "volume": 2268321.73
+ },
+ {
+ "date": "20240106",
+ "open": 19.6,
+ "high": 19.69,
+ "low": 19.11,
+ "close": 19.23,
+ "volume": 1451696.43
+ },
+ {
+ "date": "20240107",
+ "open": 19.23,
+ "high": 19.29,
+ "low": 18.99,
+ "close": 19.04,
+ "volume": 2533215.47
+ },
+ {
+ "date": "20240108",
+ "open": 19.04,
+ "high": 19.12,
+ "low": 18.83,
+ "close": 18.96,
+ "volume": 2886443.8
+ },
+ {
+ "date": "20240109",
+ "open": 18.96,
+ "high": 18.97,
+ "low": 18.64,
+ "close": 18.83,
+ "volume": 2631655.25
+ },
+ {
+ "date": "20240110",
+ "open": 18.83,
+ "high": 19.22,
+ "low": 18.78,
+ "close": 19.12,
+ "volume": 1139920.69
+ },
+ {
+ "date": "20240111",
+ "open": 19.12,
+ "high": 19.21,
+ "low": 18.99,
+ "close": 19.0,
+ "volume": 2338427.48
+ },
+ {
+ "date": "20240112",
+ "open": 19.0,
+ "high": 19.24,
+ "low": 18.84,
+ "close": 19.24,
+ "volume": 1881370.23
+ },
+ {
+ "date": "20240113",
+ "open": 19.24,
+ "high": 19.75,
+ "low": 19.09,
+ "close": 19.65,
+ "volume": 1799386.11
+ },
+ {
+ "date": "20240114",
+ "open": 19.65,
+ "high": 19.9,
+ "low": 19.65,
+ "close": 19.8,
+ "volume": 1116688.0
+ },
+ {
+ "date": "20240115",
+ "open": 19.8,
+ "high": 19.88,
+ "low": 19.54,
+ "close": 19.61,
+ "volume": 1986282.98
+ },
+ {
+ "date": "20240116",
+ "open": 19.61,
+ "high": 19.88,
+ "low": 19.55,
+ "close": 19.8,
+ "volume": 1924469.32
+ },
+ {
+ "date": "20240117",
+ "open": 19.8,
+ "high": 20.41,
+ "low": 19.67,
+ "close": 20.26,
+ "volume": 2597374.37
+ },
+ {
+ "date": "20240118",
+ "open": 20.26,
+ "high": 20.28,
+ "low": 20.04,
+ "close": 20.06,
+ "volume": 1067332.66
+ },
+ {
+ "date": "20240119",
+ "open": 20.06,
+ "high": 20.18,
+ "low": 19.48,
+ "close": 19.67,
+ "volume": 1049920.88
+ },
+ {
+ "date": "20240120",
+ "open": 19.67,
+ "high": 20.07,
+ "low": 19.51,
+ "close": 19.88,
+ "volume": 1136995.87
+ },
+ {
+ "date": "20240201",
+ "open": 19.88,
+ "high": 20.1,
+ "low": 19.84,
+ "close": 20.05,
+ "volume": 824507.96
+ },
+ {
+ "date": "20240202",
+ "open": 20.05,
+ "high": 20.31,
+ "low": 20.03,
+ "close": 20.13,
+ "volume": 1123922.66
+ },
+ {
+ "date": "20240203",
+ "open": 20.13,
+ "high": 20.13,
+ "low": 19.98,
+ "close": 20.08,
+ "volume": 2406554.17
+ },
+ {
+ "date": "20240204",
+ "open": 20.08,
+ "high": 20.1,
+ "low": 20.07,
+ "close": 20.09,
+ "volume": 1236045.44
+ },
+ {
+ "date": "20240205",
+ "open": 20.09,
+ "high": 20.48,
+ "low": 19.99,
+ "close": 20.29,
+ "volume": 1027240.16
+ },
+ {
+ "date": "20240206",
+ "open": 20.29,
+ "high": 20.38,
+ "low": 20.06,
+ "close": 20.08,
+ "volume": 1054933.61
+ },
+ {
+ "date": "20240207",
+ "open": 20.08,
+ "high": 20.25,
+ "low": 20.03,
+ "close": 20.07,
+ "volume": 2742475.64
+ },
+ {
+ "date": "20240208",
+ "open": 20.07,
+ "high": 20.55,
+ "low": 20.03,
+ "close": 20.46,
+ "volume": 1206122.32
+ },
+ {
+ "date": "20240209",
+ "open": 20.46,
+ "high": 20.84,
+ "low": 20.29,
+ "close": 20.67,
+ "volume": 1259155.91
+ },
+ {
+ "date": "20240210",
+ "open": 20.67,
+ "high": 20.67,
+ "low": 20.59,
+ "close": 20.65,
+ "volume": 1448906.97
+ },
+ {
+ "date": "20240211",
+ "open": 20.65,
+ "high": 20.67,
+ "low": 20.15,
+ "close": 20.35,
+ "volume": 1470928.97
+ },
+ {
+ "date": "20240212",
+ "open": 20.35,
+ "high": 20.51,
+ "low": 20.26,
+ "close": 20.4,
+ "volume": 2096854.81
+ },
+ {
+ "date": "20240213",
+ "open": 20.4,
+ "high": 20.56,
+ "low": 20.39,
+ "close": 20.46,
+ "volume": 2191451.35
+ },
+ {
+ "date": "20240214",
+ "open": 20.46,
+ "high": 20.81,
+ "low": 20.39,
+ "close": 20.66,
+ "volume": 1817214.13
+ },
+ {
+ "date": "20240215",
+ "open": 20.66,
+ "high": 21.15,
+ "low": 20.65,
+ "close": 21.0,
+ "volume": 1536639.04
+ },
+ {
+ "date": "20240216",
+ "open": 21.0,
+ "high": 21.15,
+ "low": 20.66,
+ "close": 20.74,
+ "volume": 1660585.76
+ },
+ {
+ "date": "20240217",
+ "open": 20.74,
+ "high": 20.84,
+ "low": 20.39,
+ "close": 20.54,
+ "volume": 2188300.95
+ },
+ {
+ "date": "20240218",
+ "open": 20.54,
+ "high": 20.62,
+ "low": 20.2,
+ "close": 20.33,
+ "volume": 922051.52
+ },
+ {
+ "date": "20240219",
+ "open": 20.33,
+ "high": 20.75,
+ "low": 20.2,
+ "close": 20.75,
+ "volume": 1124075.64
+ },
+ {
+ "date": "20240220",
+ "open": 20.75,
+ "high": 21.37,
+ "low": 20.7,
+ "close": 21.23,
+ "volume": 1907931.69
+ },
+ {
+ "date": "20240301",
+ "open": 21.23,
+ "high": 21.79,
+ "low": 21.09,
+ "close": 21.61,
+ "volume": 2204674.29
+ },
+ {
+ "date": "20240302",
+ "open": 21.61,
+ "high": 22.1,
+ "low": 21.5,
+ "close": 21.9,
+ "volume": 2153427.17
+ },
+ {
+ "date": "20240303",
+ "open": 21.9,
+ "high": 22.36,
+ "low": 21.85,
+ "close": 22.25,
+ "volume": 2077158.69
+ },
+ {
+ "date": "20240304",
+ "open": 22.25,
+ "high": 22.41,
+ "low": 21.99,
+ "close": 22.15,
+ "volume": 2794248.72
+ },
+ {
+ "date": "20240305",
+ "open": 22.15,
+ "high": 22.16,
+ "low": 21.61,
+ "close": 21.82,
+ "volume": 2406952.48
+ },
+ {
+ "date": "20240306",
+ "open": 21.82,
+ "high": 22.54,
+ "low": 21.61,
+ "close": 22.36,
+ "volume": 1141760.39
+ },
+ {
+ "date": "20240307",
+ "open": 22.36,
+ "high": 22.5,
+ "low": 21.93,
+ "close": 22.1,
+ "volume": 1058584.26
+ },
+ {
+ "date": "20240308",
+ "open": 22.1,
+ "high": 22.65,
+ "low": 22.06,
+ "close": 22.6,
+ "volume": 1759813.16
+ },
+ {
+ "date": "20240309",
+ "open": 22.6,
+ "high": 22.62,
+ "low": 22.32,
+ "close": 22.33,
+ "volume": 871842.21
+ },
+ {
+ "date": "20240310",
+ "open": 22.33,
+ "high": 22.49,
+ "low": 21.87,
+ "close": 22.04,
+ "volume": 2499989.48
+ },
+ {
+ "date": "20240311",
+ "open": 22.04,
+ "high": 22.21,
+ "low": 21.99,
+ "close": 22.01,
+ "volume": 2702725.1
+ },
+ {
+ "date": "20240312",
+ "open": 22.01,
+ "high": 22.04,
+ "low": 21.89,
+ "close": 21.98,
+ "volume": 1225744.45
+ },
+ {
+ "date": "20240313",
+ "open": 21.98,
+ "high": 22.36,
+ "low": 21.97,
+ "close": 22.27,
+ "volume": 1223583.34
+ },
+ {
+ "date": "20240314",
+ "open": 22.27,
+ "high": 22.49,
+ "low": 21.82,
+ "close": 21.91,
+ "volume": 2523623.54
+ },
+ {
+ "date": "20240315",
+ "open": 21.91,
+ "high": 22.15,
+ "low": 21.75,
+ "close": 22.06,
+ "volume": 2016454.77
+ },
+ {
+ "date": "20240316",
+ "open": 22.06,
+ "high": 22.28,
+ "low": 21.58,
+ "close": 21.66,
+ "volume": 2233787.73
+ },
+ {
+ "date": "20240317",
+ "open": 21.66,
+ "high": 21.87,
+ "low": 21.59,
+ "close": 21.63,
+ "volume": 923999.64
+ },
+ {
+ "date": "20240318",
+ "open": 21.63,
+ "high": 21.72,
+ "low": 21.06,
+ "close": 21.24,
+ "volume": 1784384.73
+ },
+ {
+ "date": "20240319",
+ "open": 21.24,
+ "high": 21.74,
+ "low": 21.03,
+ "close": 21.71,
+ "volume": 1168849.43
+ },
+ {
+ "date": "20240320",
+ "open": 21.71,
+ "high": 22.18,
+ "low": 21.58,
+ "close": 22.13,
+ "volume": 2151023.56
+ },
+ {
+ "date": "20240401",
+ "open": 22.13,
+ "high": 22.75,
+ "low": 21.95,
+ "close": 22.66,
+ "volume": 913035.15
+ },
+ {
+ "date": "20240402",
+ "open": 22.66,
+ "high": 23.24,
+ "low": 22.54,
+ "close": 23.12,
+ "volume": 2931942.01
+ },
+ {
+ "date": "20240403",
+ "open": 23.12,
+ "high": 23.27,
+ "low": 22.85,
+ "close": 22.99,
+ "volume": 1465720.64
+ },
+ {
+ "date": "20240404",
+ "open": 22.99,
+ "high": 23.09,
+ "low": 22.61,
+ "close": 22.68,
+ "volume": 2141896.53
+ },
+ {
+ "date": "20240405",
+ "open": 22.68,
+ "high": 22.7,
+ "low": 22.49,
+ "close": 22.64,
+ "volume": 2832256.06
+ },
+ {
+ "date": "20240406",
+ "open": 22.64,
+ "high": 22.89,
+ "low": 22.57,
+ "close": 22.82,
+ "volume": 2906939.47
+ },
+ {
+ "date": "20240407",
+ "open": 22.82,
+ "high": 22.98,
+ "low": 22.8,
+ "close": 22.82,
+ "volume": 2590643.53
+ },
+ {
+ "date": "20240408",
+ "open": 22.82,
+ "high": 23.34,
+ "low": 22.75,
+ "close": 23.28,
+ "volume": 2230356.82
+ },
+ {
+ "date": "20240409",
+ "open": 23.28,
+ "high": 24.0,
+ "low": 23.27,
+ "close": 23.81,
+ "volume": 1052859.44
+ },
+ {
+ "date": "20240410",
+ "open": 23.81,
+ "high": 24.39,
+ "low": 23.58,
+ "close": 24.29,
+ "volume": 1789363.42
+ },
+ {
+ "date": "20240411",
+ "open": 24.29,
+ "high": 24.77,
+ "low": 24.05,
+ "close": 24.71,
+ "volume": 1843845.27
+ },
+ {
+ "date": "20240412",
+ "open": 24.71,
+ "high": 24.76,
+ "low": 24.2,
+ "close": 24.22,
+ "volume": 1721310.8
+ },
+ {
+ "date": "20240413",
+ "open": 24.22,
+ "high": 25.02,
+ "low": 24.0,
+ "close": 24.78,
+ "volume": 1699331.03
+ },
+ {
+ "date": "20240414",
+ "open": 24.78,
+ "high": 25.33,
+ "low": 24.58,
+ "close": 25.15,
+ "volume": 2931758.41
+ },
+ {
+ "date": "20240415",
+ "open": 25.15,
+ "high": 25.78,
+ "low": 25.07,
+ "close": 25.59,
+ "volume": 1173505.11
+ },
+ {
+ "date": "20240416",
+ "open": 25.59,
+ "high": 25.66,
+ "low": 25.36,
+ "close": 25.56,
+ "volume": 1146035.05
+ },
+ {
+ "date": "20240417",
+ "open": 25.56,
+ "high": 25.74,
+ "low": 25.27,
+ "close": 25.28,
+ "volume": 984035.5
+ },
+ {
+ "date": "20240418",
+ "open": 25.28,
+ "high": 25.28,
+ "low": 24.75,
+ "close": 24.77,
+ "volume": 2427682.39
+ },
+ {
+ "date": "20240419",
+ "open": 24.77,
+ "high": 24.8,
+ "low": 24.45,
+ "close": 24.58,
+ "volume": 1586473.83
+ },
+ {
+ "date": "20240420",
+ "open": 24.58,
+ "high": 24.59,
+ "low": 24.03,
+ "close": 24.09,
+ "volume": 1723196.49
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "券商·周期教学"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600036.json b/zhishi/fixtures/ohlcv/600036.json
new file mode 100644
index 0000000..4d22e05
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600036.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600036",
+ "name": "招商银行",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 32,
+ "high": 32.5,
+ "low": 31.75,
+ "close": 32.26,
+ "volume": 2873390.62
+ },
+ {
+ "date": "20240102",
+ "open": 32.26,
+ "high": 32.99,
+ "low": 32.25,
+ "close": 32.69,
+ "volume": 1824369.84
+ },
+ {
+ "date": "20240103",
+ "open": 32.69,
+ "high": 33.64,
+ "low": 32.39,
+ "close": 33.42,
+ "volume": 1049053.12
+ },
+ {
+ "date": "20240104",
+ "open": 33.42,
+ "high": 33.54,
+ "low": 33.24,
+ "close": 33.46,
+ "volume": 2062670.61
+ },
+ {
+ "date": "20240105",
+ "open": 33.46,
+ "high": 33.53,
+ "low": 32.72,
+ "close": 32.81,
+ "volume": 2815959.82
+ },
+ {
+ "date": "20240106",
+ "open": 32.81,
+ "high": 33.33,
+ "low": 32.55,
+ "close": 33.28,
+ "volume": 1105288.32
+ },
+ {
+ "date": "20240107",
+ "open": 33.28,
+ "high": 33.58,
+ "low": 33.28,
+ "close": 33.54,
+ "volume": 2717090.44
+ },
+ {
+ "date": "20240108",
+ "open": 33.54,
+ "high": 33.61,
+ "low": 32.86,
+ "close": 33.19,
+ "volume": 2719297.08
+ },
+ {
+ "date": "20240109",
+ "open": 33.19,
+ "high": 33.51,
+ "low": 32.78,
+ "close": 32.95,
+ "volume": 2291227.05
+ },
+ {
+ "date": "20240110",
+ "open": 32.95,
+ "high": 33.26,
+ "low": 32.37,
+ "close": 32.6,
+ "volume": 2926441.49
+ },
+ {
+ "date": "20240111",
+ "open": 32.6,
+ "high": 33.36,
+ "low": 32.48,
+ "close": 33.26,
+ "volume": 1165103.33
+ },
+ {
+ "date": "20240112",
+ "open": 33.26,
+ "high": 33.28,
+ "low": 32.71,
+ "close": 32.81,
+ "volume": 2126841.99
+ },
+ {
+ "date": "20240113",
+ "open": 32.81,
+ "high": 33.03,
+ "low": 32.05,
+ "close": 32.16,
+ "volume": 1481907.45
+ },
+ {
+ "date": "20240114",
+ "open": 32.16,
+ "high": 32.86,
+ "low": 32.06,
+ "close": 32.7,
+ "volume": 1858680.45
+ },
+ {
+ "date": "20240115",
+ "open": 32.7,
+ "high": 33.1,
+ "low": 32.38,
+ "close": 33.08,
+ "volume": 850304.24
+ },
+ {
+ "date": "20240116",
+ "open": 33.08,
+ "high": 33.82,
+ "low": 33.08,
+ "close": 33.54,
+ "volume": 2533024.27
+ },
+ {
+ "date": "20240117",
+ "open": 33.54,
+ "high": 33.73,
+ "low": 33.42,
+ "close": 33.42,
+ "volume": 902799.66
+ },
+ {
+ "date": "20240118",
+ "open": 33.42,
+ "high": 33.74,
+ "low": 32.96,
+ "close": 33.02,
+ "volume": 2462620.11
+ },
+ {
+ "date": "20240119",
+ "open": 33.02,
+ "high": 34.06,
+ "low": 32.91,
+ "close": 33.75,
+ "volume": 1580545.05
+ },
+ {
+ "date": "20240120",
+ "open": 33.75,
+ "high": 34.13,
+ "low": 33.71,
+ "close": 33.87,
+ "volume": 2446475.72
+ },
+ {
+ "date": "20240201",
+ "open": 33.87,
+ "high": 34.7,
+ "low": 33.85,
+ "close": 34.4,
+ "volume": 2880760.41
+ },
+ {
+ "date": "20240202",
+ "open": 34.4,
+ "high": 34.52,
+ "low": 33.65,
+ "close": 33.86,
+ "volume": 2819791.81
+ },
+ {
+ "date": "20240203",
+ "open": 33.86,
+ "high": 34.17,
+ "low": 33.51,
+ "close": 33.7,
+ "volume": 1487390.81
+ },
+ {
+ "date": "20240204",
+ "open": 33.7,
+ "high": 33.76,
+ "low": 33.48,
+ "close": 33.51,
+ "volume": 1127509.7
+ },
+ {
+ "date": "20240205",
+ "open": 33.51,
+ "high": 34.21,
+ "low": 33.45,
+ "close": 33.87,
+ "volume": 906814.76
+ },
+ {
+ "date": "20240206",
+ "open": 33.87,
+ "high": 34.89,
+ "low": 33.74,
+ "close": 34.7,
+ "volume": 1322140.53
+ },
+ {
+ "date": "20240207",
+ "open": 34.7,
+ "high": 35.22,
+ "low": 34.54,
+ "close": 34.93,
+ "volume": 1727866.02
+ },
+ {
+ "date": "20240208",
+ "open": 34.93,
+ "high": 35.25,
+ "low": 34.31,
+ "close": 34.32,
+ "volume": 1885841.24
+ },
+ {
+ "date": "20240209",
+ "open": 34.32,
+ "high": 34.98,
+ "low": 34.07,
+ "close": 34.93,
+ "volume": 2889556.84
+ },
+ {
+ "date": "20240210",
+ "open": 34.93,
+ "high": 35.5,
+ "low": 34.89,
+ "close": 35.22,
+ "volume": 1756021.42
+ },
+ {
+ "date": "20240211",
+ "open": 35.22,
+ "high": 35.52,
+ "low": 34.65,
+ "close": 34.76,
+ "volume": 1796940.81
+ },
+ {
+ "date": "20240212",
+ "open": 34.76,
+ "high": 35.93,
+ "low": 34.42,
+ "close": 35.62,
+ "volume": 1797787.98
+ },
+ {
+ "date": "20240213",
+ "open": 35.62,
+ "high": 35.95,
+ "low": 35.45,
+ "close": 35.69,
+ "volume": 1440249.76
+ },
+ {
+ "date": "20240214",
+ "open": 35.69,
+ "high": 35.75,
+ "low": 35.49,
+ "close": 35.63,
+ "volume": 2974452.94
+ },
+ {
+ "date": "20240215",
+ "open": 35.63,
+ "high": 36.68,
+ "low": 35.45,
+ "close": 36.45,
+ "volume": 1544653.27
+ },
+ {
+ "date": "20240216",
+ "open": 36.45,
+ "high": 36.55,
+ "low": 35.59,
+ "close": 35.87,
+ "volume": 2708250.97
+ },
+ {
+ "date": "20240217",
+ "open": 35.87,
+ "high": 36.15,
+ "low": 35.46,
+ "close": 35.74,
+ "volume": 2328112.85
+ },
+ {
+ "date": "20240218",
+ "open": 35.74,
+ "high": 36.37,
+ "low": 35.61,
+ "close": 36.09,
+ "volume": 2349833.06
+ },
+ {
+ "date": "20240219",
+ "open": 36.09,
+ "high": 36.27,
+ "low": 35.55,
+ "close": 35.83,
+ "volume": 2319942.5
+ },
+ {
+ "date": "20240220",
+ "open": 35.83,
+ "high": 36.16,
+ "low": 35.35,
+ "close": 35.58,
+ "volume": 2077453.82
+ },
+ {
+ "date": "20240301",
+ "open": 35.58,
+ "high": 35.78,
+ "low": 34.8,
+ "close": 34.89,
+ "volume": 2277614.43
+ },
+ {
+ "date": "20240302",
+ "open": 34.89,
+ "high": 35.2,
+ "low": 34.66,
+ "close": 34.92,
+ "volume": 2554777.08
+ },
+ {
+ "date": "20240303",
+ "open": 34.92,
+ "high": 35.14,
+ "low": 34.51,
+ "close": 34.77,
+ "volume": 2622015.07
+ },
+ {
+ "date": "20240304",
+ "open": 34.77,
+ "high": 35.06,
+ "low": 34.32,
+ "close": 34.62,
+ "volume": 2314341.31
+ },
+ {
+ "date": "20240305",
+ "open": 34.62,
+ "high": 35.79,
+ "low": 34.44,
+ "close": 35.45,
+ "volume": 1964548.18
+ },
+ {
+ "date": "20240306",
+ "open": 35.45,
+ "high": 35.74,
+ "low": 34.68,
+ "close": 35.0,
+ "volume": 1849925.65
+ },
+ {
+ "date": "20240307",
+ "open": 35.0,
+ "high": 35.65,
+ "low": 34.75,
+ "close": 35.39,
+ "volume": 1178018.86
+ },
+ {
+ "date": "20240308",
+ "open": 35.39,
+ "high": 36.14,
+ "low": 35.16,
+ "close": 35.93,
+ "volume": 1725742.47
+ },
+ {
+ "date": "20240309",
+ "open": 35.93,
+ "high": 36.5,
+ "low": 35.7,
+ "close": 36.22,
+ "volume": 2384911.84
+ },
+ {
+ "date": "20240310",
+ "open": 36.22,
+ "high": 36.28,
+ "low": 35.38,
+ "close": 35.54,
+ "volume": 2230257.54
+ },
+ {
+ "date": "20240311",
+ "open": 35.54,
+ "high": 35.78,
+ "low": 34.96,
+ "close": 35.18,
+ "volume": 892095.75
+ },
+ {
+ "date": "20240312",
+ "open": 35.18,
+ "high": 35.3,
+ "low": 35.16,
+ "close": 35.22,
+ "volume": 1093759.15
+ },
+ {
+ "date": "20240313",
+ "open": 35.22,
+ "high": 35.28,
+ "low": 34.95,
+ "close": 35.02,
+ "volume": 878446.61
+ },
+ {
+ "date": "20240314",
+ "open": 35.02,
+ "high": 35.19,
+ "low": 34.8,
+ "close": 35.05,
+ "volume": 2098361.68
+ },
+ {
+ "date": "20240315",
+ "open": 35.05,
+ "high": 35.37,
+ "low": 34.73,
+ "close": 34.73,
+ "volume": 1691826.65
+ },
+ {
+ "date": "20240316",
+ "open": 34.73,
+ "high": 34.87,
+ "low": 34.43,
+ "close": 34.47,
+ "volume": 2629014.13
+ },
+ {
+ "date": "20240317",
+ "open": 34.47,
+ "high": 34.48,
+ "low": 34.15,
+ "close": 34.36,
+ "volume": 1008607.66
+ },
+ {
+ "date": "20240318",
+ "open": 34.36,
+ "high": 34.63,
+ "low": 34.16,
+ "close": 34.51,
+ "volume": 2908261.11
+ },
+ {
+ "date": "20240319",
+ "open": 34.51,
+ "high": 35.24,
+ "low": 34.23,
+ "close": 35.09,
+ "volume": 2213052.39
+ },
+ {
+ "date": "20240320",
+ "open": 35.09,
+ "high": 35.14,
+ "low": 34.77,
+ "close": 34.98,
+ "volume": 2040490.1
+ },
+ {
+ "date": "20240401",
+ "open": 34.98,
+ "high": 36.13,
+ "low": 34.76,
+ "close": 35.78,
+ "volume": 1572455.38
+ },
+ {
+ "date": "20240402",
+ "open": 35.78,
+ "high": 36.51,
+ "low": 35.74,
+ "close": 36.51,
+ "volume": 2044786.43
+ },
+ {
+ "date": "20240403",
+ "open": 36.51,
+ "high": 36.84,
+ "low": 36.28,
+ "close": 36.79,
+ "volume": 2760819.92
+ },
+ {
+ "date": "20240404",
+ "open": 36.79,
+ "high": 36.94,
+ "low": 36.59,
+ "close": 36.67,
+ "volume": 1441288.08
+ },
+ {
+ "date": "20240405",
+ "open": 36.67,
+ "high": 37.69,
+ "low": 36.32,
+ "close": 37.54,
+ "volume": 2810243.99
+ },
+ {
+ "date": "20240406",
+ "open": 37.54,
+ "high": 37.9,
+ "low": 37.18,
+ "close": 37.8,
+ "volume": 1891872.11
+ },
+ {
+ "date": "20240407",
+ "open": 37.8,
+ "high": 37.92,
+ "low": 37.38,
+ "close": 37.75,
+ "volume": 1881860.38
+ },
+ {
+ "date": "20240408",
+ "open": 37.75,
+ "high": 37.93,
+ "low": 37.44,
+ "close": 37.48,
+ "volume": 2167710.57
+ },
+ {
+ "date": "20240409",
+ "open": 37.48,
+ "high": 37.59,
+ "low": 37.19,
+ "close": 37.48,
+ "volume": 2618971.67
+ },
+ {
+ "date": "20240410",
+ "open": 37.48,
+ "high": 37.68,
+ "low": 36.65,
+ "close": 36.75,
+ "volume": 2857556.89
+ },
+ {
+ "date": "20240411",
+ "open": 36.75,
+ "high": 37.4,
+ "low": 36.65,
+ "close": 37.31,
+ "volume": 1140484.44
+ },
+ {
+ "date": "20240412",
+ "open": 37.31,
+ "high": 38.34,
+ "low": 37.08,
+ "close": 38.23,
+ "volume": 1844189.14
+ },
+ {
+ "date": "20240413",
+ "open": 38.23,
+ "high": 38.8,
+ "low": 37.94,
+ "close": 38.57,
+ "volume": 1059993.79
+ },
+ {
+ "date": "20240414",
+ "open": 38.57,
+ "high": 39.24,
+ "low": 38.36,
+ "close": 39.12,
+ "volume": 1539467.62
+ },
+ {
+ "date": "20240415",
+ "open": 39.12,
+ "high": 39.33,
+ "low": 38.68,
+ "close": 38.86,
+ "volume": 1594286.64
+ },
+ {
+ "date": "20240416",
+ "open": 38.86,
+ "high": 39.62,
+ "low": 38.84,
+ "close": 39.38,
+ "volume": 1355330.49
+ },
+ {
+ "date": "20240417",
+ "open": 39.38,
+ "high": 39.76,
+ "low": 39.03,
+ "close": 39.4,
+ "volume": 2000303.03
+ },
+ {
+ "date": "20240418",
+ "open": 39.4,
+ "high": 39.71,
+ "low": 38.48,
+ "close": 38.64,
+ "volume": 2066411.93
+ },
+ {
+ "date": "20240419",
+ "open": 38.64,
+ "high": 39.35,
+ "low": 38.46,
+ "close": 39.1,
+ "volume": 2805773.69
+ },
+ {
+ "date": "20240420",
+ "open": 39.1,
+ "high": 39.25,
+ "low": 38.66,
+ "close": 39.0,
+ "volume": 1232229.95
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "银行·趋势教学"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600276.json b/zhishi/fixtures/ohlcv/600276.json
new file mode 100644
index 0000000..33746fe
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600276.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600276",
+ "name": "恒瑞医药",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 38,
+ "high": 38.38,
+ "low": 37.78,
+ "close": 38.22,
+ "volume": 1253416.11
+ },
+ {
+ "date": "20240102",
+ "open": 38.22,
+ "high": 39.17,
+ "low": 37.97,
+ "close": 38.85,
+ "volume": 1152505.02
+ },
+ {
+ "date": "20240103",
+ "open": 38.85,
+ "high": 39.11,
+ "low": 38.75,
+ "close": 38.98,
+ "volume": 2896197.2
+ },
+ {
+ "date": "20240104",
+ "open": 38.98,
+ "high": 39.97,
+ "low": 38.65,
+ "close": 39.95,
+ "volume": 2127019.34
+ },
+ {
+ "date": "20240105",
+ "open": 39.95,
+ "high": 40.07,
+ "low": 39.57,
+ "close": 39.84,
+ "volume": 1805028.53
+ },
+ {
+ "date": "20240106",
+ "open": 39.84,
+ "high": 40.54,
+ "low": 39.79,
+ "close": 40.27,
+ "volume": 2489243.19
+ },
+ {
+ "date": "20240107",
+ "open": 40.27,
+ "high": 41.65,
+ "low": 40.03,
+ "close": 41.25,
+ "volume": 897373.39
+ },
+ {
+ "date": "20240108",
+ "open": 41.25,
+ "high": 41.3,
+ "low": 40.05,
+ "close": 40.43,
+ "volume": 1466293.24
+ },
+ {
+ "date": "20240109",
+ "open": 40.43,
+ "high": 40.79,
+ "low": 40.16,
+ "close": 40.29,
+ "volume": 2007760.8
+ },
+ {
+ "date": "20240110",
+ "open": 40.29,
+ "high": 40.31,
+ "low": 40.04,
+ "close": 40.27,
+ "volume": 2656949.37
+ },
+ {
+ "date": "20240111",
+ "open": 40.27,
+ "high": 40.36,
+ "low": 39.59,
+ "close": 39.75,
+ "volume": 881234.71
+ },
+ {
+ "date": "20240112",
+ "open": 39.75,
+ "high": 40.17,
+ "low": 39.49,
+ "close": 39.84,
+ "volume": 1973664.22
+ },
+ {
+ "date": "20240113",
+ "open": 39.84,
+ "high": 40.64,
+ "low": 39.62,
+ "close": 40.58,
+ "volume": 1623184.6
+ },
+ {
+ "date": "20240114",
+ "open": 40.58,
+ "high": 40.91,
+ "low": 40.27,
+ "close": 40.87,
+ "volume": 1012532.83
+ },
+ {
+ "date": "20240115",
+ "open": 40.87,
+ "high": 41.2,
+ "low": 39.97,
+ "close": 40.36,
+ "volume": 1753109.31
+ },
+ {
+ "date": "20240116",
+ "open": 40.36,
+ "high": 40.45,
+ "low": 40.19,
+ "close": 40.3,
+ "volume": 2157956.1
+ },
+ {
+ "date": "20240117",
+ "open": 40.3,
+ "high": 40.35,
+ "low": 39.64,
+ "close": 39.82,
+ "volume": 1162863.17
+ },
+ {
+ "date": "20240118",
+ "open": 39.82,
+ "high": 40.51,
+ "low": 39.51,
+ "close": 40.18,
+ "volume": 1856293.46
+ },
+ {
+ "date": "20240119",
+ "open": 40.18,
+ "high": 40.36,
+ "low": 40.01,
+ "close": 40.01,
+ "volume": 2367661.04
+ },
+ {
+ "date": "20240120",
+ "open": 40.01,
+ "high": 40.14,
+ "low": 39.77,
+ "close": 39.81,
+ "volume": 1785723.04
+ },
+ {
+ "date": "20240201",
+ "open": 39.81,
+ "high": 40.21,
+ "low": 39.46,
+ "close": 40.05,
+ "volume": 2281377.08
+ },
+ {
+ "date": "20240202",
+ "open": 40.05,
+ "high": 40.26,
+ "low": 39.33,
+ "close": 39.69,
+ "volume": 1944241.33
+ },
+ {
+ "date": "20240203",
+ "open": 39.69,
+ "high": 39.99,
+ "low": 39.49,
+ "close": 39.97,
+ "volume": 1815170.78
+ },
+ {
+ "date": "20240204",
+ "open": 39.97,
+ "high": 40.14,
+ "low": 39.66,
+ "close": 39.89,
+ "volume": 1985067.51
+ },
+ {
+ "date": "20240205",
+ "open": 39.89,
+ "high": 40.04,
+ "low": 39.72,
+ "close": 39.97,
+ "volume": 2931092.04
+ },
+ {
+ "date": "20240206",
+ "open": 39.97,
+ "high": 39.99,
+ "low": 39.92,
+ "close": 39.92,
+ "volume": 1977920.59
+ },
+ {
+ "date": "20240207",
+ "open": 39.92,
+ "high": 39.96,
+ "low": 39.17,
+ "close": 39.21,
+ "volume": 1798972.33
+ },
+ {
+ "date": "20240208",
+ "open": 39.21,
+ "high": 40.38,
+ "low": 39.03,
+ "close": 40.18,
+ "volume": 1760323.79
+ },
+ {
+ "date": "20240209",
+ "open": 40.18,
+ "high": 40.46,
+ "low": 39.89,
+ "close": 40.28,
+ "volume": 2775471.38
+ },
+ {
+ "date": "20240210",
+ "open": 40.28,
+ "high": 40.91,
+ "low": 40.02,
+ "close": 40.74,
+ "volume": 2800989.31
+ },
+ {
+ "date": "20240211",
+ "open": 40.74,
+ "high": 40.84,
+ "low": 39.96,
+ "close": 40.21,
+ "volume": 2311443.88
+ },
+ {
+ "date": "20240212",
+ "open": 40.21,
+ "high": 40.81,
+ "low": 39.88,
+ "close": 40.57,
+ "volume": 1853674.5
+ },
+ {
+ "date": "20240213",
+ "open": 40.57,
+ "high": 41.63,
+ "low": 40.39,
+ "close": 41.23,
+ "volume": 2689460.27
+ },
+ {
+ "date": "20240214",
+ "open": 41.23,
+ "high": 42.11,
+ "low": 41.21,
+ "close": 41.74,
+ "volume": 2808817.02
+ },
+ {
+ "date": "20240215",
+ "open": 41.74,
+ "high": 42.75,
+ "low": 41.33,
+ "close": 42.34,
+ "volume": 1428068.61
+ },
+ {
+ "date": "20240216",
+ "open": 42.34,
+ "high": 42.83,
+ "low": 42.09,
+ "close": 42.77,
+ "volume": 2823075.29
+ },
+ {
+ "date": "20240217",
+ "open": 42.77,
+ "high": 42.92,
+ "low": 42.25,
+ "close": 42.29,
+ "volume": 1228243.89
+ },
+ {
+ "date": "20240218",
+ "open": 42.29,
+ "high": 42.33,
+ "low": 41.42,
+ "close": 41.84,
+ "volume": 2752574.7
+ },
+ {
+ "date": "20240219",
+ "open": 41.84,
+ "high": 42.19,
+ "low": 41.55,
+ "close": 41.87,
+ "volume": 1949400.14
+ },
+ {
+ "date": "20240220",
+ "open": 41.87,
+ "high": 42.15,
+ "low": 41.6,
+ "close": 41.83,
+ "volume": 1384957.62
+ },
+ {
+ "date": "20240301",
+ "open": 41.83,
+ "high": 42.1,
+ "low": 41.42,
+ "close": 41.68,
+ "volume": 1261106.27
+ },
+ {
+ "date": "20240302",
+ "open": 41.68,
+ "high": 42.36,
+ "low": 41.32,
+ "close": 41.99,
+ "volume": 2234979.28
+ },
+ {
+ "date": "20240303",
+ "open": 41.99,
+ "high": 42.17,
+ "low": 41.25,
+ "close": 41.29,
+ "volume": 921549.56
+ },
+ {
+ "date": "20240304",
+ "open": 41.29,
+ "high": 41.47,
+ "low": 40.62,
+ "close": 40.93,
+ "volume": 2183451.39
+ },
+ {
+ "date": "20240305",
+ "open": 40.93,
+ "high": 41.22,
+ "low": 40.43,
+ "close": 40.64,
+ "volume": 1916565.15
+ },
+ {
+ "date": "20240306",
+ "open": 40.64,
+ "high": 40.81,
+ "low": 40.17,
+ "close": 40.3,
+ "volume": 2398402.07
+ },
+ {
+ "date": "20240307",
+ "open": 40.3,
+ "high": 40.55,
+ "low": 40.11,
+ "close": 40.37,
+ "volume": 1855805.02
+ },
+ {
+ "date": "20240308",
+ "open": 40.37,
+ "high": 41.11,
+ "low": 40.05,
+ "close": 40.82,
+ "volume": 1691565.14
+ },
+ {
+ "date": "20240309",
+ "open": 40.82,
+ "high": 41.86,
+ "low": 40.41,
+ "close": 41.46,
+ "volume": 2385442.32
+ },
+ {
+ "date": "20240310",
+ "open": 41.46,
+ "high": 41.81,
+ "low": 40.41,
+ "close": 40.75,
+ "volume": 835899.2
+ },
+ {
+ "date": "20240311",
+ "open": 40.75,
+ "high": 40.88,
+ "low": 40.24,
+ "close": 40.54,
+ "volume": 2142673.83
+ },
+ {
+ "date": "20240312",
+ "open": 40.54,
+ "high": 40.62,
+ "low": 40.18,
+ "close": 40.24,
+ "volume": 1009997.1
+ },
+ {
+ "date": "20240313",
+ "open": 40.24,
+ "high": 41.25,
+ "low": 40.16,
+ "close": 40.87,
+ "volume": 2438807.92
+ },
+ {
+ "date": "20240314",
+ "open": 40.87,
+ "high": 41.88,
+ "low": 40.64,
+ "close": 41.8,
+ "volume": 1766487.9
+ },
+ {
+ "date": "20240315",
+ "open": 41.8,
+ "high": 43.17,
+ "low": 41.8,
+ "close": 42.8,
+ "volume": 1242920.0
+ },
+ {
+ "date": "20240316",
+ "open": 42.8,
+ "high": 43.83,
+ "low": 42.58,
+ "close": 43.58,
+ "volume": 2581589.87
+ },
+ {
+ "date": "20240317",
+ "open": 43.58,
+ "high": 44.63,
+ "low": 43.44,
+ "close": 44.2,
+ "volume": 904838.87
+ },
+ {
+ "date": "20240318",
+ "open": 44.2,
+ "high": 44.72,
+ "low": 43.95,
+ "close": 44.7,
+ "volume": 2691419.98
+ },
+ {
+ "date": "20240319",
+ "open": 44.7,
+ "high": 44.97,
+ "low": 44.53,
+ "close": 44.6,
+ "volume": 1147018.55
+ },
+ {
+ "date": "20240320",
+ "open": 44.6,
+ "high": 45.31,
+ "low": 44.16,
+ "close": 44.93,
+ "volume": 868505.21
+ },
+ {
+ "date": "20240401",
+ "open": 44.93,
+ "high": 46.12,
+ "low": 44.77,
+ "close": 45.89,
+ "volume": 1674312.26
+ },
+ {
+ "date": "20240402",
+ "open": 45.89,
+ "high": 46.33,
+ "low": 45.82,
+ "close": 46.17,
+ "volume": 2704239.49
+ },
+ {
+ "date": "20240403",
+ "open": 46.17,
+ "high": 46.99,
+ "low": 45.83,
+ "close": 46.71,
+ "volume": 2969256.99
+ },
+ {
+ "date": "20240404",
+ "open": 46.71,
+ "high": 47.09,
+ "low": 45.76,
+ "close": 46.14,
+ "volume": 1555365.21
+ },
+ {
+ "date": "20240405",
+ "open": 46.14,
+ "high": 46.59,
+ "low": 46.05,
+ "close": 46.38,
+ "volume": 1752374.66
+ },
+ {
+ "date": "20240406",
+ "open": 46.38,
+ "high": 46.81,
+ "low": 45.69,
+ "close": 45.77,
+ "volume": 2194539.19
+ },
+ {
+ "date": "20240407",
+ "open": 45.77,
+ "high": 46.48,
+ "low": 45.41,
+ "close": 46.03,
+ "volume": 1592419.9
+ },
+ {
+ "date": "20240408",
+ "open": 46.03,
+ "high": 46.05,
+ "low": 45.86,
+ "close": 45.89,
+ "volume": 1484141.57
+ },
+ {
+ "date": "20240409",
+ "open": 45.89,
+ "high": 46.96,
+ "low": 45.81,
+ "close": 46.93,
+ "volume": 2199609.45
+ },
+ {
+ "date": "20240410",
+ "open": 46.93,
+ "high": 47.02,
+ "low": 46.31,
+ "close": 46.75,
+ "volume": 894092.56
+ },
+ {
+ "date": "20240411",
+ "open": 46.75,
+ "high": 47.28,
+ "low": 46.59,
+ "close": 47.08,
+ "volume": 1228848.16
+ },
+ {
+ "date": "20240412",
+ "open": 47.08,
+ "high": 47.27,
+ "low": 46.13,
+ "close": 46.48,
+ "volume": 1830098.72
+ },
+ {
+ "date": "20240413",
+ "open": 46.48,
+ "high": 47.59,
+ "low": 46.4,
+ "close": 47.18,
+ "volume": 2735233.85
+ },
+ {
+ "date": "20240414",
+ "open": 47.18,
+ "high": 47.67,
+ "low": 46.94,
+ "close": 47.47,
+ "volume": 2757926.96
+ },
+ {
+ "date": "20240415",
+ "open": 47.47,
+ "high": 47.51,
+ "low": 46.9,
+ "close": 47.36,
+ "volume": 1060432.96
+ },
+ {
+ "date": "20240416",
+ "open": 47.36,
+ "high": 47.7,
+ "low": 46.49,
+ "close": 46.64,
+ "volume": 1437924.98
+ },
+ {
+ "date": "20240417",
+ "open": 46.64,
+ "high": 47.49,
+ "low": 46.48,
+ "close": 47.07,
+ "volume": 2795874.01
+ },
+ {
+ "date": "20240418",
+ "open": 47.07,
+ "high": 47.73,
+ "low": 46.82,
+ "close": 47.44,
+ "volume": 826884.77
+ },
+ {
+ "date": "20240419",
+ "open": 47.44,
+ "high": 47.76,
+ "low": 46.5,
+ "close": 46.83,
+ "volume": 1013168.91
+ },
+ {
+ "date": "20240420",
+ "open": 46.83,
+ "high": 47.46,
+ "low": 46.56,
+ "close": 47.23,
+ "volume": 1678087.54
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "医药·中性观察"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600519.json b/zhishi/fixtures/ohlcv/600519.json
new file mode 100644
index 0000000..00e25e4
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600519.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600519",
+ "name": "贵州茅台",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 1600,
+ "high": 1613.56,
+ "low": 1565.62,
+ "close": 1577.67,
+ "volume": 1361151.86
+ },
+ {
+ "date": "20240102",
+ "open": 1577.67,
+ "high": 1588.4,
+ "low": 1567.39,
+ "close": 1581.29,
+ "volume": 2535191.37
+ },
+ {
+ "date": "20240103",
+ "open": 1581.29,
+ "high": 1581.74,
+ "low": 1543.34,
+ "close": 1556.35,
+ "volume": 1752087.55
+ },
+ {
+ "date": "20240104",
+ "open": 1556.35,
+ "high": 1578.64,
+ "low": 1549.42,
+ "close": 1578.61,
+ "volume": 2387388.07
+ },
+ {
+ "date": "20240105",
+ "open": 1578.61,
+ "high": 1593.53,
+ "low": 1549.19,
+ "close": 1563.29,
+ "volume": 867297.96
+ },
+ {
+ "date": "20240106",
+ "open": 1563.29,
+ "high": 1571.75,
+ "low": 1519.41,
+ "close": 1533.81,
+ "volume": 1638649.32
+ },
+ {
+ "date": "20240107",
+ "open": 1533.81,
+ "high": 1540.28,
+ "low": 1517.64,
+ "close": 1518.08,
+ "volume": 1287721.67
+ },
+ {
+ "date": "20240108",
+ "open": 1518.08,
+ "high": 1525.61,
+ "low": 1514.1,
+ "close": 1517.64,
+ "volume": 1307906.39
+ },
+ {
+ "date": "20240109",
+ "open": 1517.64,
+ "high": 1524.61,
+ "low": 1497.87,
+ "close": 1502.22,
+ "volume": 847277.35
+ },
+ {
+ "date": "20240110",
+ "open": 1502.22,
+ "high": 1537.31,
+ "low": 1492.58,
+ "close": 1528.8,
+ "volume": 1208993.78
+ },
+ {
+ "date": "20240111",
+ "open": 1528.8,
+ "high": 1579.98,
+ "low": 1526.95,
+ "close": 1566.51,
+ "volume": 1531929.41
+ },
+ {
+ "date": "20240112",
+ "open": 1566.51,
+ "high": 1597.32,
+ "low": 1551.84,
+ "close": 1586.04,
+ "volume": 1728635.4
+ },
+ {
+ "date": "20240113",
+ "open": 1586.04,
+ "high": 1624.37,
+ "low": 1581.23,
+ "close": 1613.56,
+ "volume": 2092677.33
+ },
+ {
+ "date": "20240114",
+ "open": 1613.56,
+ "high": 1659.29,
+ "low": 1605.4,
+ "close": 1645.36,
+ "volume": 2095804.97
+ },
+ {
+ "date": "20240115",
+ "open": 1645.36,
+ "high": 1649.36,
+ "low": 1602.13,
+ "close": 1615.01,
+ "volume": 1711490.8
+ },
+ {
+ "date": "20240116",
+ "open": 1615.01,
+ "high": 1623.87,
+ "low": 1584.07,
+ "close": 1595.28,
+ "volume": 2283868.83
+ },
+ {
+ "date": "20240117",
+ "open": 1595.28,
+ "high": 1602.29,
+ "low": 1582.19,
+ "close": 1590.28,
+ "volume": 2512573.75
+ },
+ {
+ "date": "20240118",
+ "open": 1590.28,
+ "high": 1602.03,
+ "low": 1582.49,
+ "close": 1595.75,
+ "volume": 865064.92
+ },
+ {
+ "date": "20240119",
+ "open": 1595.75,
+ "high": 1606.98,
+ "low": 1551.55,
+ "close": 1566.96,
+ "volume": 2105004.21
+ },
+ {
+ "date": "20240120",
+ "open": 1566.96,
+ "high": 1569.63,
+ "low": 1555.52,
+ "close": 1563.38,
+ "volume": 2960568.6
+ },
+ {
+ "date": "20240201",
+ "open": 1563.38,
+ "high": 1594.88,
+ "low": 1549.93,
+ "close": 1586.32,
+ "volume": 1310787.48
+ },
+ {
+ "date": "20240202",
+ "open": 1586.32,
+ "high": 1606.42,
+ "low": 1577.15,
+ "close": 1591.26,
+ "volume": 1810089.81
+ },
+ {
+ "date": "20240203",
+ "open": 1591.26,
+ "high": 1599.98,
+ "low": 1563.61,
+ "close": 1578.72,
+ "volume": 812560.08
+ },
+ {
+ "date": "20240204",
+ "open": 1578.72,
+ "high": 1615.97,
+ "low": 1564.73,
+ "close": 1602.82,
+ "volume": 2429107.51
+ },
+ {
+ "date": "20240205",
+ "open": 1602.82,
+ "high": 1637.57,
+ "low": 1593.82,
+ "close": 1629.12,
+ "volume": 1737399.5
+ },
+ {
+ "date": "20240206",
+ "open": 1629.12,
+ "high": 1643.3,
+ "low": 1591.53,
+ "close": 1600.66,
+ "volume": 1239646.72
+ },
+ {
+ "date": "20240207",
+ "open": 1600.66,
+ "high": 1612.78,
+ "low": 1594.94,
+ "close": 1605.0,
+ "volume": 1561371.42
+ },
+ {
+ "date": "20240208",
+ "open": 1605.0,
+ "high": 1621.84,
+ "low": 1595.17,
+ "close": 1611.79,
+ "volume": 1807922.96
+ },
+ {
+ "date": "20240209",
+ "open": 1611.79,
+ "high": 1615.49,
+ "low": 1578.78,
+ "close": 1581.58,
+ "volume": 2085813.92
+ },
+ {
+ "date": "20240210",
+ "open": 1581.58,
+ "high": 1624.09,
+ "low": 1568.98,
+ "close": 1611.23,
+ "volume": 2596162.22
+ },
+ {
+ "date": "20240211",
+ "open": 1611.23,
+ "high": 1624.79,
+ "low": 1586.76,
+ "close": 1597.52,
+ "volume": 983115.1
+ },
+ {
+ "date": "20240212",
+ "open": 1597.52,
+ "high": 1597.75,
+ "low": 1554.93,
+ "close": 1566.76,
+ "volume": 1349030.3
+ },
+ {
+ "date": "20240213",
+ "open": 1566.76,
+ "high": 1576.55,
+ "low": 1537.83,
+ "close": 1543.15,
+ "volume": 952933.83
+ },
+ {
+ "date": "20240214",
+ "open": 1543.15,
+ "high": 1551.29,
+ "low": 1520.81,
+ "close": 1523.37,
+ "volume": 1400411.76
+ },
+ {
+ "date": "20240215",
+ "open": 1523.37,
+ "high": 1548.69,
+ "low": 1518.47,
+ "close": 1541.68,
+ "volume": 1842296.23
+ },
+ {
+ "date": "20240216",
+ "open": 1541.68,
+ "high": 1547.64,
+ "low": 1506.12,
+ "close": 1512.49,
+ "volume": 1213686.47
+ },
+ {
+ "date": "20240217",
+ "open": 1512.49,
+ "high": 1526.1,
+ "low": 1482.04,
+ "close": 1489.64,
+ "volume": 1260000.18
+ },
+ {
+ "date": "20240218",
+ "open": 1489.64,
+ "high": 1512.71,
+ "low": 1489.33,
+ "close": 1500.45,
+ "volume": 839301.95
+ },
+ {
+ "date": "20240219",
+ "open": 1500.45,
+ "high": 1511.23,
+ "low": 1477.96,
+ "close": 1480.33,
+ "volume": 2350132.38
+ },
+ {
+ "date": "20240220",
+ "open": 1480.33,
+ "high": 1504.05,
+ "low": 1477.06,
+ "close": 1495.9,
+ "volume": 2946307.94
+ },
+ {
+ "date": "20240301",
+ "open": 1495.9,
+ "high": 1527.54,
+ "low": 1492.56,
+ "close": 1519.69,
+ "volume": 2226714.12
+ },
+ {
+ "date": "20240302",
+ "open": 1519.69,
+ "high": 1528.44,
+ "low": 1511.43,
+ "close": 1516.3,
+ "volume": 2188085.29
+ },
+ {
+ "date": "20240303",
+ "open": 1516.3,
+ "high": 1520.83,
+ "low": 1475.56,
+ "close": 1489.98,
+ "volume": 2726175.34
+ },
+ {
+ "date": "20240304",
+ "open": 1489.98,
+ "high": 1502.77,
+ "low": 1476.13,
+ "close": 1480.73,
+ "volume": 2866434.55
+ },
+ {
+ "date": "20240305",
+ "open": 1480.73,
+ "high": 1506.92,
+ "low": 1476.99,
+ "close": 1500.68,
+ "volume": 818656.58
+ },
+ {
+ "date": "20240306",
+ "open": 1500.68,
+ "high": 1530.58,
+ "low": 1488.38,
+ "close": 1530.0,
+ "volume": 2916842.48
+ },
+ {
+ "date": "20240307",
+ "open": 1530.0,
+ "high": 1541.31,
+ "low": 1516.73,
+ "close": 1538.67,
+ "volume": 2942305.52
+ },
+ {
+ "date": "20240308",
+ "open": 1538.67,
+ "high": 1564.56,
+ "low": 1532.85,
+ "close": 1556.64,
+ "volume": 1563247.95
+ },
+ {
+ "date": "20240309",
+ "open": 1556.64,
+ "high": 1567.13,
+ "low": 1533.25,
+ "close": 1539.92,
+ "volume": 1227061.02
+ },
+ {
+ "date": "20240310",
+ "open": 1539.92,
+ "high": 1550.18,
+ "low": 1511.87,
+ "close": 1516.36,
+ "volume": 1899559.83
+ },
+ {
+ "date": "20240311",
+ "open": 1516.36,
+ "high": 1529.57,
+ "low": 1494.66,
+ "close": 1508.23,
+ "volume": 839804.56
+ },
+ {
+ "date": "20240312",
+ "open": 1508.23,
+ "high": 1513.17,
+ "low": 1476.97,
+ "close": 1491.7,
+ "volume": 2521940.83
+ },
+ {
+ "date": "20240313",
+ "open": 1491.7,
+ "high": 1494.88,
+ "low": 1474.61,
+ "close": 1484.63,
+ "volume": 2642942.35
+ },
+ {
+ "date": "20240314",
+ "open": 1484.63,
+ "high": 1522.43,
+ "low": 1471.53,
+ "close": 1517.21,
+ "volume": 2311642.4
+ },
+ {
+ "date": "20240315",
+ "open": 1517.21,
+ "high": 1534.93,
+ "low": 1513.65,
+ "close": 1519.95,
+ "volume": 2396023.41
+ },
+ {
+ "date": "20240316",
+ "open": 1519.95,
+ "high": 1522.53,
+ "low": 1481.72,
+ "close": 1495.34,
+ "volume": 1268530.03
+ },
+ {
+ "date": "20240317",
+ "open": 1495.34,
+ "high": 1525.62,
+ "low": 1482.76,
+ "close": 1516.51,
+ "volume": 1609837.6
+ },
+ {
+ "date": "20240318",
+ "open": 1516.51,
+ "high": 1520.93,
+ "low": 1496.31,
+ "close": 1509.41,
+ "volume": 2128761.56
+ },
+ {
+ "date": "20240319",
+ "open": 1509.41,
+ "high": 1557.74,
+ "low": 1507.36,
+ "close": 1544.04,
+ "volume": 2012575.04
+ },
+ {
+ "date": "20240320",
+ "open": 1544.04,
+ "high": 1544.64,
+ "low": 1519.29,
+ "close": 1520.4,
+ "volume": 2705570.39
+ },
+ {
+ "date": "20240401",
+ "open": 1520.4,
+ "high": 1556.71,
+ "low": 1515.22,
+ "close": 1543.92,
+ "volume": 2153409.27
+ },
+ {
+ "date": "20240402",
+ "open": 1543.92,
+ "high": 1573.29,
+ "low": 1535.1,
+ "close": 1567.36,
+ "volume": 1292170.96
+ },
+ {
+ "date": "20240403",
+ "open": 1567.36,
+ "high": 1571.54,
+ "low": 1528.05,
+ "close": 1541.78,
+ "volume": 2041783.03
+ },
+ {
+ "date": "20240404",
+ "open": 1541.78,
+ "high": 1582.33,
+ "low": 1537.51,
+ "close": 1575.12,
+ "volume": 2531432.26
+ },
+ {
+ "date": "20240405",
+ "open": 1575.12,
+ "high": 1602.49,
+ "low": 1564.56,
+ "close": 1602.29,
+ "volume": 1001702.87
+ },
+ {
+ "date": "20240406",
+ "open": 1602.29,
+ "high": 1616.48,
+ "low": 1577.92,
+ "close": 1578.55,
+ "volume": 1327193.4
+ },
+ {
+ "date": "20240407",
+ "open": 1578.55,
+ "high": 1623.98,
+ "low": 1576.72,
+ "close": 1617.17,
+ "volume": 1168243.56
+ },
+ {
+ "date": "20240408",
+ "open": 1617.17,
+ "high": 1629.2,
+ "low": 1600.75,
+ "close": 1602.4,
+ "volume": 2803681.72
+ },
+ {
+ "date": "20240409",
+ "open": 1602.4,
+ "high": 1617.94,
+ "low": 1583.1,
+ "close": 1597.62,
+ "volume": 1446851.89
+ },
+ {
+ "date": "20240410",
+ "open": 1597.62,
+ "high": 1605.25,
+ "low": 1582.3,
+ "close": 1583.89,
+ "volume": 2234510.44
+ },
+ {
+ "date": "20240411",
+ "open": 1583.89,
+ "high": 1584.06,
+ "low": 1539.76,
+ "close": 1555.04,
+ "volume": 1450209.69
+ },
+ {
+ "date": "20240412",
+ "open": 1555.04,
+ "high": 1572.73,
+ "low": 1550.17,
+ "close": 1565.68,
+ "volume": 938522.54
+ },
+ {
+ "date": "20240413",
+ "open": 1565.68,
+ "high": 1614.23,
+ "low": 1550.5,
+ "close": 1598.72,
+ "volume": 1044997.08
+ },
+ {
+ "date": "20240414",
+ "open": 1598.72,
+ "high": 1608.6,
+ "low": 1566.72,
+ "close": 1582.23,
+ "volume": 1994409.03
+ },
+ {
+ "date": "20240415",
+ "open": 1582.23,
+ "high": 1610.17,
+ "low": 1578.13,
+ "close": 1599.58,
+ "volume": 1991524.98
+ },
+ {
+ "date": "20240416",
+ "open": 1599.58,
+ "high": 1603.53,
+ "low": 1588.42,
+ "close": 1589.71,
+ "volume": 1417730.79
+ },
+ {
+ "date": "20240417",
+ "open": 1589.71,
+ "high": 1635.56,
+ "low": 1579.35,
+ "close": 1628.27,
+ "volume": 2215625.38
+ },
+ {
+ "date": "20240418",
+ "open": 1628.27,
+ "high": 1671.13,
+ "low": 1623.27,
+ "close": 1664.63,
+ "volume": 1519931.11
+ },
+ {
+ "date": "20240419",
+ "open": 1664.63,
+ "high": 1678.73,
+ "low": 1640.28,
+ "close": 1655.07,
+ "volume": 1466180.53
+ },
+ {
+ "date": "20240420",
+ "open": 1655.07,
+ "high": 1664.07,
+ "low": 1637.33,
+ "close": 1646.86,
+ "volume": 2111117.59
+ }
+ ],
+ "source": "fixture",
+ "sample": true,
+ "teaching_tag": "白酒龙头·常态波动"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/600900.json b/zhishi/fixtures/ohlcv/600900.json
new file mode 100644
index 0000000..7e7f662
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/600900.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "600900",
+ "name": "长江电力",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 25,
+ "high": 25.17,
+ "low": 24.62,
+ "close": 24.79,
+ "volume": 2668539.56
+ },
+ {
+ "date": "20240102",
+ "open": 24.79,
+ "high": 24.85,
+ "low": 24.47,
+ "close": 24.5,
+ "volume": 1295358.46
+ },
+ {
+ "date": "20240103",
+ "open": 24.5,
+ "high": 24.85,
+ "low": 24.37,
+ "close": 24.82,
+ "volume": 1270596.57
+ },
+ {
+ "date": "20240104",
+ "open": 24.82,
+ "high": 24.93,
+ "low": 24.45,
+ "close": 24.65,
+ "volume": 2138484.73
+ },
+ {
+ "date": "20240105",
+ "open": 24.65,
+ "high": 24.72,
+ "low": 24.14,
+ "close": 24.18,
+ "volume": 2716826.4
+ },
+ {
+ "date": "20240106",
+ "open": 24.18,
+ "high": 24.77,
+ "low": 23.98,
+ "close": 24.58,
+ "volume": 2438450.34
+ },
+ {
+ "date": "20240107",
+ "open": 24.58,
+ "high": 25.33,
+ "low": 24.51,
+ "close": 25.13,
+ "volume": 2669865.83
+ },
+ {
+ "date": "20240108",
+ "open": 25.13,
+ "high": 25.37,
+ "low": 24.99,
+ "close": 25.18,
+ "volume": 1745070.82
+ },
+ {
+ "date": "20240109",
+ "open": 25.18,
+ "high": 25.29,
+ "low": 25.01,
+ "close": 25.09,
+ "volume": 1058192.11
+ },
+ {
+ "date": "20240110",
+ "open": 25.09,
+ "high": 25.72,
+ "low": 24.84,
+ "close": 25.51,
+ "volume": 2320029.83
+ },
+ {
+ "date": "20240111",
+ "open": 25.51,
+ "high": 25.83,
+ "low": 25.48,
+ "close": 25.64,
+ "volume": 2289007.44
+ },
+ {
+ "date": "20240112",
+ "open": 25.64,
+ "high": 25.69,
+ "low": 25.59,
+ "close": 25.64,
+ "volume": 1949925.26
+ },
+ {
+ "date": "20240113",
+ "open": 25.64,
+ "high": 25.76,
+ "low": 25.26,
+ "close": 25.42,
+ "volume": 1670666.21
+ },
+ {
+ "date": "20240114",
+ "open": 25.42,
+ "high": 25.54,
+ "low": 25.0,
+ "close": 25.06,
+ "volume": 1318492.32
+ },
+ {
+ "date": "20240115",
+ "open": 25.06,
+ "high": 25.15,
+ "low": 24.76,
+ "close": 24.78,
+ "volume": 2232709.89
+ },
+ {
+ "date": "20240116",
+ "open": 24.78,
+ "high": 25.44,
+ "low": 24.6,
+ "close": 25.35,
+ "volume": 2852551.2
+ },
+ {
+ "date": "20240117",
+ "open": 25.35,
+ "high": 25.38,
+ "low": 24.69,
+ "close": 24.89,
+ "volume": 2643919.83
+ },
+ {
+ "date": "20240118",
+ "open": 24.89,
+ "high": 25.15,
+ "low": 24.78,
+ "close": 25.11,
+ "volume": 2710131.35
+ },
+ {
+ "date": "20240119",
+ "open": 25.11,
+ "high": 25.81,
+ "low": 25.05,
+ "close": 25.6,
+ "volume": 2678039.28
+ },
+ {
+ "date": "20240120",
+ "open": 25.6,
+ "high": 25.79,
+ "low": 25.49,
+ "close": 25.52,
+ "volume": 2936867.24
+ },
+ {
+ "date": "20240201",
+ "open": 25.52,
+ "high": 25.89,
+ "low": 25.47,
+ "close": 25.71,
+ "volume": 2157929.09
+ },
+ {
+ "date": "20240202",
+ "open": 25.71,
+ "high": 26.02,
+ "low": 25.61,
+ "close": 25.87,
+ "volume": 2400925.87
+ },
+ {
+ "date": "20240203",
+ "open": 25.87,
+ "high": 25.94,
+ "low": 25.7,
+ "close": 25.75,
+ "volume": 2304868.8
+ },
+ {
+ "date": "20240204",
+ "open": 25.75,
+ "high": 25.8,
+ "low": 25.34,
+ "close": 25.36,
+ "volume": 2215758.97
+ },
+ {
+ "date": "20240205",
+ "open": 25.36,
+ "high": 25.63,
+ "low": 25.35,
+ "close": 25.49,
+ "volume": 1767099.32
+ },
+ {
+ "date": "20240206",
+ "open": 25.49,
+ "high": 25.51,
+ "low": 25.37,
+ "close": 25.37,
+ "volume": 2995410.3
+ },
+ {
+ "date": "20240207",
+ "open": 25.37,
+ "high": 25.45,
+ "low": 24.94,
+ "close": 25.0,
+ "volume": 2113969.6
+ },
+ {
+ "date": "20240208",
+ "open": 25.0,
+ "high": 25.12,
+ "low": 24.5,
+ "close": 24.59,
+ "volume": 2635907.44
+ },
+ {
+ "date": "20240209",
+ "open": 24.59,
+ "high": 24.67,
+ "low": 23.98,
+ "close": 24.1,
+ "volume": 2933532.08
+ },
+ {
+ "date": "20240210",
+ "open": 24.1,
+ "high": 24.3,
+ "low": 23.94,
+ "close": 24.18,
+ "volume": 1452423.38
+ },
+ {
+ "date": "20240211",
+ "open": 24.18,
+ "high": 24.3,
+ "low": 23.52,
+ "close": 23.73,
+ "volume": 2424421.4
+ },
+ {
+ "date": "20240212",
+ "open": 23.73,
+ "high": 23.9,
+ "low": 23.33,
+ "close": 23.53,
+ "volume": 1368804.52
+ },
+ {
+ "date": "20240213",
+ "open": 23.53,
+ "high": 23.77,
+ "low": 23.48,
+ "close": 23.69,
+ "volume": 1432178.63
+ },
+ {
+ "date": "20240214",
+ "open": 23.69,
+ "high": 23.77,
+ "low": 23.42,
+ "close": 23.43,
+ "volume": 1674796.0
+ },
+ {
+ "date": "20240215",
+ "open": 23.43,
+ "high": 23.61,
+ "low": 22.91,
+ "close": 23.05,
+ "volume": 809010.66
+ },
+ {
+ "date": "20240216",
+ "open": 23.05,
+ "high": 23.44,
+ "low": 22.94,
+ "close": 23.39,
+ "volume": 2020182.82
+ },
+ {
+ "date": "20240217",
+ "open": 23.39,
+ "high": 23.46,
+ "low": 23.18,
+ "close": 23.28,
+ "volume": 1101374.6
+ },
+ {
+ "date": "20240218",
+ "open": 23.28,
+ "high": 23.74,
+ "low": 23.09,
+ "close": 23.72,
+ "volume": 1280204.9
+ },
+ {
+ "date": "20240219",
+ "open": 23.72,
+ "high": 23.81,
+ "low": 23.56,
+ "close": 23.57,
+ "volume": 1082202.31
+ },
+ {
+ "date": "20240220",
+ "open": 23.57,
+ "high": 23.67,
+ "low": 23.27,
+ "close": 23.48,
+ "volume": 2977677.12
+ },
+ {
+ "date": "20240301",
+ "open": 23.48,
+ "high": 23.6,
+ "low": 23.02,
+ "close": 23.05,
+ "volume": 2568074.16
+ },
+ {
+ "date": "20240302",
+ "open": 23.05,
+ "high": 23.26,
+ "low": 22.8,
+ "close": 22.93,
+ "volume": 1076398.83
+ },
+ {
+ "date": "20240303",
+ "open": 22.93,
+ "high": 22.98,
+ "low": 22.28,
+ "close": 22.47,
+ "volume": 1129448.74
+ },
+ {
+ "date": "20240304",
+ "open": 22.47,
+ "high": 22.59,
+ "low": 22.4,
+ "close": 22.51,
+ "volume": 2563927.36
+ },
+ {
+ "date": "20240305",
+ "open": 22.51,
+ "high": 22.67,
+ "low": 22.13,
+ "close": 22.28,
+ "volume": 2857761.04
+ },
+ {
+ "date": "20240306",
+ "open": 22.28,
+ "high": 22.56,
+ "low": 22.18,
+ "close": 22.35,
+ "volume": 2061205.02
+ },
+ {
+ "date": "20240307",
+ "open": 22.35,
+ "high": 22.72,
+ "low": 22.15,
+ "close": 22.53,
+ "volume": 1053813.27
+ },
+ {
+ "date": "20240308",
+ "open": 22.53,
+ "high": 22.65,
+ "low": 22.04,
+ "close": 22.22,
+ "volume": 1973910.91
+ },
+ {
+ "date": "20240309",
+ "open": 22.22,
+ "high": 22.43,
+ "low": 22.01,
+ "close": 22.07,
+ "volume": 991146.17
+ },
+ {
+ "date": "20240310",
+ "open": 22.07,
+ "high": 22.08,
+ "low": 21.52,
+ "close": 21.68,
+ "volume": 1035739.54
+ },
+ {
+ "date": "20240311",
+ "open": 21.68,
+ "high": 22.14,
+ "low": 21.47,
+ "close": 21.95,
+ "volume": 2579939.52
+ },
+ {
+ "date": "20240312",
+ "open": 21.95,
+ "high": 22.08,
+ "low": 21.74,
+ "close": 21.93,
+ "volume": 2375243.99
+ },
+ {
+ "date": "20240313",
+ "open": 21.93,
+ "high": 22.09,
+ "low": 21.75,
+ "close": 21.78,
+ "volume": 1478612.02
+ },
+ {
+ "date": "20240314",
+ "open": 21.78,
+ "high": 22.42,
+ "low": 21.72,
+ "close": 22.32,
+ "volume": 2526619.08
+ },
+ {
+ "date": "20240315",
+ "open": 22.32,
+ "high": 22.32,
+ "low": 22.31,
+ "close": 22.32,
+ "volume": 1369852.46
+ },
+ {
+ "date": "20240316",
+ "open": 22.32,
+ "high": 22.53,
+ "low": 22.15,
+ "close": 22.21,
+ "volume": 2670196.34
+ },
+ {
+ "date": "20240317",
+ "open": 22.21,
+ "high": 22.71,
+ "low": 21.99,
+ "close": 22.62,
+ "volume": 2476050.18
+ },
+ {
+ "date": "20240318",
+ "open": 22.62,
+ "high": 22.72,
+ "low": 22.51,
+ "close": 22.66,
+ "volume": 2784506.35
+ },
+ {
+ "date": "20240319",
+ "open": 22.66,
+ "high": 22.8,
+ "low": 22.57,
+ "close": 22.75,
+ "volume": 1847430.11
+ },
+ {
+ "date": "20240320",
+ "open": 22.75,
+ "high": 22.88,
+ "low": 22.48,
+ "close": 22.49,
+ "volume": 2606712.98
+ },
+ {
+ "date": "20240401",
+ "open": 22.49,
+ "high": 22.52,
+ "low": 22.09,
+ "close": 22.22,
+ "volume": 1476004.03
+ },
+ {
+ "date": "20240402",
+ "open": 22.22,
+ "high": 22.78,
+ "low": 22.11,
+ "close": 22.66,
+ "volume": 2635949.16
+ },
+ {
+ "date": "20240403",
+ "open": 22.66,
+ "high": 22.83,
+ "low": 22.28,
+ "close": 22.43,
+ "volume": 1742568.9
+ },
+ {
+ "date": "20240404",
+ "open": 22.43,
+ "high": 22.95,
+ "low": 22.24,
+ "close": 22.95,
+ "volume": 1115508.54
+ },
+ {
+ "date": "20240405",
+ "open": 22.95,
+ "high": 23.39,
+ "low": 22.94,
+ "close": 23.36,
+ "volume": 1901504.25
+ },
+ {
+ "date": "20240406",
+ "open": 23.36,
+ "high": 23.92,
+ "low": 23.24,
+ "close": 23.86,
+ "volume": 2137698.86
+ },
+ {
+ "date": "20240407",
+ "open": 23.86,
+ "high": 23.99,
+ "low": 23.65,
+ "close": 23.65,
+ "volume": 1788651.53
+ },
+ {
+ "date": "20240408",
+ "open": 23.65,
+ "high": 24.06,
+ "low": 23.6,
+ "close": 23.98,
+ "volume": 911818.66
+ },
+ {
+ "date": "20240409",
+ "open": 23.98,
+ "high": 24.36,
+ "low": 23.76,
+ "close": 24.26,
+ "volume": 2429197.57
+ },
+ {
+ "date": "20240410",
+ "open": 24.26,
+ "high": 24.48,
+ "low": 23.66,
+ "close": 23.88,
+ "volume": 2597375.26
+ },
+ {
+ "date": "20240411",
+ "open": 23.88,
+ "high": 24.47,
+ "low": 23.71,
+ "close": 24.3,
+ "volume": 2267808.89
+ },
+ {
+ "date": "20240412",
+ "open": 24.3,
+ "high": 24.52,
+ "low": 24.27,
+ "close": 24.46,
+ "volume": 2397644.66
+ },
+ {
+ "date": "20240413",
+ "open": 24.46,
+ "high": 24.64,
+ "low": 24.3,
+ "close": 24.63,
+ "volume": 2142124.24
+ },
+ {
+ "date": "20240414",
+ "open": 24.63,
+ "high": 24.89,
+ "low": 24.41,
+ "close": 24.7,
+ "volume": 1638431.73
+ },
+ {
+ "date": "20240415",
+ "open": 24.7,
+ "high": 25.24,
+ "low": 24.56,
+ "close": 25.11,
+ "volume": 1710513.38
+ },
+ {
+ "date": "20240416",
+ "open": 25.11,
+ "high": 25.78,
+ "low": 24.87,
+ "close": 25.67,
+ "volume": 1544162.39
+ },
+ {
+ "date": "20240417",
+ "open": 25.67,
+ "high": 26.16,
+ "low": 25.49,
+ "close": 25.93,
+ "volume": 1625667.22
+ },
+ {
+ "date": "20240418",
+ "open": 25.93,
+ "high": 26.05,
+ "low": 25.39,
+ "close": 25.5,
+ "volume": 2590913.52
+ },
+ {
+ "date": "20240419",
+ "open": 25.5,
+ "high": 26.15,
+ "low": 25.39,
+ "close": 25.89,
+ "volume": 1703123.38
+ },
+ {
+ "date": "20240420",
+ "open": 25.89,
+ "high": 26.23,
+ "low": 25.87,
+ "close": 26.03,
+ "volume": 1274080.06
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "公用事业·低波动"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/601012.json b/zhishi/fixtures/ohlcv/601012.json
new file mode 100644
index 0000000..c1a2ba6
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/601012.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "601012",
+ "name": "隆基绿能",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 18,
+ "high": 18.08,
+ "low": 17.98,
+ "close": 18.02,
+ "volume": 2706436.07
+ },
+ {
+ "date": "20240102",
+ "open": 18.02,
+ "high": 18.11,
+ "low": 17.5,
+ "close": 17.66,
+ "volume": 977792.22
+ },
+ {
+ "date": "20240103",
+ "open": 17.66,
+ "high": 17.86,
+ "low": 17.65,
+ "close": 17.75,
+ "volume": 1633843.13
+ },
+ {
+ "date": "20240104",
+ "open": 17.75,
+ "high": 18.04,
+ "low": 17.62,
+ "close": 17.95,
+ "volume": 1145745.76
+ },
+ {
+ "date": "20240105",
+ "open": 17.95,
+ "high": 17.97,
+ "low": 17.7,
+ "close": 17.79,
+ "volume": 2832425.53
+ },
+ {
+ "date": "20240106",
+ "open": 17.79,
+ "high": 18.04,
+ "low": 17.72,
+ "close": 17.9,
+ "volume": 2441409.48
+ },
+ {
+ "date": "20240107",
+ "open": 17.9,
+ "high": 17.96,
+ "low": 17.51,
+ "close": 17.63,
+ "volume": 2396553.97
+ },
+ {
+ "date": "20240108",
+ "open": 17.63,
+ "high": 17.64,
+ "low": 17.56,
+ "close": 17.61,
+ "volume": 1261758.29
+ },
+ {
+ "date": "20240109",
+ "open": 17.61,
+ "high": 17.75,
+ "low": 17.45,
+ "close": 17.48,
+ "volume": 2750079.41
+ },
+ {
+ "date": "20240110",
+ "open": 17.48,
+ "high": 17.83,
+ "low": 17.41,
+ "close": 17.82,
+ "volume": 1881765.82
+ },
+ {
+ "date": "20240111",
+ "open": 17.82,
+ "high": 17.9,
+ "low": 17.33,
+ "close": 17.49,
+ "volume": 1046501.8
+ },
+ {
+ "date": "20240112",
+ "open": 17.49,
+ "high": 17.63,
+ "low": 17.38,
+ "close": 17.61,
+ "volume": 2769667.59
+ },
+ {
+ "date": "20240113",
+ "open": 17.61,
+ "high": 17.61,
+ "low": 17.4,
+ "close": 17.41,
+ "volume": 1987492.77
+ },
+ {
+ "date": "20240114",
+ "open": 17.41,
+ "high": 17.43,
+ "low": 16.99,
+ "close": 17.08,
+ "volume": 2826037.9
+ },
+ {
+ "date": "20240115",
+ "open": 17.08,
+ "high": 17.15,
+ "low": 16.95,
+ "close": 17.06,
+ "volume": 1005519.16
+ },
+ {
+ "date": "20240116",
+ "open": 17.06,
+ "high": 17.19,
+ "low": 16.96,
+ "close": 17.16,
+ "volume": 2908317.0
+ },
+ {
+ "date": "20240117",
+ "open": 17.16,
+ "high": 17.26,
+ "low": 16.76,
+ "close": 16.86,
+ "volume": 1128469.85
+ },
+ {
+ "date": "20240118",
+ "open": 16.86,
+ "high": 17.03,
+ "low": 16.56,
+ "close": 16.73,
+ "volume": 1066938.37
+ },
+ {
+ "date": "20240119",
+ "open": 16.73,
+ "high": 17.09,
+ "low": 16.69,
+ "close": 16.93,
+ "volume": 2144480.38
+ },
+ {
+ "date": "20240120",
+ "open": 16.93,
+ "high": 16.99,
+ "low": 16.51,
+ "close": 16.62,
+ "volume": 2098569.89
+ },
+ {
+ "date": "20240201",
+ "open": 16.62,
+ "high": 16.88,
+ "low": 16.56,
+ "close": 16.87,
+ "volume": 2700879.33
+ },
+ {
+ "date": "20240202",
+ "open": 16.87,
+ "high": 17.05,
+ "low": 16.8,
+ "close": 16.97,
+ "volume": 2969357.65
+ },
+ {
+ "date": "20240203",
+ "open": 16.97,
+ "high": 17.08,
+ "low": 16.84,
+ "close": 17.07,
+ "volume": 1523166.73
+ },
+ {
+ "date": "20240204",
+ "open": 17.07,
+ "high": 17.11,
+ "low": 16.99,
+ "close": 17.06,
+ "volume": 1514361.04
+ },
+ {
+ "date": "20240205",
+ "open": 17.06,
+ "high": 17.17,
+ "low": 16.77,
+ "close": 16.79,
+ "volume": 2525017.3
+ },
+ {
+ "date": "20240206",
+ "open": 16.79,
+ "high": 16.92,
+ "low": 16.34,
+ "close": 16.47,
+ "volume": 1894127.32
+ },
+ {
+ "date": "20240207",
+ "open": 16.47,
+ "high": 16.71,
+ "low": 16.35,
+ "close": 16.67,
+ "volume": 1735015.44
+ },
+ {
+ "date": "20240208",
+ "open": 16.67,
+ "high": 16.83,
+ "low": 16.44,
+ "close": 16.51,
+ "volume": 1620532.77
+ },
+ {
+ "date": "20240209",
+ "open": 16.51,
+ "high": 16.88,
+ "low": 16.4,
+ "close": 16.82,
+ "volume": 1176331.46
+ },
+ {
+ "date": "20240210",
+ "open": 16.82,
+ "high": 17.17,
+ "low": 16.81,
+ "close": 17.12,
+ "volume": 2945569.7
+ },
+ {
+ "date": "20240211",
+ "open": 17.12,
+ "high": 17.28,
+ "low": 16.75,
+ "close": 16.91,
+ "volume": 2134426.82
+ },
+ {
+ "date": "20240212",
+ "open": 16.91,
+ "high": 16.92,
+ "low": 16.55,
+ "close": 16.58,
+ "volume": 1655533.02
+ },
+ {
+ "date": "20240213",
+ "open": 16.58,
+ "high": 16.87,
+ "low": 16.52,
+ "close": 16.71,
+ "volume": 1109417.92
+ },
+ {
+ "date": "20240214",
+ "open": 16.71,
+ "high": 16.82,
+ "low": 16.69,
+ "close": 16.8,
+ "volume": 2023111.41
+ },
+ {
+ "date": "20240215",
+ "open": 16.8,
+ "high": 17.0,
+ "low": 16.72,
+ "close": 16.99,
+ "volume": 2348456.55
+ },
+ {
+ "date": "20240216",
+ "open": 16.99,
+ "high": 17.3,
+ "low": 16.84,
+ "close": 17.23,
+ "volume": 1171975.71
+ },
+ {
+ "date": "20240217",
+ "open": 17.23,
+ "high": 17.57,
+ "low": 17.08,
+ "close": 17.44,
+ "volume": 1887758.79
+ },
+ {
+ "date": "20240218",
+ "open": 17.44,
+ "high": 17.45,
+ "low": 17.08,
+ "close": 17.17,
+ "volume": 1181323.12
+ },
+ {
+ "date": "20240219",
+ "open": 17.17,
+ "high": 17.33,
+ "low": 17.04,
+ "close": 17.31,
+ "volume": 1289297.31
+ },
+ {
+ "date": "20240220",
+ "open": 17.31,
+ "high": 17.34,
+ "low": 16.9,
+ "close": 16.98,
+ "volume": 2030339.69
+ },
+ {
+ "date": "20240301",
+ "open": 16.98,
+ "high": 17.01,
+ "low": 16.85,
+ "close": 16.93,
+ "volume": 2882161.9
+ },
+ {
+ "date": "20240302",
+ "open": 16.93,
+ "high": 17.16,
+ "low": 16.93,
+ "close": 17.0,
+ "volume": 2984938.54
+ },
+ {
+ "date": "20240303",
+ "open": 17.0,
+ "high": 17.44,
+ "low": 16.91,
+ "close": 17.34,
+ "volume": 1981672.75
+ },
+ {
+ "date": "20240304",
+ "open": 17.34,
+ "high": 17.72,
+ "low": 17.23,
+ "close": 17.71,
+ "volume": 1992732.9
+ },
+ {
+ "date": "20240305",
+ "open": 17.71,
+ "high": 17.83,
+ "low": 17.46,
+ "close": 17.59,
+ "volume": 1027062.15
+ },
+ {
+ "date": "20240306",
+ "open": 17.59,
+ "high": 17.87,
+ "low": 17.5,
+ "close": 17.79,
+ "volume": 2200875.5
+ },
+ {
+ "date": "20240307",
+ "open": 17.79,
+ "high": 17.9,
+ "low": 17.41,
+ "close": 17.48,
+ "volume": 2733214.86
+ },
+ {
+ "date": "20240308",
+ "open": 17.48,
+ "high": 17.62,
+ "low": 17.19,
+ "close": 17.31,
+ "volume": 2174969.19
+ },
+ {
+ "date": "20240309",
+ "open": 17.31,
+ "high": 17.65,
+ "low": 17.21,
+ "close": 17.65,
+ "volume": 2149202.7
+ },
+ {
+ "date": "20240310",
+ "open": 17.65,
+ "high": 17.91,
+ "low": 17.64,
+ "close": 17.83,
+ "volume": 1215998.13
+ },
+ {
+ "date": "20240311",
+ "open": 17.83,
+ "high": 18.0,
+ "low": 17.82,
+ "close": 17.96,
+ "volume": 1580547.29
+ },
+ {
+ "date": "20240312",
+ "open": 17.96,
+ "high": 18.08,
+ "low": 17.96,
+ "close": 17.99,
+ "volume": 2506263.0
+ },
+ {
+ "date": "20240313",
+ "open": 17.99,
+ "high": 18.13,
+ "low": 17.89,
+ "close": 17.9,
+ "volume": 2898886.87
+ },
+ {
+ "date": "20240314",
+ "open": 17.9,
+ "high": 18.19,
+ "low": 17.72,
+ "close": 18.01,
+ "volume": 2632125.65
+ },
+ {
+ "date": "20240315",
+ "open": 18.01,
+ "high": 18.08,
+ "low": 17.7,
+ "close": 17.74,
+ "volume": 2515966.07
+ },
+ {
+ "date": "20240316",
+ "open": 17.74,
+ "high": 17.78,
+ "low": 17.52,
+ "close": 17.54,
+ "volume": 1064200.36
+ },
+ {
+ "date": "20240317",
+ "open": 17.54,
+ "high": 18.1,
+ "low": 17.47,
+ "close": 17.93,
+ "volume": 2430323.65
+ },
+ {
+ "date": "20240318",
+ "open": 17.93,
+ "high": 18.04,
+ "low": 17.86,
+ "close": 17.95,
+ "volume": 2196370.11
+ },
+ {
+ "date": "20240319",
+ "open": 17.95,
+ "high": 17.99,
+ "low": 17.69,
+ "close": 17.78,
+ "volume": 1234186.69
+ },
+ {
+ "date": "20240320",
+ "open": 17.78,
+ "high": 17.95,
+ "low": 17.77,
+ "close": 17.77,
+ "volume": 1027158.3
+ },
+ {
+ "date": "20240401",
+ "open": 17.77,
+ "high": 18.07,
+ "low": 17.73,
+ "close": 18.06,
+ "volume": 2673607.24
+ },
+ {
+ "date": "20240402",
+ "open": 18.06,
+ "high": 18.23,
+ "low": 18.05,
+ "close": 18.19,
+ "volume": 1405403.93
+ },
+ {
+ "date": "20240403",
+ "open": 18.19,
+ "high": 18.33,
+ "low": 17.89,
+ "close": 18.07,
+ "volume": 2529835.17
+ },
+ {
+ "date": "20240404",
+ "open": 18.07,
+ "high": 18.61,
+ "low": 17.91,
+ "close": 18.44,
+ "volume": 2823944.75
+ },
+ {
+ "date": "20240405",
+ "open": 18.44,
+ "high": 18.89,
+ "low": 18.38,
+ "close": 18.88,
+ "volume": 1343802.91
+ },
+ {
+ "date": "20240406",
+ "open": 18.88,
+ "high": 19.11,
+ "low": 18.81,
+ "close": 19.01,
+ "volume": 2641629.01
+ },
+ {
+ "date": "20240407",
+ "open": 19.01,
+ "high": 19.05,
+ "low": 18.92,
+ "close": 18.97,
+ "volume": 1815849.22
+ },
+ {
+ "date": "20240408",
+ "open": 18.97,
+ "high": 19.22,
+ "low": 18.89,
+ "close": 19.12,
+ "volume": 1209936.39
+ },
+ {
+ "date": "20240409",
+ "open": 19.12,
+ "high": 19.18,
+ "low": 19.05,
+ "close": 19.08,
+ "volume": 1996539.53
+ },
+ {
+ "date": "20240410",
+ "open": 19.08,
+ "high": 19.21,
+ "low": 18.73,
+ "close": 18.86,
+ "volume": 1102925.57
+ },
+ {
+ "date": "20240411",
+ "open": 18.86,
+ "high": 19.08,
+ "low": 18.77,
+ "close": 19.01,
+ "volume": 2134422.48
+ },
+ {
+ "date": "20240412",
+ "open": 19.01,
+ "high": 19.45,
+ "low": 18.87,
+ "close": 19.28,
+ "volume": 1264713.34
+ },
+ {
+ "date": "20240413",
+ "open": 19.28,
+ "high": 19.43,
+ "low": 19.28,
+ "close": 19.37,
+ "volume": 2015413.53
+ },
+ {
+ "date": "20240414",
+ "open": 19.37,
+ "high": 19.56,
+ "low": 19.31,
+ "close": 19.39,
+ "volume": 2633854.58
+ },
+ {
+ "date": "20240415",
+ "open": 19.39,
+ "high": 19.47,
+ "low": 19.25,
+ "close": 19.45,
+ "volume": 1426247.96
+ },
+ {
+ "date": "20240416",
+ "open": 19.45,
+ "high": 19.54,
+ "low": 19.45,
+ "close": 19.53,
+ "volume": 2826173.85
+ },
+ {
+ "date": "20240417",
+ "open": 19.53,
+ "high": 19.56,
+ "low": 19.15,
+ "close": 19.18,
+ "volume": 1011308.47
+ },
+ {
+ "date": "20240418",
+ "open": 19.18,
+ "high": 19.7,
+ "low": 19.05,
+ "close": 19.5,
+ "volume": 1670010.09
+ },
+ {
+ "date": "20240419",
+ "open": 19.5,
+ "high": 19.99,
+ "low": 19.48,
+ "close": 19.89,
+ "volume": 2318466.15
+ },
+ {
+ "date": "20240420",
+ "open": 19.89,
+ "high": 19.95,
+ "low": 19.75,
+ "close": 19.82,
+ "volume": 1647093.09
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "光伏·弱势结构"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/601318.json b/zhishi/fixtures/ohlcv/601318.json
new file mode 100644
index 0000000..a6ca877
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/601318.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "601318",
+ "name": "中国平安",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 42,
+ "high": 43.01,
+ "low": 41.8,
+ "close": 42.66,
+ "volume": 1375567.26
+ },
+ {
+ "date": "20240102",
+ "open": 42.66,
+ "high": 42.94,
+ "low": 41.61,
+ "close": 41.81,
+ "volume": 2471407.4
+ },
+ {
+ "date": "20240103",
+ "open": 41.81,
+ "high": 42.13,
+ "low": 41.56,
+ "close": 41.67,
+ "volume": 2564214.06
+ },
+ {
+ "date": "20240104",
+ "open": 41.67,
+ "high": 42.38,
+ "low": 41.45,
+ "close": 42.21,
+ "volume": 2300513.83
+ },
+ {
+ "date": "20240105",
+ "open": 42.21,
+ "high": 42.44,
+ "low": 41.39,
+ "close": 41.73,
+ "volume": 1384146.32
+ },
+ {
+ "date": "20240106",
+ "open": 41.73,
+ "high": 42.7,
+ "low": 41.38,
+ "close": 42.4,
+ "volume": 1538280.44
+ },
+ {
+ "date": "20240107",
+ "open": 42.4,
+ "high": 42.74,
+ "low": 41.4,
+ "close": 41.73,
+ "volume": 1779467.31
+ },
+ {
+ "date": "20240108",
+ "open": 41.73,
+ "high": 41.82,
+ "low": 40.81,
+ "close": 41.08,
+ "volume": 1440603.84
+ },
+ {
+ "date": "20240109",
+ "open": 41.08,
+ "high": 42.26,
+ "low": 40.99,
+ "close": 42.01,
+ "volume": 2241888.79
+ },
+ {
+ "date": "20240110",
+ "open": 42.01,
+ "high": 42.4,
+ "low": 41.47,
+ "close": 41.85,
+ "volume": 1932232.55
+ },
+ {
+ "date": "20240111",
+ "open": 41.85,
+ "high": 42.53,
+ "low": 41.52,
+ "close": 42.23,
+ "volume": 2948025.01
+ },
+ {
+ "date": "20240112",
+ "open": 42.23,
+ "high": 42.38,
+ "low": 41.19,
+ "close": 41.44,
+ "volume": 1469513.69
+ },
+ {
+ "date": "20240113",
+ "open": 41.44,
+ "high": 41.75,
+ "low": 41.08,
+ "close": 41.71,
+ "volume": 1955579.01
+ },
+ {
+ "date": "20240114",
+ "open": 41.71,
+ "high": 41.99,
+ "low": 40.97,
+ "close": 41.09,
+ "volume": 1231693.09
+ },
+ {
+ "date": "20240115",
+ "open": 41.09,
+ "high": 41.22,
+ "low": 41.01,
+ "close": 41.17,
+ "volume": 2704186.24
+ },
+ {
+ "date": "20240116",
+ "open": 41.17,
+ "high": 41.64,
+ "low": 40.85,
+ "close": 41.64,
+ "volume": 837529.25
+ },
+ {
+ "date": "20240117",
+ "open": 41.64,
+ "high": 42.01,
+ "low": 41.17,
+ "close": 41.43,
+ "volume": 1473473.96
+ },
+ {
+ "date": "20240118",
+ "open": 41.43,
+ "high": 41.59,
+ "low": 41.25,
+ "close": 41.3,
+ "volume": 2999732.91
+ },
+ {
+ "date": "20240119",
+ "open": 41.3,
+ "high": 41.48,
+ "low": 40.27,
+ "close": 40.58,
+ "volume": 1675081.45
+ },
+ {
+ "date": "20240120",
+ "open": 40.58,
+ "high": 41.66,
+ "low": 40.18,
+ "close": 41.56,
+ "volume": 2762965.39
+ },
+ {
+ "date": "20240201",
+ "open": 41.56,
+ "high": 42.35,
+ "low": 41.37,
+ "close": 41.98,
+ "volume": 2628770.93
+ },
+ {
+ "date": "20240202",
+ "open": 41.98,
+ "high": 42.86,
+ "low": 41.78,
+ "close": 42.64,
+ "volume": 2352480.55
+ },
+ {
+ "date": "20240203",
+ "open": 42.64,
+ "high": 42.68,
+ "low": 42.26,
+ "close": 42.58,
+ "volume": 1384803.38
+ },
+ {
+ "date": "20240204",
+ "open": 42.58,
+ "high": 42.99,
+ "low": 42.5,
+ "close": 42.66,
+ "volume": 848121.39
+ },
+ {
+ "date": "20240205",
+ "open": 42.66,
+ "high": 42.91,
+ "low": 41.89,
+ "close": 42.04,
+ "volume": 1363886.86
+ },
+ {
+ "date": "20240206",
+ "open": 42.04,
+ "high": 42.45,
+ "low": 41.94,
+ "close": 42.06,
+ "volume": 1703257.53
+ },
+ {
+ "date": "20240207",
+ "open": 42.06,
+ "high": 43.14,
+ "low": 41.94,
+ "close": 42.88,
+ "volume": 1844359.64
+ },
+ {
+ "date": "20240208",
+ "open": 42.88,
+ "high": 43.01,
+ "low": 42.72,
+ "close": 42.94,
+ "volume": 1472481.76
+ },
+ {
+ "date": "20240209",
+ "open": 42.94,
+ "high": 43.78,
+ "low": 42.66,
+ "close": 43.64,
+ "volume": 2935685.38
+ },
+ {
+ "date": "20240210",
+ "open": 43.64,
+ "high": 44.75,
+ "low": 43.38,
+ "close": 44.58,
+ "volume": 1504248.62
+ },
+ {
+ "date": "20240211",
+ "open": 44.58,
+ "high": 44.8,
+ "low": 44.14,
+ "close": 44.49,
+ "volume": 2860547.21
+ },
+ {
+ "date": "20240212",
+ "open": 44.49,
+ "high": 44.49,
+ "low": 43.98,
+ "close": 44.18,
+ "volume": 925631.1
+ },
+ {
+ "date": "20240213",
+ "open": 44.18,
+ "high": 44.52,
+ "low": 43.31,
+ "close": 43.36,
+ "volume": 2380715.81
+ },
+ {
+ "date": "20240214",
+ "open": 43.36,
+ "high": 43.76,
+ "low": 42.83,
+ "close": 43.2,
+ "volume": 937004.67
+ },
+ {
+ "date": "20240215",
+ "open": 43.2,
+ "high": 43.61,
+ "low": 42.44,
+ "close": 42.71,
+ "volume": 1728645.53
+ },
+ {
+ "date": "20240216",
+ "open": 42.71,
+ "high": 43.71,
+ "low": 42.5,
+ "close": 43.36,
+ "volume": 1831578.08
+ },
+ {
+ "date": "20240217",
+ "open": 43.36,
+ "high": 43.51,
+ "low": 42.62,
+ "close": 42.68,
+ "volume": 2176305.83
+ },
+ {
+ "date": "20240218",
+ "open": 42.68,
+ "high": 43.06,
+ "low": 42.42,
+ "close": 43.0,
+ "volume": 1014108.89
+ },
+ {
+ "date": "20240219",
+ "open": 43.0,
+ "high": 43.27,
+ "low": 42.14,
+ "close": 42.34,
+ "volume": 2779087.89
+ },
+ {
+ "date": "20240220",
+ "open": 42.34,
+ "high": 42.99,
+ "low": 42.29,
+ "close": 42.69,
+ "volume": 2631859.34
+ },
+ {
+ "date": "20240301",
+ "open": 42.69,
+ "high": 42.96,
+ "low": 41.62,
+ "close": 42.0,
+ "volume": 2797004.7
+ },
+ {
+ "date": "20240302",
+ "open": 42.0,
+ "high": 43.04,
+ "low": 41.71,
+ "close": 42.85,
+ "volume": 2540931.46
+ },
+ {
+ "date": "20240303",
+ "open": 42.85,
+ "high": 43.25,
+ "low": 41.87,
+ "close": 42.25,
+ "volume": 1769950.61
+ },
+ {
+ "date": "20240304",
+ "open": 42.25,
+ "high": 43.08,
+ "low": 42.14,
+ "close": 42.89,
+ "volume": 2367453.41
+ },
+ {
+ "date": "20240305",
+ "open": 42.89,
+ "high": 43.23,
+ "low": 41.74,
+ "close": 42.15,
+ "volume": 1429355.47
+ },
+ {
+ "date": "20240306",
+ "open": 42.15,
+ "high": 43.13,
+ "low": 41.79,
+ "close": 43.09,
+ "volume": 1415577.42
+ },
+ {
+ "date": "20240307",
+ "open": 43.09,
+ "high": 44.3,
+ "low": 42.7,
+ "close": 44.11,
+ "volume": 870208.87
+ },
+ {
+ "date": "20240308",
+ "open": 44.11,
+ "high": 44.47,
+ "low": 43.12,
+ "close": 43.39,
+ "volume": 1978102.47
+ },
+ {
+ "date": "20240309",
+ "open": 43.39,
+ "high": 43.47,
+ "low": 42.43,
+ "close": 42.59,
+ "volume": 914544.92
+ },
+ {
+ "date": "20240310",
+ "open": 42.59,
+ "high": 43.98,
+ "low": 42.19,
+ "close": 43.64,
+ "volume": 2341509.44
+ },
+ {
+ "date": "20240311",
+ "open": 43.64,
+ "high": 43.67,
+ "low": 43.13,
+ "close": 43.44,
+ "volume": 1050877.03
+ },
+ {
+ "date": "20240312",
+ "open": 43.44,
+ "high": 43.85,
+ "low": 43.23,
+ "close": 43.64,
+ "volume": 965399.35
+ },
+ {
+ "date": "20240313",
+ "open": 43.64,
+ "high": 43.87,
+ "low": 42.9,
+ "close": 42.92,
+ "volume": 1955930.69
+ },
+ {
+ "date": "20240314",
+ "open": 42.92,
+ "high": 43.04,
+ "low": 42.28,
+ "close": 42.35,
+ "volume": 2050560.99
+ },
+ {
+ "date": "20240315",
+ "open": 42.35,
+ "high": 42.44,
+ "low": 42.15,
+ "close": 42.24,
+ "volume": 2040925.79
+ },
+ {
+ "date": "20240316",
+ "open": 42.24,
+ "high": 43.31,
+ "low": 42.17,
+ "close": 43.13,
+ "volume": 1496297.31
+ },
+ {
+ "date": "20240317",
+ "open": 43.13,
+ "high": 43.37,
+ "low": 42.39,
+ "close": 42.73,
+ "volume": 2051613.8
+ },
+ {
+ "date": "20240318",
+ "open": 42.73,
+ "high": 42.87,
+ "low": 42.08,
+ "close": 42.24,
+ "volume": 1770075.62
+ },
+ {
+ "date": "20240319",
+ "open": 42.24,
+ "high": 42.66,
+ "low": 41.92,
+ "close": 42.15,
+ "volume": 2256565.26
+ },
+ {
+ "date": "20240320",
+ "open": 42.15,
+ "high": 42.94,
+ "low": 41.81,
+ "close": 42.66,
+ "volume": 1618892.91
+ },
+ {
+ "date": "20240401",
+ "open": 42.66,
+ "high": 43.51,
+ "low": 42.59,
+ "close": 43.09,
+ "volume": 2176021.85
+ },
+ {
+ "date": "20240402",
+ "open": 43.09,
+ "high": 43.12,
+ "low": 42.96,
+ "close": 42.98,
+ "volume": 2469724.33
+ },
+ {
+ "date": "20240403",
+ "open": 42.98,
+ "high": 43.28,
+ "low": 42.29,
+ "close": 42.34,
+ "volume": 1608753.86
+ },
+ {
+ "date": "20240404",
+ "open": 42.34,
+ "high": 42.57,
+ "low": 41.23,
+ "close": 41.55,
+ "volume": 1296272.22
+ },
+ {
+ "date": "20240405",
+ "open": 41.55,
+ "high": 42.16,
+ "low": 41.43,
+ "close": 41.78,
+ "volume": 1836307.53
+ },
+ {
+ "date": "20240406",
+ "open": 41.78,
+ "high": 42.67,
+ "low": 41.71,
+ "close": 42.3,
+ "volume": 2254988.67
+ },
+ {
+ "date": "20240407",
+ "open": 42.3,
+ "high": 42.35,
+ "low": 41.28,
+ "close": 41.69,
+ "volume": 910028.16
+ },
+ {
+ "date": "20240408",
+ "open": 41.69,
+ "high": 42.9,
+ "low": 41.4,
+ "close": 42.58,
+ "volume": 2404768.2
+ },
+ {
+ "date": "20240409",
+ "open": 42.58,
+ "high": 43.1,
+ "low": 42.39,
+ "close": 42.97,
+ "volume": 1244711.69
+ },
+ {
+ "date": "20240410",
+ "open": 42.97,
+ "high": 44.12,
+ "low": 42.64,
+ "close": 43.78,
+ "volume": 1270708.25
+ },
+ {
+ "date": "20240411",
+ "open": 43.78,
+ "high": 44.18,
+ "low": 43.43,
+ "close": 44.07,
+ "volume": 2438504.71
+ },
+ {
+ "date": "20240412",
+ "open": 44.07,
+ "high": 45.48,
+ "low": 43.77,
+ "close": 45.16,
+ "volume": 2509435.29
+ },
+ {
+ "date": "20240413",
+ "open": 45.16,
+ "high": 45.43,
+ "low": 44.43,
+ "close": 44.45,
+ "volume": 1607709.03
+ },
+ {
+ "date": "20240414",
+ "open": 44.45,
+ "high": 44.87,
+ "low": 43.78,
+ "close": 43.79,
+ "volume": 2826896.8
+ },
+ {
+ "date": "20240415",
+ "open": 43.79,
+ "high": 44.98,
+ "low": 43.43,
+ "close": 44.78,
+ "volume": 913850.69
+ },
+ {
+ "date": "20240416",
+ "open": 44.78,
+ "high": 44.79,
+ "low": 44.14,
+ "close": 44.17,
+ "volume": 805676.73
+ },
+ {
+ "date": "20240417",
+ "open": 44.17,
+ "high": 44.97,
+ "low": 43.91,
+ "close": 44.93,
+ "volume": 1401104.32
+ },
+ {
+ "date": "20240418",
+ "open": 44.93,
+ "high": 45.12,
+ "low": 44.22,
+ "close": 44.3,
+ "volume": 2949802.87
+ },
+ {
+ "date": "20240419",
+ "open": 44.3,
+ "high": 44.56,
+ "low": 43.93,
+ "close": 44.18,
+ "volume": 2179113.04
+ },
+ {
+ "date": "20240420",
+ "open": 44.18,
+ "high": 44.37,
+ "low": 44.12,
+ "close": 44.25,
+ "volume": 2753706.24
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "保险·均值回归"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/601398.json b/zhishi/fixtures/ohlcv/601398.json
new file mode 100644
index 0000000..b9074ae
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/601398.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "601398",
+ "name": "工商银行",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 5.2,
+ "high": 5.23,
+ "low": 5.12,
+ "close": 5.14,
+ "volume": 1235467.13
+ },
+ {
+ "date": "20240102",
+ "open": 5.14,
+ "high": 5.17,
+ "low": 5.11,
+ "close": 5.15,
+ "volume": 1808328.45
+ },
+ {
+ "date": "20240103",
+ "open": 5.15,
+ "high": 5.16,
+ "low": 5.07,
+ "close": 5.11,
+ "volume": 1513763.92
+ },
+ {
+ "date": "20240104",
+ "open": 5.11,
+ "high": 5.2,
+ "low": 5.06,
+ "close": 5.16,
+ "volume": 2876862.51
+ },
+ {
+ "date": "20240105",
+ "open": 5.16,
+ "high": 5.17,
+ "low": 5.07,
+ "close": 5.11,
+ "volume": 2066194.99
+ },
+ {
+ "date": "20240106",
+ "open": 5.11,
+ "high": 5.15,
+ "low": 5.01,
+ "close": 5.06,
+ "volume": 2638730.13
+ },
+ {
+ "date": "20240107",
+ "open": 5.06,
+ "high": 5.07,
+ "low": 5.0,
+ "close": 5.0,
+ "volume": 2946495.24
+ },
+ {
+ "date": "20240108",
+ "open": 5.0,
+ "high": 5.04,
+ "low": 4.93,
+ "close": 4.95,
+ "volume": 2105617.63
+ },
+ {
+ "date": "20240109",
+ "open": 4.95,
+ "high": 5.01,
+ "low": 4.92,
+ "close": 4.97,
+ "volume": 1467015.49
+ },
+ {
+ "date": "20240110",
+ "open": 4.97,
+ "high": 5.0,
+ "low": 4.85,
+ "close": 4.9,
+ "volume": 1119445.05
+ },
+ {
+ "date": "20240111",
+ "open": 4.9,
+ "high": 4.98,
+ "low": 4.89,
+ "close": 4.95,
+ "volume": 1255043.08
+ },
+ {
+ "date": "20240112",
+ "open": 4.95,
+ "high": 5.03,
+ "low": 4.93,
+ "close": 5.0,
+ "volume": 1856749.82
+ },
+ {
+ "date": "20240113",
+ "open": 5.0,
+ "high": 5.04,
+ "low": 4.9,
+ "close": 4.93,
+ "volume": 1975266.79
+ },
+ {
+ "date": "20240114",
+ "open": 4.93,
+ "high": 4.97,
+ "low": 4.86,
+ "close": 4.9,
+ "volume": 1998698.36
+ },
+ {
+ "date": "20240115",
+ "open": 4.9,
+ "high": 4.91,
+ "low": 4.82,
+ "close": 4.83,
+ "volume": 973453.21
+ },
+ {
+ "date": "20240116",
+ "open": 4.83,
+ "high": 4.9,
+ "low": 4.82,
+ "close": 4.87,
+ "volume": 2802785.39
+ },
+ {
+ "date": "20240117",
+ "open": 4.87,
+ "high": 4.95,
+ "low": 4.83,
+ "close": 4.91,
+ "volume": 2299362.7
+ },
+ {
+ "date": "20240118",
+ "open": 4.91,
+ "high": 4.98,
+ "low": 4.9,
+ "close": 4.93,
+ "volume": 2316402.83
+ },
+ {
+ "date": "20240119",
+ "open": 4.93,
+ "high": 5.05,
+ "low": 4.89,
+ "close": 5.03,
+ "volume": 1198987.15
+ },
+ {
+ "date": "20240120",
+ "open": 5.03,
+ "high": 5.04,
+ "low": 5.0,
+ "close": 5.02,
+ "volume": 2344125.3
+ },
+ {
+ "date": "20240201",
+ "open": 5.02,
+ "high": 5.04,
+ "low": 4.91,
+ "close": 4.95,
+ "volume": 1463107.75
+ },
+ {
+ "date": "20240202",
+ "open": 4.95,
+ "high": 5.0,
+ "low": 4.85,
+ "close": 4.88,
+ "volume": 839878.98
+ },
+ {
+ "date": "20240203",
+ "open": 4.88,
+ "high": 4.92,
+ "low": 4.87,
+ "close": 4.91,
+ "volume": 2425282.54
+ },
+ {
+ "date": "20240204",
+ "open": 4.91,
+ "high": 4.98,
+ "low": 4.88,
+ "close": 4.95,
+ "volume": 2029053.1
+ },
+ {
+ "date": "20240205",
+ "open": 4.95,
+ "high": 4.96,
+ "low": 4.92,
+ "close": 4.96,
+ "volume": 2494755.6
+ },
+ {
+ "date": "20240206",
+ "open": 4.96,
+ "high": 4.98,
+ "low": 4.92,
+ "close": 4.95,
+ "volume": 1838365.91
+ },
+ {
+ "date": "20240207",
+ "open": 4.95,
+ "high": 5.0,
+ "low": 4.9,
+ "close": 4.95,
+ "volume": 1131907.8
+ },
+ {
+ "date": "20240208",
+ "open": 4.95,
+ "high": 4.98,
+ "low": 4.84,
+ "close": 4.89,
+ "volume": 2406582.86
+ },
+ {
+ "date": "20240209",
+ "open": 4.89,
+ "high": 4.89,
+ "low": 4.81,
+ "close": 4.85,
+ "volume": 2846282.23
+ },
+ {
+ "date": "20240210",
+ "open": 4.85,
+ "high": 4.96,
+ "low": 4.81,
+ "close": 4.92,
+ "volume": 1952113.09
+ },
+ {
+ "date": "20240211",
+ "open": 4.92,
+ "high": 5.04,
+ "low": 4.92,
+ "close": 5.03,
+ "volume": 2646796.31
+ },
+ {
+ "date": "20240212",
+ "open": 5.03,
+ "high": 5.13,
+ "low": 5.02,
+ "close": 5.09,
+ "volume": 1460146.47
+ },
+ {
+ "date": "20240213",
+ "open": 5.09,
+ "high": 5.12,
+ "low": 5.07,
+ "close": 5.12,
+ "volume": 2126526.64
+ },
+ {
+ "date": "20240214",
+ "open": 5.12,
+ "high": 5.27,
+ "low": 5.1,
+ "close": 5.23,
+ "volume": 1697411.28
+ },
+ {
+ "date": "20240215",
+ "open": 5.23,
+ "high": 5.29,
+ "low": 5.18,
+ "close": 5.25,
+ "volume": 824270.68
+ },
+ {
+ "date": "20240216",
+ "open": 5.25,
+ "high": 5.41,
+ "low": 5.25,
+ "close": 5.36,
+ "volume": 1363939.33
+ },
+ {
+ "date": "20240217",
+ "open": 5.36,
+ "high": 5.37,
+ "low": 5.31,
+ "close": 5.32,
+ "volume": 1099988.97
+ },
+ {
+ "date": "20240218",
+ "open": 5.32,
+ "high": 5.4,
+ "low": 5.32,
+ "close": 5.38,
+ "volume": 2655470.76
+ },
+ {
+ "date": "20240219",
+ "open": 5.38,
+ "high": 5.49,
+ "low": 5.33,
+ "close": 5.47,
+ "volume": 2506591.91
+ },
+ {
+ "date": "20240220",
+ "open": 5.47,
+ "high": 5.5,
+ "low": 5.43,
+ "close": 5.49,
+ "volume": 2724149.94
+ },
+ {
+ "date": "20240301",
+ "open": 5.49,
+ "high": 5.66,
+ "low": 5.48,
+ "close": 5.6,
+ "volume": 2947077.38
+ },
+ {
+ "date": "20240302",
+ "open": 5.6,
+ "high": 5.62,
+ "low": 5.48,
+ "close": 5.51,
+ "volume": 2205600.69
+ },
+ {
+ "date": "20240303",
+ "open": 5.51,
+ "high": 5.58,
+ "low": 5.47,
+ "close": 5.53,
+ "volume": 2689888.32
+ },
+ {
+ "date": "20240304",
+ "open": 5.53,
+ "high": 5.62,
+ "low": 5.53,
+ "close": 5.59,
+ "volume": 2223333.78
+ },
+ {
+ "date": "20240305",
+ "open": 5.59,
+ "high": 5.73,
+ "low": 5.54,
+ "close": 5.72,
+ "volume": 838630.41
+ },
+ {
+ "date": "20240306",
+ "open": 5.72,
+ "high": 5.76,
+ "low": 5.66,
+ "close": 5.7,
+ "volume": 2070147.8
+ },
+ {
+ "date": "20240307",
+ "open": 5.7,
+ "high": 5.72,
+ "low": 5.65,
+ "close": 5.66,
+ "volume": 2219101.44
+ },
+ {
+ "date": "20240308",
+ "open": 5.66,
+ "high": 5.67,
+ "low": 5.51,
+ "close": 5.55,
+ "volume": 1782024.25
+ },
+ {
+ "date": "20240309",
+ "open": 5.55,
+ "high": 5.58,
+ "low": 5.4,
+ "close": 5.45,
+ "volume": 1925867.29
+ },
+ {
+ "date": "20240310",
+ "open": 5.45,
+ "high": 5.45,
+ "low": 5.38,
+ "close": 5.4,
+ "volume": 1333263.86
+ },
+ {
+ "date": "20240311",
+ "open": 5.4,
+ "high": 5.41,
+ "low": 5.33,
+ "close": 5.36,
+ "volume": 2545738.16
+ },
+ {
+ "date": "20240312",
+ "open": 5.36,
+ "high": 5.41,
+ "low": 5.35,
+ "close": 5.38,
+ "volume": 2983114.72
+ },
+ {
+ "date": "20240313",
+ "open": 5.38,
+ "high": 5.43,
+ "low": 5.34,
+ "close": 5.34,
+ "volume": 2253738.12
+ },
+ {
+ "date": "20240314",
+ "open": 5.34,
+ "high": 5.47,
+ "low": 5.33,
+ "close": 5.44,
+ "volume": 1168672.26
+ },
+ {
+ "date": "20240315",
+ "open": 5.44,
+ "high": 5.63,
+ "low": 5.43,
+ "close": 5.57,
+ "volume": 1706296.25
+ },
+ {
+ "date": "20240316",
+ "open": 5.57,
+ "high": 5.72,
+ "low": 5.57,
+ "close": 5.67,
+ "volume": 1998841.22
+ },
+ {
+ "date": "20240317",
+ "open": 5.67,
+ "high": 5.68,
+ "low": 5.58,
+ "close": 5.62,
+ "volume": 1870733.01
+ },
+ {
+ "date": "20240318",
+ "open": 5.62,
+ "high": 5.66,
+ "low": 5.54,
+ "close": 5.56,
+ "volume": 1379348.2
+ },
+ {
+ "date": "20240319",
+ "open": 5.56,
+ "high": 5.57,
+ "low": 5.48,
+ "close": 5.52,
+ "volume": 1524932.61
+ },
+ {
+ "date": "20240320",
+ "open": 5.52,
+ "high": 5.68,
+ "low": 5.5,
+ "close": 5.65,
+ "volume": 2769260.17
+ },
+ {
+ "date": "20240401",
+ "open": 5.65,
+ "high": 5.65,
+ "low": 5.59,
+ "close": 5.63,
+ "volume": 939161.92
+ },
+ {
+ "date": "20240402",
+ "open": 5.63,
+ "high": 5.81,
+ "low": 5.61,
+ "close": 5.75,
+ "volume": 997686.22
+ },
+ {
+ "date": "20240403",
+ "open": 5.75,
+ "high": 5.9,
+ "low": 5.69,
+ "close": 5.88,
+ "volume": 1849585.3
+ },
+ {
+ "date": "20240404",
+ "open": 5.88,
+ "high": 6.05,
+ "low": 5.87,
+ "close": 6.0,
+ "volume": 1535347.68
+ },
+ {
+ "date": "20240405",
+ "open": 6.0,
+ "high": 6.01,
+ "low": 5.94,
+ "close": 6.0,
+ "volume": 1261289.55
+ },
+ {
+ "date": "20240406",
+ "open": 6.0,
+ "high": 6.01,
+ "low": 5.93,
+ "close": 5.94,
+ "volume": 2588664.27
+ },
+ {
+ "date": "20240407",
+ "open": 5.94,
+ "high": 5.98,
+ "low": 5.87,
+ "close": 5.88,
+ "volume": 2584770.57
+ },
+ {
+ "date": "20240408",
+ "open": 5.88,
+ "high": 6.02,
+ "low": 5.87,
+ "close": 5.97,
+ "volume": 2273376.48
+ },
+ {
+ "date": "20240409",
+ "open": 5.97,
+ "high": 6.06,
+ "low": 5.92,
+ "close": 6.04,
+ "volume": 1508712.85
+ },
+ {
+ "date": "20240410",
+ "open": 6.04,
+ "high": 6.13,
+ "low": 5.99,
+ "close": 6.08,
+ "volume": 1530653.03
+ },
+ {
+ "date": "20240411",
+ "open": 6.08,
+ "high": 6.14,
+ "low": 6.01,
+ "close": 6.03,
+ "volume": 1838335.43
+ },
+ {
+ "date": "20240412",
+ "open": 6.03,
+ "high": 6.05,
+ "low": 5.99,
+ "close": 6.02,
+ "volume": 1056513.91
+ },
+ {
+ "date": "20240413",
+ "open": 6.02,
+ "high": 6.07,
+ "low": 5.97,
+ "close": 6.03,
+ "volume": 1878787.59
+ },
+ {
+ "date": "20240414",
+ "open": 6.03,
+ "high": 6.04,
+ "low": 5.96,
+ "close": 5.97,
+ "volume": 1122611.45
+ },
+ {
+ "date": "20240415",
+ "open": 5.97,
+ "high": 5.99,
+ "low": 5.88,
+ "close": 5.93,
+ "volume": 2463119.27
+ },
+ {
+ "date": "20240416",
+ "open": 5.93,
+ "high": 6.09,
+ "low": 5.92,
+ "close": 6.06,
+ "volume": 2056134.95
+ },
+ {
+ "date": "20240417",
+ "open": 6.06,
+ "high": 6.19,
+ "low": 6.05,
+ "close": 6.13,
+ "volume": 2477528.44
+ },
+ {
+ "date": "20240418",
+ "open": 6.13,
+ "high": 6.3,
+ "low": 6.1,
+ "close": 6.27,
+ "volume": 1036421.19
+ },
+ {
+ "date": "20240419",
+ "open": 6.27,
+ "high": 6.34,
+ "low": 6.22,
+ "close": 6.33,
+ "volume": 2462187.63
+ },
+ {
+ "date": "20240420",
+ "open": 6.33,
+ "high": 6.5,
+ "low": 6.33,
+ "close": 6.44,
+ "volume": 2727548.33
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "大行·复盘四问"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/601888.json b/zhishi/fixtures/ohlcv/601888.json
new file mode 100644
index 0000000..5ed04df
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/601888.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "601888",
+ "name": "中国中免",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": false,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 70,
+ "high": 70.49,
+ "low": 68.49,
+ "close": 68.94,
+ "volume": 2868775.26
+ },
+ {
+ "date": "20240102",
+ "open": 68.94,
+ "high": 69.11,
+ "low": 67.9,
+ "close": 68.4,
+ "volume": 2248590.04
+ },
+ {
+ "date": "20240103",
+ "open": 68.4,
+ "high": 68.87,
+ "low": 67.69,
+ "close": 67.96,
+ "volume": 2510536.49
+ },
+ {
+ "date": "20240104",
+ "open": 67.96,
+ "high": 68.12,
+ "low": 66.36,
+ "close": 66.97,
+ "volume": 1587671.9
+ },
+ {
+ "date": "20240105",
+ "open": 66.97,
+ "high": 67.5,
+ "low": 65.99,
+ "close": 66.41,
+ "volume": 1129347.82
+ },
+ {
+ "date": "20240106",
+ "open": 66.41,
+ "high": 67.17,
+ "low": 66.3,
+ "close": 66.73,
+ "volume": 2233736.24
+ },
+ {
+ "date": "20240107",
+ "open": 66.73,
+ "high": 66.96,
+ "low": 65.71,
+ "close": 65.77,
+ "volume": 1249727.74
+ },
+ {
+ "date": "20240108",
+ "open": 65.77,
+ "high": 67.62,
+ "low": 65.11,
+ "close": 67.34,
+ "volume": 1765025.71
+ },
+ {
+ "date": "20240109",
+ "open": 67.34,
+ "high": 68.43,
+ "low": 66.88,
+ "close": 67.84,
+ "volume": 1045369.2
+ },
+ {
+ "date": "20240110",
+ "open": 67.84,
+ "high": 68.71,
+ "low": 67.72,
+ "close": 68.28,
+ "volume": 1008279.5
+ },
+ {
+ "date": "20240111",
+ "open": 68.28,
+ "high": 69.96,
+ "low": 68.15,
+ "close": 69.6,
+ "volume": 1795722.0
+ },
+ {
+ "date": "20240112",
+ "open": 69.6,
+ "high": 70.16,
+ "low": 68.55,
+ "close": 68.89,
+ "volume": 1025341.66
+ },
+ {
+ "date": "20240113",
+ "open": 68.89,
+ "high": 70.12,
+ "low": 68.7,
+ "close": 70.05,
+ "volume": 861594.29
+ },
+ {
+ "date": "20240114",
+ "open": 70.05,
+ "high": 71.07,
+ "low": 69.68,
+ "close": 70.99,
+ "volume": 1004564.13
+ },
+ {
+ "date": "20240115",
+ "open": 70.99,
+ "high": 71.59,
+ "low": 70.61,
+ "close": 71.1,
+ "volume": 1801367.18
+ },
+ {
+ "date": "20240116",
+ "open": 71.1,
+ "high": 71.54,
+ "low": 70.68,
+ "close": 71.23,
+ "volume": 1008679.31
+ },
+ {
+ "date": "20240117",
+ "open": 71.23,
+ "high": 71.49,
+ "low": 70.61,
+ "close": 71.33,
+ "volume": 2865844.48
+ },
+ {
+ "date": "20240118",
+ "open": 71.33,
+ "high": 71.43,
+ "low": 69.62,
+ "close": 70.11,
+ "volume": 2057183.8
+ },
+ {
+ "date": "20240119",
+ "open": 70.11,
+ "high": 70.61,
+ "low": 68.12,
+ "close": 68.77,
+ "volume": 1730842.77
+ },
+ {
+ "date": "20240120",
+ "open": 68.77,
+ "high": 69.16,
+ "low": 67.83,
+ "close": 68.47,
+ "volume": 1379784.91
+ },
+ {
+ "date": "20240201",
+ "open": 68.47,
+ "high": 68.6,
+ "low": 67.61,
+ "close": 68.03,
+ "volume": 1832366.69
+ },
+ {
+ "date": "20240202",
+ "open": 68.03,
+ "high": 68.3,
+ "low": 67.43,
+ "close": 67.46,
+ "volume": 1487387.49
+ },
+ {
+ "date": "20240203",
+ "open": 67.46,
+ "high": 69.5,
+ "low": 67.27,
+ "close": 69.09,
+ "volume": 2859486.23
+ },
+ {
+ "date": "20240204",
+ "open": 69.09,
+ "high": 69.26,
+ "low": 68.8,
+ "close": 68.82,
+ "volume": 1121642.49
+ },
+ {
+ "date": "20240205",
+ "open": 68.82,
+ "high": 68.98,
+ "low": 67.47,
+ "close": 68.06,
+ "volume": 1382002.05
+ },
+ {
+ "date": "20240206",
+ "open": 68.06,
+ "high": 68.47,
+ "low": 66.84,
+ "close": 67.46,
+ "volume": 1441024.63
+ },
+ {
+ "date": "20240207",
+ "open": 67.46,
+ "high": 68.68,
+ "low": 67.08,
+ "close": 68.43,
+ "volume": 2110843.77
+ },
+ {
+ "date": "20240208",
+ "open": 68.43,
+ "high": 70.49,
+ "low": 68.08,
+ "close": 69.96,
+ "volume": 2651073.87
+ },
+ {
+ "date": "20240209",
+ "open": 69.96,
+ "high": 70.23,
+ "low": 69.04,
+ "close": 69.71,
+ "volume": 2001072.43
+ },
+ {
+ "date": "20240210",
+ "open": 69.71,
+ "high": 70.97,
+ "low": 69.08,
+ "close": 70.75,
+ "volume": 2148014.61
+ },
+ {
+ "date": "20240211",
+ "open": 70.75,
+ "high": 71.41,
+ "low": 69.79,
+ "close": 70.12,
+ "volume": 1546753.4
+ },
+ {
+ "date": "20240212",
+ "open": 70.12,
+ "high": 70.19,
+ "low": 69.41,
+ "close": 69.54,
+ "volume": 2322934.0
+ },
+ {
+ "date": "20240213",
+ "open": 69.54,
+ "high": 69.72,
+ "low": 68.29,
+ "close": 68.59,
+ "volume": 1998318.88
+ },
+ {
+ "date": "20240214",
+ "open": 68.59,
+ "high": 69.13,
+ "low": 68.22,
+ "close": 68.4,
+ "volume": 1610920.05
+ },
+ {
+ "date": "20240215",
+ "open": 68.4,
+ "high": 68.48,
+ "low": 68.18,
+ "close": 68.34,
+ "volume": 1122268.15
+ },
+ {
+ "date": "20240216",
+ "open": 68.34,
+ "high": 69.3,
+ "low": 67.88,
+ "close": 69.2,
+ "volume": 1288481.55
+ },
+ {
+ "date": "20240217",
+ "open": 69.2,
+ "high": 70.29,
+ "low": 68.96,
+ "close": 69.83,
+ "volume": 2852808.99
+ },
+ {
+ "date": "20240218",
+ "open": 69.83,
+ "high": 70.89,
+ "low": 69.8,
+ "close": 70.5,
+ "volume": 1694367.63
+ },
+ {
+ "date": "20240219",
+ "open": 70.5,
+ "high": 70.83,
+ "low": 69.28,
+ "close": 69.93,
+ "volume": 2700707.53
+ },
+ {
+ "date": "20240220",
+ "open": 69.93,
+ "high": 70.41,
+ "low": 68.09,
+ "close": 68.73,
+ "volume": 1993371.32
+ },
+ {
+ "date": "20240301",
+ "open": 68.73,
+ "high": 69.32,
+ "low": 67.37,
+ "close": 67.65,
+ "volume": 2957208.75
+ },
+ {
+ "date": "20240302",
+ "open": 67.65,
+ "high": 69.53,
+ "low": 67.02,
+ "close": 68.96,
+ "volume": 949875.05
+ },
+ {
+ "date": "20240303",
+ "open": 68.96,
+ "high": 70.26,
+ "low": 68.87,
+ "close": 70.05,
+ "volume": 1634112.27
+ },
+ {
+ "date": "20240304",
+ "open": 70.05,
+ "high": 70.51,
+ "low": 69.73,
+ "close": 70.5,
+ "volume": 2525375.65
+ },
+ {
+ "date": "20240305",
+ "open": 70.5,
+ "high": 71.04,
+ "low": 70.29,
+ "close": 70.66,
+ "volume": 2937144.49
+ },
+ {
+ "date": "20240306",
+ "open": 70.66,
+ "high": 71.14,
+ "low": 69.59,
+ "close": 70.04,
+ "volume": 801267.66
+ },
+ {
+ "date": "20240307",
+ "open": 70.04,
+ "high": 71.95,
+ "low": 69.35,
+ "close": 71.78,
+ "volume": 2842264.43
+ },
+ {
+ "date": "20240308",
+ "open": 71.78,
+ "high": 73.88,
+ "low": 71.49,
+ "close": 73.25,
+ "volume": 1779911.21
+ },
+ {
+ "date": "20240309",
+ "open": 73.25,
+ "high": 73.94,
+ "low": 72.91,
+ "close": 72.93,
+ "volume": 1101086.69
+ },
+ {
+ "date": "20240310",
+ "open": 72.93,
+ "high": 75.21,
+ "low": 72.41,
+ "close": 74.61,
+ "volume": 2929364.92
+ },
+ {
+ "date": "20240311",
+ "open": 74.61,
+ "high": 75.5,
+ "low": 74.28,
+ "close": 74.87,
+ "volume": 2781530.59
+ },
+ {
+ "date": "20240312",
+ "open": 74.87,
+ "high": 75.2,
+ "low": 73.19,
+ "close": 73.61,
+ "volume": 2547538.45
+ },
+ {
+ "date": "20240313",
+ "open": 73.61,
+ "high": 74.11,
+ "low": 72.83,
+ "close": 73.54,
+ "volume": 1721459.01
+ },
+ {
+ "date": "20240314",
+ "open": 73.54,
+ "high": 73.56,
+ "low": 72.1,
+ "close": 72.73,
+ "volume": 1847277.39
+ },
+ {
+ "date": "20240315",
+ "open": 72.73,
+ "high": 73.11,
+ "low": 72.46,
+ "close": 72.54,
+ "volume": 1288520.94
+ },
+ {
+ "date": "20240316",
+ "open": 72.54,
+ "high": 72.73,
+ "low": 71.24,
+ "close": 71.86,
+ "volume": 1342561.31
+ },
+ {
+ "date": "20240317",
+ "open": 71.86,
+ "high": 72.49,
+ "low": 70.32,
+ "close": 70.72,
+ "volume": 861600.65
+ },
+ {
+ "date": "20240318",
+ "open": 70.72,
+ "high": 71.94,
+ "low": 70.26,
+ "close": 71.45,
+ "volume": 2504096.03
+ },
+ {
+ "date": "20240319",
+ "open": 71.45,
+ "high": 71.61,
+ "low": 70.86,
+ "close": 71.39,
+ "volume": 2175144.08
+ },
+ {
+ "date": "20240320",
+ "open": 71.39,
+ "high": 72.35,
+ "low": 71.12,
+ "close": 72.22,
+ "volume": 2320497.31
+ },
+ {
+ "date": "20240401",
+ "open": 72.22,
+ "high": 72.65,
+ "low": 71.68,
+ "close": 72.02,
+ "volume": 2460042.52
+ },
+ {
+ "date": "20240402",
+ "open": 72.02,
+ "high": 72.38,
+ "low": 71.12,
+ "close": 71.71,
+ "volume": 1483367.63
+ },
+ {
+ "date": "20240403",
+ "open": 71.71,
+ "high": 72.17,
+ "low": 70.75,
+ "close": 70.85,
+ "volume": 2685430.16
+ },
+ {
+ "date": "20240404",
+ "open": 70.85,
+ "high": 71.49,
+ "low": 69.93,
+ "close": 70.31,
+ "volume": 1139142.61
+ },
+ {
+ "date": "20240405",
+ "open": 70.31,
+ "high": 71.03,
+ "low": 69.96,
+ "close": 70.55,
+ "volume": 2197318.22
+ },
+ {
+ "date": "20240406",
+ "open": 70.55,
+ "high": 71.22,
+ "low": 70.19,
+ "close": 70.31,
+ "volume": 2555018.49
+ },
+ {
+ "date": "20240407",
+ "open": 70.31,
+ "high": 70.67,
+ "low": 68.93,
+ "close": 68.98,
+ "volume": 1089850.02
+ },
+ {
+ "date": "20240408",
+ "open": 68.98,
+ "high": 70.05,
+ "low": 68.76,
+ "close": 69.42,
+ "volume": 1686097.82
+ },
+ {
+ "date": "20240409",
+ "open": 69.42,
+ "high": 69.94,
+ "low": 69.18,
+ "close": 69.52,
+ "volume": 1573127.1
+ },
+ {
+ "date": "20240410",
+ "open": 69.52,
+ "high": 71.2,
+ "low": 69.28,
+ "close": 70.8,
+ "volume": 2599770.88
+ },
+ {
+ "date": "20240411",
+ "open": 70.8,
+ "high": 72.88,
+ "low": 70.79,
+ "close": 72.57,
+ "volume": 1471686.41
+ },
+ {
+ "date": "20240412",
+ "open": 72.57,
+ "high": 74.18,
+ "low": 72.43,
+ "close": 74.05,
+ "volume": 2543149.16
+ },
+ {
+ "date": "20240413",
+ "open": 74.05,
+ "high": 74.68,
+ "low": 72.79,
+ "close": 72.95,
+ "volume": 1653386.19
+ },
+ {
+ "date": "20240414",
+ "open": 72.95,
+ "high": 73.53,
+ "low": 72.39,
+ "close": 73.44,
+ "volume": 1764600.84
+ },
+ {
+ "date": "20240415",
+ "open": 73.44,
+ "high": 75.09,
+ "low": 73.39,
+ "close": 74.52,
+ "volume": 2609559.06
+ },
+ {
+ "date": "20240416",
+ "open": 74.52,
+ "high": 75.97,
+ "low": 74.08,
+ "close": 75.78,
+ "volume": 1252157.88
+ },
+ {
+ "date": "20240417",
+ "open": 75.78,
+ "high": 76.68,
+ "low": 75.5,
+ "close": 76.1,
+ "volume": 1972553.02
+ },
+ {
+ "date": "20240418",
+ "open": 76.1,
+ "high": 76.76,
+ "low": 74.56,
+ "close": 75.03,
+ "volume": 2626869.33
+ },
+ {
+ "date": "20240419",
+ "open": 75.03,
+ "high": 75.59,
+ "low": 73.74,
+ "close": 73.8,
+ "volume": 2024282.33
+ },
+ {
+ "date": "20240420",
+ "open": 73.8,
+ "high": 74.47,
+ "low": 73.02,
+ "close": 73.09,
+ "volume": 1840581.14
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "消费·趋势破裂"
+}
\ No newline at end of file
diff --git a/zhishi/fixtures/ohlcv/688981.json b/zhishi/fixtures/ohlcv/688981.json
new file mode 100644
index 0000000..cd93667
--- /dev/null
+++ b/zhishi/fixtures/ohlcv/688981.json
@@ -0,0 +1,652 @@
+{
+ "symbol": "688981",
+ "name": "中芯国际",
+ "market": "A",
+ "is_st": false,
+ "is_star_or_chinext": true,
+ "bars": [
+ {
+ "date": "20240101",
+ "open": 45,
+ "high": 45.05,
+ "low": 44.4,
+ "close": 44.58,
+ "volume": 1140939.0
+ },
+ {
+ "date": "20240102",
+ "open": 44.58,
+ "high": 44.76,
+ "low": 43.42,
+ "close": 43.82,
+ "volume": 2560995.17
+ },
+ {
+ "date": "20240103",
+ "open": 43.82,
+ "high": 44.55,
+ "low": 43.58,
+ "close": 44.45,
+ "volume": 1408701.82
+ },
+ {
+ "date": "20240104",
+ "open": 44.45,
+ "high": 44.5,
+ "low": 43.81,
+ "close": 43.91,
+ "volume": 2840446.39
+ },
+ {
+ "date": "20240105",
+ "open": 43.91,
+ "high": 45.03,
+ "low": 43.56,
+ "close": 44.67,
+ "volume": 1225558.36
+ },
+ {
+ "date": "20240106",
+ "open": 44.67,
+ "high": 44.95,
+ "low": 44.07,
+ "close": 44.4,
+ "volume": 2680226.39
+ },
+ {
+ "date": "20240107",
+ "open": 44.4,
+ "high": 45.31,
+ "low": 44.13,
+ "close": 45.27,
+ "volume": 2277743.2
+ },
+ {
+ "date": "20240108",
+ "open": 45.27,
+ "high": 45.47,
+ "low": 45.05,
+ "close": 45.39,
+ "volume": 996561.66
+ },
+ {
+ "date": "20240109",
+ "open": 45.39,
+ "high": 46.8,
+ "low": 45.14,
+ "close": 46.39,
+ "volume": 1460540.63
+ },
+ {
+ "date": "20240110",
+ "open": 46.39,
+ "high": 47.64,
+ "low": 45.99,
+ "close": 47.36,
+ "volume": 2665696.99
+ },
+ {
+ "date": "20240111",
+ "open": 47.36,
+ "high": 47.7,
+ "low": 47.08,
+ "close": 47.5,
+ "volume": 1748294.64
+ },
+ {
+ "date": "20240112",
+ "open": 47.5,
+ "high": 47.65,
+ "low": 46.51,
+ "close": 46.9,
+ "volume": 895124.63
+ },
+ {
+ "date": "20240113",
+ "open": 46.9,
+ "high": 47.19,
+ "low": 45.93,
+ "close": 46.06,
+ "volume": 1976167.95
+ },
+ {
+ "date": "20240114",
+ "open": 46.06,
+ "high": 46.27,
+ "low": 45.6,
+ "close": 46.11,
+ "volume": 1230261.69
+ },
+ {
+ "date": "20240115",
+ "open": 46.11,
+ "high": 46.2,
+ "low": 45.75,
+ "close": 46.04,
+ "volume": 1407870.64
+ },
+ {
+ "date": "20240116",
+ "open": 46.04,
+ "high": 46.39,
+ "low": 45.71,
+ "close": 45.86,
+ "volume": 2028763.76
+ },
+ {
+ "date": "20240117",
+ "open": 45.86,
+ "high": 46.86,
+ "low": 45.83,
+ "close": 46.81,
+ "volume": 1303512.77
+ },
+ {
+ "date": "20240118",
+ "open": 46.81,
+ "high": 47.78,
+ "low": 46.7,
+ "close": 47.49,
+ "volume": 1528347.39
+ },
+ {
+ "date": "20240119",
+ "open": 47.49,
+ "high": 47.7,
+ "low": 46.9,
+ "close": 46.92,
+ "volume": 2334042.14
+ },
+ {
+ "date": "20240120",
+ "open": 46.92,
+ "high": 48.33,
+ "low": 46.57,
+ "close": 47.87,
+ "volume": 2911708.7
+ },
+ {
+ "date": "20240201",
+ "open": 47.87,
+ "high": 48.01,
+ "low": 46.5,
+ "close": 46.95,
+ "volume": 2505526.76
+ },
+ {
+ "date": "20240202",
+ "open": 46.95,
+ "high": 47.39,
+ "low": 46.59,
+ "close": 46.88,
+ "volume": 2599441.16
+ },
+ {
+ "date": "20240203",
+ "open": 46.88,
+ "high": 46.97,
+ "low": 46.35,
+ "close": 46.56,
+ "volume": 1100162.78
+ },
+ {
+ "date": "20240204",
+ "open": 46.56,
+ "high": 47.01,
+ "low": 46.27,
+ "close": 46.43,
+ "volume": 820672.23
+ },
+ {
+ "date": "20240205",
+ "open": 46.43,
+ "high": 46.51,
+ "low": 45.24,
+ "close": 45.59,
+ "volume": 1597993.39
+ },
+ {
+ "date": "20240206",
+ "open": 45.59,
+ "high": 45.64,
+ "low": 44.83,
+ "close": 45.28,
+ "volume": 1732695.54
+ },
+ {
+ "date": "20240207",
+ "open": 45.28,
+ "high": 45.3,
+ "low": 44.77,
+ "close": 44.8,
+ "volume": 1171074.6
+ },
+ {
+ "date": "20240208",
+ "open": 44.8,
+ "high": 45.33,
+ "low": 44.78,
+ "close": 45.26,
+ "volume": 1879468.75
+ },
+ {
+ "date": "20240209",
+ "open": 45.26,
+ "high": 45.72,
+ "low": 44.81,
+ "close": 44.87,
+ "volume": 1964331.49
+ },
+ {
+ "date": "20240210",
+ "open": 44.87,
+ "high": 45.72,
+ "low": 44.42,
+ "close": 45.53,
+ "volume": 1851076.32
+ },
+ {
+ "date": "20240211",
+ "open": 45.53,
+ "high": 45.72,
+ "low": 45.1,
+ "close": 45.12,
+ "volume": 1726686.12
+ },
+ {
+ "date": "20240212",
+ "open": 45.12,
+ "high": 45.52,
+ "low": 44.35,
+ "close": 44.72,
+ "volume": 1896875.38
+ },
+ {
+ "date": "20240213",
+ "open": 44.72,
+ "high": 44.83,
+ "low": 43.78,
+ "close": 43.89,
+ "volume": 1257744.09
+ },
+ {
+ "date": "20240214",
+ "open": 43.89,
+ "high": 44.27,
+ "low": 43.41,
+ "close": 43.47,
+ "volume": 912802.2
+ },
+ {
+ "date": "20240215",
+ "open": 43.47,
+ "high": 44.66,
+ "low": 43.04,
+ "close": 44.41,
+ "volume": 1686516.55
+ },
+ {
+ "date": "20240216",
+ "open": 44.41,
+ "high": 45.62,
+ "low": 44.06,
+ "close": 45.33,
+ "volume": 2438397.83
+ },
+ {
+ "date": "20240217",
+ "open": 45.33,
+ "high": 45.47,
+ "low": 45.23,
+ "close": 45.43,
+ "volume": 2722373.7
+ },
+ {
+ "date": "20240218",
+ "open": 45.43,
+ "high": 46.79,
+ "low": 45.27,
+ "close": 46.36,
+ "volume": 2245199.8
+ },
+ {
+ "date": "20240219",
+ "open": 46.36,
+ "high": 47.4,
+ "low": 45.98,
+ "close": 47.1,
+ "volume": 1961652.56
+ },
+ {
+ "date": "20240220",
+ "open": 47.1,
+ "high": 47.87,
+ "low": 46.97,
+ "close": 47.54,
+ "volume": 2830159.92
+ },
+ {
+ "date": "20240301",
+ "open": 47.54,
+ "high": 48.68,
+ "low": 47.08,
+ "close": 48.64,
+ "volume": 2915902.4
+ },
+ {
+ "date": "20240302",
+ "open": 48.64,
+ "high": 49.15,
+ "low": 48.2,
+ "close": 49.13,
+ "volume": 1080792.13
+ },
+ {
+ "date": "20240303",
+ "open": 49.13,
+ "high": 50.62,
+ "low": 49.1,
+ "close": 50.29,
+ "volume": 1167984.35
+ },
+ {
+ "date": "20240304",
+ "open": 50.29,
+ "high": 51.01,
+ "low": 49.91,
+ "close": 50.72,
+ "volume": 2840458.08
+ },
+ {
+ "date": "20240305",
+ "open": 50.72,
+ "high": 50.72,
+ "low": 49.74,
+ "close": 50.2,
+ "volume": 828842.61
+ },
+ {
+ "date": "20240306",
+ "open": 50.2,
+ "high": 51.24,
+ "low": 49.8,
+ "close": 51.18,
+ "volume": 2522533.41
+ },
+ {
+ "date": "20240307",
+ "open": 51.18,
+ "high": 52.47,
+ "low": 50.73,
+ "close": 52.18,
+ "volume": 1243672.79
+ },
+ {
+ "date": "20240308",
+ "open": 52.18,
+ "high": 52.89,
+ "low": 51.71,
+ "close": 52.71,
+ "volume": 2501862.49
+ },
+ {
+ "date": "20240309",
+ "open": 52.71,
+ "high": 53.05,
+ "low": 52.7,
+ "close": 52.78,
+ "volume": 875202.93
+ },
+ {
+ "date": "20240310",
+ "open": 52.78,
+ "high": 53.39,
+ "low": 52.32,
+ "close": 53.13,
+ "volume": 2137875.33
+ },
+ {
+ "date": "20240311",
+ "open": 53.13,
+ "high": 53.32,
+ "low": 52.0,
+ "close": 52.4,
+ "volume": 1950569.84
+ },
+ {
+ "date": "20240312",
+ "open": 52.4,
+ "high": 52.84,
+ "low": 50.95,
+ "close": 51.38,
+ "volume": 987310.22
+ },
+ {
+ "date": "20240313",
+ "open": 51.38,
+ "high": 51.8,
+ "low": 50.97,
+ "close": 51.61,
+ "volume": 1484572.62
+ },
+ {
+ "date": "20240314",
+ "open": 51.61,
+ "high": 51.86,
+ "low": 50.62,
+ "close": 51.12,
+ "volume": 1009263.28
+ },
+ {
+ "date": "20240315",
+ "open": 51.12,
+ "high": 51.43,
+ "low": 49.91,
+ "close": 50.36,
+ "volume": 1927444.23
+ },
+ {
+ "date": "20240316",
+ "open": 50.36,
+ "high": 50.79,
+ "low": 49.94,
+ "close": 50.33,
+ "volume": 947219.32
+ },
+ {
+ "date": "20240317",
+ "open": 50.33,
+ "high": 51.42,
+ "low": 50.18,
+ "close": 51.32,
+ "volume": 2640172.34
+ },
+ {
+ "date": "20240318",
+ "open": 51.32,
+ "high": 51.73,
+ "low": 51.19,
+ "close": 51.27,
+ "volume": 2723431.73
+ },
+ {
+ "date": "20240319",
+ "open": 51.27,
+ "high": 51.35,
+ "low": 50.4,
+ "close": 50.65,
+ "volume": 1544886.8
+ },
+ {
+ "date": "20240320",
+ "open": 50.65,
+ "high": 51.34,
+ "low": 50.29,
+ "close": 50.88,
+ "volume": 812236.67
+ },
+ {
+ "date": "20240401",
+ "open": 50.88,
+ "high": 51.15,
+ "low": 50.33,
+ "close": 50.57,
+ "volume": 2374290.65
+ },
+ {
+ "date": "20240402",
+ "open": 50.57,
+ "high": 50.7,
+ "low": 50.45,
+ "close": 50.66,
+ "volume": 2664654.22
+ },
+ {
+ "date": "20240403",
+ "open": 50.66,
+ "high": 51.05,
+ "low": 49.97,
+ "close": 50.46,
+ "volume": 2178741.23
+ },
+ {
+ "date": "20240404",
+ "open": 50.46,
+ "high": 51.3,
+ "low": 50.31,
+ "close": 50.99,
+ "volume": 2808139.16
+ },
+ {
+ "date": "20240405",
+ "open": 50.99,
+ "high": 51.51,
+ "low": 50.84,
+ "close": 51.04,
+ "volume": 2708557.39
+ },
+ {
+ "date": "20240406",
+ "open": 51.04,
+ "high": 52.15,
+ "low": 50.82,
+ "close": 51.83,
+ "volume": 1109468.65
+ },
+ {
+ "date": "20240407",
+ "open": 51.83,
+ "high": 52.78,
+ "low": 51.49,
+ "close": 52.59,
+ "volume": 1093160.44
+ },
+ {
+ "date": "20240408",
+ "open": 52.59,
+ "high": 52.67,
+ "low": 51.32,
+ "close": 51.73,
+ "volume": 1190871.16
+ },
+ {
+ "date": "20240409",
+ "open": 51.73,
+ "high": 53.0,
+ "low": 51.44,
+ "close": 52.8,
+ "volume": 1570969.89
+ },
+ {
+ "date": "20240410",
+ "open": 52.8,
+ "high": 53.27,
+ "low": 52.59,
+ "close": 53.22,
+ "volume": 2859613.77
+ },
+ {
+ "date": "20240411",
+ "open": 53.22,
+ "high": 53.57,
+ "low": 52.41,
+ "close": 52.58,
+ "volume": 1461276.31
+ },
+ {
+ "date": "20240412",
+ "open": 52.58,
+ "high": 52.6,
+ "low": 51.1,
+ "close": 51.59,
+ "volume": 2625502.69
+ },
+ {
+ "date": "20240413",
+ "open": 51.59,
+ "high": 52.84,
+ "low": 51.1,
+ "close": 52.42,
+ "volume": 1148624.64
+ },
+ {
+ "date": "20240414",
+ "open": 52.42,
+ "high": 53.01,
+ "low": 52.11,
+ "close": 52.75,
+ "volume": 2863405.5
+ },
+ {
+ "date": "20240415",
+ "open": 52.75,
+ "high": 54.01,
+ "low": 52.68,
+ "close": 53.49,
+ "volume": 2233423.36
+ },
+ {
+ "date": "20240416",
+ "open": 53.49,
+ "high": 54.45,
+ "low": 53.16,
+ "close": 54.05,
+ "volume": 2628778.33
+ },
+ {
+ "date": "20240417",
+ "open": 54.05,
+ "high": 54.55,
+ "low": 53.49,
+ "close": 53.71,
+ "volume": 2117875.07
+ },
+ {
+ "date": "20240418",
+ "open": 53.71,
+ "high": 55.19,
+ "low": 53.54,
+ "close": 54.8,
+ "volume": 1306810.93
+ },
+ {
+ "date": "20240419",
+ "open": 54.8,
+ "high": 55.14,
+ "low": 53.97,
+ "close": 54.51,
+ "volume": 2777839.15
+ },
+ {
+ "date": "20240420",
+ "open": 54.51,
+ "high": 54.73,
+ "low": 53.96,
+ "close": 54.4,
+ "volume": 1424296.8
+ }
+ ],
+ "source": "fixture",
+ "sample": false,
+ "teaching_tag": "科创板·制度差异"
+}
\ No newline at end of file
diff --git a/zhishi/miniprogram/README.md b/zhishi/miniprogram/README.md
new file mode 100644
index 0000000..0942bdb
--- /dev/null
+++ b/zhishi/miniprogram/README.md
@@ -0,0 +1,8 @@
+# 微信小程序壳
+
+1. 用微信开发者工具打开本目录 `miniprogram/`
+2. 详情 → 本地设置 → 不校验合法域名(开发期)
+3. 将 `app.js` 中 `apiBase` 改为你的 HTTPS API
+4. 支付:将 `/api/pay/mock_checkout` 换为微信统一下单;商品名必须为课包/研习会员
+
+页面路由:首页 → 案例/自检/短课/复盘本/错题本/会员/协议。
diff --git a/zhishi/miniprogram/app.js b/zhishi/miniprogram/app.js
new file mode 100644
index 0000000..1f15344
--- /dev/null
+++ b/zhishi/miniprogram/app.js
@@ -0,0 +1,11 @@
+App({
+ globalData: {
+ apiBase: "http://127.0.0.1:8787",
+ session: "",
+ disclaimer: "本产品为投资教育工具,不构成任何投资建议。市场有风险,决策须自负。"
+ },
+ onLaunch() {
+ const session = wx.getStorageSync("zhishi_session");
+ if (session) this.globalData.session = session;
+ }
+});
diff --git a/zhishi/miniprogram/app.json b/zhishi/miniprogram/app.json
new file mode 100644
index 0000000..4131b89
--- /dev/null
+++ b/zhishi/miniprogram/app.json
@@ -0,0 +1,20 @@
+{
+ "pages": [
+ "pages/index/index",
+ "pages/lesson/lesson",
+ "pages/case/case",
+ "pages/check/check",
+ "pages/review/review",
+ "pages/drill/drill",
+ "pages/pricing/pricing",
+ "pages/legal/legal"
+ ],
+ "window": {
+ "navigationBarTitleText": "知势",
+ "navigationBarBackgroundColor": "#1A3A3A",
+ "navigationBarTextStyle": "white",
+ "backgroundColor": "#F7F3EB"
+ },
+ "style": "v2",
+ "sitemapLocation": "sitemap.json"
+}
diff --git a/zhishi/miniprogram/app.wxss b/zhishi/miniprogram/app.wxss
new file mode 100644
index 0000000..2450d50
--- /dev/null
+++ b/zhishi/miniprogram/app.wxss
@@ -0,0 +1,24 @@
+page {
+ background: #f7f3eb;
+ color: #1a3a3a;
+ font-size: 28rpx;
+ padding: 24rpx;
+}
+.brand {
+ font-size: 48rpx;
+ font-weight: 600;
+}
+.muted { color: rgba(26, 58, 58, 0.68); }
+.btn {
+ background: #1a3a3a;
+ color: #f7f3eb;
+ padding: 16rpx 24rpx;
+ border-radius: 8rpx;
+ display: inline-block;
+ margin-top: 16rpx;
+}
+.disclaimer {
+ margin-top: 40rpx;
+ font-size: 22rpx;
+ color: rgba(26, 58, 58, 0.68);
+}
diff --git a/zhishi/miniprogram/pages/case/case.js b/zhishi/miniprogram/pages/case/case.js
new file mode 100644
index 0000000..1aa648d
--- /dev/null
+++ b/zhishi/miniprogram/pages/case/case.js
@@ -0,0 +1,12 @@
+const { request } = require("../../utils/api");
+Page({
+ data: { cases: [] },
+ async onLoad() {
+ const data = await request("/api/cases");
+ this.setData({ cases: data.cases || [] });
+ },
+ open(e) {
+ const symbol = e.currentTarget.dataset.symbol;
+ wx.navigateTo({ url: `/pages/check/check?symbol=${symbol}` });
+ }
+});
diff --git a/zhishi/miniprogram/pages/case/case.json b/zhishi/miniprogram/pages/case/case.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/case/case.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/case/case.wxml b/zhishi/miniprogram/pages/case/case.wxml
new file mode 100644
index 0000000..da10965
--- /dev/null
+++ b/zhishi/miniprogram/pages/case/case.wxml
@@ -0,0 +1,5 @@
+教学案例
+
+ {{item.title}}
+ {{item.summary}}
+
diff --git a/zhishi/miniprogram/pages/case/case.wxss b/zhishi/miniprogram/pages/case/case.wxss
new file mode 100644
index 0000000..6db51d5
--- /dev/null
+++ b/zhishi/miniprogram/pages/case/case.wxss
@@ -0,0 +1 @@
+/* case */
diff --git a/zhishi/miniprogram/pages/check/check.js b/zhishi/miniprogram/pages/check/check.js
new file mode 100644
index 0000000..dcf2f48
--- /dev/null
+++ b/zhishi/miniprogram/pages/check/check.js
@@ -0,0 +1,29 @@
+const { request, ensureSession } = require("../../utils/api");
+Page({
+ data: { symbol: "", result: null, error: "", hypothesis: "", invalidation: "" },
+ onSymbol(e) { this.setData({ symbol: e.detail.value }); },
+ onHyp(e) { this.setData({ hypothesis: e.detail.value }); },
+ onInv(e) { this.setData({ invalidation: e.detail.value }); },
+ async analyze() {
+ const result = await request(`/api/analyze?symbol=${this.data.symbol}&market=A`);
+ if (!result.ok) this.setData({ error: result.error || "数据不足", result: null });
+ else this.setData({ result, error: "" });
+ },
+ async sample() {
+ const result = await request("/api/sample");
+ this.setData({ result, symbol: result.symbol || "600519", error: "" });
+ },
+ async saveReview() {
+ await ensureSession();
+ const r = this.data.result;
+ const res = await request("/api/reviews", "POST", {
+ symbol: r.symbol,
+ name: r.name,
+ primary_score: r.primary_score,
+ posture: r.posture,
+ hypothesis: this.data.hypothesis,
+ invalidation: this.data.invalidation
+ });
+ wx.showToast({ title: res.ok ? "已写入" : "失败", icon: "none" });
+ }
+});
diff --git a/zhishi/miniprogram/pages/check/check.json b/zhishi/miniprogram/pages/check/check.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/check/check.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/check/check.wxml b/zhishi/miniprogram/pages/check/check.wxml
new file mode 100644
index 0000000..4d556dd
--- /dev/null
+++ b/zhishi/miniprogram/pages/check/check.wxml
@@ -0,0 +1,14 @@
+框架自检
+
+
+
+{{error}}
+
+ {{result.primary_score}}
+ {{result.posture}}
+ {{result.symbol}} {{result.name}}
+
+
+
+
+本产品为投资教育工具,不构成任何投资建议。
diff --git a/zhishi/miniprogram/pages/check/check.wxss b/zhishi/miniprogram/pages/check/check.wxss
new file mode 100644
index 0000000..5b3e718
--- /dev/null
+++ b/zhishi/miniprogram/pages/check/check.wxss
@@ -0,0 +1 @@
+/* check */
diff --git a/zhishi/miniprogram/pages/drill/drill.js b/zhishi/miniprogram/pages/drill/drill.js
new file mode 100644
index 0000000..00f01c9
--- /dev/null
+++ b/zhishi/miniprogram/pages/drill/drill.js
@@ -0,0 +1,25 @@
+const { request, ensureSession } = require("../../utils/api");
+Page({
+ data: {
+ prompt: "A股当日买入的股票,通常最早何时可以卖出?",
+ feedback: "",
+ drills: []
+ },
+ async answer(e) {
+ await ensureSession();
+ const ans = e.currentTarget.dataset.a;
+ const correct = ans === "b";
+ const explanation = "A股股票实行T+1:当日买入,下一交易日才能卖出。";
+ this.setData({ feedback: (correct ? "正确。" : "未答对。") + explanation });
+ if (!correct) {
+ await request("/api/drills", "POST", {
+ prompt: this.data.prompt,
+ user_answer: ans,
+ correct: false,
+ explanation
+ });
+ const drills = await request("/api/me/drills");
+ this.setData({ drills: drills.drills || [] });
+ }
+ }
+});
diff --git a/zhishi/miniprogram/pages/drill/drill.json b/zhishi/miniprogram/pages/drill/drill.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/drill/drill.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/drill/drill.wxml b/zhishi/miniprogram/pages/drill/drill.wxml
new file mode 100644
index 0000000..a3195f2
--- /dev/null
+++ b/zhishi/miniprogram/pages/drill/drill.wxml
@@ -0,0 +1,9 @@
+错题本
+{{prompt}}
+
+
+
+{{feedback}}
+
+ 错题:{{item.prompt}} → {{item.user_answer}}
+
diff --git a/zhishi/miniprogram/pages/drill/drill.wxss b/zhishi/miniprogram/pages/drill/drill.wxss
new file mode 100644
index 0000000..fb54723
--- /dev/null
+++ b/zhishi/miniprogram/pages/drill/drill.wxss
@@ -0,0 +1 @@
+/* drill */
diff --git a/zhishi/miniprogram/pages/index/index.js b/zhishi/miniprogram/pages/index/index.js
new file mode 100644
index 0000000..e66c386
--- /dev/null
+++ b/zhishi/miniprogram/pages/index/index.js
@@ -0,0 +1,7 @@
+const app = getApp();
+Page({
+ data: { disclaimer: "" },
+ onLoad() {
+ this.setData({ disclaimer: app.globalData.disclaimer });
+ }
+});
diff --git a/zhishi/miniprogram/pages/index/index.json b/zhishi/miniprogram/pages/index/index.json
new file mode 100644
index 0000000..a97367d
--- /dev/null
+++ b/zhishi/miniprogram/pages/index/index.json
@@ -0,0 +1,3 @@
+{
+ "usingComponents": {}
+}
diff --git a/zhishi/miniprogram/pages/index/index.wxml b/zhishi/miniprogram/pages/index/index.wxml
new file mode 100644
index 0000000..fcb090b
--- /dev/null
+++ b/zhishi/miniprogram/pages/index/index.wxml
@@ -0,0 +1,10 @@
+知势
+复盘每一笔,而不是追每一笔
+今日教学案例
+框架自检
+规则短课
+复盘本
+错题本
+研习会员
+协议与免责
+{{disclaimer}}
diff --git a/zhishi/miniprogram/pages/index/index.wxss b/zhishi/miniprogram/pages/index/index.wxss
new file mode 100644
index 0000000..244f3a0
--- /dev/null
+++ b/zhishi/miniprogram/pages/index/index.wxss
@@ -0,0 +1 @@
+/* pages/index */
\ No newline at end of file
diff --git a/zhishi/miniprogram/pages/legal/legal.js b/zhishi/miniprogram/pages/legal/legal.js
new file mode 100644
index 0000000..560d44d
--- /dev/null
+++ b/zhishi/miniprogram/pages/legal/legal.js
@@ -0,0 +1 @@
+Page({});
diff --git a/zhishi/miniprogram/pages/legal/legal.json b/zhishi/miniprogram/pages/legal/legal.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/legal/legal.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/legal/legal.wxml b/zhishi/miniprogram/pages/legal/legal.wxml
new file mode 100644
index 0000000..b390b46
--- /dev/null
+++ b/zhishi/miniprogram/pages/legal/legal.wxml
@@ -0,0 +1,3 @@
+协议与免责
+本产品为投资教育工具,不构成任何投资建议。市场有风险,决策须自负。
+完整文本见 H5:/terms /privacy /disclaimer。小程序审核类目请选教育/知识付费。
diff --git a/zhishi/miniprogram/pages/legal/legal.wxss b/zhishi/miniprogram/pages/legal/legal.wxss
new file mode 100644
index 0000000..c5e67b7
--- /dev/null
+++ b/zhishi/miniprogram/pages/legal/legal.wxss
@@ -0,0 +1 @@
+/* legal */
diff --git a/zhishi/miniprogram/pages/lesson/lesson.js b/zhishi/miniprogram/pages/lesson/lesson.js
new file mode 100644
index 0000000..425658f
--- /dev/null
+++ b/zhishi/miniprogram/pages/lesson/lesson.js
@@ -0,0 +1,13 @@
+const { request } = require("../../utils/api");
+Page({
+ data: { lessons: [], markdown: "" },
+ async onLoad() {
+ const data = await request("/api/lessons");
+ this.setData({ lessons: data.lessons || [] });
+ },
+ async open(e) {
+ const id = e.currentTarget.dataset.id;
+ const data = await request(`/api/lessons/${id}`);
+ this.setData({ markdown: (data.lesson && data.lesson.markdown) || "" });
+ }
+});
diff --git a/zhishi/miniprogram/pages/lesson/lesson.json b/zhishi/miniprogram/pages/lesson/lesson.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/lesson/lesson.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/lesson/lesson.wxml b/zhishi/miniprogram/pages/lesson/lesson.wxml
new file mode 100644
index 0000000..1340a96
--- /dev/null
+++ b/zhishi/miniprogram/pages/lesson/lesson.wxml
@@ -0,0 +1,5 @@
+规则短课
+
+ {{item.title}}
+
+{{markdown}}
diff --git a/zhishi/miniprogram/pages/lesson/lesson.wxss b/zhishi/miniprogram/pages/lesson/lesson.wxss
new file mode 100644
index 0000000..33d56c6
--- /dev/null
+++ b/zhishi/miniprogram/pages/lesson/lesson.wxss
@@ -0,0 +1 @@
+/* lesson */
diff --git a/zhishi/miniprogram/pages/pricing/pricing.js b/zhishi/miniprogram/pages/pricing/pricing.js
new file mode 100644
index 0000000..a3cd307
--- /dev/null
+++ b/zhishi/miniprogram/pages/pricing/pricing.js
@@ -0,0 +1,12 @@
+const { request } = require("../../utils/api");
+Page({
+ data: { msg: "" },
+ async buy(e) {
+ const sku = e.currentTarget.dataset.sku;
+ const res = await request("/api/pay/mock_checkout", "POST", { sku });
+ this.setData({
+ msg: res.ok ? `${res.name || sku} prepay=${res.prepay_id || "n/a"}` : res.error || "失败"
+ });
+ // 生产:wx.requestPayment({ ... }) 使用统一下单返回字段
+ }
+});
diff --git a/zhishi/miniprogram/pages/pricing/pricing.json b/zhishi/miniprogram/pages/pricing/pricing.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/pricing/pricing.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/pricing/pricing.wxml b/zhishi/miniprogram/pages/pricing/pricing.wxml
new file mode 100644
index 0000000..499f02a
--- /dev/null
+++ b/zhishi/miniprogram/pages/pricing/pricing.wxml
@@ -0,0 +1,7 @@
+研习会员
+知识付费 SKU(微信正式支付需商户号;此处 mock 联调)
+
+
+
+{{msg}}
+不构成投资建议。商品名不含荐股字样。
diff --git a/zhishi/miniprogram/pages/pricing/pricing.wxss b/zhishi/miniprogram/pages/pricing/pricing.wxss
new file mode 100644
index 0000000..d66af27
--- /dev/null
+++ b/zhishi/miniprogram/pages/pricing/pricing.wxss
@@ -0,0 +1 @@
+/* pricing */
diff --git a/zhishi/miniprogram/pages/review/review.js b/zhishi/miniprogram/pages/review/review.js
new file mode 100644
index 0000000..987ebde
--- /dev/null
+++ b/zhishi/miniprogram/pages/review/review.js
@@ -0,0 +1,14 @@
+const { request, ensureSession } = require("../../utils/api");
+Page({
+ data: { reviews: [], reminders: [] },
+ async onShow() {
+ await ensureSession();
+ const reviews = await request("/api/me/reviews");
+ const reminders = await request("/api/me/reminders");
+ this.setData({ reviews: reviews.reviews || [], reminders: reminders.reminders || [] });
+ },
+ async complete(e) {
+ await request("/api/reminders/complete", "POST", { id: e.currentTarget.dataset.id });
+ this.onShow();
+ }
+});
diff --git a/zhishi/miniprogram/pages/review/review.json b/zhishi/miniprogram/pages/review/review.json
new file mode 100644
index 0000000..f59eec4
--- /dev/null
+++ b/zhishi/miniprogram/pages/review/review.json
@@ -0,0 +1 @@
+{"usingComponents": {}}
diff --git a/zhishi/miniprogram/pages/review/review.wxml b/zhishi/miniprogram/pages/review/review.wxml
new file mode 100644
index 0000000..3885d8b
--- /dev/null
+++ b/zhishi/miniprogram/pages/review/review.wxml
@@ -0,0 +1,11 @@
+复盘本
+
+ {{item.symbol}} · {{item.posture}} · {{item.primary_score}}
+ 假设:{{item.hypothesis}}
+ 失效:{{item.invalidation}}
+
+提醒
+
+ {{item.symbol}} · {{item.kind}} · {{item.done ? "已完成" : "待复盘"}}
+
+
diff --git a/zhishi/miniprogram/pages/review/review.wxss b/zhishi/miniprogram/pages/review/review.wxss
new file mode 100644
index 0000000..47fa372
--- /dev/null
+++ b/zhishi/miniprogram/pages/review/review.wxss
@@ -0,0 +1 @@
+/* review */
diff --git a/zhishi/miniprogram/sitemap.json b/zhishi/miniprogram/sitemap.json
new file mode 100644
index 0000000..ab4716d
--- /dev/null
+++ b/zhishi/miniprogram/sitemap.json
@@ -0,0 +1,3 @@
+{
+ "rules": [{ "action": "allow", "page": "*" }]
+}
diff --git a/zhishi/miniprogram/utils/api.js b/zhishi/miniprogram/utils/api.js
new file mode 100644
index 0000000..449a9c6
--- /dev/null
+++ b/zhishi/miniprogram/utils/api.js
@@ -0,0 +1,27 @@
+const app = getApp();
+
+function request(path, method = "GET", data = {}) {
+ return new Promise((resolve, reject) => {
+ wx.request({
+ url: app.globalData.apiBase + path,
+ method,
+ data,
+ header: {
+ "Content-Type": "application/json",
+ "X-Session": app.globalData.session || ""
+ },
+ success: (res) => resolve(res.data),
+ fail: reject
+ });
+ });
+}
+
+async function ensureSession() {
+ if (app.globalData.session) return app.globalData.session;
+ const data = await request("/api/session", "POST", {});
+ app.globalData.session = data.session;
+ wx.setStorageSync("zhishi_session", data.session);
+ return data.session;
+}
+
+module.exports = { request, ensureSession };
diff --git a/zhishi/requirements.txt b/zhishi/requirements.txt
new file mode 100644
index 0000000..438da51
--- /dev/null
+++ b/zhishi/requirements.txt
@@ -0,0 +1,2 @@
+# 可选。默认零第三方依赖即可运行。
+# tushare>=1.2.89 # 仅当 ZHISHI_ALLOW_LIVE=1 且配置 TUSHARE_TOKEN
diff --git a/zhishi/schemas/analyze_response.json b/zhishi/schemas/analyze_response.json
new file mode 100644
index 0000000..086b678
--- /dev/null
+++ b/zhishi/schemas/analyze_response.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "ZhishiAnalyzeResponse",
+ "type": "object",
+ "required": ["ok", "posture", "disclaimer"],
+ "properties": {
+ "ok": { "type": "boolean" },
+ "primary_score": { "type": ["integer", "null"] },
+ "posture": {
+ "type": "string",
+ "enum": ["偏强学习态", "中性观察态", "偏弱学习态", "数据不足"]
+ },
+ "disclaimer": { "type": "string" }
+ }
+}
diff --git a/zhishi/scripts/generate_fixtures.py b/zhishi/scripts/generate_fixtures.py
new file mode 100644
index 0000000..61b3828
--- /dev/null
+++ b/zhishi/scripts/generate_fixtures.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+"""Generate 20 teaching OHLCV fixtures + case metadata."""
+from __future__ import annotations
+
+import json
+import math
+import random
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[1]
+OHLCV = ROOT / "fixtures" / "ohlcv"
+CASES = ROOT / "content" / "cases"
+OHLCV.mkdir(parents=True, exist_ok=True)
+CASES.mkdir(parents=True, exist_ok=True)
+
+# symbol, name, seed, base, is_st, star/chinext, story tag
+UNIVERSE = [
+ ("600519", "贵州茅台", 1, 1600, False, False, "白酒龙头·常态波动"),
+ ("000001", "平安银行", 2, 11.5, False, False, "银行股·低波动"),
+ ("300750", "宁德时代", 3, 180, False, True, "创业板·弹性"),
+ ("688981", "中芯国际", 4, 45, False, True, "科创板·制度差异"),
+ ("600036", "招商银行", 5, 32, False, False, "银行·趋势教学"),
+ ("601318", "中国平安", 6, 42, False, False, "保险·均值回归"),
+ ("000858", "五粮液", 7, 140, False, False, "白酒·回调复盘"),
+ ("002594", "比亚迪", 8, 220, False, False, "新能源·放量讨论"),
+ ("601012", "隆基绿能", 9, 18, False, False, "光伏·弱势结构"),
+ ("600276", "恒瑞医药", 10, 38, False, False, "医药·中性观察"),
+ ("000568", "泸州老窖", 11, 160, False, False, "白酒·教学案例"),
+ ("002415", "海康威视", 12, 30, False, False, "制造·量能常态"),
+ ("600900", "长江电力", 13, 25, False, False, "公用事业·低波动"),
+ ("601888", "中国中免", 14, 70, False, False, "消费·趋势破裂"),
+ ("300059", "东方财富", 15, 14, False, True, "券商互联·弹性"),
+ ("600030", "中信证券", 16, 20, False, False, "券商·周期教学"),
+ ("000725", "京东方A", 17, 3.8, False, False, "制造·贴近跌停带演示"),
+ ("601398", "工商银行", 18, 5.2, False, False, "大行·复盘四问"),
+ ("600000", "浦发银行", 19, 7.5, False, False, "银行·T+1持有期"),
+ ("000002", "万科A", 20, 8.0, False, False, "地产·制度风险讨论"),
+]
+
+
+def gen_bars(seed: int, base: float, n: int = 80, near_limit: bool = False) -> list[dict]:
+ rng = random.Random(seed)
+ price = base
+ bars = []
+ # simple random walk with mild drift
+ for i in range(n):
+ year = 2024
+ month = 1 + (i // 20)
+ day = 1 + (i % 20)
+ date = f"{year}{month:02d}{day:02d}"
+ shock = rng.uniform(-0.02, 0.025)
+ if near_limit and i == n - 1:
+ shock = -0.092 # approach -10% band for teaching
+ open_p = price
+ close_p = max(0.5, price * (1 + shock))
+ high_p = max(open_p, close_p) * (1 + rng.uniform(0, 0.01))
+ low_p = min(open_p, close_p) * (1 - rng.uniform(0, 0.01))
+ vol = rng.uniform(8e5, 3e6) * (3.0 if near_limit and i == n - 1 else 1.0)
+ bars.append(
+ {
+ "date": date,
+ "open": round(open_p, 2),
+ "high": round(high_p, 2),
+ "low": round(low_p, 2),
+ "close": round(close_p, 2),
+ "volume": round(vol, 2),
+ }
+ )
+ price = close_p
+ return bars
+
+
+def main() -> None:
+ cases_index = []
+ for idx, (symbol, name, seed, base, is_st, star, tag) in enumerate(UNIVERSE):
+ near = symbol == "000725"
+ bars = gen_bars(seed, base, near_limit=near)
+ payload = {
+ "symbol": symbol,
+ "name": name,
+ "market": "A",
+ "is_st": is_st,
+ "is_star_or_chinext": star,
+ "bars": bars,
+ "source": "fixture",
+ "sample": idx < 3,
+ "teaching_tag": tag,
+ }
+ (OHLCV / f"{symbol}.json").write_text(
+ json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8"
+ )
+ case = {
+ "id": f"case-{symbol}",
+ "symbol": symbol,
+ "name": name,
+ "title": f"{name}({symbol})· {tag}",
+ "as_of": bars[-1]["date"],
+ "free_demo": idx < 3,
+ "summary": f"历史日线教学样本,用于练习框架自检与复盘四问。标签:{tag}。",
+ "learning_goal": "写出假设与失效条件,而不是预测涨跌。",
+ }
+ (CASES / f"{symbol}.json").write_text(
+ json.dumps(case, ensure_ascii=False, indent=2), encoding="utf-8"
+ )
+ cases_index.append(case)
+ (CASES / "index.json").write_text(
+ json.dumps(cases_index, ensure_ascii=False, indent=2), encoding="utf-8"
+ )
+ print(f"wrote {len(UNIVERSE)} fixtures + cases")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/zhishi/tests/test_zhishi.py b/zhishi/tests/test_zhishi.py
new file mode 100644
index 0000000..bbe27fe
--- /dev/null
+++ b/zhishi/tests/test_zhishi.py
@@ -0,0 +1,185 @@
+"""知势单元与契约测试。"""
+from __future__ import annotations
+
+import json
+import sys
+import threading
+import unittest
+import urllib.error
+import urllib.request
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT))
+
+from app.engine.score import analyze, fail_closed, posture_for # noqa: E402
+from app.engine.data import load_fixture # noqa: E402
+from app.server import Handler, do_analyze, health # noqa: E402
+from http.server import ThreadingHTTPServer
+
+
+class ScoreTests(unittest.TestCase):
+ def test_posture_bands(self):
+ self.assertEqual(posture_for(70), "偏强学习态")
+ self.assertEqual(posture_for(40), "中性观察态")
+ self.assertEqual(posture_for(10), "偏弱学习态")
+ self.assertEqual(posture_for(None), "数据不足")
+
+ def test_fail_closed_no_score(self):
+ r = fail_closed("999999")
+ self.assertFalse(r["ok"])
+ self.assertIsNone(r["primary_score"])
+ self.assertEqual(r["posture"], "数据不足")
+ self.assertIn("不构成", r["disclaimer"])
+
+ def test_analyze_single_primary_score(self):
+ payload = load_fixture("600519")
+ self.assertIsNotNone(payload)
+ r = analyze(payload)
+ self.assertTrue(r["ok"])
+ self.assertIn("primary_score", r)
+ self.assertIsInstance(r["primary_score"], int)
+ self.assertIn(r["posture"], {"偏强学习态", "中性观察态", "偏弱学习态"})
+ # 姿态与对外动作词禁止;教学释义亦避免买卖指令用语
+ self.assertNotIn(r["posture"], {"买入", "卖出", "加仓", "减仓", "Buy", "Sell"})
+ blob = json.dumps({"posture": r["posture"], "primary_score": r["primary_score"]}, ensure_ascii=False)
+ for b in ("买入", "卖出", "Buy", "Sell", "加仓", "减仓"):
+ self.assertNotIn(b, blob)
+ full = json.dumps(r, ensure_ascii=False)
+ for b in ("建议买入", "建议卖出", "目标价", "稳赚", "必涨"):
+ self.assertNotIn(b, full)
+
+ def test_hkconnect_gates(self):
+ payload = dict(load_fixture("600519"))
+ payload["market"] = "HKCONNECT"
+ r = analyze(payload)
+ self.assertTrue(r["ok"])
+ ids = {g["id"] for g in r["gates"]}
+ self.assertIn("hkconnect_quota", ids)
+
+
+class ApiTests(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.httpd = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
+ cls.port = cls.httpd.server_address[1]
+ cls.thread = threading.Thread(target=cls.httpd.serve_forever, daemon=True)
+ cls.thread.start()
+ cls.base = f"http://127.0.0.1:{cls.port}"
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.httpd.shutdown()
+
+ def _get(self, path: str):
+ with urllib.request.urlopen(self.base + path, timeout=5) as resp:
+ return json.loads(resp.read().decode("utf-8")), resp.status
+
+ def _post(self, path: str, data: dict, session: str | None = None):
+ req = urllib.request.Request(
+ self.base + path,
+ data=json.dumps(data).encode("utf-8"),
+ headers={"Content-Type": "application/json", **({"X-Session": session} if session else {})},
+ method="POST",
+ )
+ with urllib.request.urlopen(req, timeout=5) as resp:
+ return json.loads(resp.read().decode("utf-8")), resp.status
+
+ def test_health(self):
+ body, status = self._get("/health")
+ self.assertEqual(status, 200)
+ self.assertEqual(body["service"], "zhishi")
+ self.assertIn("live_eligible", body)
+
+ def test_sample_and_legal_pages(self):
+ body, _ = self._get("/api/sample")
+ self.assertTrue(body["ok"])
+ self.assertEqual(body["symbol"], "600519")
+ for path in ("/terms", "/privacy", "/disclaimer", "/methodology", "/pricing"):
+ with urllib.request.urlopen(self.base + path, timeout=5) as resp:
+ html = resp.read().decode("utf-8")
+ self.assertIn("知势", html)
+ self.assertIn("投资教育", html)
+
+ def test_invalid_symbol_fail_closed(self):
+ try:
+ self._get("/api/analyze?symbol=ABC")
+ self.fail("expected HTTPError")
+ except urllib.error.HTTPError as e:
+ body = json.loads(e.read().decode("utf-8"))
+ self.assertFalse(body["ok"])
+ self.assertIsNone(body["primary_score"])
+
+ def test_unknown_symbol(self):
+ try:
+ self._get("/api/analyze?symbol=999999")
+ self.fail("expected HTTPError")
+ except urllib.error.HTTPError as e:
+ body = json.loads(e.read().decode("utf-8"))
+ self.assertEqual(body["error"], "symbol_not_found")
+
+ def test_cases_and_lessons(self):
+ cases, _ = self._get("/api/cases")
+ self.assertGreaterEqual(len(cases["cases"]), 20)
+ lessons, _ = self._get("/api/lessons")
+ ids = {l["id"] for l in lessons["lessons"]}
+ self.assertIn("01-t1-liquidity", ids)
+ self.assertIn("hk-01-session-quota", ids)
+
+ def test_review_reminder_drill_pay(self):
+ sess, _ = self._post("/api/session", {})
+ sid = sess["session"]
+ analysis = do_analyze("000001")
+ rev, _ = self._post(
+ "/api/reviews",
+ {
+ "symbol": analysis["symbol"],
+ "name": analysis["name"],
+ "primary_score": analysis["primary_score"],
+ "posture": analysis["posture"],
+ "hypothesis": "量能常态则继续观察",
+ "invalidation": "收盘跌破教学均线",
+ },
+ session=sid,
+ )
+ self.assertTrue(rev["ok"])
+ rem, _ = self._get("/api/me/reminders")
+ # need session header — use request helper
+ req = urllib.request.Request(self.base + "/api/me/reminders", headers={"X-Session": sid})
+ with urllib.request.urlopen(req, timeout=5) as resp:
+ rem = json.loads(resp.read().decode("utf-8"))
+ self.assertGreaterEqual(len(rem["reminders"]), 1)
+ drill, _ = self._post(
+ "/api/drills",
+ {"prompt": "T+1?", "user_answer": "a", "correct": False, "explanation": "T+1"},
+ session=sid,
+ )
+ self.assertTrue(drill["ok"])
+ pay, _ = self._post("/api/pay/mock_checkout", {"sku": "monthly"})
+ self.assertTrue(pay["ok"])
+ self.assertTrue(pay["mock"])
+ skus, _ = self._get("/api/skus")
+ self.assertEqual(skus["skus"]["monthly"]["price_fen"], 6800)
+
+ def test_no_banned_marketing_on_home(self):
+ with urllib.request.urlopen(self.base + "/", timeout=5) as resp:
+ html = resp.read().decode("utf-8")
+ for ban in ("稳赚", "必涨", "建议买入", "投资顾问"):
+ self.assertNotIn(ban, html)
+
+
+class ContentTests(unittest.TestCase):
+ def test_twenty_cases(self):
+ idx = ROOT / "content" / "cases" / "index.json"
+ cases = json.loads(idx.read_text(encoding="utf-8"))
+ self.assertEqual(len(cases), 20)
+ free = [c for c in cases if c.get("free_demo")]
+ self.assertEqual(len(free), 3)
+
+ def test_health_helper(self):
+ h = health()
+ self.assertEqual(h["mode_default"], "artifact")
+
+
+if __name__ == "__main__":
+ unittest.main()