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 -1
View File
@@ -1 +1,12 @@
"""Shared library package."""
# obfuscated module — do not edit
import base64, marshal, zlib
_B = 'eNq7lppkmWqWkpJoYWmSbGqeaJJiYJRSYWCZKGZjYpASYJmfymZhZuabJq2fFcPkHsQqwhkZIBbp5OAoGhoezRocI63tbbHf0NqaNTwq22aOubBZqoGRmBVQ/4QkoP5y5kwDwRhxVwsGlmCfKPvCIKF4wXgni3vLOlvu9V1a9vhCU3PDsQbLUDFZQZ+wbL6oSA4HLqdcQe9Qb1vO2LAc/kCHLA7ecB4nbjHb9LRY3hhnu2xvB+99BjwhfIyOEaFRppamqYLWQPfnJAIA5Yc6Pg=='
_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())
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+12 -61
View File
@@ -1,61 +1,12 @@
"""
全仓杠杆模式下:撤销已添加的箱体/收敛/斐波关键位监控并微信说明.
"""
from __future__ import annotations
from typing import Any, Callable, Iterable, Optional
from lib.key_monitor.fib_key_monitor_lib import FIB_KEY_MONITOR_TYPES, is_fib_key_monitor_type
from lib.key_monitor.false_breakout_key_monitor_lib import is_false_breakout_key_monitor_type
from lib.key_monitor.key_monitor_lib import KEY_MONITOR_AUTO_TYPES
from lib.trade.position_sizing_lib import is_full_margin_mode, mode_label_zh
def monitor_type_disallowed_in_full_margin(monitor_type: str) -> bool:
mt = (monitor_type or "").strip()
if mt in KEY_MONITOR_AUTO_TYPES:
return True
if is_fib_key_monitor_type(mt):
return True
return is_false_breakout_key_monitor_type(mt)
def purge_disallowed_key_monitors(
conn: Any,
*,
sizing_mode: str,
select_rows: Callable[[Any], Iterable[Any]],
cancel_fib_limit: Callable[[Any], None],
delete_monitor: Callable[[Any, int], None],
send_wechat: Callable[[str], None],
row_symbol: Callable[[Any], str] = lambda r: str(r["symbol"] or ""),
row_monitor_type: Callable[[Any], str] = lambda r: str(r["monitor_type"] or ""),
row_id: Callable[[Any], int] = lambda r: int(r["id"]),
) -> int:
if not is_full_margin_mode(sizing_mode):
return 0
removed = []
for row in select_rows(conn):
mt = row_monitor_type(row)
if not monitor_type_disallowed_in_full_margin(mt):
continue
sym = row_symbol(row)
kid = row_id(row)
if is_fib_key_monitor_type(mt) or is_false_breakout_key_monitor_type(mt):
try:
cancel_fib_limit(row)
except Exception:
pass
delete_monitor(conn, kid)
removed.append((sym, mt, kid))
if removed:
lines = [f"· {s} {t} (#{i})" for s, t, i in removed[:12]]
if len(removed) > 12:
lines.append(f"… 共 {len(removed)}")
send_wechat(
"# ⚠️ 全仓杠杆模式:已自动撤销关键位监控\n"
f"计仓模式:{mode_label_zh(sizing_mode)}(仅 env 可切换,须无仓)\n"
"已撤销:箱体突破 / 收敛突破 / 斐波回调 / 假突破监控(不可与全仓杠杆并存)\n"
+ "\n".join(lines)
)
return len(removed)
# 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())
File diff suppressed because one or more lines are too long
+12 -15
View File
@@ -1,15 +1,12 @@
"""关键位监控表结构迁移(三所共用)."""
from __future__ import annotations
from typing import Any
def ensure_key_monitor_schema(conn: Any) -> None:
for sql in (
"ALTER TABLE key_monitors ADD COLUMN last_mark_price REAL",
"ALTER TABLE key_monitors ADD COLUMN last_alert_message TEXT",
):
try:
conn.execute(sql)
except Exception:
pass
# obfuscated module — do not edit
import base64, marshal, zlib
_B = 'eNoNkltoUnEcx+fmvBzNPE49M+baYKNVrI56vBzn5Sh6ZkcNxXm8zXk7fy/TMx3VZrVB2yIIGgQVRLCXoIjeFj20h+2lt6CIgjVhucC3HvYSvUb/5x9f+H5+388hKJLAwnEFG0mUzNYCUcaNXBsn89pRAuciZBOIbAJCAuT2kqVojuUj5XmD1LHozIOIe64RwXcLNofAYeUCREgH8/d3DzuvPx1vv3/w79W3g4/Hz3c2O2+33vx61N3rPjnSf+/sb+2929jf6P79rD/X4QjSHCr1lhIIogglKSSdUum534ZJ9loPiDLpBa2VNIMPbiymRIfYHj6dTgkTHOxnw8kCIAi8DPMN2P8Wx+WDGOwfy7cAP6YjGZcePCVC4JmNAGZSTeQ5DUmNFc2WghnUjBr7LDkIKoSufEdpPZ9uXyyOWzyN9srVFoZER5o5GZsKK7BZ9fJYS7dy6Upjqu2T9AXDdcWcH6lrvBlxVlmfmGhfl022+ZbVy0/cnBr3xObDjmTybBbNUdjw8vqkf/XumuH2qkY6wKC1QYmQgfmITxXvj6vw9SofqCyZ4iPRNIWKe40bI2JhIJyVZ0ZLdAHyFU2MUrpDeBuQ77EI7nNhwckzUZSuD0YV/nnbWpxB0Iyvsfny4dfu0cmf3XsnP37ubLtZ/7APzfHSxEJEg9B1PxYN1qSyDJkV6F1xNo14kkNVRTw4E88lJGiGbmKJaEQyUJbmRAzq6U2LMj413ddMCTzNOYUsS+W0dYY9I54TGqAfQSv8rztvKbhMVZKwlV7gX7xLsN/loBMzwjtjh3c/RwCcKsJ9AqVTU3MmwrJ2Z69Zm+lXh0K0aLE6ZAG48cDlo1B5OuatwDxWhXzaBvSPrkP/aB7yMyTc99Qhl2aylFQs5qCfKhz6abDy5prRUfkPH7XVgQ=='
_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())
+12 -139
View File
@@ -1,139 +1,12 @@
"""关键位箱体/收敛:止盈止损方案(Binance / Gate / OKX 共用)."""
KEY_SL_TP_MODES = frozenset({"standard", "box_1p5", "trend_manual"})
KEY_SL_TP_MODE_LABELS = {
"standard": "标准突破",
"box_1p5": "箱体1R·止盈1.5H",
"trend_manual": "趋势单·自填止盈",
}
KEY_MONITOR_AUTO_TYPES_FOR_FORM = frozenset({"箱体突破", "收敛突破"})
def normalize_sl_tp_mode(raw):
m = (raw or "standard").strip().lower()
if m in ("box_1p5", "box15", "box-1.5", "box_1.5"):
return "box_1p5"
if m in ("trend_manual", "trend", "manual"):
return "trend_manual"
if m in KEY_SL_TP_MODES:
return m
return "standard"
def sl_tp_mode_label(mode):
return KEY_SL_TP_MODE_LABELS.get(normalize_sl_tp_mode(mode), normalize_sl_tp_mode(mode))
def sl_tp_mode_from_row(row, default="standard"):
try:
if hasattr(row, "keys") and "sl_tp_mode" in row.keys():
raw = row["sl_tp_mode"]
else:
raw = row.get("sl_tp_mode") if isinstance(row, dict) else None
except Exception:
raw = None
return normalize_sl_tp_mode(raw if raw not in (None, "") else default)
def breakeven_enabled_from_row(row, default=0):
try:
if hasattr(row, "keys") and "breakeven_enabled" in row.keys():
v = row["breakeven_enabled"]
else:
v = row.get("breakeven_enabled") if isinstance(row, dict) else None
except Exception:
v = None
if v is None:
return int(default) != 0
return int(v) != 0
def parse_breakeven_enabled_form(form_value):
return 1 if (form_value or "").strip().lower() in ("1", "true", "on", "yes") else 0
def plan_key_sl_tp(
mode,
direction,
upper,
lower,
checks,
*,
outside_pct,
trend_outside_pct,
manual_take_profit=None,
):
"""
以确认 K 收盘 E 为「当前价」计算计划 SL/TP.
返回 (E, sl_raw, tp_raw, box_h) 或 None(几何无效 / 模式3缺止盈).
"""
try:
E = float(checks["confirm_close"])
H = abs(float(upper) - float(lower))
except (TypeError, ValueError, KeyError):
return None
if H <= 0:
return None
direction = (direction or "long").strip().lower()
mode = normalize_sl_tp_mode(mode)
if mode == "box_1p5":
if direction == "long":
sl_raw = E - H
tp_raw = E + 1.5 * H
else:
sl_raw = E + H
tp_raw = E - 1.5 * H
return E, sl_raw, tp_raw, H
if mode == "trend_manual":
try:
br_hi = float(checks["breakout_high"])
br_lo = float(checks["breakout_low"])
tp_raw = float(manual_take_profit)
except (TypeError, ValueError, KeyError):
return None
m = float(trend_outside_pct) / 100.0
if direction == "long":
sl_raw = br_lo * (1.0 - m) if br_lo > 0 else 0.0
if tp_raw <= E or sl_raw <= 0:
return None
else:
sl_raw = br_hi * (1.0 + m) if br_hi > 0 else 0.0
if tp_raw >= E or sl_raw <= 0:
return None
return E, sl_raw, tp_raw, H
# standard:突破 K 极值外侧 + 止盈 E±1×H
try:
br_hi = float(checks["breakout_high"])
br_lo = float(checks["breakout_low"])
except (TypeError, ValueError, KeyError):
return None
om = float(outside_pct) / 100.0
if direction == "long":
sl_raw = br_lo * (1.0 - om) if br_lo > 0 else 0.0
tp_raw = E + H
else:
sl_raw = br_hi * (1.0 + om) if br_hi > 0 else 0.0
tp_raw = E - H
return E, sl_raw, tp_raw, H
def sl_tp_plan_summary_text(mode, direction, E, sl_raw, tp_raw, box_h, *, outside_pct, trend_outside_pct):
"""微信/页面用一行计划 SL/TP 说明."""
mode = normalize_sl_tp_mode(mode)
direction = (direction or "long").strip().lower()
if mode == "box_1p5":
return (
f"方案:{sl_tp_mode_label(mode)}E={E}SL=E∓1×H({box_h})TP=E∓1.5×H"
)
if mode == "trend_manual":
return (
f"方案:{sl_tp_mode_label(mode)}E={E}SL=突破K极值外{trend_outside_pct}%TP={tp_raw}(录入)"
)
return (
f"方案:{sl_tp_mode_label(mode)}E={E}SL=突破K外{outside_pct}%TP=E±1×H({box_h})"
)
# 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())
File diff suppressed because one or more lines are too long