diff --git a/.env.example b/.env.example
index b466ff0..c3a76c5 100644
--- a/.env.example
+++ b/.env.example
@@ -74,9 +74,9 @@ DAILY_START_CAPITAL=30
DAILY_LOSS_CAPITAL=20
# 日内盈利后基数(U)
DAILY_PROFIT_CAPITAL=50
-# BTC 默认杠杆倍数
+# 永期对冲·永续开仓杠杆(env 页「永期·永续杠杆」;页面未填时回退)
BTC_LEVERAGE=10
-# 山寨币默认杠杆倍数
+# ETH 永续开仓杠杆(键名沿用 ALT_LEVERAGE)
ALT_LEVERAGE=5
# 交易日重置小时(北京时间)
TRADING_DAY_RESET_HOUR=8
@@ -271,16 +271,14 @@ RECONCILE_FLAT_CONFIRM_POLLS=3
FULL_MARGIN_BUFFER_RATIO=0.98
# =============================================================================
-# 自动划转(页顶「将 swap 补足到 XU」;与 DAILY_START_CAPITAL 独立,需一致时请设为相同值)
+# 自动划转(CoinOX 已禁用,勿开启;保留键仅兼容旧 .env)
# =============================================================================
-AUTO_TRANSFER_ENABLED=false
-# 交易账户(swap)目标余额 U:每日 8 点(北京)自动划入或划出至 funding;持仓中不划转
-AUTO_TRANSFER_AMOUNT=30
-AUTO_TRANSFER_FROM=funding
-AUTO_TRANSFER_TO=swap
-TRANSFER_CCY=USDT
-# 北京时间该整点小时内尝试;账簿按 UTC 自然日去重
-AUTO_TRANSFER_BJ_HOUR=8
+# AUTO_TRANSFER_ENABLED=false
+# AUTO_TRANSFER_AMOUNT=30
+# AUTO_TRANSFER_FROM=funding
+# AUTO_TRANSFER_TO=swap
+# TRANSFER_CCY=USDT
+# AUTO_TRANSFER_BJ_HOUR=8
# 强制清仓整点(北京时间,默认 0=凌晨00点)
FORCE_CLOSE_BJ_HOUR=0
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
diff --git a/app.py b/app.py
index 07a108a..c0137a6 100644
--- a/app.py
+++ b/app.py
@@ -393,7 +393,8 @@ PRICE_REFRESH_SECONDS = int(os.getenv("PRICE_REFRESH_SECONDS", "5"))
KEY_ALERT_MAX_TIMES = int(os.getenv("KEY_ALERT_MAX_TIMES", "3"))
KEY_ALERT_INTERVAL_MINUTES = int(os.getenv("KEY_ALERT_INTERVAL_MINUTES", "5"))
KEY_BREAKOUT_LIMIT_PCT = float(os.getenv("KEY_BREAKOUT_LIMIT_PCT", "1.5"))
-AUTO_TRANSFER_ENABLED = os.getenv("AUTO_TRANSFER_ENABLED", "false").lower() == "true"
+# CoinOX 不提供自动划转(env 页已去掉该分区)
+AUTO_TRANSFER_ENABLED = False
AUTO_TRANSFER_AMOUNT = float(os.getenv("AUTO_TRANSFER_AMOUNT", "30"))
AUTO_TRANSFER_FROM = os.getenv("AUTO_TRANSFER_FROM", "funding")
AUTO_TRANSFER_TO = os.getenv("AUTO_TRANSFER_TO", "swap")
@@ -6974,6 +6975,8 @@ def render_main_page(page="trade", embed_mode=None):
hedge_plan_option_primary=os.getenv("HEDGE_PLAN_OPTION_PRIMARY", "true").lower()
in ("1", "true", "yes", "on"),
hedge_plan_budget_buffer=float(os.getenv("HEDGE_PLAN_BUDGET_BUFFER") or "0.95"),
+ hedge_plan_btc_leverage=int(BTC_LEVERAGE or 10),
+ hedge_plan_eth_leverage=int(ALT_LEVERAGE or 5),
options_trade_budget=OKX_OPTIONS_TRADE_BUDGET_USDC,
options_budget_buffer=float(os.getenv("OKX_OPTIONS_BUDGET_BUFFER") or "0.95"),
options_compound_full_enabled=os.getenv(
diff --git a/lib/common/static/hedge_plan.js b/lib/common/static/hedge_plan.js
index ad2bcc9..61644b2 100644
--- a/lib/common/static/hedge_plan.js
+++ b/lib/common/static/hedge_plan.js
@@ -40,6 +40,7 @@
optionPrimary: root.getAttribute("data-option-primary") !== "0",
opLevTouched: false,
opRatioTouched: false,
+ perpLevTouched: false,
tradingUsdc: null,
fundingUsdc: null,
tradeBudgetUsdc: null,
@@ -377,6 +378,14 @@
};
}
+ function defaultPerpLeverage(uly) {
+ const u = (uly || "ETH").toUpperCase();
+ const btc = Number(root.getAttribute("data-btc-leverage") || 10);
+ const eth = Number(root.getAttribute("data-eth-leverage") || 5);
+ if (u === "BTC") return Number.isFinite(btc) && btc > 0 ? btc : 10;
+ return Number.isFinite(eth) && eth > 0 ? eth : 5;
+ }
+
function syncUnderlyingUI() {
const uly = state.underlying || "ETH";
document.querySelectorAll(".hp-uly-btn, .hp-uly-btn-oo").forEach(function (b) {
@@ -388,6 +397,11 @@
if (lab) lab.textContent = uly;
const ooLab = $("hp-oo-uly-label");
if (ooLab) ooLab.textContent = uly;
+ // 永续开仓杠杆跟随 env(BTC_LEVERAGE / ALT_LEVERAGE=ETH)
+ const levEl = $("hp-perp-leverage");
+ if (levEl && !state.perpLevTouched) {
+ levEl.value = String(defaultPerpLeverage(uly));
+ }
}
function syncMoneyUI() {
@@ -1664,7 +1678,7 @@
strike_interval: numInput("hp-strike-interval", 15),
min_option_hours: numInput("hp-min-hours", 36),
option_leverage: numInput("hp-opt-leverage", 100),
- leverage: numInput("hp-perp-leverage", 100),
+ leverage: numInput("hp-perp-leverage", defaultPerpLeverage(state.underlying)),
moneyness: opMoneyKind(),
hours_to_expiry: exp ? hoursFromExpMs(exp.exp_time) : null,
};
@@ -1868,6 +1882,11 @@
renderListStrikes();
});
}
+ if ($("hp-perp-leverage")) {
+ $("hp-perp-leverage").addEventListener("input", function () {
+ state.perpLevTouched = true;
+ });
+ }
if ($("hp-opt-leverage")) {
$("hp-opt-leverage").addEventListener("input", function () {
state.opLevTouched = true;
@@ -2618,7 +2637,7 @@
strike_interval: numInput("hp-strike-interval", 15),
min_option_hours: numInput("hp-min-hours", 36),
option_leverage: optLev,
- leverage: numInput("hp-perp-leverage", 100),
+ leverage: numInput("hp-perp-leverage", defaultPerpLeverage(state.underlying)),
moneyness: opMoneyKind(),
};
const d = await apiJson("/api/hedge-plan/start", {
@@ -2684,7 +2703,7 @@
ask: state.selected.ask,
index_px: entry,
exchange_symbol: (state.market && state.market.exchange_symbol) || "",
- leverage: numInput("hp-perp-leverage", 100),
+ leverage: numInput("hp-perp-leverage", defaultPerpLeverage(state.underlying)),
option_leverage: numInput("hp-opt-leverage", 100),
premium_budget: numInput("hp-premium-budget", 0),
option_perp_ratio: numInput("hp-opt-perp-ratio", 2),
diff --git a/lib/env/env_ui_manifest.py b/lib/env/env_ui_manifest.py
index 7fb6e32..079a6de 100644
--- a/lib/env/env_ui_manifest.py
+++ b/lib/env/env_ui_manifest.py
@@ -119,7 +119,7 @@ _SHARED_SECTIONS: list[dict[str, Any]] = [
},
]
-# CoinOX env 页:去掉关键位/AI复盘/永续手工单等无关项
+# CoinOX env 页:去掉关键位/AI复盘/自动划转等无关项
_COINOX_SHARED_SECTIONS: list[dict[str, Any]] = [
{
"title": "企业微信",
@@ -129,14 +129,18 @@ _COINOX_SHARED_SECTIONS: list[dict[str, Any]] = [
],
},
{
- "title": "资金与杠杆",
+ "title": "永期·永续杠杆",
"fields": [
- ("POSITION_SIZING_MODE", "计仓模式", "切换须无仓后重启"),
- ("RISK_PERCENT", "以损定仓风险%", "单笔风险占资金比例"),
- ("FULL_MARGIN_BUFFER_RATIO", "全仓资金缓冲比例", "如 0.98"),
- ("BTC_LEVERAGE", "BTC 默认杠杆", ""),
- ("ALT_LEVERAGE", "山寨默认杠杆", ""),
- ("TRADING_DAY_RESET_HOUR", "交易日切点(北京时间)", "整点,默认 8"),
+ (
+ "BTC_LEVERAGE",
+ "BTC 永续开仓杠杆",
+ "永期对冲开永续腿时用;页面未填杠杆时回退本值",
+ ),
+ (
+ "ALT_LEVERAGE",
+ "ETH 永续开仓杠杆",
+ "永期对冲开 ETH-USDT 永续时用;页面未填杠杆时回退本值",
+ ),
],
},
{
@@ -147,17 +151,6 @@ _COINOX_SHARED_SECTIONS: list[dict[str, Any]] = [
("SIM_FEE_RATE", "模拟手续费率", "默认 0.0005"),
],
},
- {
- "title": "自动划转",
- "fields": [
- ("AUTO_TRANSFER_ENABLED", "启用自动划转", ""),
- ("AUTO_TRANSFER_AMOUNT", "目标余额(U)", "交易账户目标 USDT"),
- ("AUTO_TRANSFER_FROM", "划出账户", "余额不足时从此账户划入交易账户"),
- ("AUTO_TRANSFER_TO", "划入账户", "目标余额所在账户,一般为 swap"),
- ("AUTO_TRANSFER_BJ_HOUR", "执行整点(北京时间)", ""),
- ("TRANSFER_CCY", "划转币种", ""),
- ],
- },
]
_MODE_SECTION: dict[str, Any] = {
diff --git a/lib/hedge_plan/hedge_plan_register.py b/lib/hedge_plan/hedge_plan_register.py
index 926b1a1..8cdd9f0 100644
--- a/lib/hedge_plan/hedge_plan_register.py
+++ b/lib/hedge_plan/hedge_plan_register.py
@@ -845,18 +845,19 @@ def register_hedge_plan_routes(app: Flask, cfg: dict[str, Any]) -> None:
err = validate_start_body(plan_type, body)
if err:
return jsonify({"ok": False, "msg": err, "gates": gates}), 400
- # 补齐永续杠杆(以期权为主默认 100;保险模式 BTC/ETH 用 btc_leverage)
+ # 补齐永续杠杆:页面未填时用 env(BTC_LEVERAGE / ALT_LEVERAGE=ETH)
if plan_type == "perp_options" and not body.get("leverage"):
from lib.hedge_plan.hedge_plan_option_primary_lib import is_option_primary
- if is_option_primary(body):
+ base = str(body.get("underlying") or "ETH").upper()
+ if base == "BTC":
+ body["leverage"] = int(cfg.get("btc_leverage") or 10)
+ elif base == "ETH":
+ body["leverage"] = int(cfg.get("alt_leverage") or cfg.get("btc_leverage") or 10)
+ elif is_option_primary(body):
body["leverage"] = 100
else:
- base = str(body.get("underlying") or "ETH").upper()
- if base in ("BTC", "ETH"):
- body["leverage"] = int(cfg.get("btc_leverage") or 10)
- else:
- body["leverage"] = int(cfg.get("alt_leverage") or 5)
+ body["leverage"] = int(cfg.get("alt_leverage") or 5)
# 以期权为主:策略启动=盯盘,不现场开仓
if plan_type == "perp_options":
from lib.hedge_plan.hedge_plan_option_primary_lib import is_option_primary
diff --git a/lib/hedge_plan/templates/hedge_plan_panel.html b/lib/hedge_plan/templates/hedge_plan_panel.html
index 458f350..9bc7a10 100644
--- a/lib/hedge_plan/templates/hedge_plan_panel.html
+++ b/lib/hedge_plan/templates/hedge_plan_panel.html
@@ -7,6 +7,8 @@
data-oo-close-mode-enabled="{{ '1' if hedge_plan_oo_close_mode_enabled else '0' }}"
data-option-primary="{{ '1' if hedge_plan_option_primary|default(true) else '0' }}"
data-budget-buffer="{{ hedge_plan_budget_buffer | default(0.95) }}"
+ data-btc-leverage="{{ hedge_plan_btc_leverage | default(10) }}"
+ data-eth-leverage="{{ hedge_plan_eth_leverage | default(5) }}"
data-sizing-mode="{{ position_sizing_mode | default('risk') }}"
data-is-full-margin="{{ '1' if position_sizing_mode == 'full_margin' else '0' }}">
{% if not hedge_plan_enabled %}
@@ -96,8 +98,8 @@