270e114658
Replace paragraph text with day-hit stats (days/days_hit/pct) so leverage and move charts list each hour with counts. Co-authored-by: Cursor <cursoragent@cursor.com>
90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
from packages.domain.aggregate import aggregate_leverage, summarize_values
|
|
from packages.domain.range import resolve_range
|
|
|
|
|
|
def test_summarize_values():
|
|
s = summarize_values([100, 200, 300, 400], min_leverage=200)
|
|
assert s["n"] == 4
|
|
assert s["mean"] == 250
|
|
assert s["median"] == 250
|
|
assert s["pct_ge_min"] == 0.75
|
|
|
|
|
|
def test_summarize_empty():
|
|
s = summarize_values([], min_leverage=100)
|
|
assert s["n"] == 0
|
|
assert s["mean"] is None
|
|
|
|
|
|
def test_resolve_range_day():
|
|
info = resolve_range("day", "2026-07-31")
|
|
assert info["start_ymd"] == "2026-07-31"
|
|
assert info["end_ymd"] == "2026-07-31"
|
|
assert info["days"] == 1
|
|
assert info["end_ms"] > info["start_ms"]
|
|
|
|
|
|
def test_resolve_range_week():
|
|
info = resolve_range("week", "2026-07-31")
|
|
assert info["start_ymd"] == "2026-07-25"
|
|
assert info["end_ymd"] == "2026-07-31"
|
|
assert info["days"] == 7
|
|
|
|
|
|
def test_resolve_range_month_rolling():
|
|
info = resolve_range("month", "2026-07-31", month_mode="rolling_30")
|
|
assert info["start_ymd"] == "2026-07-02"
|
|
assert info["days"] == 30
|
|
|
|
|
|
def test_resolve_range_month_calendar():
|
|
info = resolve_range("month", "2026-07-31", month_mode="calendar")
|
|
assert info["start_ymd"] == "2026-07-01"
|
|
assert info["end_ymd"] == "2026-07-31"
|
|
|
|
|
|
def test_aggregate_leverage_buckets():
|
|
# 2026-07-31 14:30 Asia/Shanghai
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo
|
|
|
|
sh = ZoneInfo("Asia/Shanghai")
|
|
ts = int(datetime(2026, 7, 31, 14, 30, tzinfo=sh).timestamp() * 1000)
|
|
rows = [
|
|
{"ts_ms": ts, "side": "C", "leverage": 120},
|
|
{"ts_ms": ts, "side": "P", "leverage": 80},
|
|
{"ts_ms": ts, "side": "C", "leverage": 180},
|
|
]
|
|
buckets = aggregate_leverage(rows, bucket_minutes=60, min_leverage=100, side="C")
|
|
assert len(buckets) == 24
|
|
b14 = next(b for b in buckets if b["bucket_start_min"] == 14 * 60)
|
|
assert b14["n"] == 2
|
|
assert b14["mean"] == 150
|
|
assert b14["label"] == "14:00"
|
|
assert b14["days"] == 1
|
|
assert b14["days_hit"] == 1
|
|
assert b14["pct_days_hit"] == 1.0
|
|
empty = next(b for b in buckets if b["bucket_start_min"] == 0)
|
|
assert empty["n"] == 0
|
|
assert empty["days"] == 0
|
|
assert empty["days_hit"] == 0
|
|
|
|
|
|
def test_aggregate_leverage_days_hit():
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo
|
|
|
|
sh = ZoneInfo("Asia/Shanghai")
|
|
ts1 = int(datetime(2026, 7, 30, 11, 10, tzinfo=sh).timestamp() * 1000)
|
|
ts2 = int(datetime(2026, 7, 31, 11, 20, tzinfo=sh).timestamp() * 1000)
|
|
rows = [
|
|
{"ts_ms": ts1, "side": "C", "leverage": 120}, # day1 hit
|
|
{"ts_ms": ts2, "side": "C", "leverage": 80}, # day2 miss
|
|
]
|
|
buckets = aggregate_leverage(rows, bucket_minutes=60, min_leverage=100, side="C")
|
|
b11 = next(b for b in buckets if b["bucket_start_min"] == 11 * 60)
|
|
assert b11["days"] == 2
|
|
assert b11["days_hit"] == 1
|
|
assert b11["pct_days_hit"] == 0.5
|
|
assert b11["n"] == 2
|