User edition: prune docs, license gate, obfuscate core lib.

Keep deploy/basic docs only; integrate sq.bz121.com license client; encrypt strategy/trade/key_monitor/options/hedge_plan for release.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-17 16:30:58 +08:00
parent 53863559f4
commit 16ef0f31e3
154 changed files with 1998 additions and 27914 deletions
+12 -115
View File
@@ -1,115 +1,12 @@
"""按交易日聚合实例 trade_records 盈亏,供统计分析页日历 API 使用."""
from __future__ import annotations
import json
from datetime import datetime, timedelta
from typing import Any, Callable
def build_trade_stats_calendar(
pnls: list[tuple],
year: int,
month: int,
segment_key: str,
row_matches_fn: Callable[[Any, str], bool],
*,
reset_hour: int = 8,
) -> dict[str, Any]:
"""pnls: _load_completed_trade_pnls 返回值 (pnl, close_dt, trading_day, row)."""
y = int(year)
m = int(month)
if m < 1 or m > 12:
raise ValueError("month 无效")
first = f"{y:04d}-{m:02d}-01"
if m == 12:
next_first = datetime(y + 1, 1, 1)
else:
next_first = datetime(y, m + 1, 1)
last = (next_first - timedelta(days=1)).strftime("%Y-%m-%d")
seg = (segment_key or "all").strip() or "all"
days: dict[str, dict[str, Any]] = {}
for pnl, _close_dt, td, row in pnls:
if not td or td < first or td > last:
continue
if not row_matches_fn(row, seg):
continue
bucket = days.setdefault(
td,
{
"trading_day": td,
"open_count": 0,
"pnl_total": 0.0,
"turnover_total": 0.0,
"commission_total": 0.0,
"has_sick": False,
"sick_count": 0,
},
)
bucket["open_count"] += 1
bucket["pnl_total"] += float(pnl or 0)
try:
bucket["turnover_total"] += float(row["exchange_turnover_usdt"] or 0)
except (TypeError, ValueError, KeyError):
pass
try:
bucket["commission_total"] += float(row["exchange_commission_usdt"] or 0)
except (TypeError, ValueError, KeyError):
pass
for d in days.values():
d["pnl_total"] = round(float(d["pnl_total"]), 4)
d["turnover_total"] = round(float(d["turnover_total"]), 4)
d["commission_total"] = round(float(d["commission_total"]), 4)
month_pnl = sum(float(d["pnl_total"]) for d in days.values())
month_count = sum(int(d["open_count"]) for d in days.values())
return {
"year": y,
"month": m,
"date_from": first,
"date_to": last,
"segment": seg,
"reset_hour": int(reset_hour),
"days": days,
"month_pnl_total": round(month_pnl, 4),
"month_open_count": month_count,
}
def build_initial_stats_calendar(
pnls: list[tuple],
now_dt: datetime,
row_matches_fn: Callable[[Any, str], bool],
*,
reset_hour: int = 8,
segment_key: str = "all",
) -> dict[str, Any]:
"""统计页首屏内嵌日历(当前自然月,默认品类)."""
return build_trade_stats_calendar(
pnls,
now_dt.year,
now_dt.month,
segment_key,
row_matches_fn,
reset_hour=reset_hour,
)
def build_stats_calendar_bootstrap(
pnls: list[tuple],
now_dt: datetime,
row_matches_fn: Callable[[Any, str], bool],
*,
reset_hour: int = 8,
segment_key: str = "all",
) -> tuple[dict[str, Any] | None, str | None]:
"""返回 (payload, json_str);失败时 (None, None),供模板安全内嵌."""
try:
payload = build_initial_stats_calendar(
pnls,
now_dt,
row_matches_fn,
reset_hour=reset_hour,
segment_key=segment_key,
)
return payload, json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
except Exception:
return None, None
# obfuscated module — do not edit
import base64, marshal, zlib
_B = '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'
_K = '5eb9e6dda894c57a4e02d809ae440d49'
def _d(b, k):
raw = zlib.decompress(base64.b64decode(b))
key = k.encode("utf-8") if isinstance(k, str) else k
out = bytearray(len(raw))
for i, c in enumerate(raw):
out[i] = c ^ key[i % len(key)]
return bytes(out)
exec(marshal.loads(_d(_B, _K)), globals())