feat(web): 增量自动刷新、结构区修复与默认指标/周期

自动刷新常态只拉 recent 尾部 K,每 1 分钟全量重算缠论;修复结构区缓存导入;默认指标/4h·1h·15m/近30天;同步 ECR-009 screener 相关改动。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-08 15:45:40 +08:00
co-authored by Cursor
parent 0f6eb92a1f
commit 18a7f485e6
23 changed files with 2133 additions and 310 deletions
+77 -2
View File
@@ -31,6 +31,8 @@ def test_wyckoff_crypto_page_ok(client):
resp = client.get("/wyckoff_crypto")
assert resp.status_code == 200
assert b"Crypto Wyckoff Screener" in resp.data
assert b"fCombo" in resp.data
assert b"chartCanvas" in resp.data
def test_wyckoff_crypto_meta_ok(client):
@@ -38,11 +40,84 @@ def test_wyckoff_crypto_meta_ok(client):
assert resp.status_code == 200
data = resp.get_json()
assert "engine_version" in data
assert data.get("timeframes") == ["1d", "1w", "1M"]
assert data.get("combo", {}).get("id") == "h8_4_1"
assert data["combo"]["low"] == "1h"
ids = {c["id"] for c in data.get("combos") or []}
assert "h8_4_1" in ids and "d_w_m" in ids
def test_wyckoff_crypto_scan_ok(client):
resp = client.get("/api/wyckoff_crypto/scan?limit=5")
resp = client.get("/api/wyckoff_crypto/scan?limit=5&combo_id=h8_4_1")
assert resp.status_code == 200
data = resp.get_json()
assert "rows" in data
assert data.get("combo", {}).get("id") == "h8_4_1"
def test_wyckoff_crypto_klines_bad_request(client):
resp = client.get("/api/wyckoff_crypto/klines")
assert resp.status_code == 400
def test_wyckoff_crypto_klines_ok(client):
resp = client.get(
"/api/wyckoff_crypto/klines?symbol=BTC/USDT:USDT&tf=1h&limit=10&combo_id=h8_4_1"
)
assert resp.status_code == 200
data = resp.get_json()
assert "items" in data
assert data.get("tf") == "1h"
assert data.get("intraday") is True
if data["items"]:
assert "datetime" in data["items"][0]
assert "ts" in data["items"][0]
assert "T" in data["items"][0]["datetime"]
assert "+08:00" in data["items"][0]["datetime"]
def test_wyckoff_crypto_klines_bad_limit_ok(client):
resp = client.get(
"/api/wyckoff_crypto/klines?symbol=BTC/USDT:USDT&tf=1h&limit=abc&combo_id=h8_4_1"
)
assert resp.status_code == 200
def test_wyckoff_crypto_overlay_ok(client):
resp = client.get(
"/api/wyckoff_crypto/overlay?symbol=BTC/USDT:USDT&tf=1h&bars=60&combo_id=h8_4_1"
)
assert resp.status_code == 200
data = resp.get_json()
assert "phases" in data
assert "events" in data
def test_combos_add_and_list(client, tmp_path, monkeypatch):
from crypto_wyckoff import combos as cm
monkeypatch.setattr(cm, "_COMBOS_FILE", tmp_path / "combos.json")
monkeypatch.setattr(cm, "_cache", None)
resp = client.get("/api/wyckoff_crypto/combos")
assert resp.status_code == 200
assert len(resp.get_json()["combos"]) >= 2
bad = client.post(
"/api/wyckoff_crypto/combos",
json={"high": "1h", "mid": "4h", "low": "8h"},
)
assert bad.status_code == 400
ok = client.post(
"/api/wyckoff_crypto/combos",
json={"high": "12h", "mid": "4h", "low": "1h", "label": "12h/4h/1h"},
)
assert ok.status_code == 200
cid = ok.get_json()["combo"]["id"]
assert cid == "12h_4h_1h"
deleted = client.delete(f"/api/wyckoff_crypto/combos/{cid}")
assert deleted.status_code == 200
builtin = client.delete("/api/wyckoff_crypto/combos/h8_4_1")
assert builtin.status_code == 400