交易所 API 改为仅服务器配置:前端去掉密钥、新机示例为空,并防止坏钥反复请求触发 Gate 封 IP。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -76,10 +76,9 @@ TRADING_DAY_RESET_OPEN_GUARD_ENABLED=true
|
||||
|
||||
# 是否开启 Binance 实盘下单(false=只做本地流程,true=真实下单)
|
||||
LIVE_TRADING_ENABLED=true
|
||||
# Binance API Key(需开通合约,万向划转等权限)
|
||||
BINANCE_API_KEY=REPLACE_WITH_BINANCE_API_KEY
|
||||
# Binance API Secret
|
||||
BINANCE_API_SECRET=REPLACE_WITH_BINANCE_API_SECRET
|
||||
# Binance API(仅服务器 .env 配置;新机保持为空,填真钥后 pm2 restart --update-env;勿用占位符以免鉴权狂打)
|
||||
BINANCE_API_KEY=
|
||||
BINANCE_API_SECRET=
|
||||
# 保证金模式:cross=全仓,isolated=逐仓
|
||||
BINANCE_MARGIN_MODE=cross
|
||||
# 持仓模式:hedge=双向(需账户开启双向持仓,下单带 positionSide);oneway=单向
|
||||
|
||||
@@ -35,6 +35,11 @@ import sys
|
||||
if _REPO_ROOT not in sys.path:
|
||||
sys.path.insert(0, _REPO_ROOT)
|
||||
from lib.paths import common_static_dir
|
||||
from lib.exchange.api_credentials_lib import (
|
||||
is_exchange_auth_error,
|
||||
load_markets_public_fallback,
|
||||
normalize_api_credential,
|
||||
)
|
||||
from lib.ai.ai_client import ai_generate, ai_review, ai_short_advice
|
||||
from lib.ai.ai_review_lib import (
|
||||
build_journal_ai_chart_path,
|
||||
@@ -347,8 +352,8 @@ def _resolve_app_tz():
|
||||
|
||||
APP_TZ = _resolve_app_tz()
|
||||
LIVE_TRADING_ENABLED = os.getenv("LIVE_TRADING_ENABLED", "false").lower() == "true"
|
||||
BINANCE_API_KEY = (os.getenv("BINANCE_API_KEY") or "").strip()
|
||||
BINANCE_API_SECRET = (os.getenv("BINANCE_API_SECRET") or "").strip()
|
||||
BINANCE_API_KEY = normalize_api_credential(os.getenv("BINANCE_API_KEY"))
|
||||
BINANCE_API_SECRET = normalize_api_credential(os.getenv("BINANCE_API_SECRET"))
|
||||
BINANCE_MARGIN_MODE = (os.getenv("BINANCE_MARGIN_MODE") or "cross").strip().lower()
|
||||
# hedge=双向持仓(需 positionSide);oneway / single=单向持仓
|
||||
_raw_binance_pos = (os.getenv("BINANCE_POSITION_MODE") or "hedge").strip().lower()
|
||||
@@ -490,6 +495,8 @@ if BINANCE_API_KEY and BINANCE_API_SECRET:
|
||||
exchange.apiKey = BINANCE_API_KEY
|
||||
exchange.secret = BINANCE_API_SECRET
|
||||
MARKETS_LOADED = False
|
||||
# 鉴权失败后停止私有 API(资金/持仓),避免坏钥反复请求;尤其 Gate 易封 IP
|
||||
EXCHANGE_AUTH_DISABLED_MSG = ""
|
||||
ACCOUNT_BALANCE_CACHE = {
|
||||
"updated_at": 0.0,
|
||||
"funding_usdt": None,
|
||||
@@ -2859,6 +2866,8 @@ def enrich_order_item(raw_item, current_capital):
|
||||
|
||||
|
||||
def ensure_exchange_live_ready():
|
||||
if EXCHANGE_AUTH_DISABLED_MSG:
|
||||
return False, EXCHANGE_AUTH_DISABLED_MSG
|
||||
if not LIVE_TRADING_ENABLED:
|
||||
return False, "未开启实盘下单(LIVE_TRADING_ENABLED=false)"
|
||||
if not (BINANCE_API_KEY and BINANCE_API_SECRET):
|
||||
@@ -2893,9 +2902,23 @@ def order_row_key_signal_type(row):
|
||||
|
||||
def exchange_private_api_configured():
|
||||
"""仅表示已配置密钥;与是否允许下单(LIVE_TRADING_ENABLED)无关,用于只读拉仓等."""
|
||||
if EXCHANGE_AUTH_DISABLED_MSG:
|
||||
return False
|
||||
return bool(BINANCE_API_KEY and BINANCE_API_SECRET)
|
||||
|
||||
|
||||
def _disable_private_api_after_auth_error(exc):
|
||||
global EXCHANGE_AUTH_DISABLED_MSG, BINANCE_API_KEY, BINANCE_API_SECRET
|
||||
from lib.exchange.api_credentials_lib import strip_ccxt_credentials
|
||||
|
||||
strip_ccxt_credentials(exchange)
|
||||
BINANCE_API_KEY = ""
|
||||
BINANCE_API_SECRET = ""
|
||||
EXCHANGE_AUTH_DISABLED_MSG = (
|
||||
f"API 鉴权失败,已停止私有请求(请在服务器 .env 修正密钥后重启): {exc}"
|
||||
)
|
||||
|
||||
|
||||
def _float_balance_field(val):
|
||||
if val is None or val == "":
|
||||
return None
|
||||
@@ -3178,11 +3201,15 @@ def get_exchange_capitals(force=False):
|
||||
return ACCOUNT_BALANCE_CACHE["funding_usdt"], ACCOUNT_BALANCE_CACHE["trading_usdt"]
|
||||
try:
|
||||
ACCOUNT_BALANCE_CACHE["funding_usdt"] = _fetch_binance_funding_usdt()
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if is_exchange_auth_error(e):
|
||||
_disable_private_api_after_auth_error(e)
|
||||
ACCOUNT_BALANCE_CACHE["funding_usdt"] = None
|
||||
try:
|
||||
ACCOUNT_BALANCE_CACHE["trading_usdt"] = _fetch_binance_swap_usdt_total()
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if is_exchange_auth_error(e):
|
||||
_disable_private_api_after_auth_error(e)
|
||||
# 勿保留上一次成功请求的旧值:鉴权失败时否则会误以为「合约余额仍能读」
|
||||
ACCOUNT_BALANCE_CACHE["trading_usdt"] = None
|
||||
ACCOUNT_BALANCE_CACHE["updated_at"] = now_ts
|
||||
@@ -3585,7 +3612,15 @@ def calc_trend_manual_breakeven_stop(direction, entry_price, offset_pct=None):
|
||||
def ensure_markets_loaded(force=False):
|
||||
global MARKETS_LOADED
|
||||
if force or not MARKETS_LOADED:
|
||||
exchange.load_markets(reload=force)
|
||||
try:
|
||||
exchange.load_markets(reload=force)
|
||||
except Exception as e:
|
||||
# 坏钥时立刻去掉签名再拉公开 markets,避免反复鉴权(尤其勿拖累同机 Gate)
|
||||
if is_exchange_auth_error(e) and (getattr(exchange, "apiKey", None) or getattr(exchange, "secret", None)):
|
||||
_disable_private_api_after_auth_error(e)
|
||||
load_markets_public_fallback(exchange, reload=True)
|
||||
else:
|
||||
raise
|
||||
MARKETS_LOADED = True
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user