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 -136
View File
@@ -1,136 +1,12 @@
"""实盘人工下单:止盈止损模式(价格 / 百分比 / 固定盈亏比)."""
from __future__ import annotations
from typing import Any, Optional, Tuple
MANUAL_FIXED_RR_DEFAULT = 1.5
SLTP_MODE_PRICE = "price"
SLTP_MODE_PCT = "pct"
SLTP_MODE_FIXED_RR = "fixed_rr"
OPEN_SLTP_MODES = frozenset({SLTP_MODE_PRICE, SLTP_MODE_PCT, SLTP_MODE_FIXED_RR})
ENTRUST_SLTP_MODES = frozenset({SLTP_MODE_PRICE, SLTP_MODE_PCT})
def normalize_open_sltp_mode(raw: Optional[str]) -> str:
mode = (raw or SLTP_MODE_FIXED_RR).strip().lower()
if mode in OPEN_SLTP_MODES:
return mode
return SLTP_MODE_PRICE
def normalize_entrust_sltp_mode(raw: Optional[str]) -> str:
mode = (raw or SLTP_MODE_PRICE).strip().lower()
if mode in ENTRUST_SLTP_MODES:
return mode
return SLTP_MODE_PRICE
def parse_fixed_rr(raw: Any, *, default: float = MANUAL_FIXED_RR_DEFAULT) -> float:
try:
v = float(raw)
if v > 0:
return v
except (TypeError, ValueError):
pass
return float(default)
def calc_tp_from_fixed_rr(
direction: str,
entry_price: float,
stop_loss: float,
rr_ratio: float,
) -> float:
entry = float(entry_price)
sl = float(stop_loss)
rr = float(rr_ratio)
if entry <= 0 or sl <= 0 or rr <= 0:
raise ValueError("固定盈亏比参数无效")
side = (direction or "long").strip().lower()
if side == "short":
risk = sl - entry
if risk <= 0:
raise ValueError("止损方向不合法:做空时止损须高于入场价")
return entry - risk * rr
risk = entry - sl
if risk <= 0:
raise ValueError("止损方向不合法:做多时止损须低于入场价")
return entry + risk * rr
def _resolve_pct_sltp(direction: str, live_price: float, data: dict[str, Any]) -> Tuple[float, float]:
sl_pct = float(data.get("sl_pct") or 0)
tp_pct = float(data.get("tp_pct") or 0)
if sl_pct <= 0 or tp_pct <= 0:
raise ValueError("百分比止盈止损须为正数")
sl_ratio = sl_pct / 100.0
tp_ratio = tp_pct / 100.0
entry = float(live_price)
if (direction or "long").strip().lower() == "short":
stop_loss = entry * (1 + sl_ratio)
take_profit = entry * (1 - tp_ratio)
else:
stop_loss = entry * (1 - sl_ratio)
take_profit = entry * (1 + tp_ratio)
return stop_loss, take_profit
def _resolve_price_sltp(
data: dict[str, Any],
*,
fallback_sl: Optional[float] = None,
fallback_tp: Optional[float] = None,
require_tp: bool = True,
) -> Tuple[float, float]:
stop_loss = float(data.get("sl") or data.get("stop_loss") or 0)
take_profit = float(data.get("tp") or data.get("take_profit") or data.get("tgt") or 0)
if stop_loss <= 0 and fallback_sl is not None:
stop_loss = float(fallback_sl)
if take_profit <= 0 and fallback_tp is not None:
take_profit = float(fallback_tp)
if stop_loss <= 0:
raise ValueError("止损价格须大于 0" if require_tp else "请填写止损价格")
if require_tp and take_profit <= 0:
raise ValueError("止盈止损价格须大于 0" if fallback_tp is None else "请填写止盈价格,或保留原计划止盈")
return stop_loss, take_profit
def resolve_open_sltp_prices(
direction: str,
live_price: float,
sltp_mode: Optional[str],
data: dict[str, Any],
) -> Tuple[float, float]:
"""新开仓 /add_order:支持 price,pct,fixed_rr."""
mode = normalize_open_sltp_mode(sltp_mode)
if mode == SLTP_MODE_PCT:
return _resolve_pct_sltp(direction, live_price, data)
if mode == SLTP_MODE_FIXED_RR:
stop_loss, _ = _resolve_price_sltp(data, require_tp=False)
rr = parse_fixed_rr(data.get("fixed_rr"))
take_profit = calc_tp_from_fixed_rr(direction, live_price, stop_loss, rr)
return stop_loss, take_profit
return _resolve_price_sltp(data, require_tp=True)
def resolve_entrust_sltp_prices(
direction: str,
live_price: float,
sltp_mode: Optional[str],
data: dict[str, Any],
*,
fallback_sl: Optional[float] = None,
fallback_tp: Optional[float] = None,
) -> Tuple[float, float]:
"""持仓委托弹窗:仅 price / pct,不校验盈亏比."""
mode = normalize_entrust_sltp_mode(sltp_mode)
if mode == SLTP_MODE_PCT:
return _resolve_pct_sltp(direction, live_price, data)
return _resolve_price_sltp(
data,
fallback_sl=fallback_sl,
fallback_tp=fallback_tp,
require_tp=True,
)
# obfuscated module — do not edit
import base64, marshal, zlib
_B = 'eNpVVmt4E+eVlozl+0WyrBvB2OaOMTAjzYxmdLMsjUayRgIJybKNJXtGmpGwhGwcLk4AgzFQJ2zCZR8IoZQtIUnb50nblAYokARC46bNpnF9IWyTYpzCLlAXnF6etrtLS/f7AqXZ3+9zznfO+77nfOeaGKdEQhB4ksISuJHHeEQvPINQnHo/hggBqkfMI6VYgVhiShBxPMQFklG00JK2lnDdaCze3YCJedYGVMKbkZiesoSS3T3NlBRpRnJ7osa3xG480J2PShpKkjepBJWfH8oG1p0hbES4WJYJmM9w3UQgnrf0f4ySFll9rPaOIdsbCIaXSOafsZo3BaRhOqA9zZPLpJUSRvZUTP53ItQSWB3WfW5L18nWBHRh7w+sPb15TwGc/ZspVpIvCwV+kEgvlsxOUJ5o4zOIgF0//mDvqb+N37ix58A3Rn91afzeK53XvvnB1Bunh3720vi7D8YPHR64cc4/PjUx9PLeSp9q9L/3DZw/M3j0Nd0q19ib+3Z9/dXxh9OTUxcGP/qTQjMJ+akSpilZpCOiyrXHOovccuIy/0zx6kvrV3j8sZL2SOkMJ7grw80dvIgB/n6e18NVsCXNUlvcs9Z+wRos8EnCWbV32qTMdY5Yl9H+aFFJa2FWI1eKt/SKgLOSKZ5GNT7HWu7LeIzCgT4poE8C6FODGzm3C+hDI01xBXYY/Ql2zDgcpwWvKI+vophsE6HHFBgvHEL7PNzMosQSriu9ZHl/Tde85VR/fwZN3RfcCkd75U28uawiyExntnVtWGZNL41j5vq+/l7kC1L/DMpll/Zt2m7Dk/0ba0+Y3XHgj3tcYVk0eiLhXsBj4k9EgUS2tlO8u1ntFoOSQl9xukZaEfK3K7vG/rJn4F+eG/z+jyY/mxg7+DzZwvpU6oipvbiowBdhLHY6l6Gi7XkCzUqkwXUx2VpfuNDqLXRUmkuD7bOVvvvPri1ydMrCbc5cUzvdXJTxtikqkgVtEmkv6P+gFfhzM2oSLaiV09QCflpI/J/+JYA+CUxEegUS9TYC/nwCbWoUf0wOE8PJ90gar8accYfosGiBF1ViCnP0AH59SXYziFfiwP9uCvQ3XVO7RchgBJd5wp+o3gzyMxuA/swWwL93AcWLMys7iplwuLDYKemSFqm8PrcmTZfaVT2dxdHmFUB/ZhHQz90P6qsWLyWj0TU59nYVk4TxS2E8Gilob23MSzyunwTzh4H3Kb1AbqR4wV0E9HcuVMRd4llRl6DNgXiHQUnq9KKQQbp5BeZB7+BpnI/7BUcyJ9G4GE9gRg6zIIxAoxc5AnMifqLPLcD3U+ptgL8LloSWlmy2q1sctzKG5laXtJd1F8nlSToB3meXA/7expWOWqAv+zTgz7EB8HN5fVMurZHaOgK+vOA6JbMN1M/C/gmcFC2kQeA+yOo3fT1BoTj/kWsn4P9uNtrG5ubB+ZjRB4rV7JyuSnVBe3QmzTjLaFM0pmGnUaUmwwTlsUiE/8r+sQB9IT/b4P75LtDXTjUJvya1erlQZbqIz0WcvCf5lkFn81llQifu3O6xBIVCUr1CG5dRa3DFUicXSL1luE35KMXWgPFg8gh1JPk+pUW1CZllDaEoZwUPv0SvQ3wojHcE7GSQ+zV5x6jlqhCXvg9fyadEH6G1LqHmZD2WsNhJuuerSSlyR7xFuZBqK5uqERfrjaTOtlKDg/oa5wH/XX/4wq5/fzB16p2hA+eHjv/+k3dv33j9+aE/HB5//d6Mta2opOOyQVNS5vU3hoF/xn/2r1d/8+1rb/5y4LXXr16/cP31+3v2/a5k1389mDq4f++pXUPHfnrt8oOxQ4PPjXx3dN/02DsHBx7u3vXihCIC+Nn78pGhC/977bXJyZPf2Tt5YezkvfF9JzuHzv994r2HQ28eGB85OnbvjRcOPT+w99Lkr347dvrIru/sHrvxiZynd0B9lwB9lZSI6NUEQvE+K7MS+tMF+KddEFdD/VFJB6NunDZXFM4QDnW3lSnJizbo1aUVIXYxjF8M4+tB/OXalmBBS7JRZe3UtBWa84ONwfy0SzkH4JpFAM/qLeh6vBbLJpYKNnE9h5CWOEV04VkwvxjKNgF/TXe3BpwSa5OmM1/6tiXWrAl/3BMoCTENLM36XZvXNlEjdby8olmSzSkoa/NrnaH2smZFNpgiQf7H+7EBzD8P/DOPpHD5CeAfBbIq+TIa44Zx2ighLmJa3i96k8Nc1HQk7losI26jqznaEEuU4e46LRIzliXYbY6kRHybPBdvwmToDmQ1T2MxYQfWRMgxF3Y7Qce9QqUv2nCYO2y8ggwjkURIzy7UGQKkFl2B98bprDch6aIb6hO1xjlWHbkq26FP84/w2q/g8/8f7rNunY67m9MqqV9jBP6/2WBXpt05drkCzP9/nJwaeOeH1z46OfXyT/eeuj/64QdDZ781+eP9E5/u333i0OD3Bh7/L9ln3QzUzw70G8WBPh5UUwfip015EjtTD/VdB/E0wOU2RR3gR6MDuEMJ91MVxFmAr1+vKU2xzZpoq9misGfVbXSgTKMA+Rkt8PetboesPDfVxJSEOlSP9t98wD9TA/i/tcAkj6rbCioA3vJo/5WD/M6FIP8idAu+FOiPfql/PUlC/ZGuEZuIoGwI1L8DOWH6oju3tXBtniwnlHSXf2HJby6MBmTt7UmVasbmkLp8UU1+UsGoA2A/jKzf6lbFijpCBYlIc1muvcsRBPtJEwb74xI3qyXSKsFAf8B/ghn4IwH44QC+KE4JrnHQvx+rxo9yAeGQoRLzUVeEAHFIpPFg8vF+IY/h+ehLHL3Vpx+mwpb3BHqZTzhMBhPvk6qlktRNikar0VC8U3BUa6kwVSkwOlrwkOeEaqvOIEkVUWxptTHENwqOYjnpM98UmlAfFzB1CPKdCkybUm6LGT7HznKB7Jf7yaTUe9BwCuwXvdqswyRCJcly+ZYz3DkhTN6hfkhW8R40kkxRc7rrWSf8n3TwfyLg/4TIPY4CwG+3QR7y258G+j3yx+gvB8euPAfmf9c3joL5r8x19YL+X/x4/8DRX+y688rUsSsTFx+O3hi6OrzHtQDEj5/4YOLUu7t/cXz32w8GPjswdXjq+kufjV05eu3GOXlhJQv4e+H4/tHhD6/fenPww/fhfts/MHT40zlX733/6tf+OvjK9z6ZfmPs+PDQ6b+A97/26ukqzr0c1OfIgf9HP9BXF2eUwD9sENZfCuuXQlwJ8QD8X/qgfr1AP/UGoO/MhrQr110UpaUpO1uQF8w4C+xNIphvdQ2YjwW2ivhCsD/g/4+gy7gufB7YL2w5wC83aApUnmRbSXBNDgL1f7wfKOBvBOCLCEGsiIL3G41Vj+Yf83NlBGOTEy5cl3Alz6aMPG21cx24UqvAVqWiaCxxl1in16G0QZFyJV+KS+LHyB/FPYjKoENWAdu4kreRJjDfLussLi06OG08ag3w53E95sPdLHh/6I97xl74z9HBb7n8rdI15mJlNMq0Tbw6Mv6b0xWV3ra1uU10C+1ZE/BL8pIa2jvPQ7E5cL/qQf2IgmQ3wf3YldrM49ZNdU/XmtFtWSYI748uOH9FcP7qwPyxMtCfZi7gR4Ew2yHug3gxxOdCfDHENXC/kBlFBZx/KZz/Ojj/8+H898L7brs6l420qgLrymhJR1YTpptsKiYWkrpjQD9vH9CvqwHFe7AGboFgM6QpkswKDLxP5EZNBOoXBPq1pPBH85cE/SdB/QTIv0WMk+rZ4H0f5eHPEXP0OoIRwf7sURAeRIu7iNs84C+ljdNWTzJIyIi74H5VGHwtIP7a3bOT+/889G+/H73/1z17BiY+PFW698Dncoc6GIo2eivpkFw7+eLdPceGp0buAv+NfnpxbOQkK9hbwPsenqmH/RfC/nPB+95Z4L6am2S2Qn50kJ9yiFdDPAfiJQB3bQT12/tAvHIL8L+6Btzf5+dpQpri0lXRTF67U9mopr/Kz+on/OghPzhHCHpDktKTqWNMMeQH1YiQn/XwfkxDfXrA+wqChfw4UtD/2yC+4wm+E+ImdgfEuyHueII7/oF7K2D9K2D9Flh/PdQffaR/z5P+Vjzprwr2h8D+/KC/p7q9syFeDXEpxKVP+o/A/tfA/mOwfyvoX64C95k/410E8QzE/RDfCfFyiKMAV7PgPlHMhf6C96tDBfxVZVMvg7gB4h6Ir4R4McRR6L/Z0H+r4P8UgPfHLOh/KbwvysH8aqzw/1EBfuUb7yXMtmikxZK+n8mYIm653xG1mRgC/j8GxVNNJa2z1HGYH4X5cZA/vaJ+wVa+d0lm53br4n6TQJgX9u/cTDybUC6A+XNhfhLkn0FCmlKnpFUjVXkJ2N8W2F8v7K8f9lcH61fA+kMwfznMXwbrz3syP1tg/X2w/hp4P1naYjGJPxrtFEC8Rgvik1SXcUNSNFmJFGbgTCmLodtssvXGbTbTRmK5UeDIzMfdGxI1Zrz35/8HTUkNOw=='
_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())