优化前改动

This commit is contained in:
ddrwode
2026-02-06 14:32:24 +08:00
parent e22048fe0d
commit c58f020e9e

View File

@@ -149,6 +149,35 @@ class BitmartFuturesTransactionConservative:
self.auto_optimize_script_path = Path(__file__).with_name("optimize_params.py")
self.auto_optimized_this_run = False
# 方案B智能动态模式
self.enable_smart_mode = os.getenv("BITMART_SMART_MODE_ENABLED", "1").strip().lower() not in {"0", "false", "off", "no"}
# 波动率分档阈值(单位:百分比)
self.vol_regime_low_threshold_pct = float(os.getenv("BITMART_VOL_REGIME_LOW_PCT", "0.22"))
self.vol_regime_high_threshold_pct = float(os.getenv("BITMART_VOL_REGIME_HIGH_PCT", "0.45"))
self.mid_vol_order_size_multiplier = float(os.getenv("BITMART_MID_VOL_SIZE_MULT", "0.7"))
self.high_vol_order_size_multiplier = float(os.getenv("BITMART_HIGH_VOL_SIZE_MULT", "0.3"))
self.high_vol_pause_trading = os.getenv("BITMART_HIGH_VOL_PAUSE", "1").strip().lower() not in {"0", "false", "off", "no"}
self.mid_vol_stop_loss_multiplier = float(os.getenv("BITMART_MID_VOL_SL_MULT", "0.85"))
self.high_vol_stop_loss_multiplier = float(os.getenv("BITMART_HIGH_VOL_SL_MULT", "0.70"))
# 时间过滤:亚洲时段 + 跳过换线小时
self.trade_asia_session_only = os.getenv("BITMART_ASIA_SESSION_ONLY", "1").strip().lower() not in {"0", "false", "off", "no"}
self.asia_session_start_hour_utc = int(os.getenv("BITMART_ASIA_START_HOUR_UTC", "1"))
self.asia_session_end_hour_utc = int(os.getenv("BITMART_ASIA_END_HOUR_UTC", "10"))
self.blocked_utc_hours_utc = self._parse_int_set_csv(os.getenv("BITMART_BLOCKED_UTC_HOURS", "0,8,16"), {0, 8, 16})
# 日内盈亏管理
self.daily_profit_reduce_size_usd = float(os.getenv("BITMART_DAILY_PROFIT_REDUCE_SIZE_USD", "8"))
self.daily_reduced_size_multiplier = float(os.getenv("BITMART_DAILY_REDUCED_SIZE_MULT", "0.5"))
self.daily_max_loss_usd = float(os.getenv("BITMART_DAILY_MAX_LOSS_USD", "-10"))
self.daily_halt_on_loss = os.getenv("BITMART_DAILY_HALT_ON_LOSS", "1").strip().lower() not in {"0", "false", "off", "no"}
self.daily_balance_refresh_seconds = float(os.getenv("BITMART_DAILY_BALANCE_REFRESH_SECONDS", "15"))
self.daily_stat_day = None
self.daily_start_balance = None
self.daily_current_balance = None
self.daily_pnl_usd = 0.0
self.daily_halt = False
self.last_daily_balance_refresh_time = 0.0
self.last_smart_status_log_time = 0.0
# 启动时尝试读取动态参数(可由优化脚本自动生成)
self.load_runtime_params()
self.capture_base_risk_params()
@@ -203,6 +232,22 @@ class BitmartFuturesTransactionConservative:
"dynamic_vol_target_pct",
"dynamic_scale_min",
"dynamic_scale_max",
"enable_smart_mode",
"vol_regime_low_threshold_pct",
"vol_regime_high_threshold_pct",
"mid_vol_order_size_multiplier",
"high_vol_order_size_multiplier",
"high_vol_pause_trading",
"mid_vol_stop_loss_multiplier",
"high_vol_stop_loss_multiplier",
"trade_asia_session_only",
"asia_session_start_hour_utc",
"asia_session_end_hour_utc",
"blocked_utc_hours_utc",
"daily_profit_reduce_size_usd",
"daily_reduced_size_multiplier",
"daily_max_loss_usd",
"daily_halt_on_loss",
}
try:
@@ -218,8 +263,23 @@ class BitmartFuturesTransactionConservative:
continue
if key == "leverage":
setattr(self, key, str(value))
elif key in {"dynamic_risk_enabled", "enable_shadow_reverse", "enable_trend_filter", "enable_ai_filter"}:
elif key in {
"dynamic_risk_enabled",
"enable_shadow_reverse",
"enable_trend_filter",
"enable_ai_filter",
"enable_smart_mode",
"high_vol_pause_trading",
"trade_asia_session_only",
"daily_halt_on_loss",
}:
setattr(self, key, self._to_bool(value))
elif key == "blocked_utc_hours_utc":
if isinstance(value, (list, tuple, set)):
parsed = {int(v) for v in value if str(v).strip().isdigit()}
setattr(self, key, {h for h in parsed if 0 <= h <= 23} or {0, 8, 16})
else:
setattr(self, key, self._parse_int_set_csv(str(value), {0, 8, 16}))
else:
setattr(self, key, value)
@@ -232,7 +292,8 @@ class BitmartFuturesTransactionConservative:
f"BreakoutBuf={self.open_breakout_buffer_pct}%, "
f"OpenCD={self.open_cooldown_seconds}s, ReverseCD={self.reverse_cooldown_seconds}s, "
f"ReverseMove={self.reverse_min_move_pct}%, "
f"TrendFilter={self.enable_trend_filter}, AIFilter={self.enable_ai_filter}"
f"TrendFilter={self.enable_trend_filter}, AIFilter={self.enable_ai_filter}, "
f"SmartMode={self.enable_smart_mode}"
)
except Exception as e:
logger.error(f"加载动态参数文件失败: {e} | path={params_path}")
@@ -470,9 +531,155 @@ class BitmartFuturesTransactionConservative:
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
return False
def _parse_int_set_csv(self, text, default):
if not text:
return set(default)
result = set()
for item in str(text).split(","):
token = item.strip()
if not token:
continue
try:
value = int(token)
except Exception:
continue
if 0 <= value <= 23:
result.add(value)
return result or set(default)
def _clip(self, value, low, high):
return max(low, min(high, value))
def _normalize_hour(self, hour):
return int(hour) % 24
def _utc_hour(self, ts=None):
return int(time.strftime("%H", time.gmtime(ts if ts is not None else time.time())))
def _utc_day(self, ts=None):
return time.strftime("%Y-%m-%d", time.gmtime(ts if ts is not None else time.time()))
def _is_hour_in_range(self, hour, start, end):
hour = self._normalize_hour(hour)
start = self._normalize_hour(start)
end = self._normalize_hour(end)
if start <= end:
return start <= hour <= end
return hour >= start or hour <= end
def infer_volatility_regime(self):
vol_pct = self.get_recent_volatility_pct_from_cache(20)
if vol_pct is None:
return "unknown", None
low_th = max(0.0, float(self.vol_regime_low_threshold_pct))
high_th = max(low_th, float(self.vol_regime_high_threshold_pct))
if vol_pct >= high_th:
return "high", vol_pct
if vol_pct <= low_th:
return "low", vol_pct
return "mid", vol_pct
def refresh_daily_pnl_state(self, force=False):
now = time.time()
day = self._utc_day(now)
if self.daily_stat_day != day:
self.daily_stat_day = day
self.daily_start_balance = None
self.daily_current_balance = None
self.daily_pnl_usd = 0.0
self.daily_halt = False
self.last_daily_balance_refresh_time = 0.0
logger.info(f"日内风控重置: day={day}")
if not force and (now - self.last_daily_balance_refresh_time) < self.daily_balance_refresh_seconds:
return
balance = self.get_available_balance()
self.last_daily_balance_refresh_time = now
if balance is None:
return
self.daily_current_balance = float(balance)
if self.daily_start_balance is None:
self.daily_start_balance = float(balance)
logger.info(f"日内风控基准余额: {self.daily_start_balance:.4f} USDT")
self.daily_pnl_usd = float(self.daily_current_balance - self.daily_start_balance)
if self.daily_halt_on_loss and self.daily_pnl_usd <= float(self.daily_max_loss_usd):
if not self.daily_halt:
logger.warning(
f"触发日内亏损熔断: DailyPnL={self.daily_pnl_usd:.2f} <= {self.daily_max_loss_usd:.2f}"
)
self.daily_halt = True
def get_smart_trade_controls(self):
controls = {
"vol_regime": "unknown",
"vol_pct": None,
"size_multiplier": 1.0,
"stop_loss_multiplier": 1.0,
"allow_new_trade": True,
"block_reason": "",
"daily_pnl_usd": self.daily_pnl_usd,
"daily_halt": self.daily_halt,
}
if not self.enable_smart_mode:
return controls
# 1) 波动率分档
vol_regime, vol_pct = self.infer_volatility_regime()
controls["vol_regime"] = vol_regime
controls["vol_pct"] = vol_pct
if vol_regime == "mid":
controls["size_multiplier"] *= max(0.05, float(self.mid_vol_order_size_multiplier))
controls["stop_loss_multiplier"] *= max(0.05, float(self.mid_vol_stop_loss_multiplier))
elif vol_regime == "high":
controls["size_multiplier"] *= max(0.05, float(self.high_vol_order_size_multiplier))
controls["stop_loss_multiplier"] *= max(0.05, float(self.high_vol_stop_loss_multiplier))
if self.high_vol_pause_trading:
controls["allow_new_trade"] = False
controls["block_reason"] = "高波动暂停开新仓"
# 2) 时间段过滤
hour = self._utc_hour()
if hour in self.blocked_utc_hours_utc:
controls["allow_new_trade"] = False
controls["block_reason"] = f"UTC {hour}:00 属于换线禁交易时段"
elif self.trade_asia_session_only:
if not self._is_hour_in_range(hour, self.asia_session_start_hour_utc, self.asia_session_end_hour_utc):
controls["allow_new_trade"] = False
controls["block_reason"] = (
f"非亚洲交易时段(UTC {hour}:00不在 {self.asia_session_start_hour_utc}-{self.asia_session_end_hour_utc})"
)
# 3) 日内盈亏管理
self.refresh_daily_pnl_state(force=False)
controls["daily_pnl_usd"] = self.daily_pnl_usd
controls["daily_halt"] = self.daily_halt
if self.daily_pnl_usd >= float(self.daily_profit_reduce_size_usd):
controls["size_multiplier"] *= max(0.05, float(self.daily_reduced_size_multiplier))
if self.daily_halt:
controls["allow_new_trade"] = False
controls["block_reason"] = f"日内亏损达到阈值 {self.daily_max_loss_usd:.2f},暂停开新仓"
return controls
def log_smart_trade_controls(self, controls):
now = time.time()
if now - self.last_smart_status_log_time < 30:
return
self.last_smart_status_log_time = now
vol_text = "n/a" if controls["vol_pct"] is None else f"{controls['vol_pct']:.4f}%"
logger.info(
"智能模式状态: "
f"regime={controls['vol_regime']} vol={vol_text} "
f"sizeMult={controls['size_multiplier']:.3f} slMult={controls['stop_loss_multiplier']:.3f} "
f"dailyPnL={controls['daily_pnl_usd']:.2f} allowNew={controls['allow_new_trade']} "
f"reason={controls['block_reason'] or '-'}"
)
def _ema_series(self, closes, period):
period = max(1, int(period))
if not closes:
@@ -1339,6 +1546,9 @@ class BitmartFuturesTransactionConservative:
logger.error("杠杆设置失败,程序继续运行但可能下单失败")
return
# 初始化日内风控状态方案B
self.refresh_daily_pnl_state(force=True)
if self.start_price_stream():
logger.success("实时价格流已启动WebSocket 优先)")
else:
@@ -1395,14 +1605,20 @@ class BitmartFuturesTransactionConservative:
continue
logger.debug(f"当前持仓状态: {self.start} (0=无, 1=多, -1=空)")
smart_controls = self.get_smart_trade_controls()
self.log_smart_trade_controls(smart_controls)
effective_stop_loss = self.stop_loss_usd
sl_mult = max(0.05, float(smart_controls.get("stop_loss_multiplier", 1.0)))
if effective_stop_loss < 0:
effective_stop_loss = -abs(float(effective_stop_loss)) * sl_mult
# 3.5 止损/止盈/保本锁盈/移动止损
if self.start != 0:
pnl_usd = self.get_unrealized_pnl_usd()
if pnl_usd is not None:
# 固定止损:亏损达到 stop_loss_usd 平仓
if pnl_usd <= self.stop_loss_usd:
logger.info(f"仓位亏损 {pnl_usd:.2f} 美元 <= 止损 {self.stop_loss_usd} 美元,执行止损平仓")
if pnl_usd <= effective_stop_loss:
logger.info(f"仓位亏损 {pnl_usd:.2f} 美元 <= 止损 {effective_stop_loss:.2f} 美元,执行止损平仓")
self.平仓()
self.max_unrealized_pnl_seen = None
time.sleep(3)
@@ -1441,6 +1657,11 @@ class BitmartFuturesTransactionConservative:
# 4. 检查信号
signal = self.check_signal(current_price, prev_kline, current_kline)
# 4.5 智能模式拦截:高波动暂停/时间过滤/日内亏损熔断
if signal and not smart_controls["allow_new_trade"]:
logger.info(f"智能模式阻止交易: {signal[0]} | {smart_controls['block_reason']}")
signal = None
# 5. 反手过滤:冷却时间 + 最小价差
if signal and signal[0].startswith('reverse_'):
if not self.can_reverse(current_price, signal[1]):
@@ -1455,9 +1676,13 @@ class BitmartFuturesTransactionConservative:
# 6. 有信号则执行交易
if signal:
trade_success = self.execute_trade(signal)
dynamic_size = max(1.0, float(self.default_order_size) * float(smart_controls["size_multiplier"]))
dynamic_size = round(dynamic_size, 4)
trade_success = self.execute_trade(signal, size=dynamic_size)
if trade_success:
logger.success(f"交易执行完成: {signal[0]}, 当前持仓状态: {self.start}")
logger.success(
f"交易执行完成: {signal[0]}, 下单数量={dynamic_size}, 当前持仓状态: {self.start}"
)
page_start = True
else:
logger.warning(f"交易执行失败或被阻止: {signal[0]}")