Route sim transfer and convert through local wallets instead of OKX private API.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+133
-6
@@ -136,6 +136,36 @@ def apply_sim_hooks(app_module: Any) -> None:
|
|||||||
app_module.place_exchange_order = place_exchange_order
|
app_module.place_exchange_order = place_exchange_order
|
||||||
app_module.close_exchange_order = close_exchange_order
|
app_module.close_exchange_order = close_exchange_order
|
||||||
app_module.get_live_position_contracts = get_live_position_contracts
|
app_module.get_live_position_contracts = get_live_position_contracts
|
||||||
|
|
||||||
|
_orig_xfer = getattr(app_module, "execute_transfer_usdt", None)
|
||||||
|
if callable(_orig_xfer):
|
||||||
|
|
||||||
|
def execute_transfer_usdt(amount, from_account, to_account):
|
||||||
|
if is_sim_mode(app_module.get_db):
|
||||||
|
from lib.sim.wallets_lib import SimWallets, normalize_sim_account
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = SimWallets(app_module.get_db).transfer(
|
||||||
|
ccy="USDT",
|
||||||
|
amount=float(amount),
|
||||||
|
from_account=normalize_sim_account(from_account),
|
||||||
|
to_account=normalize_sim_account(to_account),
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return False, str(e), None
|
||||||
|
if not result.get("ok"):
|
||||||
|
return False, result.get("detail") or result.get("msg") or "划转失败", None
|
||||||
|
try:
|
||||||
|
from lib.instance.instance_live_push_lib import notify_instance_balance_changed
|
||||||
|
|
||||||
|
notify_instance_balance_changed()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return True, "sim 划转成功", result
|
||||||
|
return _orig_xfer(amount, from_account, to_account)
|
||||||
|
|
||||||
|
app_module.execute_transfer_usdt = execute_transfer_usdt
|
||||||
|
|
||||||
app_module._sim_hooks_applied = True
|
app_module._sim_hooks_applied = True
|
||||||
|
|
||||||
_patch_okx_options_lib(app_module)
|
_patch_okx_options_lib(app_module)
|
||||||
@@ -154,6 +184,8 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
_orig_fetch_pos = opt_lib.fetch_option_positions
|
_orig_fetch_pos = opt_lib.fetch_option_positions
|
||||||
_orig_ready = opt_lib.options_api_ready
|
_orig_ready = opt_lib.options_api_ready
|
||||||
_orig_fetch_bal = opt_lib.fetch_options_balances
|
_orig_fetch_bal = opt_lib.fetch_options_balances
|
||||||
|
_orig_transfer = opt_lib.transfer_ccy
|
||||||
|
_orig_swap = opt_lib.spot_market_swap_usdt_usdc
|
||||||
|
|
||||||
def options_header_balances(ex, *, force: bool = False):
|
def options_header_balances(ex, *, force: bool = False):
|
||||||
try:
|
try:
|
||||||
@@ -169,19 +201,30 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
pass
|
pass
|
||||||
return _orig_header(ex, force=force)
|
return _orig_header(ex, force=force)
|
||||||
|
|
||||||
def fetch_options_balances(ex, *, force: bool = False):
|
def fetch_options_balances(
|
||||||
|
ex, *, force: bool = False, scope: str = "main", sub_acct: str = ""
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
w = broker().balances_header()
|
w = broker().balances_header()
|
||||||
|
fu = float(w["funding_usdt"])
|
||||||
|
fc = float(w["funding_usdc"])
|
||||||
|
tu = float(w["trading_usdt"])
|
||||||
|
tc = float(w["trading_usdc"])
|
||||||
return {
|
return {
|
||||||
"trading_usdc": float(w["trading_usdc"]),
|
"scope": "main",
|
||||||
"funding_usdc": float(w["funding_usdc"]),
|
"funding_usdt": fu,
|
||||||
"funding_usdt": float(w["funding_usdt"]),
|
"funding_usdc": fc,
|
||||||
"trading_usdt": float(w["trading_usdt"]),
|
"trading_usdt": tu,
|
||||||
|
"trading_usdc": tc,
|
||||||
|
"funding_usdt_avail": fu,
|
||||||
|
"funding_usdc_avail": fc,
|
||||||
|
"trading_usdt_avail": tu,
|
||||||
|
"trading_usdc_avail": tc,
|
||||||
}
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return _orig_fetch_bal(ex, force=force)
|
return _orig_fetch_bal(ex, force=force, scope=scope, sub_acct=sub_acct)
|
||||||
|
|
||||||
def options_api_ready(ex):
|
def options_api_ready(ex):
|
||||||
try:
|
try:
|
||||||
@@ -191,6 +234,72 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
pass
|
pass
|
||||||
return _orig_ready(ex)
|
return _orig_ready(ex)
|
||||||
|
|
||||||
|
def transfer_ccy(ex, ccy, amount, from_acct, to_acct):
|
||||||
|
try:
|
||||||
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
|
from lib.sim.wallets_lib import SimWallets, normalize_sim_account
|
||||||
|
|
||||||
|
result = SimWallets(_GET_DB).transfer(
|
||||||
|
ccy=str(ccy or "USDC"),
|
||||||
|
amount=float(amount),
|
||||||
|
from_account=normalize_sim_account(from_acct),
|
||||||
|
to_account=normalize_sim_account(to_acct),
|
||||||
|
)
|
||||||
|
if not result.get("ok"):
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"msg": result.get("detail") or result.get("msg") or "划转失败",
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
from lib.instance.instance_live_push_lib import notify_instance_balance_changed
|
||||||
|
|
||||||
|
notify_instance_balance_changed()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return {"ok": True, "msg": "sim 划转成功", "sim": True, **result}
|
||||||
|
except Exception as e:
|
||||||
|
return {"ok": False, "msg": str(e)}
|
||||||
|
return _orig_transfer(ex, ccy, amount, from_acct, to_acct)
|
||||||
|
|
||||||
|
def spot_market_swap_usdt_usdc(ex, *, direction: str = "usdt_to_usdc", amount: float = 0):
|
||||||
|
try:
|
||||||
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
|
from lib.sim.wallets_lib import SimWallets
|
||||||
|
|
||||||
|
d = (direction or "usdt_to_usdc").strip().lower()
|
||||||
|
if d == "usdc_to_usdt":
|
||||||
|
from_ccy, to_ccy = "USDC", "USDT"
|
||||||
|
else:
|
||||||
|
from_ccy, to_ccy = "USDT", "USDC"
|
||||||
|
result = SimWallets(_GET_DB).convert(
|
||||||
|
from_ccy=from_ccy,
|
||||||
|
to_ccy=to_ccy,
|
||||||
|
amount=float(amount),
|
||||||
|
account="funding",
|
||||||
|
)
|
||||||
|
if not result.get("ok"):
|
||||||
|
result = SimWallets(_GET_DB).convert(
|
||||||
|
from_ccy=from_ccy,
|
||||||
|
to_ccy=to_ccy,
|
||||||
|
amount=float(amount),
|
||||||
|
account="trading",
|
||||||
|
)
|
||||||
|
if not result.get("ok"):
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"msg": result.get("detail") or result.get("msg") or "兑换失败",
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
from lib.instance.instance_live_push_lib import notify_instance_balance_changed
|
||||||
|
|
||||||
|
notify_instance_balance_changed()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return {"ok": True, "msg": "sim 兑换成功(1:1)", "sim": True, **result}
|
||||||
|
except Exception as e:
|
||||||
|
return {"ok": False, "msg": str(e)}
|
||||||
|
return _orig_swap(ex, direction=direction, amount=amount)
|
||||||
|
|
||||||
def fetch_option_order(ex, *, inst_id: str, ord_id: str):
|
def fetch_option_order(ex, *, inst_id: str, ord_id: str):
|
||||||
oid = str(ord_id or "")
|
oid = str(ord_id or "")
|
||||||
if oid.startswith("sim-"):
|
if oid.startswith("sim-"):
|
||||||
@@ -243,6 +352,8 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
opt_lib.options_header_balances = options_header_balances
|
opt_lib.options_header_balances = options_header_balances
|
||||||
opt_lib.fetch_options_balances = fetch_options_balances
|
opt_lib.fetch_options_balances = fetch_options_balances
|
||||||
opt_lib.options_api_ready = options_api_ready
|
opt_lib.options_api_ready = options_api_ready
|
||||||
|
opt_lib.transfer_ccy = transfer_ccy
|
||||||
|
opt_lib.spot_market_swap_usdt_usdc = spot_market_swap_usdt_usdc
|
||||||
opt_lib.fetch_option_order = fetch_option_order
|
opt_lib.fetch_option_order = fetch_option_order
|
||||||
opt_lib.wait_option_order_full_fill = wait_option_order_full_fill
|
opt_lib.wait_option_order_full_fill = wait_option_order_full_fill
|
||||||
opt_lib.fetch_option_positions = fetch_option_positions
|
opt_lib.fetch_option_positions = fetch_option_positions
|
||||||
@@ -279,6 +390,22 @@ def patch_options_cfg(cfg: dict[str, Any]) -> dict[str, Any]:
|
|||||||
if not callable(get_db):
|
if not callable(get_db):
|
||||||
return cfg
|
return cfg
|
||||||
set_get_db(get_db)
|
set_get_db(get_db)
|
||||||
|
|
||||||
|
# 与 apply_sim_hooks 对齐: cfg 里可能仍是 import 时的旧引用
|
||||||
|
import lib.exchange.okx_options_lib as opt_lib
|
||||||
|
|
||||||
|
for key in (
|
||||||
|
"transfer_ccy",
|
||||||
|
"spot_market_swap_usdt_usdc",
|
||||||
|
"options_api_ready",
|
||||||
|
"fetch_options_balances",
|
||||||
|
"fetch_option_positions",
|
||||||
|
"fetch_option_order",
|
||||||
|
"wait_option_order_full_fill",
|
||||||
|
):
|
||||||
|
if key in cfg and hasattr(opt_lib, key):
|
||||||
|
cfg[key] = getattr(opt_lib, key)
|
||||||
|
|
||||||
live_limit = cfg.get("place_option_limit_order")
|
live_limit = cfg.get("place_option_limit_order")
|
||||||
live_market = cfg.get("place_option_market_order")
|
live_market = cfg.get("place_option_market_order")
|
||||||
if callable(live_limit) and callable(live_market):
|
if callable(live_limit) and callable(live_market):
|
||||||
|
|||||||
+12
-2
@@ -21,6 +21,16 @@ _ACCT_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_sim_account(account: str | None) -> str:
|
||||||
|
"""统一账户别名: swap/unified → trading; spot → funding."""
|
||||||
|
a = (account or "").strip().lower()
|
||||||
|
if a in ("trading", "swap", "unified", "18"):
|
||||||
|
return "trading"
|
||||||
|
if a in ("funding", "spot", "6"):
|
||||||
|
return "funding"
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
class InsufficientFunds(RuntimeError):
|
class InsufficientFunds(RuntimeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -172,8 +182,8 @@ class SimWallets:
|
|||||||
if amt <= 0:
|
if amt <= 0:
|
||||||
return {"ok": False, "detail": "划转金额须大于 0"}
|
return {"ok": False, "detail": "划转金额须大于 0"}
|
||||||
ccy_l = (ccy or "USDT").strip().lower()
|
ccy_l = (ccy or "USDT").strip().lower()
|
||||||
fa = (from_account or "").strip().lower()
|
fa = normalize_sim_account(from_account)
|
||||||
ta = (to_account or "").strip().lower()
|
ta = normalize_sim_account(to_account)
|
||||||
if fa not in ("funding", "trading") or ta not in ("funding", "trading"):
|
if fa not in ("funding", "trading") or ta not in ("funding", "trading"):
|
||||||
return {"ok": False, "detail": "账户仅支持 funding / trading"}
|
return {"ok": False, "detail": "账户仅支持 funding / trading"}
|
||||||
if fa == ta:
|
if fa == ta:
|
||||||
|
|||||||
Reference in New Issue
Block a user