模拟盘对齐币本位:钱包支持 ETH/BTC,现货桥与期权权利金走本地撮合。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,16 +20,10 @@ from lib.options.options_margin_mode_lib import (
|
|||||||
plan_coin_open_by_budget,
|
plan_coin_open_by_budget,
|
||||||
premium_ccy_for_mode,
|
premium_ccy_for_mode,
|
||||||
)
|
)
|
||||||
|
from lib.options import options_spot_bridge_lib as _spot_bridge
|
||||||
from lib.options.options_spot_bridge_lib import (
|
from lib.options.options_spot_bridge_lib import (
|
||||||
BRIDGE_BOUGHT,
|
BRIDGE_BOUGHT,
|
||||||
BRIDGE_HOLDING,
|
BRIDGE_HOLDING,
|
||||||
bridge_blocks_new_open_msg,
|
|
||||||
fetch_trading_coin_available,
|
|
||||||
insert_bridge,
|
|
||||||
rollback_bought_coin_to_usdt,
|
|
||||||
sell_residual_after_option_flat,
|
|
||||||
spot_market_buy_coin_with_usdt,
|
|
||||||
update_bridge,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +72,7 @@ def open_coin_option_buy_full(
|
|||||||
conn = cfg["get_db"]()
|
conn = cfg["get_db"]()
|
||||||
try:
|
try:
|
||||||
init_options_tables(conn)
|
init_options_tables(conn)
|
||||||
block = bridge_blocks_new_open_msg(conn)
|
block = _spot_bridge.bridge_blocks_new_open_msg(conn)
|
||||||
if block:
|
if block:
|
||||||
return {"ok": False, "msg": block, "can_open": False}
|
return {"ok": False, "msg": block, "can_open": False}
|
||||||
|
|
||||||
@@ -149,8 +143,8 @@ def open_coin_option_buy_full(
|
|||||||
sheets = int(plan["sheets"])
|
sheets = int(plan["sheets"])
|
||||||
|
|
||||||
# 1) 仅买「权利金×现货缓冲」所需 USDT,不全额兑换预算
|
# 1) 仅买「权利金×现货缓冲」所需 USDT,不全额兑换预算
|
||||||
coin_before = fetch_trading_coin_available(ex, underlying) or 0.0
|
coin_before = _spot_bridge.fetch_trading_coin_available(ex, underlying) or 0.0
|
||||||
buy = spot_market_buy_coin_with_usdt(ex, underlying=underlying, usdt_amount=buy_usdt)
|
buy = _spot_bridge.spot_market_buy_coin_with_usdt(ex, underlying=underlying, usdt_amount=buy_usdt)
|
||||||
if not buy.get("ok"):
|
if not buy.get("ok"):
|
||||||
return {
|
return {
|
||||||
"ok": False,
|
"ok": False,
|
||||||
@@ -158,7 +152,7 @@ def open_coin_option_buy_full(
|
|||||||
"budget": budget_info,
|
"budget": budget_info,
|
||||||
"plan": plan,
|
"plan": plan,
|
||||||
}
|
}
|
||||||
bridge_id = insert_bridge(
|
bridge_id = _spot_bridge.insert_bridge(
|
||||||
conn,
|
conn,
|
||||||
underlying=underlying,
|
underlying=underlying,
|
||||||
status=BRIDGE_BOUGHT,
|
status=BRIDGE_BOUGHT,
|
||||||
@@ -175,9 +169,9 @@ def open_coin_option_buy_full(
|
|||||||
invalidate_options_balance_cache()
|
invalidate_options_balance_cache()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
coin_after = fetch_trading_coin_available(ex, underlying)
|
coin_after = _spot_bridge.fetch_trading_coin_available(ex, underlying)
|
||||||
if coin_after is None:
|
if coin_after is None:
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="买币后读不到可用余额"
|
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="买币后读不到可用余额"
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
@@ -192,11 +186,11 @@ def open_coin_option_buy_full(
|
|||||||
# 落账延迟时退化为用当前可用,但仍写入上限提示
|
# 落账延迟时退化为用当前可用,但仍写入上限提示
|
||||||
coin_bought = float(coin_after)
|
coin_bought = float(coin_after)
|
||||||
if coin_bought <= 0:
|
if coin_bought <= 0:
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="买入量无效"
|
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="买入量无效"
|
||||||
)
|
)
|
||||||
return {"ok": False, "msg": "买币后可用增量无效", "rollback": rb, "budget": budget_info}
|
return {"ok": False, "msg": "买币后可用增量无效", "rollback": rb, "budget": budget_info}
|
||||||
update_bridge(conn, bridge_id, coin_bought=float(coin_bought))
|
_spot_bridge.update_bridge(conn, bridge_id, coin_bought=float(coin_bought))
|
||||||
|
|
||||||
sizing = calc_sheets_from_coin_balance(
|
sizing = calc_sheets_from_coin_balance(
|
||||||
quote_per_unit=float(ask),
|
quote_per_unit=float(ask),
|
||||||
@@ -205,7 +199,7 @@ def open_coin_option_buy_full(
|
|||||||
coin_available=float(coin_bought),
|
coin_available=float(coin_bought),
|
||||||
)
|
)
|
||||||
if not sizing.get("ok"):
|
if not sizing.get("ok"):
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn,
|
conn,
|
||||||
ex,
|
ex,
|
||||||
bridge_id=bridge_id,
|
bridge_id=bridge_id,
|
||||||
@@ -219,7 +213,7 @@ def open_coin_option_buy_full(
|
|||||||
sheets = min(int(sizing["sheets"]), int(plan["sheets"]))
|
sheets = min(int(sizing["sheets"]), int(plan["sheets"]))
|
||||||
capped, cap_msg = cap_option_buy_sheets_to_ask_depth(sheets, ask_sz, min_sz=min_sz)
|
capped, cap_msg = cap_option_buy_sheets_to_ask_depth(sheets, ask_sz, min_sz=min_sz)
|
||||||
if capped is None:
|
if capped is None:
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn, ex, bridge_id=bridge_id, underlying=underlying, reason=cap_msg or "深度不足"
|
conn, ex, bridge_id=bridge_id, underlying=underlying, reason=cap_msg or "深度不足"
|
||||||
)
|
)
|
||||||
return {"ok": False, "msg": cap_msg or "卖一深度不足", "rollback": rb}
|
return {"ok": False, "msg": cap_msg or "卖一深度不足", "rollback": rb}
|
||||||
@@ -278,14 +272,14 @@ def open_coin_option_buy_full(
|
|||||||
"retried_half": True,
|
"retried_half": True,
|
||||||
}
|
}
|
||||||
if not order.get("ok"):
|
if not order.get("ok"):
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn, ex, bridge_id=bridge_id, underlying=underlying, reason=order.get("msg") or "下单失败"
|
conn, ex, bridge_id=bridge_id, underlying=underlying, reason=order.get("msg") or "下单失败"
|
||||||
)
|
)
|
||||||
return {"ok": False, "msg": order.get("msg") or "期权下单失败", "order": order, "rollback": rb}
|
return {"ok": False, "msg": order.get("msg") or "期权下单失败", "order": order, "rollback": rb}
|
||||||
|
|
||||||
ord_id = str((order.get("data") or {}).get("ordId") or "").strip()
|
ord_id = str((order.get("data") or {}).get("ordId") or "").strip()
|
||||||
if not ord_id:
|
if not ord_id:
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="无订单号"
|
conn, ex, bridge_id=bridge_id, underlying=underlying, reason="无订单号"
|
||||||
)
|
)
|
||||||
return {"ok": False, "msg": "下单成功但未返回订单号", "rollback": rb}
|
return {"ok": False, "msg": "下单成功但未返回订单号", "rollback": rb}
|
||||||
@@ -305,7 +299,7 @@ def open_coin_option_buy_full(
|
|||||||
if not fill.get("ok"):
|
if not fill.get("ok"):
|
||||||
filled_n = int(fill.get("filled_sheets") or 0)
|
filled_n = int(fill.get("filled_sheets") or 0)
|
||||||
if filled_n <= 0:
|
if filled_n <= 0:
|
||||||
rb = rollback_bought_coin_to_usdt(
|
rb = _spot_bridge.rollback_bought_coin_to_usdt(
|
||||||
conn,
|
conn,
|
||||||
ex,
|
ex,
|
||||||
bridge_id=bridge_id,
|
bridge_id=bridge_id,
|
||||||
@@ -319,7 +313,7 @@ def open_coin_option_buy_full(
|
|||||||
premium_paid = round(float(ask) * eth_amount, 8)
|
premium_paid = round(float(ask) * eth_amount, 8)
|
||||||
premium_ccy = premium_ccy_for_mode("coin", underlying)
|
premium_ccy = premium_ccy_for_mode("coin", underlying)
|
||||||
|
|
||||||
update_bridge(
|
_spot_bridge.update_bridge(
|
||||||
conn,
|
conn,
|
||||||
bridge_id,
|
bridge_id,
|
||||||
status=BRIDGE_HOLDING,
|
status=BRIDGE_HOLDING,
|
||||||
@@ -471,7 +465,7 @@ def maybe_sell_spot_after_close(
|
|||||||
from lib.options.options_db import init_options_tables
|
from lib.options.options_db import init_options_tables
|
||||||
|
|
||||||
init_options_tables(conn)
|
init_options_tables(conn)
|
||||||
return sell_residual_after_option_flat(conn, ex, underlying=underlying, inst_id=inst_id)
|
return _spot_bridge.sell_residual_after_option_flat(conn, ex, underlying=underlying, inst_id=inst_id)
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
+87
-3
@@ -64,6 +64,19 @@ def _contract_size(exchange: Any, symbol: str) -> float:
|
|||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
|
|
||||||
|
def _premium_ccy_for_inst(inst_id: str) -> str:
|
||||||
|
try:
|
||||||
|
from lib.options.options_margin_mode_lib import (
|
||||||
|
margin_mode_from_inst_id,
|
||||||
|
premium_ccy_for_mode,
|
||||||
|
)
|
||||||
|
|
||||||
|
underly = (str(inst_id or "").split("-")[0] or "ETH").upper()
|
||||||
|
return premium_ccy_for_mode(margin_mode_from_inst_id(inst_id), underly)
|
||||||
|
except Exception:
|
||||||
|
return "USDC"
|
||||||
|
|
||||||
|
|
||||||
class SimBroker:
|
class SimBroker:
|
||||||
def __init__(self, get_db: Callable) -> None:
|
def __init__(self, get_db: Callable) -> None:
|
||||||
self.get_db = get_db
|
self.get_db = get_db
|
||||||
@@ -377,9 +390,10 @@ class SimBroker:
|
|||||||
qty = n * ct_mult
|
qty = n * ct_mult
|
||||||
pr = option_fill(action="open", bid=bid, ask=ask, qty=qty, fee_rate=fr)
|
pr = option_fill(action="open", bid=bid, ask=ask, qty=qty, fee_rate=fr)
|
||||||
cost = pr.notional + pr.fee
|
cost = pr.notional + pr.fee
|
||||||
|
prem_ccy = _premium_ccy_for_inst(inst_id)
|
||||||
try:
|
try:
|
||||||
self.wallets.debit_trading(
|
self.wallets.debit_trading(
|
||||||
"USDC",
|
prem_ccy,
|
||||||
cost,
|
cost,
|
||||||
kind="option_open",
|
kind="option_open",
|
||||||
note=f"buy {inst_id} x{n}@{pr.fill_px}",
|
note=f"buy {inst_id} x{n}@{pr.fill_px}",
|
||||||
@@ -490,8 +504,9 @@ class SimBroker:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if credit > 0:
|
if credit > 0:
|
||||||
|
prem_ccy = _premium_ccy_for_inst(inst_id)
|
||||||
self.wallets.credit_trading(
|
self.wallets.credit_trading(
|
||||||
"USDC",
|
prem_ccy,
|
||||||
credit,
|
credit,
|
||||||
kind="option_close",
|
kind="option_close",
|
||||||
note=f"sell {inst_id} x{close_n}@{pr.fill_px}",
|
note=f"sell {inst_id} x{close_n}@{pr.fill_px}",
|
||||||
@@ -552,6 +567,67 @@ class SimBroker:
|
|||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def convert_usdt_coin(
|
||||||
|
self,
|
||||||
|
exchange: Any,
|
||||||
|
*,
|
||||||
|
underlying: str,
|
||||||
|
direction: str,
|
||||||
|
amount: float,
|
||||||
|
fee_rate: float | None = None,
|
||||||
|
account: str = "trading",
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""模拟 ETH/BTC-USDT 现货市价兑换(交易账户)."""
|
||||||
|
from lib.options.options_margin_mode_lib import spot_quote_inst_id
|
||||||
|
from lib.sim.pricing_lib import spot_coin_usdt_fill
|
||||||
|
|
||||||
|
coin = (underlying or "ETH").strip().upper() or "ETH"
|
||||||
|
if coin not in ("ETH", "BTC"):
|
||||||
|
return {"ok": False, "msg": f"不支持标的 {coin}"}
|
||||||
|
# spot_quote_inst_id → ETH-USDT;ccxt 常用 ETH/USDT
|
||||||
|
inst = spot_quote_inst_id(coin)
|
||||||
|
symbol = inst.replace("-", "/") if inst else f"{coin}/USDT"
|
||||||
|
fr = sim_fee_rate(fee_rate)
|
||||||
|
bid, ask = _ticker_bid_ask(exchange, symbol)
|
||||||
|
fill = spot_coin_usdt_fill(
|
||||||
|
direction=direction,
|
||||||
|
amount=float(amount),
|
||||||
|
bid=bid,
|
||||||
|
ask=ask,
|
||||||
|
fee_rate=fr,
|
||||||
|
coin=coin,
|
||||||
|
)
|
||||||
|
result = SimWallets(self.get_db).convert(
|
||||||
|
from_ccy=fill.from_ccy,
|
||||||
|
to_ccy=fill.to_ccy,
|
||||||
|
amount=fill.from_amount,
|
||||||
|
account=account or "trading",
|
||||||
|
to_amount=fill.to_amount,
|
||||||
|
rate=fill.fill_px,
|
||||||
|
fee=fill.fee,
|
||||||
|
note=f"{symbol} mkt {fill.fill_px:.4f} (bid {bid:.4f}/ask {ask:.4f})",
|
||||||
|
)
|
||||||
|
if not result.get("ok"):
|
||||||
|
return result
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
"direction": fill.direction,
|
||||||
|
"underlying": coin,
|
||||||
|
"bid": bid,
|
||||||
|
"ask": ask,
|
||||||
|
"base_px": fill.base_px,
|
||||||
|
"fill_px": fill.fill_px,
|
||||||
|
"fee_rate": fr,
|
||||||
|
"symbol": symbol,
|
||||||
|
"inst_id": inst,
|
||||||
|
"coin_bought": fill.to_amount if fill.direction == "usdt_to_coin" else None,
|
||||||
|
"coin_sold": fill.from_amount if fill.direction == "coin_to_usdt" else None,
|
||||||
|
"usdt_spent": fill.from_amount if fill.direction == "usdt_to_coin" else None,
|
||||||
|
"usdt_recovered": fill.to_amount if fill.direction == "coin_to_usdt" else None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
def _index_px_for_option(
|
def _index_px_for_option(
|
||||||
self,
|
self,
|
||||||
exchange: Any,
|
exchange: Any,
|
||||||
@@ -645,6 +721,14 @@ class SimBroker:
|
|||||||
else:
|
else:
|
||||||
intrinsic_u = 0.0
|
intrinsic_u = 0.0
|
||||||
|
|
||||||
|
prem_ccy = _premium_ccy_for_inst(inst_id)
|
||||||
|
# 币本位到期兑付用币数量: 实值/指数 × 张数 × 乘数
|
||||||
|
if prem_ccy in ("ETH", "BTC") and float(spot) > 0:
|
||||||
|
settle_recv = round(
|
||||||
|
max(0.0, (intrinsic_u / float(spot)) * sheets * ct_mult),
|
||||||
|
8,
|
||||||
|
)
|
||||||
|
|
||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
conn.execute("DELETE FROM sim_option_positions WHERE inst_id=?", (inst_id,))
|
conn.execute("DELETE FROM sim_option_positions WHERE inst_id=?", (inst_id,))
|
||||||
@@ -681,7 +765,7 @@ class SimBroker:
|
|||||||
|
|
||||||
if settle_recv > 1e-12:
|
if settle_recv > 1e-12:
|
||||||
self.wallets.credit_trading(
|
self.wallets.credit_trading(
|
||||||
"USDC",
|
prem_ccy,
|
||||||
settle_recv,
|
settle_recv,
|
||||||
kind="option_expiry",
|
kind="option_expiry",
|
||||||
note=f"expiry settle {inst_id} @{spot:g} recv={settle_recv}",
|
note=f"expiry settle {inst_id} @{spot:g} recv={settle_recv}",
|
||||||
|
|||||||
@@ -14,6 +14,19 @@ def _env_float(key: str, default: float) -> float:
|
|||||||
return float(default)
|
return float(default)
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_sim_wallet_coin_columns(conn: sqlite3.Connection) -> None:
|
||||||
|
"""旧库补齐币本位 ETH/BTC 列."""
|
||||||
|
cols = {
|
||||||
|
str(r[1])
|
||||||
|
for r in conn.execute("PRAGMA table_info(sim_wallets)").fetchall()
|
||||||
|
}
|
||||||
|
for col in ("funding_eth", "trading_eth", "funding_btc", "trading_btc"):
|
||||||
|
if col not in cols:
|
||||||
|
conn.execute(
|
||||||
|
f"ALTER TABLE sim_wallets ADD COLUMN {col} REAL NOT NULL DEFAULT 0"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def init_sim_tables(conn: sqlite3.Connection) -> None:
|
def init_sim_tables(conn: sqlite3.Connection) -> None:
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
@@ -23,10 +36,15 @@ def init_sim_tables(conn: sqlite3.Connection) -> None:
|
|||||||
trading_usdt REAL NOT NULL DEFAULT 0,
|
trading_usdt REAL NOT NULL DEFAULT 0,
|
||||||
funding_usdc REAL NOT NULL DEFAULT 0,
|
funding_usdc REAL NOT NULL DEFAULT 0,
|
||||||
trading_usdc REAL NOT NULL DEFAULT 0,
|
trading_usdc REAL NOT NULL DEFAULT 0,
|
||||||
|
funding_eth REAL NOT NULL DEFAULT 0,
|
||||||
|
trading_eth REAL NOT NULL DEFAULT 0,
|
||||||
|
funding_btc REAL NOT NULL DEFAULT 0,
|
||||||
|
trading_btc REAL NOT NULL DEFAULT 0,
|
||||||
updated_at TEXT
|
updated_at TEXT
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
_ensure_sim_wallet_coin_columns(conn)
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS sim_perp_positions (
|
CREATE TABLE IF NOT EXISTS sim_perp_positions (
|
||||||
|
|||||||
+144
-8
@@ -192,10 +192,10 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
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()
|
||||||
return (
|
return (
|
||||||
round(float(w["trading_usdc"]), 2),
|
round(float(w.get("trading_usdc") or 0), 2),
|
||||||
round(float(w["funding_usdc"]), 2),
|
round(float(w.get("funding_usdc") or 0), 2),
|
||||||
round(float(w["funding_usdt"]), 2),
|
round(float(w.get("funding_usdt") or 0), 2),
|
||||||
round(float(w["trading_usdt"]), 2),
|
round(float(w.get("trading_usdt") or 0), 2),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -207,20 +207,32 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
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"])
|
fu = float(w.get("funding_usdt") or 0)
|
||||||
fc = float(w["funding_usdc"])
|
fc = float(w.get("funding_usdc") or 0)
|
||||||
tu = float(w["trading_usdt"])
|
tu = float(w.get("trading_usdt") or 0)
|
||||||
tc = float(w["trading_usdc"])
|
tc = float(w.get("trading_usdc") or 0)
|
||||||
|
fe = float(w.get("funding_eth") or 0)
|
||||||
|
te = float(w.get("trading_eth") or 0)
|
||||||
|
fb = float(w.get("funding_btc") or 0)
|
||||||
|
tb = float(w.get("trading_btc") or 0)
|
||||||
return {
|
return {
|
||||||
"scope": "main",
|
"scope": "main",
|
||||||
"funding_usdt": fu,
|
"funding_usdt": fu,
|
||||||
"funding_usdc": fc,
|
"funding_usdc": fc,
|
||||||
"trading_usdt": tu,
|
"trading_usdt": tu,
|
||||||
"trading_usdc": tc,
|
"trading_usdc": tc,
|
||||||
|
"funding_eth": fe,
|
||||||
|
"trading_eth": te,
|
||||||
|
"funding_btc": fb,
|
||||||
|
"trading_btc": tb,
|
||||||
"funding_usdt_avail": fu,
|
"funding_usdt_avail": fu,
|
||||||
"funding_usdc_avail": fc,
|
"funding_usdc_avail": fc,
|
||||||
"trading_usdt_avail": tu,
|
"trading_usdt_avail": tu,
|
||||||
"trading_usdc_avail": tc,
|
"trading_usdc_avail": tc,
|
||||||
|
"funding_eth_avail": fe,
|
||||||
|
"trading_eth_avail": te,
|
||||||
|
"funding_btc_avail": fb,
|
||||||
|
"trading_btc_avail": tb,
|
||||||
}
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -355,6 +367,130 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
|||||||
opt_lib.fetch_option_positions = fetch_option_positions
|
opt_lib.fetch_option_positions = fetch_option_positions
|
||||||
opt_lib._sim_hooks_applied = True
|
opt_lib._sim_hooks_applied = True
|
||||||
|
|
||||||
|
_patch_spot_bridge_lib()
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_spot_bridge_lib() -> None:
|
||||||
|
"""币本位现货桥:模拟盘走本地 USDT↔ETH/BTC,勿打实盘 private_post_trade_order."""
|
||||||
|
import lib.options.options_spot_bridge_lib as bridge_lib
|
||||||
|
|
||||||
|
if getattr(bridge_lib, "_sim_hooks_applied", False):
|
||||||
|
return
|
||||||
|
|
||||||
|
_orig_buy = bridge_lib.spot_market_buy_coin_with_usdt
|
||||||
|
_orig_sell = bridge_lib.spot_market_sell_coin_to_usdt
|
||||||
|
_orig_avail = bridge_lib.fetch_trading_coin_available
|
||||||
|
|
||||||
|
def fetch_trading_coin_available(ex, ccy: str):
|
||||||
|
try:
|
||||||
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
|
ccy_u = (ccy or "").strip().upper()
|
||||||
|
if ccy_u not in ("ETH", "BTC"):
|
||||||
|
return None
|
||||||
|
w = broker().balances_header()
|
||||||
|
return float(w.get(f"trading_{ccy_u.lower()}") or 0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return _orig_avail(ex, ccy)
|
||||||
|
|
||||||
|
def spot_market_buy_coin_with_usdt(ex, *, underlying: str, usdt_amount: float):
|
||||||
|
try:
|
||||||
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
|
pub = ex
|
||||||
|
if pub is None and _APP_MODULE is not None:
|
||||||
|
pub = getattr(_APP_MODULE, "exchange", None) or getattr(
|
||||||
|
_APP_MODULE, "exchange_options", None
|
||||||
|
)
|
||||||
|
if pub is None:
|
||||||
|
return {"ok": False, "msg": "sim: 无公开行情 exchange"}
|
||||||
|
result = broker().convert_usdt_coin(
|
||||||
|
pub,
|
||||||
|
underlying=underlying,
|
||||||
|
direction="usdt_to_coin",
|
||||||
|
amount=float(usdt_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,
|
||||||
|
"inst_id": result.get("inst_id") or "",
|
||||||
|
"ord_id": f"sim-spot-buy-{result.get('fill_px') or 0}",
|
||||||
|
"sim": True,
|
||||||
|
"coin_bought": result.get("coin_bought"),
|
||||||
|
"data": {"sCode": "0", "sMsg": "sim filled"},
|
||||||
|
**{k: result[k] for k in ("fill_px", "usdt_spent", "underlying") if k in result},
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"ok": False, "msg": str(e)}
|
||||||
|
return _orig_buy(ex, underlying=underlying, usdt_amount=usdt_amount)
|
||||||
|
|
||||||
|
def spot_market_sell_coin_to_usdt(ex, *, underlying: str, coin_amount: float | None = None):
|
||||||
|
try:
|
||||||
|
if _GET_DB is not None and is_sim_mode(_GET_DB):
|
||||||
|
coin = (underlying or "ETH").strip().upper() or "ETH"
|
||||||
|
amt = coin_amount
|
||||||
|
if amt is None or float(amt) <= 0:
|
||||||
|
amt = fetch_trading_coin_available(ex, coin)
|
||||||
|
if amt is None or float(amt) <= 0:
|
||||||
|
return {"ok": False, "msg": f"交易账户无可用 {coin}"}
|
||||||
|
sell_sz = float(amt)
|
||||||
|
if sell_sz > 1e-8:
|
||||||
|
sell_sz = max(0.0, sell_sz * 0.999)
|
||||||
|
if sell_sz <= 0:
|
||||||
|
return {"ok": False, "msg": f"{coin} 可卖数量过小"}
|
||||||
|
pub = ex
|
||||||
|
if pub is None and _APP_MODULE is not None:
|
||||||
|
pub = getattr(_APP_MODULE, "exchange", None) or getattr(
|
||||||
|
_APP_MODULE, "exchange_options", None
|
||||||
|
)
|
||||||
|
if pub is None:
|
||||||
|
return {"ok": False, "msg": "sim: 无公开行情 exchange"}
|
||||||
|
result = broker().convert_usdt_coin(
|
||||||
|
pub,
|
||||||
|
underlying=coin,
|
||||||
|
direction="coin_to_usdt",
|
||||||
|
amount=float(sell_sz),
|
||||||
|
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,
|
||||||
|
"inst_id": result.get("inst_id") or "",
|
||||||
|
"ord_id": f"sim-spot-sell-{result.get('fill_px') or 0}",
|
||||||
|
"coin_sold": float(sell_sz),
|
||||||
|
"sim": True,
|
||||||
|
"usdt_recovered": result.get("usdt_recovered"),
|
||||||
|
"data": {"sCode": "0", "sMsg": "sim filled"},
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"ok": False, "msg": str(e)}
|
||||||
|
return _orig_sell(ex, underlying=underlying, coin_amount=coin_amount)
|
||||||
|
|
||||||
|
bridge_lib.fetch_trading_coin_available = fetch_trading_coin_available
|
||||||
|
bridge_lib.spot_market_buy_coin_with_usdt = spot_market_buy_coin_with_usdt
|
||||||
|
bridge_lib.spot_market_sell_coin_to_usdt = spot_market_sell_coin_to_usdt
|
||||||
|
bridge_lib._sim_hooks_applied = True
|
||||||
|
|
||||||
|
|
||||||
def wrap_option_place_fns(get_db: Callable, live_place_limit, live_place_market):
|
def wrap_option_place_fns(get_db: Callable, live_place_limit, live_place_market):
|
||||||
"""返回按模式分流的 place_option_limit/market."""
|
"""返回按模式分流的 place_option_limit/market."""
|
||||||
|
|||||||
@@ -145,3 +145,58 @@ def spot_usdc_usdt_fill(
|
|||||||
fee=fee,
|
fee=fee,
|
||||||
)
|
)
|
||||||
raise ValueError("direction 须为 usdt_to_usdc 或 usdc_to_usdt")
|
raise ValueError("direction 须为 usdt_to_usdc 或 usdc_to_usdt")
|
||||||
|
|
||||||
|
|
||||||
|
def spot_coin_usdt_fill(
|
||||||
|
*,
|
||||||
|
direction: str,
|
||||||
|
amount: float,
|
||||||
|
bid: float,
|
||||||
|
ask: float,
|
||||||
|
fee_rate: float,
|
||||||
|
coin: str = "ETH",
|
||||||
|
) -> SpotConvertResult:
|
||||||
|
"""
|
||||||
|
对齐实盘 ETH-USDT / BTC-USDT 现货市价:
|
||||||
|
- usdt_to_coin: 用 USDT 买币, 吃卖一 ×(1+f); amount=USDT
|
||||||
|
- coin_to_usdt: 卖币换 USDT, 吃买一 ×(1-f); amount=币数量
|
||||||
|
"""
|
||||||
|
f = float(fee_rate)
|
||||||
|
amt = float(amount)
|
||||||
|
ccy = (coin or "ETH").strip().upper() or "ETH"
|
||||||
|
d = (direction or "").strip().lower()
|
||||||
|
if d in ("usdt_to_coin", "usdt_to_eth", "usdt_to_btc"):
|
||||||
|
base = float(ask)
|
||||||
|
fill = base * (1.0 + f)
|
||||||
|
if fill <= 0:
|
||||||
|
raise ValueError("无效卖一价")
|
||||||
|
to_amt = amt / fill
|
||||||
|
fee = amt * f
|
||||||
|
return SpotConvertResult(
|
||||||
|
direction="usdt_to_coin",
|
||||||
|
from_ccy="USDT",
|
||||||
|
to_ccy=ccy,
|
||||||
|
from_amount=amt,
|
||||||
|
to_amount=to_amt,
|
||||||
|
base_px=base,
|
||||||
|
fill_px=fill,
|
||||||
|
fee=fee,
|
||||||
|
)
|
||||||
|
if d in ("coin_to_usdt", "eth_to_usdt", "btc_to_usdt"):
|
||||||
|
base = float(bid)
|
||||||
|
fill = base * (1.0 - f)
|
||||||
|
if fill <= 0:
|
||||||
|
raise ValueError("无效买一价")
|
||||||
|
to_amt = amt * fill
|
||||||
|
fee = to_amt * f
|
||||||
|
return SpotConvertResult(
|
||||||
|
direction="coin_to_usdt",
|
||||||
|
from_ccy=ccy,
|
||||||
|
to_ccy="USDT",
|
||||||
|
from_amount=amt,
|
||||||
|
to_amount=to_amt,
|
||||||
|
base_px=base,
|
||||||
|
fill_px=fill,
|
||||||
|
fee=fee,
|
||||||
|
)
|
||||||
|
raise ValueError("direction 须为 usdt_to_coin 或 coin_to_usdt")
|
||||||
|
|||||||
+58
-25
@@ -1,4 +1,4 @@
|
|||||||
"""模拟资金钱包: funding/trading × USDT/USDC."""
|
"""模拟资金钱包: funding/trading × USDT/USDC/ETH/BTC."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -11,6 +11,10 @@ WALLET_KEYS = (
|
|||||||
"trading_usdt",
|
"trading_usdt",
|
||||||
"funding_usdc",
|
"funding_usdc",
|
||||||
"trading_usdc",
|
"trading_usdc",
|
||||||
|
"funding_eth",
|
||||||
|
"trading_eth",
|
||||||
|
"funding_btc",
|
||||||
|
"trading_btc",
|
||||||
)
|
)
|
||||||
|
|
||||||
_ACCT_MAP = {
|
_ACCT_MAP = {
|
||||||
@@ -18,6 +22,10 @@ _ACCT_MAP = {
|
|||||||
("trading", "usdt"): "trading_usdt",
|
("trading", "usdt"): "trading_usdt",
|
||||||
("funding", "usdc"): "funding_usdc",
|
("funding", "usdc"): "funding_usdc",
|
||||||
("trading", "usdc"): "trading_usdc",
|
("trading", "usdc"): "trading_usdc",
|
||||||
|
("funding", "eth"): "funding_eth",
|
||||||
|
("trading", "eth"): "trading_eth",
|
||||||
|
("funding", "btc"): "funding_btc",
|
||||||
|
("trading", "btc"): "trading_btc",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -42,13 +50,26 @@ class SimWallets:
|
|||||||
def _now(self) -> str:
|
def _now(self) -> str:
|
||||||
return datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
return datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
def _row_to_snap(self, row: Any) -> dict[str, float]:
|
||||||
|
if row is None:
|
||||||
|
return {k: 0.0 for k in WALLET_KEYS}
|
||||||
|
keys = set(row.keys()) if hasattr(row, "keys") else set()
|
||||||
|
out: dict[str, float] = {}
|
||||||
|
for k in WALLET_KEYS:
|
||||||
|
if keys and k not in keys:
|
||||||
|
out[k] = 0.0
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
out[k] = float(row[k] or 0)
|
||||||
|
except (KeyError, IndexError, TypeError, ValueError):
|
||||||
|
out[k] = 0.0
|
||||||
|
return out
|
||||||
|
|
||||||
def snapshot(self) -> dict[str, float]:
|
def snapshot(self) -> dict[str, float]:
|
||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
||||||
if row is None:
|
return self._row_to_snap(row)
|
||||||
return {k: 0.0 for k in WALLET_KEYS}
|
|
||||||
return {k: float(row[k] or 0) for k in WALLET_KEYS}
|
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -56,6 +77,7 @@ class SimWallets:
|
|||||||
return self.snapshot()
|
return self.snapshot()
|
||||||
|
|
||||||
def total_usdt_equiv(self, snap: dict[str, float] | None = None) -> float:
|
def total_usdt_equiv(self, snap: dict[str, float] | None = None) -> float:
|
||||||
|
"""稳定币合计(不含 ETH/BTC 折算)."""
|
||||||
v = snap or self.view()
|
v = snap or self.view()
|
||||||
return round(
|
return round(
|
||||||
float(v.get("funding_usdt") or 0)
|
float(v.get("funding_usdt") or 0)
|
||||||
@@ -71,23 +93,30 @@ class SimWallets:
|
|||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
now = self._now()
|
now = self._now()
|
||||||
|
full = {k: float(snap.get(k) or 0) for k in WALLET_KEYS}
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
UPDATE sim_wallets SET
|
UPDATE sim_wallets SET
|
||||||
funding_usdt=?, trading_usdt=?, funding_usdc=?, trading_usdc=?, updated_at=?
|
funding_usdt=?, trading_usdt=?, funding_usdc=?, trading_usdc=?,
|
||||||
|
funding_eth=?, trading_eth=?, funding_btc=?, trading_btc=?,
|
||||||
|
updated_at=?
|
||||||
WHERE id=1
|
WHERE id=1
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
float(snap["funding_usdt"]),
|
full["funding_usdt"],
|
||||||
float(snap["trading_usdt"]),
|
full["trading_usdt"],
|
||||||
float(snap["funding_usdc"]),
|
full["funding_usdc"],
|
||||||
float(snap["trading_usdc"]),
|
full["trading_usdc"],
|
||||||
|
full["funding_eth"],
|
||||||
|
full["trading_eth"],
|
||||||
|
full["funding_btc"],
|
||||||
|
full["trading_btc"],
|
||||||
now,
|
now,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if owns:
|
if owns:
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return {k: float(snap[k]) for k in WALLET_KEYS}
|
return full
|
||||||
finally:
|
finally:
|
||||||
if owns:
|
if owns:
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -117,14 +146,14 @@ class SimWallets:
|
|||||||
raise ValueError("扣款金额须大于 0")
|
raise ValueError("扣款金额须大于 0")
|
||||||
key = _ACCT_MAP.get(("trading", (ccy or "").lower()))
|
key = _ACCT_MAP.get(("trading", (ccy or "").lower()))
|
||||||
if not key:
|
if not key:
|
||||||
raise ValueError("币种须为 USDT 或 USDC")
|
raise ValueError("币种须为 USDT/USDC/ETH/BTC")
|
||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
||||||
snap = {k: float(row[k] or 0) for k in WALLET_KEYS}
|
snap = self._row_to_snap(row)
|
||||||
bal = float(snap[key])
|
bal = float(snap[key])
|
||||||
if amt > bal + 1e-9:
|
if amt > bal + 1e-9:
|
||||||
raise InsufficientFunds(f"交易账户 {ccy.upper()} 不足(可用 {bal:.4f})")
|
raise InsufficientFunds(f"交易账户 {ccy.upper()} 不足(可用 {bal:.8f})")
|
||||||
snap[key] = bal - amt
|
snap[key] = bal - amt
|
||||||
self._write(snap, conn=conn)
|
self._write(snap, conn=conn)
|
||||||
self._ledger(
|
self._ledger(
|
||||||
@@ -149,11 +178,11 @@ class SimWallets:
|
|||||||
return self.snapshot()
|
return self.snapshot()
|
||||||
key = _ACCT_MAP.get(("trading", (ccy or "").lower()))
|
key = _ACCT_MAP.get(("trading", (ccy or "").lower()))
|
||||||
if not key:
|
if not key:
|
||||||
raise ValueError("币种须为 USDT 或 USDC")
|
raise ValueError("币种须为 USDT/USDC/ETH/BTC")
|
||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
||||||
snap = {k: float(row[k] or 0) for k in WALLET_KEYS}
|
snap = self._row_to_snap(row)
|
||||||
snap[key] = float(snap[key]) + amt
|
snap[key] = float(snap[key]) + amt
|
||||||
self._write(snap, conn=conn)
|
self._write(snap, conn=conn)
|
||||||
self._ledger(
|
self._ledger(
|
||||||
@@ -191,14 +220,14 @@ class SimWallets:
|
|||||||
src_key = _ACCT_MAP.get((fa, ccy_l))
|
src_key = _ACCT_MAP.get((fa, ccy_l))
|
||||||
dst_key = _ACCT_MAP.get((ta, ccy_l))
|
dst_key = _ACCT_MAP.get((ta, ccy_l))
|
||||||
if not src_key or not dst_key:
|
if not src_key or not dst_key:
|
||||||
return {"ok": False, "detail": "币种须为 USDT 或 USDC"}
|
return {"ok": False, "detail": "币种须为 USDT/USDC/ETH/BTC"}
|
||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
||||||
snap = {k: float(row[k] or 0) for k in WALLET_KEYS}
|
snap = self._row_to_snap(row)
|
||||||
src_bal = float(snap[src_key])
|
src_bal = float(snap[src_key])
|
||||||
if amt > src_bal + 1e-9:
|
if amt > src_bal + 1e-9:
|
||||||
return {"ok": False, "detail": f"余额不足(可用 {src_bal:.4f})"}
|
return {"ok": False, "detail": f"余额不足(可用 {src_bal:.8f})"}
|
||||||
snap[src_key] = src_bal - amt
|
snap[src_key] = src_bal - amt
|
||||||
snap[dst_key] = float(snap[dst_key]) + amt
|
snap[dst_key] = float(snap[dst_key]) + amt
|
||||||
self._write(snap, conn=conn)
|
self._write(snap, conn=conn)
|
||||||
@@ -246,7 +275,7 @@ class SimWallets:
|
|||||||
fee: float | None = None,
|
fee: float | None = None,
|
||||||
note: str | None = None,
|
note: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""USDT↔USDC 兑换. 默认交易账户; to_amount 未给时按 rate(USDT/USDC) 换算, 再否则 1:1."""
|
"""USDT↔USDC / USDT↔ETH / USDT↔BTC 兑换. to_amount 未给时按 rate(USDT per coin) 换算."""
|
||||||
amt = float(amount)
|
amt = float(amount)
|
||||||
if amt <= 0:
|
if amt <= 0:
|
||||||
return {"ok": False, "detail": "数量须大于 0"}
|
return {"ok": False, "detail": "数量须大于 0"}
|
||||||
@@ -255,13 +284,14 @@ class SimWallets:
|
|||||||
acct = normalize_sim_account(account) or "trading"
|
acct = normalize_sim_account(account) or "trading"
|
||||||
if acct not in ("funding", "trading"):
|
if acct not in ("funding", "trading"):
|
||||||
return {"ok": False, "detail": "account 须为 funding / trading"}
|
return {"ok": False, "detail": "account 须为 funding / trading"}
|
||||||
if {fa, ta} != {"usdt", "usdc"}:
|
pair = {fa, ta}
|
||||||
return {"ok": False, "detail": "仅支持 USDT↔USDC"}
|
if pair not in ({"usdt", "usdc"}, {"usdt", "eth"}, {"usdt", "btc"}):
|
||||||
|
return {"ok": False, "detail": "仅支持 USDT↔USDC/ETH/BTC"}
|
||||||
if to_amount is not None:
|
if to_amount is not None:
|
||||||
got = float(to_amount)
|
got = float(to_amount)
|
||||||
elif rate is not None and float(rate) > 0:
|
elif rate is not None and float(rate) > 0:
|
||||||
r = float(rate)
|
r = float(rate)
|
||||||
# rate = USDT per 1 USDC
|
# rate = USDT per 1 coin(USDC/ETH/BTC)
|
||||||
got = (amt / r) if fa == "usdt" else (amt * r)
|
got = (amt / r) if fa == "usdt" else (amt * r)
|
||||||
else:
|
else:
|
||||||
got = amt
|
got = amt
|
||||||
@@ -272,10 +302,10 @@ class SimWallets:
|
|||||||
conn = self.get_db()
|
conn = self.get_db()
|
||||||
try:
|
try:
|
||||||
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
row = conn.execute("SELECT * FROM sim_wallets WHERE id=1").fetchone()
|
||||||
snap = {k: float(row[k] or 0) for k in WALLET_KEYS}
|
snap = self._row_to_snap(row)
|
||||||
src = float(snap[src_key])
|
src = float(snap[src_key])
|
||||||
if amt > src + 1e-9:
|
if amt > src + 1e-9:
|
||||||
return {"ok": False, "detail": f"{acct} {fa.upper()} 不足(可用 {src:.4f})"}
|
return {"ok": False, "detail": f"{acct} {fa.upper()} 不足(可用 {src:.8f})"}
|
||||||
snap[src_key] = src - amt
|
snap[src_key] = src - amt
|
||||||
snap[dst_key] = float(snap[dst_key]) + got
|
snap[dst_key] = float(snap[dst_key]) + got
|
||||||
self._write(snap, conn=conn)
|
self._write(snap, conn=conn)
|
||||||
@@ -341,12 +371,15 @@ class SimWallets:
|
|||||||
conn.execute("DELETE FROM sim_perp_positions")
|
conn.execute("DELETE FROM sim_perp_positions")
|
||||||
conn.execute("DELETE FROM sim_option_positions")
|
conn.execute("DELETE FROM sim_option_positions")
|
||||||
conn.execute("DELETE FROM sim_option_orders")
|
conn.execute("DELETE FROM sim_option_orders")
|
||||||
now = self._now()
|
|
||||||
snap = {
|
snap = {
|
||||||
"funding_usdt": amt,
|
"funding_usdt": amt,
|
||||||
"trading_usdt": 0.0,
|
"trading_usdt": 0.0,
|
||||||
"funding_usdc": 0.0,
|
"funding_usdc": 0.0,
|
||||||
"trading_usdc": 0.0,
|
"trading_usdc": 0.0,
|
||||||
|
"funding_eth": 0.0,
|
||||||
|
"trading_eth": 0.0,
|
||||||
|
"funding_btc": 0.0,
|
||||||
|
"trading_btc": 0.0,
|
||||||
}
|
}
|
||||||
self._write(snap, conn=conn)
|
self._write(snap, conn=conn)
|
||||||
self._ledger(
|
self._ledger(
|
||||||
|
|||||||
Reference in New Issue
Block a user