修复币本位期权历史权利金/盈亏显示0.00;复盘盈亏按指数换算为U
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2560,11 +2560,25 @@
|
||||
}
|
||||
list.forEach(function (h) {
|
||||
const tr = document.createElement("tr");
|
||||
const premTxt = fmtDisplay(h.premium_paid_fmt, h.premium_paid != null ? fmtUsdc(h.premium_paid) : null);
|
||||
const ccy = posPremiumCcy(h);
|
||||
const premTxt =
|
||||
h.premium_paid != null && !Number.isNaN(Number(h.premium_paid))
|
||||
? fmtPremiumAmt(h.premium_paid, ccy) + (ccy !== "USDC" ? " " + ccy : "")
|
||||
: "—";
|
||||
const isOpen = h.status === "open";
|
||||
const pnl = isOpen ? null : h.realized_pnl;
|
||||
const pnlTxt = pnl != null ? fmt(pnl, 2) : "—";
|
||||
const pnlCls = pnl > 0 ? "pos-pnl-profit" : pnl < 0 ? "pos-pnl-loss" : "";
|
||||
let pnlTxt = "—";
|
||||
let pnlCls = "";
|
||||
if (pnl != null && !Number.isNaN(Number(pnl))) {
|
||||
const n = Number(pnl);
|
||||
pnlCls = n > 0 ? "pos-pnl-profit" : n < 0 ? "pos-pnl-loss" : "";
|
||||
if (ccy === "ETH" || ccy === "BTC") {
|
||||
const sign = n > 0 ? "+" : n < 0 ? "-" : "";
|
||||
pnlTxt = sign + fmtPremiumAmt(Math.abs(n), ccy) + " " + ccy;
|
||||
} else {
|
||||
pnlTxt = (n > 0 ? "+" : "") + fmt(n, 2);
|
||||
}
|
||||
}
|
||||
const timeTxt = (h.closed_at || h.created_at || "—").replace("T", " ").slice(0, 19);
|
||||
const histKey = h.history_key || "";
|
||||
tr.innerHTML =
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
if (v == null || v === "") return "—";
|
||||
var n = Number(v);
|
||||
if (Number.isNaN(n)) return "—";
|
||||
return (n >= 0 ? "+" : "") + n.toFixed(2);
|
||||
return (n >= 0 ? "+" : "") + n.toFixed(2) + "U";
|
||||
}
|
||||
|
||||
function fmtHold(sec) {
|
||||
|
||||
@@ -1456,6 +1456,15 @@ def format_option_history_row(
|
||||
ctime = _safe_float(raw.get("cTime"))
|
||||
opt_type, strike = option_fields_from_inst_id(inst_id)
|
||||
uly = str(raw.get("uly") or inst_id.split("-")[0] or "").replace("-USD_UM", "").replace("-USD", "")
|
||||
try:
|
||||
from lib.options.options_margin_mode_lib import margin_mode_from_inst_id, premium_ccy_for_mode
|
||||
|
||||
row_mode = margin_mode_from_inst_id(inst_id) if inst_id else "usdc"
|
||||
premium_ccy = premium_ccy_for_mode(row_mode, uly or "ETH")
|
||||
except Exception:
|
||||
row_mode = "usdc"
|
||||
premium_ccy = "USDC"
|
||||
idx_px = _safe_float(raw.get("idxPx") or raw.get("idx_px"))
|
||||
if close_type in ("3", "4"):
|
||||
status_label = "强平"
|
||||
else:
|
||||
@@ -1477,12 +1486,17 @@ def format_option_history_row(
|
||||
"strike": strike,
|
||||
"sheets": sheets_i,
|
||||
"eth_amount": eth_amount,
|
||||
"ct_mult": ct_mult,
|
||||
"open_avg_px": open_avg,
|
||||
"open_avg_px_fmt": format_option_px(open_avg, tick_sz) if open_avg is not None else None,
|
||||
"close_avg_px": close_avg,
|
||||
"close_avg_px_fmt": format_option_px(close_avg, tick_sz) if close_avg is not None else None,
|
||||
"premium_paid": premium_paid,
|
||||
"premium_paid_fmt": format_usdc_amount(premium_paid),
|
||||
"premium_paid_fmt": format_premium_amount(premium_paid, ccy=premium_ccy),
|
||||
"premium_ccy": premium_ccy,
|
||||
"margin_mode": row_mode,
|
||||
"margin_mode_label": "币本位" if row_mode == "coin" else "USDC",
|
||||
"idx_px": idx_px,
|
||||
"realized_pnl": realized,
|
||||
"pnl_ratio_pct": round(pnl_ratio * 100, 2) if pnl_ratio is not None else None,
|
||||
"status": "closed",
|
||||
@@ -1505,6 +1519,7 @@ def format_live_option_history_row(
|
||||
inst_id = str(row.get("inst_id") or "").strip()
|
||||
pos_id = str((row.get("raw") or {}).get("posId") or "").strip() or None
|
||||
close_ms = open_ms
|
||||
premium_ccy = str(row.get("premium_ccy") or "USDC").strip().upper() or "USDC"
|
||||
return {
|
||||
"source": "live",
|
||||
"history_key": option_history_row_key(
|
||||
@@ -1526,6 +1541,10 @@ def format_live_option_history_row(
|
||||
"close_avg_px_fmt": None,
|
||||
"premium_paid": row.get("premium_paid"),
|
||||
"premium_paid_fmt": row.get("premium_paid_fmt"),
|
||||
"premium_ccy": premium_ccy,
|
||||
"margin_mode": row.get("margin_mode"),
|
||||
"margin_mode_label": row.get("margin_mode_label"),
|
||||
"idx_px": row.get("idx_px"),
|
||||
"realized_pnl": row.get("upl"),
|
||||
"pnl_ratio_pct": row.get("upl_ratio_pct"),
|
||||
"status": "open",
|
||||
|
||||
@@ -3,7 +3,9 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from lib.exchange.okx_options_lib import format_premium_amount
|
||||
from lib.options.options_db import init_options_tables, sum_open_premium_paid
|
||||
from lib.options.options_margin_mode_lib import margin_mode_from_inst_id, premium_ccy_for_mode
|
||||
|
||||
|
||||
def enrich_position_row_display(
|
||||
@@ -14,8 +16,7 @@ def enrich_position_row_display(
|
||||
meta_cache: dict[str, dict[str, Any] | None] | None = None,
|
||||
premium_override: float | None = None,
|
||||
) -> dict[str, Any]:
|
||||
from lib.exchange.okx_options_lib import format_position_row, format_premium_amount, tick_sz_and_ct_mult
|
||||
from lib.options.options_margin_mode_lib import margin_mode_from_inst_id, premium_ccy_for_mode
|
||||
from lib.exchange.okx_options_lib import format_position_row, tick_sz_and_ct_mult
|
||||
|
||||
inst_id = str(raw_pos.get("instId") or "").strip()
|
||||
tick_sz, ct_mult = tick_sz_and_ct_mult(ex, inst_id, meta_cache)
|
||||
@@ -32,6 +33,59 @@ def enrich_position_row_display(
|
||||
return row
|
||||
|
||||
|
||||
def _safe_float(v: Any) -> float | None:
|
||||
if v is None or v == "":
|
||||
return None
|
||||
try:
|
||||
return float(v)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _load_local_closed_by_inst(conn: Any) -> dict[str, dict[str, Any]]:
|
||||
"""同合约取最新已平本地单,用于补交易所历史权利金/盈亏."""
|
||||
out: dict[str, dict[str, Any]] = {}
|
||||
try:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT inst_id, premium_paid, realized_pnl, premium_ccy, margin_mode,
|
||||
open_quote, close_quote, sheets, closed_at
|
||||
FROM options_trades
|
||||
WHERE status = 'closed'
|
||||
ORDER BY id DESC
|
||||
"""
|
||||
).fetchall()
|
||||
except Exception:
|
||||
return out
|
||||
for r in rows:
|
||||
inst = str(r["inst_id"] or "").strip()
|
||||
if not inst or inst in out:
|
||||
continue
|
||||
out[inst] = dict(r)
|
||||
return out
|
||||
|
||||
|
||||
def _overlay_local_closed(row: dict[str, Any], local: dict[str, Any] | None) -> dict[str, Any]:
|
||||
if not local:
|
||||
return row
|
||||
prem = _safe_float(row.get("premium_paid"))
|
||||
pnl = _safe_float(row.get("realized_pnl"))
|
||||
local_prem = _safe_float(local.get("premium_paid"))
|
||||
local_pnl = _safe_float(local.get("realized_pnl"))
|
||||
# 交易所缺数或被两位小数抹成 0 时,用本地币本位落库值
|
||||
if (prem is None or abs(prem) < 1e-10) and local_prem is not None and abs(local_prem) > 0:
|
||||
row["premium_paid"] = local_prem
|
||||
if (pnl is None or abs(pnl) < 1e-10) and local_pnl is not None and abs(local_pnl) > 0:
|
||||
row["realized_pnl"] = local_pnl
|
||||
if not row.get("premium_ccy") and local.get("premium_ccy"):
|
||||
row["premium_ccy"] = local.get("premium_ccy")
|
||||
if not row.get("margin_mode") and local.get("margin_mode"):
|
||||
row["margin_mode"] = local.get("margin_mode")
|
||||
ccy = str(row.get("premium_ccy") or "USDC").strip().upper() or "USDC"
|
||||
row["premium_paid_fmt"] = format_premium_amount(row.get("premium_paid"), ccy=ccy)
|
||||
return row
|
||||
|
||||
|
||||
def load_options_history(ex: Any, cfg: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""与期权历史页相同的数据源:交易所全平记录 + 当前持仓,排除本地隐藏项."""
|
||||
from lib.exchange.okx_options_lib import (
|
||||
@@ -55,6 +109,7 @@ def load_options_history(ex: Any, cfg: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
str(r["history_key"])
|
||||
for r in conn.execute("SELECT history_key FROM options_history_hidden").fetchall()
|
||||
}
|
||||
local_closed = _load_local_closed_by_inst(conn)
|
||||
for p in raw_live:
|
||||
inst = str(p.get("instId") or "").strip()
|
||||
premium_override = sum_open_premium_paid(conn, inst) if inst else None
|
||||
@@ -73,15 +128,16 @@ def load_options_history(ex: Any, cfg: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
except (TypeError, ValueError):
|
||||
open_ms = None
|
||||
items.append(format_live_option_history_row(row, open_ms=open_ms))
|
||||
|
||||
hist_raw = fetch_all_option_positions_history(ex, limit=200)
|
||||
for raw in hist_raw:
|
||||
inst_id = str(raw.get("instId") or "").strip()
|
||||
tick_sz, ct_mult = tick_sz_and_ct_mult(ex, inst_id, meta_cache)
|
||||
row = format_option_history_row(raw, tick_sz=tick_sz, ct_mult=ct_mult)
|
||||
items.append(_overlay_local_closed(row, local_closed.get(inst_id)))
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
hist_raw = fetch_all_option_positions_history(ex, limit=200)
|
||||
for raw in hist_raw:
|
||||
inst_id = str(raw.get("instId") or "").strip()
|
||||
tick_sz, ct_mult = tick_sz_and_ct_mult(ex, inst_id, meta_cache)
|
||||
items.append(format_option_history_row(raw, tick_sz=tick_sz, ct_mult=ct_mult))
|
||||
|
||||
open_rows = [x for x in items if x.get("status") == "open"]
|
||||
closed = [x for x in items if x.get("status") != "open"]
|
||||
closed.sort(key=lambda x: int(x.get("close_ms") or 0), reverse=True)
|
||||
|
||||
@@ -130,6 +130,9 @@ def init_options_review_tables(conn: sqlite3.Connection) -> None:
|
||||
_ensure_column(conn, "options_review_trades", "target_price_up", "REAL")
|
||||
_ensure_column(conn, "options_review_trades", "target_price_down", "REAL")
|
||||
_ensure_column(conn, "options_review_trades", "profit_rr", "REAL")
|
||||
_ensure_column(conn, "options_review_trades", "premium_ccy", "TEXT")
|
||||
_ensure_column(conn, "options_review_trades", "pnl_quote_ccy", "TEXT")
|
||||
_ensure_column(conn, "options_review_trades", "idx_px", "REAL")
|
||||
|
||||
|
||||
def _ensure_column(conn: sqlite3.Connection, table: str, col: str, typedef: str) -> None:
|
||||
|
||||
@@ -99,8 +99,140 @@ def _purge_review_trade_by_key(conn: sqlite3.Connection, history_key: str) -> bo
|
||||
return True
|
||||
|
||||
|
||||
def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) -> str:
|
||||
"""幂等写入纯期权快照;不触碰 options_review_entries;已隐藏的不再导入."""
|
||||
def _is_coin_option_row(row: dict[str, Any]) -> bool:
|
||||
ccy = str(row.get("premium_ccy") or "").strip().upper()
|
||||
if ccy in ("ETH", "BTC"):
|
||||
return True
|
||||
if str(row.get("margin_mode") or "").strip().lower() == "coin":
|
||||
return True
|
||||
inst = str(row.get("inst_id") or "").strip().upper()
|
||||
return bool(inst) and "-USD-" in inst and "_UM" not in inst
|
||||
|
||||
|
||||
def _resolve_review_index_px(
|
||||
row: dict[str, Any],
|
||||
*,
|
||||
ex: Any = None,
|
||||
cache: dict[str, float | None] | None = None,
|
||||
) -> Optional[float]:
|
||||
px = _safe_float(row.get("idx_px") or row.get("index_px") or row.get("options_index_px"))
|
||||
if px is not None and px > 0:
|
||||
return px
|
||||
underly = str(row.get("underlying") or "").strip().upper()
|
||||
if not underly:
|
||||
inst = str(row.get("inst_id") or "")
|
||||
underly = (inst.split("-")[0] if inst else "ETH").upper() or "ETH"
|
||||
if cache is not None and underly in cache:
|
||||
return cache[underly]
|
||||
if ex is None:
|
||||
return None
|
||||
try:
|
||||
from lib.exchange.okx_options_lib import fetch_index_price
|
||||
|
||||
got = fetch_index_price(ex, underly)
|
||||
px = _safe_float(got)
|
||||
if cache is not None:
|
||||
cache[underly] = px if px is not None and px > 0 else None
|
||||
return px if px is not None and px > 0 else None
|
||||
except Exception:
|
||||
if cache is not None:
|
||||
cache[underly] = None
|
||||
return None
|
||||
|
||||
|
||||
def convert_option_amounts_to_usdt(
|
||||
row: dict[str, Any],
|
||||
*,
|
||||
index_px: float | None = None,
|
||||
ex: Any = None,
|
||||
cache: dict[str, float | None] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""币本位权利金/盈亏换算为 USDT;已标记 pnl_quote_ccy=USDT 则跳过."""
|
||||
out = dict(row)
|
||||
quote = str(out.get("pnl_quote_ccy") or "").strip().upper()
|
||||
if quote in ("USDT", "USDC", "U"):
|
||||
return out
|
||||
if not _is_coin_option_row(out):
|
||||
out["pnl_quote_ccy"] = "USDT"
|
||||
return out
|
||||
px = index_px if index_px is not None and index_px > 0 else _resolve_review_index_px(
|
||||
out, ex=ex, cache=cache
|
||||
)
|
||||
if px is None or px <= 0:
|
||||
return out
|
||||
for key in ("realized_pnl", "premium_paid", "realized_pnl_total"):
|
||||
v = _safe_float(out.get(key))
|
||||
if v is not None:
|
||||
out[key] = round(float(v) * float(px), 4)
|
||||
out["idx_px"] = float(px)
|
||||
out["pnl_quote_ccy"] = "USDT"
|
||||
out["premium_ccy"] = "USDC"
|
||||
return out
|
||||
|
||||
|
||||
def repair_coin_review_rows_to_usdt(
|
||||
conn: sqlite3.Connection,
|
||||
*,
|
||||
ex: Any = None,
|
||||
) -> int:
|
||||
"""把仍按币计价落库的复盘纯期权行换算成 U(幂等)."""
|
||||
init_options_review_tables(conn)
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT * FROM options_review_trades
|
||||
WHERE source_type = ?
|
||||
AND (pnl_quote_ccy IS NULL OR TRIM(pnl_quote_ccy) = '' OR UPPER(pnl_quote_ccy) NOT IN ('USDT','USDC','U'))
|
||||
ORDER BY id DESC
|
||||
LIMIT 500
|
||||
""",
|
||||
(SOURCE_OPTION,),
|
||||
).fetchall()
|
||||
cache: dict[str, float | None] = {}
|
||||
fixed = 0
|
||||
for raw in rows:
|
||||
row = dict(raw)
|
||||
if not _is_coin_option_row(row):
|
||||
conn.execute(
|
||||
"UPDATE options_review_trades SET pnl_quote_ccy='USDT' WHERE id=?",
|
||||
(int(row["id"]),),
|
||||
)
|
||||
continue
|
||||
converted = convert_option_amounts_to_usdt(row, ex=ex, cache=cache)
|
||||
if str(converted.get("pnl_quote_ccy") or "").upper() not in ("USDT", "USDC", "U"):
|
||||
continue
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE options_review_trades
|
||||
SET premium_paid=?, realized_pnl=?, realized_pnl_total=?,
|
||||
premium_ccy=?, pnl_quote_ccy=?, idx_px=?
|
||||
WHERE id=?
|
||||
""",
|
||||
(
|
||||
converted.get("premium_paid"),
|
||||
converted.get("realized_pnl"),
|
||||
converted.get("realized_pnl")
|
||||
if converted.get("realized_pnl") is not None
|
||||
else converted.get("realized_pnl_total"),
|
||||
converted.get("premium_ccy") or "USDC",
|
||||
"USDT",
|
||||
converted.get("idx_px"),
|
||||
int(row["id"]),
|
||||
),
|
||||
)
|
||||
fixed += 1
|
||||
return fixed
|
||||
|
||||
|
||||
def upsert_option_history_row(
|
||||
conn: sqlite3.Connection,
|
||||
row: dict[str, Any],
|
||||
*,
|
||||
ex: Any = None,
|
||||
index_cache: dict[str, float | None] | None = None,
|
||||
) -> str:
|
||||
"""幂等写入纯期权快照;不触碰 options_review_entries;已隐藏的不再导入.
|
||||
币本位金额在写入前换算为 USDT.
|
||||
"""
|
||||
history_key = str(row.get("history_key") or "").strip()
|
||||
if not history_key:
|
||||
return "skip"
|
||||
@@ -112,6 +244,7 @@ def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) ->
|
||||
):
|
||||
# 若此前已导入,清掉,避免列表残留
|
||||
return "purged" if _purge_review_trade_by_key(conn, history_key) else "hidden"
|
||||
row = convert_option_amounts_to_usdt(row, ex=ex, cache=index_cache)
|
||||
opened_at = row.get("created_at") or row.get("opened_at")
|
||||
closed_at = row.get("closed_at")
|
||||
pnl = _safe_float(row.get("realized_pnl"))
|
||||
@@ -139,6 +272,9 @@ def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) ->
|
||||
"close_avg": _safe_float(row.get("close_avg_px") if row.get("close_avg_px") is not None else row.get("close_avg")),
|
||||
"premium_paid": _safe_float(row.get("premium_paid")),
|
||||
"realized_pnl": pnl,
|
||||
"premium_ccy": str(row.get("premium_ccy") or "USDC").strip().upper() or "USDC",
|
||||
"pnl_quote_ccy": str(row.get("pnl_quote_ccy") or "USDT").strip().upper() or "USDT",
|
||||
"idx_px": _safe_float(row.get("idx_px")),
|
||||
}
|
||||
cols = list(fields.keys())
|
||||
if existing:
|
||||
@@ -271,8 +407,14 @@ def hide_review_trade(conn: sqlite3.Connection, trade_id: int) -> dict[str, Any]
|
||||
|
||||
|
||||
|
||||
def sync_options_from_local_trades(conn: sqlite3.Connection) -> dict[str, Any]:
|
||||
"""从本地 options_trades 已平仓记录导入复盘快照(不访问交易所)."""
|
||||
def sync_options_from_local_trades(
|
||||
conn: sqlite3.Connection,
|
||||
*,
|
||||
ex: Any = None,
|
||||
) -> dict[str, Any]:
|
||||
"""从本地 options_trades 已平仓记录导入复盘快照(不访问交易所).
|
||||
币本位金额按指数换算为 USDT 后入库.
|
||||
"""
|
||||
init_options_review_tables(conn)
|
||||
from lib.options.options_db import init_options_tables
|
||||
|
||||
@@ -281,7 +423,8 @@ def sync_options_from_local_trades(conn: sqlite3.Connection) -> dict[str, Any]:
|
||||
"""
|
||||
SELECT id, inst_id, underlying, opt_type, strike, exp_time, sheets,
|
||||
open_quote, close_quote, premium_paid, realized_pnl,
|
||||
created_at, closed_at, signal_note, status
|
||||
created_at, closed_at, signal_note, status,
|
||||
margin_mode, premium_ccy
|
||||
FROM options_trades
|
||||
WHERE status = 'closed'
|
||||
ORDER BY id DESC
|
||||
@@ -289,6 +432,7 @@ def sync_options_from_local_trades(conn: sqlite3.Connection) -> dict[str, Any]:
|
||||
"""
|
||||
).fetchall()
|
||||
inserted = updated = skipped = 0
|
||||
index_cache: dict[str, float | None] = {}
|
||||
for r in rows:
|
||||
trade_id = int(r["id"])
|
||||
history_key = f"local_opt:{trade_id}"
|
||||
@@ -313,7 +457,11 @@ def sync_options_from_local_trades(conn: sqlite3.Connection) -> dict[str, Any]:
|
||||
"created_at": opened_at,
|
||||
"closed_at": closed_at,
|
||||
"status_label": "已平",
|
||||
"margin_mode": r["margin_mode"] if "margin_mode" in r.keys() else None,
|
||||
"premium_ccy": r["premium_ccy"] if "premium_ccy" in r.keys() else None,
|
||||
},
|
||||
ex=ex,
|
||||
index_cache=index_cache,
|
||||
)
|
||||
if action == "inserted":
|
||||
inserted += 1
|
||||
@@ -354,6 +502,7 @@ def sync_options_from_exchange(
|
||||
fmt = format_fn or format_option_history_row
|
||||
raw_rows = fetch(ex, limit=limit)
|
||||
meta_cache: dict[str, dict[str, Any] | None] = {}
|
||||
index_cache: dict[str, float | None] = {}
|
||||
inserted = updated = skipped = 0
|
||||
for raw in raw_rows:
|
||||
inst_id = str(raw.get("instId") or "").strip()
|
||||
@@ -363,7 +512,9 @@ def sync_options_from_exchange(
|
||||
except Exception:
|
||||
pass
|
||||
formatted = fmt(raw, tick_sz=tick_sz, ct_mult=ct_mult)
|
||||
action = upsert_option_history_row(conn, formatted)
|
||||
action = upsert_option_history_row(
|
||||
conn, formatted, ex=ex, index_cache=index_cache
|
||||
)
|
||||
if action == "inserted":
|
||||
inserted += 1
|
||||
elif action == "updated":
|
||||
@@ -552,7 +703,7 @@ def sync_all_review_sources(
|
||||
conn, ex, limit=options_limit, fetch_fn=fetch_fn, format_fn=format_fn
|
||||
)
|
||||
else:
|
||||
out["options"] = sync_options_from_local_trades(conn)
|
||||
out["options"] = sync_options_from_local_trades(conn, ex=ex)
|
||||
out["hedge"] = sync_hedge_plans_closed(conn)
|
||||
return out
|
||||
|
||||
@@ -579,7 +730,12 @@ def ensure_local_review_synced(
|
||||
backfill_hedge_option_legs_realized_pnl(conn, hist)
|
||||
except Exception:
|
||||
pass
|
||||
return sync_all_review_sources(conn, from_exchange=False)
|
||||
out = sync_all_review_sources(conn, ex=ex, from_exchange=False)
|
||||
try:
|
||||
out["repaired_usdt"] = repair_coin_review_rows_to_usdt(conn, ex=ex)
|
||||
except Exception:
|
||||
out["repaired_usdt"] = 0
|
||||
return out
|
||||
|
||||
|
||||
def _row_to_dict(row: Any) -> dict[str, Any]:
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""期权历史/复盘币本位金额."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from lib.exchange.okx_options_lib import format_option_history_row
|
||||
from lib.options.options_review_lib import convert_option_amounts_to_usdt
|
||||
|
||||
|
||||
class TestOptionsHistoryCoin(unittest.TestCase):
|
||||
def test_format_option_history_row_coin_premium_fmt(self) -> None:
|
||||
raw = {
|
||||
"instId": "ETH-USD-260822-2250-C",
|
||||
"openAvgPx": "0.02",
|
||||
"closeAvgPx": "0.03",
|
||||
"closeTotalPos": "2",
|
||||
"realizedPnl": "0.002",
|
||||
"pnlRatio": "0.5",
|
||||
"type": "2",
|
||||
"uTime": "1724146497000",
|
||||
"cTime": "1724126855000",
|
||||
"posId": "123",
|
||||
"uly": "ETH-USD",
|
||||
}
|
||||
row = format_option_history_row(raw, tick_sz="0.0001", ct_mult=0.1)
|
||||
self.assertEqual(row["margin_mode"], "coin")
|
||||
self.assertEqual(row["premium_ccy"], "ETH")
|
||||
self.assertAlmostEqual(float(row["premium_paid"]), 0.004, places=6)
|
||||
self.assertNotEqual(row["premium_paid_fmt"], "0.00")
|
||||
self.assertIn("0.004", str(row["premium_paid_fmt"]))
|
||||
|
||||
def test_convert_option_amounts_to_usdt(self) -> None:
|
||||
out = convert_option_amounts_to_usdt(
|
||||
{
|
||||
"inst_id": "ETH-USD-260822-2250-C",
|
||||
"premium_ccy": "ETH",
|
||||
"margin_mode": "coin",
|
||||
"premium_paid": 0.004,
|
||||
"realized_pnl": 0.002,
|
||||
},
|
||||
index_px=2000.0,
|
||||
)
|
||||
self.assertEqual(out["pnl_quote_ccy"], "USDT")
|
||||
self.assertEqual(out["premium_paid"], 8.0)
|
||||
self.assertEqual(out["realized_pnl"], 4.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user