币本位买币改为按最大可开张数×权利金×可配缓冲,不全额兑换USDT
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -134,6 +134,156 @@ def compute_coin_budget_usdt(
|
||||
}
|
||||
|
||||
|
||||
def normalize_coin_spot_buy_buffer(raw: Any = None) -> float:
|
||||
"""
|
||||
现货买入相对权利金的倍数缓冲.
|
||||
env OKX_OPTIONS_COIN_SPOT_BUY_BUFFER 默认 1.10(=多买 10%).
|
||||
也可写 0.10 表示 +10%.
|
||||
"""
|
||||
if raw is None:
|
||||
v = _env_float("OKX_OPTIONS_COIN_SPOT_BUY_BUFFER", 1.10)
|
||||
else:
|
||||
try:
|
||||
v = float(raw)
|
||||
except (TypeError, ValueError):
|
||||
v = 1.10
|
||||
if v <= 0:
|
||||
return 1.10
|
||||
if v < 1.0:
|
||||
return 1.0 + v
|
||||
return v
|
||||
|
||||
|
||||
def plan_coin_open_by_budget(
|
||||
*,
|
||||
quote_per_unit: float,
|
||||
ct_mult: float,
|
||||
min_sz: int,
|
||||
budget_usdt: float,
|
||||
index_px: float,
|
||||
ask_sz: float | None = None,
|
||||
spot_buy_buffer: float | None = None,
|
||||
target_sheets: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
先按预算/卖一估最大可开张数,再按「权利金 × 现货缓冲」算应买现货 USDT.
|
||||
不全额把预算换成币.
|
||||
"""
|
||||
import math
|
||||
|
||||
from lib.exchange.okx_options_lib import cap_option_buy_sheets_to_ask_depth
|
||||
|
||||
ask = float(quote_per_unit or 0)
|
||||
mult = float(ct_mult or 0.01)
|
||||
need = max(1, int(min_sz or 1))
|
||||
budget = max(0.0, float(budget_usdt or 0))
|
||||
idx = float(index_px or 0)
|
||||
buf = normalize_coin_spot_buy_buffer(spot_buy_buffer)
|
||||
if ask <= 0 or mult <= 0:
|
||||
return {"ok": False, "msg": "卖一价无效", "sheets": 0, "buy_usdt": 0.0}
|
||||
if idx <= 0:
|
||||
return {"ok": False, "msg": "缺少指数价,无法估算买币 USDT", "sheets": 0, "buy_usdt": 0.0}
|
||||
if budget <= 0:
|
||||
return {"ok": False, "msg": "USDT 预算无效", "sheets": 0, "buy_usdt": 0.0}
|
||||
|
||||
per_sheet_coin = ask * mult
|
||||
# 每张开仓需买的币(含缓冲)及其约合 USDT
|
||||
per_sheet_buy_coin = per_sheet_coin * buf
|
||||
per_sheet_usdt = per_sheet_buy_coin * idx
|
||||
if per_sheet_usdt <= 0:
|
||||
return {"ok": False, "msg": "无法计算单张买币成本", "sheets": 0, "buy_usdt": 0.0}
|
||||
|
||||
max_by_budget = int(math.floor((budget / per_sheet_usdt) + 1e-12))
|
||||
if target_sheets is not None:
|
||||
try:
|
||||
want = int(target_sheets)
|
||||
except (TypeError, ValueError):
|
||||
want = 0
|
||||
if want < need:
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": f"指定张数无效(需≥{need})",
|
||||
"sheets": 0,
|
||||
"buy_usdt": 0.0,
|
||||
"max_by_budget": max_by_budget,
|
||||
}
|
||||
sheets = min(want, max_by_budget)
|
||||
if sheets < want:
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": (
|
||||
f"预算约可开 {max_by_budget} 张(含现货缓冲×{buf:g}),"
|
||||
f"不足指定 {want} 张"
|
||||
),
|
||||
"sheets": 0,
|
||||
"buy_usdt": 0.0,
|
||||
"max_by_budget": max_by_budget,
|
||||
"spot_buy_buffer": buf,
|
||||
}
|
||||
else:
|
||||
sheets = max_by_budget
|
||||
|
||||
capped, cap_msg = cap_option_buy_sheets_to_ask_depth(sheets, ask_sz, min_sz=need)
|
||||
ask_depth_capped = False
|
||||
if capped is None:
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": cap_msg or "卖一深度不足",
|
||||
"sheets": 0,
|
||||
"buy_usdt": 0.0,
|
||||
"spot_buy_buffer": buf,
|
||||
}
|
||||
if int(capped) < sheets:
|
||||
sheets = int(capped)
|
||||
ask_depth_capped = True
|
||||
|
||||
if sheets < need:
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": (
|
||||
f"预算不足,无法买入 {need} 张"
|
||||
f"(单张约需 {per_sheet_usdt:.4f} USDT,含现货缓冲×{buf:g})"
|
||||
),
|
||||
"sheets": sheets,
|
||||
"buy_usdt": 0.0,
|
||||
"per_sheet_usdt": round(per_sheet_usdt, 8),
|
||||
"spot_buy_buffer": buf,
|
||||
"max_by_budget": max_by_budget,
|
||||
}
|
||||
|
||||
premium_coin = sheets * per_sheet_coin
|
||||
buy_coin = premium_coin * buf
|
||||
buy_usdt = min(budget, buy_coin * idx)
|
||||
# 再保险:向下对齐,避免浮点导致略超预算
|
||||
buy_usdt = min(budget, round(buy_usdt, 8))
|
||||
out = {
|
||||
"ok": True,
|
||||
"msg": "" if not ask_depth_capped else (cap_msg or f"已按卖一深度限制为 {sheets} 张"),
|
||||
"sheets": sheets,
|
||||
"eth_amount": round(sheets * mult, 8),
|
||||
"coin_premium": round(premium_coin, 8),
|
||||
"total_premium": round(premium_coin, 8),
|
||||
"per_sheet_coin": per_sheet_coin,
|
||||
"buy_coin": round(buy_coin, 8),
|
||||
"buy_usdt": round(buy_usdt, 8),
|
||||
"budget_usdt": round(budget, 8),
|
||||
"spot_buy_buffer": buf,
|
||||
"index_px": idx,
|
||||
"max_by_budget": max_by_budget,
|
||||
"ask_depth_capped": ask_depth_capped,
|
||||
"est_note": (
|
||||
f"按最大可开 {sheets} 张×卖一权利金×现货缓冲{buf:g}估买币;"
|
||||
f"不全额兑换预算"
|
||||
),
|
||||
}
|
||||
if target_sheets is not None:
|
||||
out["est_note"] = (
|
||||
f"指定 {sheets} 张×卖一权利金×现货缓冲{buf:g}估买币;不全额兑换"
|
||||
)
|
||||
out["target_sheets"] = int(target_sheets)
|
||||
return out
|
||||
|
||||
|
||||
def calc_sheets_from_coin_balance(
|
||||
*,
|
||||
quote_per_unit: float,
|
||||
|
||||
Reference in New Issue
Block a user