Merge OKX dual APIs into one OKX_API_* account for perp and options.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-05 21:28:33 +08:00
parent 22e6b68e6d
commit 09a763e47d
26 changed files with 166 additions and 473 deletions
+11 -10
View File
@@ -79,11 +79,12 @@ TRADING_DAY_RESET_OPEN_GUARD_ENABLED=true
# 是否开启 OKX 实盘下单(false=只做本地流程,true=真实下单)
LIVE_TRADING_ENABLED=true
# OKX API Key(实盘)
# =============================================================================
# OKX 账户 API(永续 + 期权共用同一套密钥;修改后须重启 PM2)
# 旧键 OKX_OPTIONS_API_* 已废弃:若 OKX_API_* 为空,启动时会从 OPTIONS 键回填
# =============================================================================
OKX_API_KEY=REPLACE_WITH_OKX_API_KEY
# OKX API Secret(实盘)
OKX_API_SECRET=REPLACE_WITH_OKX_API_SECRET
# OKX API Passphrase(实盘)
OKX_API_PASSPHRASE=REPLACE_WITH_OKX_API_PASSPHRASE
# 保证金模式:cross=全仓,isolated=逐仓
OKX_TD_MODE=cross
@@ -99,18 +100,19 @@ OKX_POSITION_INST_TYPE=SWAP
EXCHANGE_DISPLAY_NAME=OKX
# 企业微信推送里展示的账户备注
# OKX_ACCOUNT_LABEL=
# 顶栏是否显示永续资金账户/交易账户(热更);false 时总资金仅计期权侧
# 顶栏是否显示 USDT 资金/交易账户(热更);false 时总资金仅计期权 USDC
OKX_SHOW_PERP_FUNDS=true
# =============================================================================
# 期权(主账户 API,与永续子账户 OKX_API_* 分离;修改后须重启 PM2)
# 期权模块(与上方 OKX_API_* 同源;修改启用开关后须重启 PM2)
# 详见 docs/期权方案.md 与 docs/期权用法.md
# =============================================================================
OKX_OPTIONS_ENABLED=false
OKX_OPTIONS_API_KEY=
OKX_OPTIONS_API_SECRET=
OKX_OPTIONS_API_PASSPHRASE=
OKX_OPTIONS_ACCOUNT_LABEL=主账户·期权
# 以下 OKX_OPTIONS_API_* 已废弃,请勿再配置(仅兼容旧部署回填)
# OKX_OPTIONS_API_KEY=
# OKX_OPTIONS_API_SECRET=
# OKX_OPTIONS_API_PASSPHRASE=
OKX_OPTIONS_ACCOUNT_LABEL=账户·期权
OKX_OPTIONS_TRADE_BUDGET_USDC=10
OKX_OPTIONS_BUDGET_BUFFER=0.95
# 交易模式三选一(热更):options=单独期权 / perp_options=永期对冲 / options_options=期期对冲
@@ -123,7 +125,6 @@ OKX_OPTIONS_DEFAULT_UNDERLY=ETH
OKX_OPTIONS_CHAIN_ASK_LIQ_FILTER_ENABLED=true
OKX_OPTIONS_MAX_DTE_DAYS=2
OKX_OPTIONS_CHAIN_MAX_DTE_DAYS=14
OKX_SUB_ACCOUNT_NAME=
OKX_OPTIONS_ITM_MAX_DIST_USD=30
OKX_OPTIONS_PROFIT_ALERT_RATIO=1.0
OKX_OPTIONS_POLL_SECONDS=15
+26 -13
View File
@@ -343,16 +343,29 @@ def _resolve_app_tz():
APP_TZ = _resolve_app_tz()
LIVE_TRADING_ENABLED = os.getenv("LIVE_TRADING_ENABLED", "false").lower() == "true"
def _promote_legacy_options_api_keys() -> None:
"""1B: OKX_API_* 为空时,用废弃的 OKX_OPTIONS_API_* 回填到进程环境."""
if (os.getenv("OKX_API_KEY") or "").strip():
return
legacy_key = (os.getenv("OKX_OPTIONS_API_KEY") or "").strip()
legacy_secret = (os.getenv("OKX_OPTIONS_API_SECRET") or "").strip()
legacy_pass = (os.getenv("OKX_OPTIONS_API_PASSPHRASE") or "").strip()
if not (legacy_key and legacy_secret and legacy_pass):
return
os.environ["OKX_API_KEY"] = legacy_key
os.environ["OKX_API_SECRET"] = legacy_secret
os.environ["OKX_API_PASSPHRASE"] = legacy_pass
_promote_legacy_options_api_keys()
OKX_API_KEY = os.getenv("OKX_API_KEY", "")
OKX_API_SECRET = os.getenv("OKX_API_SECRET", "")
OKX_API_PASSPHRASE = os.getenv("OKX_API_PASSPHRASE", "")
OKX_OPTIONS_ENABLED = os.getenv("OKX_OPTIONS_ENABLED", "false").lower() in ("1", "true", "yes", "on")
OKX_OPTIONS_API_KEY = os.getenv("OKX_OPTIONS_API_KEY", "")
OKX_OPTIONS_API_SECRET = os.getenv("OKX_OPTIONS_API_SECRET", "")
OKX_OPTIONS_API_PASSPHRASE = os.getenv("OKX_OPTIONS_API_PASSPHRASE", "")
OKX_OPTIONS_TRADE_BUDGET_USDC = float(os.getenv("OKX_OPTIONS_TRADE_BUDGET_USDC", "10"))
OKX_OPTIONS_DEFAULT_UNDERLY = (os.getenv("OKX_OPTIONS_DEFAULT_UNDERLY") or "ETH").strip().upper()
OKX_SUB_ACCOUNT_NAME = (os.getenv("OKX_SUB_ACCOUNT_NAME") or "").strip()
OKX_TD_MODE = os.getenv("OKX_TD_MODE", "cross")
OKX_POS_MODE = os.getenv("OKX_POS_MODE", "hedge")
EXCHANGE_DISPLAY_NAME = (os.getenv("EXCHANGE_DISPLAY_NAME") or "OKX").strip() or "OKX"
@@ -467,7 +480,7 @@ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(ORDER_CHART_DIR, exist_ok=True)
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
# 换成 OKX 永续
# 同一套 OKX_API_*:swap 客户端跑永续,option 客户端跑期权(身份相同,defaultType 不同)
exchange = ccxt.okx({
"enableRateLimit": True,
"options": {"defaultType": "swap"}, # OKX 用 swap 表示永续
@@ -487,10 +500,10 @@ exchange_options = ccxt.okx(
)
if OKX_CCXT_PROXIES:
exchange_options.proxies = OKX_CCXT_PROXIES
if OKX_OPTIONS_API_KEY and OKX_OPTIONS_API_SECRET and OKX_OPTIONS_API_PASSPHRASE:
exchange_options.apiKey = OKX_OPTIONS_API_KEY
exchange_options.secret = OKX_OPTIONS_API_SECRET
exchange_options.password = OKX_OPTIONS_API_PASSPHRASE
if OKX_API_KEY and OKX_API_SECRET and OKX_API_PASSPHRASE:
exchange_options.apiKey = OKX_API_KEY
exchange_options.secret = OKX_API_SECRET
exchange_options.password = OKX_API_PASSPHRASE
MARKETS_LOADED = False
ACCOUNT_BALANCE_CACHE = {
@@ -6755,8 +6768,8 @@ def render_main_page(page="trade", embed_mode=None):
current_capital if _show_perp_funds else None,
options_trading_usdc,
options_funding_usdc,
options_funding_usdt,
options_trading_usdt,
None,
None,
),
options_funding_usdc=options_funding_usdc,
options_funding_usdt=options_funding_usdt,
@@ -7097,8 +7110,8 @@ def api_account_snapshot():
current_capital if _show_perp_funds else None,
options_trading_usdc,
options_funding_usdc,
options_funding_usdt,
options_trading_usdt,
None,
None,
),
"available_trading_usdt": round(available_trading_usdt, FUNDS_DECIMALS) if available_trading_usdt is not None else None,
"unrealized_pnl": unrealized_pnl,