第一版策略
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
布林带均值回归策略 — 实盘交易 (D方案: 递增加仓)
|
||||
BB(10, 2.5) | 5分钟K线 | ETH | 50x杠杆 | 递增加仓+1%/次 max=3
|
||||
BB(10, 2.5) | 5分钟K线 | ETH | 50x杠杆 逐仓 | 递增加仓+1%/次 max=3
|
||||
|
||||
逻辑:
|
||||
- 价格触及上布林带 → 平多(如有) + 开空; 已持空则加仓
|
||||
@@ -43,7 +43,7 @@ class BBTradeConfig:
|
||||
|
||||
# 仓位管理
|
||||
LEVERAGE = 50 # 杠杆倍数
|
||||
OPEN_TYPE = "cross" # 全仓模式
|
||||
OPEN_TYPE = "isolated" # 逐仓模式
|
||||
MARGIN_PCT = 0.01 # 首次开仓用权益的1%作为保证金
|
||||
|
||||
# 递增加仓 (D方案)
|
||||
@@ -207,7 +207,7 @@ class BBTrader:
|
||||
return False
|
||||
|
||||
def set_leverage(self) -> bool:
|
||||
"""设置杠杆和全仓模式"""
|
||||
"""设置杠杆和逐仓模式"""
|
||||
try:
|
||||
resp = self.api.post_submit_leverage(
|
||||
contract_symbol=self.cfg.CONTRACT_SYMBOL,
|
||||
|
||||
Binary file not shown.
@@ -36,8 +36,24 @@ class BBConfig:
|
||||
|
||||
# Risk management
|
||||
max_daily_loss: float = 150.0 # stop trading after this daily loss
|
||||
max_daily_loss_pct: float = 0.0 # if >0, daily loss limit = equity * pct (overrides fixed)
|
||||
stop_loss_pct: float = 0.0 # 0 = disabled; e.g. 0.02 = 2% SL from entry
|
||||
|
||||
# Liquidation
|
||||
liq_enabled: bool = True # enable liquidation simulation
|
||||
cross_margin: bool = True # 全仓模式: 仅当 equity<=0 爆仓; False=逐仓: 按仓位保证金算强平价
|
||||
maint_margin_rate: float = 0.005 # 逐仓时用: 0.5% 维持保证金率
|
||||
|
||||
# Slippage: applied to each trade execution price
|
||||
slippage_pct: float = 0.0005 # 0.05% slippage per trade
|
||||
|
||||
# 成交价模式: False=理想(在触轨的极价成交), True=真实(在K线收盘价成交)
|
||||
# 实盘检测到触及布林带后以市价单成交,通常接近收盘价
|
||||
fill_at_close: bool = False
|
||||
|
||||
# Max single order notional (market capacity limit, USDT)
|
||||
max_notional: float = 0.0 # 0 = unlimited; e.g. 500000 = 50万U max per order
|
||||
|
||||
# Dynamic sizing: if > 0, margin = equity * margin_pct (overrides margin_per_trade)
|
||||
margin_pct: float = 0.0 # e.g. 0.01 = 1% of equity per trade
|
||||
|
||||
@@ -124,6 +140,7 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
current_day = None
|
||||
day_start_equity = cfg.initial_capital # equity at start of each day
|
||||
|
||||
# Delayed rebate tracking
|
||||
pending_rebate = 0.0 # fees from previous day to be rebated
|
||||
@@ -151,6 +168,12 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
if position == 0:
|
||||
return
|
||||
|
||||
# Apply slippage: closing long sells lower, closing short buys higher
|
||||
if position == 1:
|
||||
exit_price = exit_price * (1 - cfg.slippage_pct)
|
||||
else:
|
||||
exit_price = exit_price * (1 + cfg.slippage_pct)
|
||||
|
||||
if position == 1:
|
||||
gross = entry_qty * (exit_price - entry_price)
|
||||
else:
|
||||
@@ -193,6 +216,12 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
nonlocal balance, total_fee, day_pnl, today_fees
|
||||
nonlocal pyramid_count, last_add_margin
|
||||
|
||||
# Apply slippage: buy higher, sell lower
|
||||
if side == "long" or (is_add and position == 1):
|
||||
price = price * (1 + cfg.slippage_pct)
|
||||
else:
|
||||
price = price * (1 - cfg.slippage_pct)
|
||||
|
||||
if is_add and cfg.pyramid_step > 0:
|
||||
# 递增加仓: margin = equity * (margin_pct + step * (count+1))
|
||||
equity = balance + unrealised(price)
|
||||
@@ -210,6 +239,12 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
if margin <= 0:
|
||||
return
|
||||
notional = margin * cfg.leverage
|
||||
|
||||
# Cap notional to market capacity limit
|
||||
if cfg.max_notional > 0 and notional > cfg.max_notional:
|
||||
notional = cfg.max_notional
|
||||
margin = notional / cfg.leverage
|
||||
|
||||
qty = notional / price
|
||||
fee = notional * cfg.fee_rate
|
||||
|
||||
@@ -245,9 +280,10 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
if bar_day is not None and bar_day != current_day:
|
||||
# New day: move today's fees to pending, reset
|
||||
if cfg.rebate_pct > 0:
|
||||
pending_rebate = today_fees * cfg.rebate_pct
|
||||
pending_rebate += today_fees * cfg.rebate_pct
|
||||
today_fees = 0.0
|
||||
rebate_applied_today = False
|
||||
day_start_equity = balance + unrealised(arr_close[i])
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
current_day = bar_day
|
||||
@@ -266,7 +302,7 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
out_position[i] = position
|
||||
continue
|
||||
|
||||
# Daily loss check
|
||||
# Daily loss check (percentage-based if configured, else fixed)
|
||||
if day_stopped:
|
||||
out_equity[i] = balance + unrealised(arr_close[i])
|
||||
out_balance[i] = balance
|
||||
@@ -274,7 +310,12 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
continue
|
||||
|
||||
cur_equity = balance + unrealised(arr_close[i])
|
||||
if day_pnl + unrealised(arr_close[i]) <= -cfg.max_daily_loss:
|
||||
if cfg.max_daily_loss_pct > 0:
|
||||
# percentage-based: use start-of-day equity
|
||||
daily_loss_limit = day_start_equity * cfg.max_daily_loss_pct
|
||||
else:
|
||||
daily_loss_limit = cfg.max_daily_loss
|
||||
if day_pnl + unrealised(arr_close[i]) <= -daily_loss_limit:
|
||||
close_position(arr_close[i], i)
|
||||
day_stopped = True
|
||||
out_equity[i] = balance
|
||||
@@ -291,39 +332,124 @@ def run_bb_backtest(df: pd.DataFrame, cfg: BBConfig) -> BBResult:
|
||||
sl_price = entry_price * (1 + cfg.stop_loss_pct)
|
||||
close_position(sl_price, i)
|
||||
|
||||
# Liquidation check
|
||||
# 全仓(cross_margin): 仅当 账户权益<=0 时爆仓,整仓担保
|
||||
# 逐仓: 按仓位保证金算强平价
|
||||
if position != 0 and cfg.liq_enabled and entry_margin > 0:
|
||||
cur_equity = balance + unrealised(arr_close[i])
|
||||
upnl = unrealised(arr_close[i])
|
||||
if cfg.cross_margin:
|
||||
# 全仓: 只有权益归零才爆仓
|
||||
if cur_equity <= 0:
|
||||
balance += upnl # 实现亏损
|
||||
balance = max(0.0, balance)
|
||||
day_pnl += upnl
|
||||
trades.append(BBTrade(
|
||||
side="long" if position == 1 else "short",
|
||||
entry_price=entry_price, exit_price=arr_close[i],
|
||||
entry_time=entry_time, exit_time=ts_index[i],
|
||||
margin=entry_margin, leverage=cfg.leverage, qty=entry_qty,
|
||||
gross_pnl=upnl, fee=0.0, net_pnl=upnl,
|
||||
))
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_time = None
|
||||
entry_margin = 0.0
|
||||
entry_qty = 0.0
|
||||
pyramid_count = 0
|
||||
last_add_margin = 0.0
|
||||
out_equity[i] = balance
|
||||
out_balance[i] = balance
|
||||
out_position[i] = 0
|
||||
if balance <= 0:
|
||||
out_equity[i:] = 0.0
|
||||
out_balance[i:] = 0.0
|
||||
break
|
||||
else:
|
||||
# 逐仓: 按强平价
|
||||
liq_threshold = 1.0 / cfg.leverage * (1 - cfg.maint_margin_rate)
|
||||
if position == 1:
|
||||
liq_price = entry_price * (1 - liq_threshold)
|
||||
if arr_low[i] <= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
trades.append(BBTrade(
|
||||
side="long", entry_price=entry_price, exit_price=liq_price,
|
||||
entry_time=entry_time, exit_time=ts_index[i],
|
||||
margin=entry_margin, leverage=cfg.leverage, qty=entry_qty,
|
||||
gross_pnl=-entry_margin, fee=0.0, net_pnl=-entry_margin,
|
||||
))
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_time = None
|
||||
entry_margin = 0.0
|
||||
entry_qty = 0.0
|
||||
pyramid_count = 0
|
||||
last_add_margin = 0.0
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
out_equity[i] = 0.0
|
||||
out_balance[i] = 0.0
|
||||
out_position[i] = 0
|
||||
out_equity[i:] = 0.0
|
||||
out_balance[i:] = 0.0
|
||||
break
|
||||
elif position == -1:
|
||||
liq_price = entry_price * (1 + liq_threshold)
|
||||
if arr_high[i] >= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
trades.append(BBTrade(
|
||||
side="short", entry_price=entry_price, exit_price=liq_price,
|
||||
entry_time=entry_time, exit_time=ts_index[i],
|
||||
margin=entry_margin, leverage=cfg.leverage, qty=entry_qty,
|
||||
gross_pnl=-entry_margin, fee=0.0, net_pnl=-entry_margin,
|
||||
))
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_time = None
|
||||
entry_margin = 0.0
|
||||
entry_qty = 0.0
|
||||
pyramid_count = 0
|
||||
last_add_margin = 0.0
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
out_equity[i:] = 0.0
|
||||
out_balance[i:] = 0.0
|
||||
break
|
||||
|
||||
# Signal detection: use high/low to check if price touched BB
|
||||
touched_upper = arr_high[i] >= arr_upper[i]
|
||||
touched_lower = arr_low[i] <= arr_lower[i]
|
||||
|
||||
# 成交价: fill_at_close=True 时用收盘价(模拟实盘市价单),否则用触轨价(理想化)
|
||||
fill_price = arr_close[i] if cfg.fill_at_close else None
|
||||
|
||||
if touched_upper and touched_lower:
|
||||
# Both touched in same bar (wide bar) — skip, too volatile
|
||||
pass
|
||||
elif touched_upper:
|
||||
# Price touched upper BB → go short
|
||||
exec_price = fill_price if fill_price is not None else arr_upper[i]
|
||||
if position == 1:
|
||||
# Close long at upper BB price
|
||||
close_position(arr_upper[i], i)
|
||||
close_position(exec_price, i)
|
||||
if position == 0:
|
||||
# Open short
|
||||
open_position("short", arr_upper[i], i)
|
||||
open_position("short", exec_price, i)
|
||||
elif position == -1 and cfg.pyramid_enabled:
|
||||
# Already short → add to short (pyramid)
|
||||
can_add = cfg.pyramid_max <= 0 or pyramid_count < cfg.pyramid_max
|
||||
if can_add:
|
||||
open_position("short", arr_upper[i], i, is_add=True)
|
||||
open_position("short", exec_price, i, is_add=True)
|
||||
elif touched_lower:
|
||||
# Price touched lower BB → go long
|
||||
exec_price = fill_price if fill_price is not None else arr_lower[i]
|
||||
if position == -1:
|
||||
# Close short at lower BB price
|
||||
close_position(arr_lower[i], i)
|
||||
close_position(exec_price, i)
|
||||
if position == 0:
|
||||
# Open long
|
||||
open_position("long", arr_lower[i], i)
|
||||
open_position("long", exec_price, i)
|
||||
elif position == 1 and cfg.pyramid_enabled:
|
||||
# Already long → add to long (pyramid)
|
||||
can_add = cfg.pyramid_max <= 0 or pyramid_count < cfg.pyramid_max
|
||||
if can_add:
|
||||
open_position("long", arr_lower[i], i, is_add=True)
|
||||
open_position("long", exec_price, i, is_add=True)
|
||||
|
||||
# Record equity
|
||||
out_equity[i] = balance + unrealised(arr_close[i])
|
||||
|
||||
@@ -18,20 +18,25 @@ PERIOD_MAP = {
|
||||
}
|
||||
|
||||
|
||||
def load_klines(period: str, start_date: str, end_date: str) -> pd.DataFrame:
|
||||
def load_klines(period: str, start_date: str, end_date: str, tz: str | None = None) -> pd.DataFrame:
|
||||
"""
|
||||
加载指定周期、指定日期范围的K线数据
|
||||
:param period: '1m','3m','5m','15m','30m','1h'
|
||||
:param start_date: 'YYYY-MM-DD'
|
||||
:param end_date: 'YYYY-MM-DD' (不包含该日)
|
||||
:param tz: 日期解释的时区,如 'Asia/Shanghai' 表示按北京时间;None 则用本地时区
|
||||
:return: DataFrame with columns: datetime, open, high, low, close
|
||||
"""
|
||||
table = PERIOD_MAP.get(period)
|
||||
if not table:
|
||||
raise ValueError(f"不支持的周期: {period}, 可选: {list(PERIOD_MAP.keys())}")
|
||||
|
||||
start_ts = int(pd.Timestamp(start_date).timestamp() * 1000)
|
||||
end_ts = int(pd.Timestamp(end_date).timestamp() * 1000)
|
||||
if tz:
|
||||
start_ts = int(pd.Timestamp(start_date, tz=tz).timestamp() * 1000)
|
||||
end_ts = int(pd.Timestamp(end_date, tz=tz).timestamp() * 1000)
|
||||
else:
|
||||
start_ts = int(pd.Timestamp(start_date).timestamp() * 1000)
|
||||
end_ts = int(pd.Timestamp(end_date).timestamp() * 1000)
|
||||
|
||||
db = SqliteDatabase(str(DB_PATH))
|
||||
db.connect()
|
||||
|
||||
BIN
strategy/results/bb_15m_200u_2020_2025.png
Normal file
BIN
strategy/results/bb_15m_200u_2020_2025.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
2193
strategy/results/bb_15m_2020_2025_conservative_daily.csv
Normal file
2193
strategy/results/bb_15m_2020_2025_conservative_daily.csv
Normal file
File diff suppressed because it is too large
Load Diff
315
strategy/results/bb_202602_trade_detail.csv
Normal file
315
strategy/results/bb_202602_trade_detail.csv
Normal file
@@ -0,0 +1,315 @@
|
||||
序号,方向,开仓时间,平仓时间,开仓价,平仓价,保证金,杠杆,数量,毛盈亏,手续费,净盈亏
|
||||
1,做多,2026-02-01 00:45:00,2026-02-01 04:20:00,2503.98,2377.2,2.0,50,0.0399,-5.06,0.05,-5.11
|
||||
2,做空,2026-02-01 04:20:00,2026-02-01 04:35:00,2377.2,2360.24,1.95,50,0.041,0.7,0.05,0.65
|
||||
3,做多,2026-02-01 04:35:00,2026-02-01 05:00:00,2360.24,2373.42,1.95,50,0.0414,0.55,0.05,0.5
|
||||
4,做空,2026-02-01 05:00:00,2026-02-01 09:05:00,2373.42,2433.28,1.96,50,0.0413,-2.47,0.05,-2.52
|
||||
5,做多,2026-02-01 09:05:00,2026-02-01 12:10:00,2433.28,2451.12,1.94,50,0.0398,0.71,0.05,0.66
|
||||
6,做空,2026-02-01 12:10:00,2026-02-01 13:00:00,2451.12,2439.68,1.94,50,0.0396,0.45,0.05,0.4
|
||||
7,做多,2026-02-01 13:00:00,2026-02-01 15:40:00,2439.68,2430.01,1.95,50,0.0399,-0.39,0.05,-0.43
|
||||
8,做空,2026-02-01 15:40:00,2026-02-01 18:30:00,2430.01,2406.59,1.94,50,0.0399,0.94,0.05,0.89
|
||||
9,做多,2026-02-01 18:30:00,2026-02-01 19:35:00,2406.59,2404.44,1.95,50,0.0405,-0.09,0.05,-0.14
|
||||
10,做空,2026-02-01 19:35:00,2026-02-01 20:20:00,2404.44,2387.44,1.95,50,0.0405,0.69,0.05,0.64
|
||||
11,做多,2026-02-01 20:20:00,2026-02-01 21:00:00,2387.44,2402.27,1.95,50,0.0409,0.61,0.05,0.56
|
||||
12,做空,2026-02-01 21:00:00,2026-02-01 21:40:00,2402.27,2392.0,1.96,50,0.0408,0.42,0.05,0.37
|
||||
13,做多,2026-02-01 21:40:00,2026-02-02 00:25:00,2392.0,2318.96,1.96,50,0.041,-3.0,0.05,-3.04
|
||||
14,做空,2026-02-02 00:25:00,2026-02-02 03:45:00,2318.96,2313.79,1.93,50,0.0416,0.22,0.05,0.17
|
||||
15,做多,2026-02-02 03:45:00,2026-02-02 04:35:00,2313.79,2342.69,1.93,50,0.0418,1.21,0.05,1.16
|
||||
16,做空,2026-02-02 04:35:00,2026-02-02 05:55:00,2342.69,2289.17,1.94,50,0.0415,2.22,0.05,2.17
|
||||
17,做多,2026-02-02 05:55:00,2026-02-02 06:10:00,2289.17,2323.39,1.96,50,0.0429,1.47,0.05,1.42
|
||||
18,做空,2026-02-02 06:10:00,2026-02-02 07:05:00,2323.39,2235.28,1.98,50,0.0426,3.75,0.05,3.7
|
||||
19,做多,2026-02-02 07:05:00,2026-02-02 08:15:00,2235.28,2307.06,2.01,50,0.0451,3.23,0.05,3.18
|
||||
20,做空,2026-02-02 08:15:00,2026-02-02 09:00:00,2307.06,2302.75,2.06,50,0.0446,0.19,0.05,0.14
|
||||
21,做多,2026-02-02 09:00:00,2026-02-02 14:15:00,2302.75,2211.45,2.06,50,0.0447,-4.08,0.05,-4.13
|
||||
22,做空,2026-02-02 14:15:00,2026-02-02 14:35:00,2211.45,2166.31,2.02,50,0.0456,2.06,0.05,2.01
|
||||
23,做多,2026-02-02 14:35:00,2026-02-02 14:40:00,2166.31,2219.94,2.04,50,0.047,2.52,0.05,2.47
|
||||
24,做空,2026-02-02 14:40:00,2026-02-02 17:15:00,2219.94,2250.82,2.06,50,0.0464,-1.43,0.05,-1.49
|
||||
25,做多,2026-02-02 17:15:00,2026-02-02 17:25:00,2250.82,2277.79,2.05,50,0.0455,1.23,0.05,1.17
|
||||
26,做空,2026-02-02 17:25:00,2026-02-02 22:10:00,2277.79,2305.44,2.06,50,0.0452,-1.25,0.05,-1.3
|
||||
27,做多,2026-02-02 22:10:00,2026-02-02 22:35:00,2305.44,2350.92,2.04,50,0.0443,2.02,0.05,1.96
|
||||
28,做空,2026-02-02 22:35:00,2026-02-03 00:50:00,2350.92,2357.15,2.06,50,0.0439,-0.27,0.05,-0.33
|
||||
29,做多,2026-02-03 00:50:00,2026-02-03 09:00:00,2357.15,2349.37,2.06,50,0.0437,-0.34,0.05,-0.39
|
||||
30,做空,2026-02-03 09:00:00,2026-02-03 10:10:00,2349.37,2327.51,2.06,50,0.0439,0.96,0.05,0.91
|
||||
31,做多,2026-02-03 10:10:00,2026-02-03 15:10:00,2327.51,2322.01,2.07,50,0.0445,-0.24,0.05,-0.3
|
||||
32,做空,2026-02-03 15:10:00,2026-02-03 16:10:00,2322.01,2311.05,2.07,50,0.0446,0.49,0.05,0.44
|
||||
33,做多,2026-02-03 16:10:00,2026-02-03 20:10:00,2311.05,2290.92,2.07,50,0.0449,-0.9,0.05,-0.95
|
||||
34,做空,2026-02-03 20:10:00,2026-02-03 22:15:00,2290.92,2299.99,2.06,50,0.045,-0.41,0.05,-0.46
|
||||
35,做多,2026-02-03 22:15:00,2026-02-03 23:25:00,2299.99,2292.96,2.06,50,0.0447,-0.31,0.05,-0.37
|
||||
36,做空,2026-02-03 23:25:00,2026-02-04 00:15:00,2292.96,2265.27,2.05,50,0.0448,1.24,0.05,1.19
|
||||
37,做多,2026-02-04 00:15:00,2026-02-04 03:10:00,2265.27,2178.1,2.07,50,0.0456,-3.97,0.05,-4.02
|
||||
38,做空,2026-02-04 03:10:00,2026-02-04 06:05:00,2178.1,2259.5,2.02,50,0.0465,-3.78,0.05,-3.84
|
||||
39,做多,2026-02-04 06:05:00,2026-02-04 09:00:00,2259.5,2264.51,1.99,50,0.0439,0.22,0.05,0.17
|
||||
40,做空,2026-02-04 09:00:00,2026-02-04 10:30:00,2264.51,2254.5,2.0,50,0.0441,0.44,0.05,0.39
|
||||
41,做多,2026-02-04 10:30:00,2026-02-04 11:10:00,2254.5,2275.54,2.0,50,0.0443,0.93,0.05,0.88
|
||||
42,做空,2026-02-04 11:10:00,2026-02-04 12:25:00,2275.54,2274.79,2.01,50,0.0441,0.03,0.05,-0.02
|
||||
43,做多,2026-02-04 12:25:00,2026-02-04 20:20:00,2274.79,2253.17,2.01,50,0.0441,-0.95,0.05,-1.0
|
||||
44,做空,2026-02-04 20:20:00,2026-02-04 20:25:00,2253.17,2234.15,2.0,50,0.0443,0.84,0.05,0.79
|
||||
45,做多,2026-02-04 20:25:00,2026-02-05 01:00:00,2234.15,2141.81,2.0,50,0.0449,-4.14,0.05,-4.19
|
||||
46,做空,2026-02-05 01:00:00,2026-02-05 01:35:00,2141.81,2100.23,1.96,50,0.0458,1.9,0.05,1.86
|
||||
47,做多,2026-02-05 01:35:00,2026-02-05 02:25:00,2100.23,2122.35,1.98,50,0.0471,1.04,0.05,0.99
|
||||
48,做空,2026-02-05 02:25:00,2026-02-05 03:20:00,2122.35,2138.64,1.99,50,0.0469,-0.76,0.05,-0.81
|
||||
49,做多,2026-02-05 03:20:00,2026-02-05 03:45:00,2138.64,2159.36,1.98,50,0.0463,0.96,0.05,0.91
|
||||
50,做空,2026-02-05 03:45:00,2026-02-05 05:05:00,2159.36,2158.46,1.99,50,0.0461,0.04,0.05,-0.01
|
||||
51,做多,2026-02-05 05:05:00,2026-02-05 10:35:00,2158.46,2153.58,1.99,50,0.0461,-0.22,0.05,-0.27
|
||||
52,做空,2026-02-05 10:35:00,2026-02-05 11:15:00,2153.58,2113.19,2.0,50,0.0463,1.87,0.05,1.82
|
||||
53,做多,2026-02-05 11:15:00,2026-02-05 12:40:00,2113.19,2121.89,2.01,50,0.0477,0.41,0.05,0.36
|
||||
54,做空,2026-02-05 12:40:00,2026-02-05 13:20:00,2121.89,2085.5,2.02,50,0.0475,1.73,0.05,1.68
|
||||
55,做多,2026-02-05 13:20:00,2026-02-05 15:00:00,2085.5,2115.39,2.03,50,0.0488,1.46,0.05,1.41
|
||||
56,做空,2026-02-05 15:00:00,2026-02-05 15:55:00,2115.39,2089.53,2.05,50,0.0484,1.25,0.05,1.2
|
||||
57,做多,2026-02-05 15:55:00,2026-02-05 16:25:00,2089.53,2110.34,2.06,50,0.0493,1.03,0.05,0.97
|
||||
58,做空,2026-02-05 16:25:00,2026-02-05 18:55:00,2110.34,2096.48,2.07,50,0.049,0.68,0.05,0.63
|
||||
59,做多,2026-02-05 18:55:00,2026-02-05 21:05:00,2096.48,2071.86,2.07,50,0.0495,-1.22,0.05,-1.27
|
||||
60,做空,2026-02-05 21:05:00,2026-02-06 01:20:00,2071.86,1987.12,2.06,50,0.0497,4.21,0.05,4.16
|
||||
61,做多,2026-02-06 01:20:00,2026-02-06 06:25:00,1987.12,1871.41,2.1,50,0.0529,-6.12,0.05,-6.17
|
||||
62,做空,2026-02-06 06:25:00,2026-02-06 08:10:00,1871.41,1766.83,2.04,50,0.0545,5.7,0.05,5.65
|
||||
63,做多,2026-02-06 08:10:00,2026-02-06 09:35:00,1766.83,1909.28,2.11,50,0.0596,8.49,0.06,8.43
|
||||
64,做空,2026-02-06 09:35:00,2026-02-06 11:50:00,1909.28,1885.62,2.19,50,0.0573,1.36,0.05,1.3
|
||||
65,做多,2026-02-06 11:50:00,2026-02-06 13:05:00,1885.62,1911.81,2.2,50,0.0584,1.53,0.06,1.47
|
||||
66,做空,2026-02-06 13:05:00,2026-02-06 16:15:00,1911.81,1879.3,2.22,50,0.0579,1.88,0.05,1.83
|
||||
67,做多,2026-02-06 16:15:00,2026-02-06 17:10:00,1879.3,1885.97,2.23,50,0.0594,0.4,0.06,0.34
|
||||
68,做空,2026-02-06 17:10:00,2026-02-06 19:00:00,1885.97,1924.17,2.24,50,0.0593,-2.26,0.06,-2.32
|
||||
69,做多,2026-02-06 19:00:00,2026-02-06 19:15:00,1924.17,1924.74,2.21,50,0.0575,0.03,0.06,-0.02
|
||||
70,做空,2026-02-06 19:15:00,2026-02-06 20:05:00,1924.74,1922.87,2.21,50,0.0575,0.11,0.06,0.05
|
||||
71,做多,2026-02-06 20:05:00,2026-02-06 21:00:00,1922.87,1932.91,2.21,50,0.0575,0.58,0.06,0.52
|
||||
72,做空,2026-02-06 21:00:00,2026-02-06 23:15:00,1932.91,1971.8,2.22,50,0.0573,-2.23,0.06,-2.29
|
||||
73,做多,2026-02-06 23:15:00,2026-02-06 23:45:00,1971.8,1990.88,2.19,50,0.0556,1.06,0.06,1.01
|
||||
74,做空,2026-02-06 23:45:00,2026-02-07 02:05:00,1990.88,2032.15,2.2,50,0.0553,-2.28,0.06,-2.34
|
||||
75,做多,2026-02-07 02:05:00,2026-02-07 04:35:00,2032.15,2073.09,2.18,50,0.0536,2.19,0.06,2.14
|
||||
76,做空,2026-02-07 04:35:00,2026-02-07 07:15:00,2073.09,2053.48,2.2,50,0.053,1.04,0.05,0.99
|
||||
77,做多,2026-02-07 07:15:00,2026-02-07 11:00:00,2053.48,2064.11,2.21,50,0.0538,0.57,0.06,0.52
|
||||
78,做空,2026-02-07 11:00:00,2026-02-07 14:15:00,2064.11,2073.13,2.23,50,0.054,-0.49,0.06,-0.54
|
||||
79,做多,2026-02-07 14:15:00,2026-02-07 19:55:00,2073.13,2017.76,2.22,50,0.0536,-2.97,0.05,-3.02
|
||||
80,做空,2026-02-07 19:55:00,2026-02-07 21:35:00,2017.76,2027.6,2.19,50,0.0543,-0.53,0.06,-0.59
|
||||
81,做多,2026-02-07 21:35:00,2026-02-08 02:15:00,2027.6,2076.87,2.18,50,0.0539,2.65,0.06,2.6
|
||||
82,做空,2026-02-08 02:15:00,2026-02-08 06:10:00,2076.87,2099.58,2.21,50,0.0532,-1.21,0.06,-1.26
|
||||
83,做多,2026-02-08 06:10:00,2026-02-08 10:20:00,2099.58,2102.05,2.2,50,0.0523,0.13,0.05,0.07
|
||||
84,做空,2026-02-08 10:20:00,2026-02-08 12:15:00,2102.05,2074.69,2.2,50,0.0524,1.43,0.05,1.38
|
||||
85,做多,2026-02-08 12:15:00,2026-02-08 12:55:00,2074.69,2086.46,2.22,50,0.0534,0.63,0.06,0.57
|
||||
86,做空,2026-02-08 12:55:00,2026-02-08 14:05:00,2086.46,2079.62,2.22,50,0.0532,0.36,0.06,0.31
|
||||
87,做多,2026-02-08 14:05:00,2026-02-08 16:20:00,2079.62,2096.67,2.22,50,0.0535,0.91,0.06,0.86
|
||||
88,做空,2026-02-08 16:20:00,2026-02-08 17:35:00,2096.67,2103.15,2.23,50,0.0532,-0.34,0.06,-0.4
|
||||
89,做多,2026-02-08 17:35:00,2026-02-08 18:05:00,2103.15,2107.65,2.23,50,0.053,0.24,0.06,0.18
|
||||
90,做空,2026-02-08 18:05:00,2026-02-08 18:20:00,2107.65,2087.85,2.23,50,0.0529,1.05,0.06,0.99
|
||||
91,做多,2026-02-08 18:20:00,2026-02-08 19:15:00,2087.85,2110.36,2.24,50,0.0536,1.21,0.06,1.15
|
||||
92,做空,2026-02-08 19:15:00,2026-02-08 21:05:00,2110.36,2123.28,2.25,50,0.0533,-0.69,0.06,-0.75
|
||||
93,做多,2026-02-08 21:05:00,2026-02-09 02:15:00,2123.28,2094.55,2.24,50,0.0528,-1.52,0.06,-1.57
|
||||
94,做空,2026-02-09 02:15:00,2026-02-09 04:45:00,2094.55,2104.6,2.22,50,0.0531,-0.53,0.06,-0.59
|
||||
95,做多,2026-02-09 04:45:00,2026-02-09 06:55:00,2104.6,2107.44,2.22,50,0.0527,0.15,0.06,0.09
|
||||
96,做空,2026-02-09 06:55:00,2026-02-09 08:25:00,2107.44,2081.4,2.22,50,0.0526,1.37,0.05,1.32
|
||||
97,做多,2026-02-09 08:25:00,2026-02-09 09:20:00,2081.4,2098.76,2.24,50,0.0539,0.94,0.06,0.88
|
||||
98,做空,2026-02-09 09:20:00,2026-02-09 09:40:00,2098.76,2063.62,2.25,50,0.0537,1.89,0.06,1.83
|
||||
99,做多,2026-02-09 09:40:00,2026-02-09 10:35:00,2063.62,2079.96,2.27,50,0.055,0.9,0.06,0.84
|
||||
100,做空,2026-02-09 10:35:00,2026-02-09 14:15:00,2079.96,2075.79,2.28,50,0.0548,0.23,0.06,0.17
|
||||
101,做多,2026-02-09 14:15:00,2026-02-09 15:10:00,2075.79,2084.33,2.28,50,0.0549,0.47,0.06,0.41
|
||||
102,做空,2026-02-09 15:10:00,2026-02-09 15:35:00,2084.33,2067.23,2.28,50,0.0548,0.94,0.06,0.88
|
||||
103,做多,2026-02-09 15:35:00,2026-02-09 20:00:00,2067.23,2031.57,2.29,50,0.0554,-1.98,0.06,-2.03
|
||||
104,做空,2026-02-09 20:00:00,2026-02-10 02:20:00,2031.57,2115.84,2.27,50,0.0559,-4.71,0.06,-4.77
|
||||
105,做多,2026-02-10 02:20:00,2026-02-10 03:30:00,2115.84,2131.85,2.22,50,0.0525,0.84,0.06,0.78
|
||||
106,做空,2026-02-10 03:30:00,2026-02-10 04:00:00,2131.85,2130.8,2.23,50,0.0523,0.05,0.06,-0.0
|
||||
107,做多,2026-02-10 04:00:00,2026-02-10 04:05:00,2130.8,2135.34,2.23,50,0.0523,0.24,0.06,0.18
|
||||
108,做空,2026-02-10 04:05:00,2026-02-10 04:15:00,2135.34,2122.59,2.23,50,0.0522,0.67,0.06,0.61
|
||||
109,做多,2026-02-10 04:15:00,2026-02-10 16:20:00,2122.59,2011.91,2.24,50,0.0527,-5.83,0.05,-5.88
|
||||
110,做空,2026-02-10 16:20:00,2026-02-10 17:50:00,2011.91,2015.22,2.19,50,0.0544,-0.18,0.05,-0.23
|
||||
111,做多,2026-02-10 17:50:00,2026-02-10 19:30:00,2015.22,2019.66,2.19,50,0.0543,0.24,0.05,0.19
|
||||
112,做空,2026-02-10 19:30:00,2026-02-10 19:40:00,2019.66,2007.94,2.19,50,0.0542,0.63,0.05,0.58
|
||||
113,做多,2026-02-10 19:40:00,2026-02-10 21:15:00,2007.94,2012.02,2.19,50,0.0546,0.22,0.05,0.17
|
||||
114,做空,2026-02-10 21:15:00,2026-02-10 22:35:00,2012.02,2012.47,2.19,50,0.0545,-0.02,0.05,-0.08
|
||||
115,做多,2026-02-10 22:35:00,2026-02-11 00:10:00,2012.47,2032.87,2.19,50,0.0545,1.11,0.06,1.06
|
||||
116,做空,2026-02-11 00:10:00,2026-02-11 02:20:00,2032.87,2013.69,2.2,50,0.0542,1.04,0.05,0.98
|
||||
117,做多,2026-02-11 02:20:00,2026-02-11 03:30:00,2013.69,2013.39,2.21,50,0.0549,-0.02,0.06,-0.07
|
||||
118,做空,2026-02-11 03:30:00,2026-02-11 05:30:00,2013.39,2001.89,2.21,50,0.0549,0.63,0.05,0.58
|
||||
119,做多,2026-02-11 05:30:00,2026-02-11 07:35:00,2001.89,2018.01,2.22,50,0.0554,0.89,0.06,0.84
|
||||
120,做空,2026-02-11 07:35:00,2026-02-11 09:20:00,2018.01,2018.06,2.22,50,0.0551,-0.0,0.06,-0.06
|
||||
121,做多,2026-02-11 09:20:00,2026-02-11 10:20:00,2018.06,2027.05,2.23,50,0.0553,0.5,0.06,0.44
|
||||
122,做空,2026-02-11 10:20:00,2026-02-11 10:45:00,2027.05,2014.32,2.24,50,0.0552,0.7,0.06,0.65
|
||||
123,做多,2026-02-11 10:45:00,2026-02-11 15:35:00,2014.32,1951.85,2.24,50,0.0557,-3.48,0.05,-3.53
|
||||
124,做空,2026-02-11 15:35:00,2026-02-11 16:05:00,1951.85,1939.79,2.21,50,0.0566,0.68,0.05,0.63
|
||||
125,做多,2026-02-11 16:05:00,2026-02-11 17:00:00,1939.79,1949.26,2.21,50,0.057,0.54,0.06,0.48
|
||||
126,做空,2026-02-11 17:00:00,2026-02-11 17:45:00,1949.26,1944.0,2.22,50,0.0569,0.3,0.06,0.24
|
||||
127,做多,2026-02-11 17:45:00,2026-02-11 20:05:00,1944.0,1961.67,2.22,50,0.0571,1.01,0.06,0.95
|
||||
128,做空,2026-02-11 20:05:00,2026-02-11 21:25:00,1961.67,1948.28,2.23,50,0.0568,0.76,0.06,0.71
|
||||
129,做多,2026-02-11 21:25:00,2026-02-11 21:30:00,1948.28,1963.0,2.23,50,0.0574,0.84,0.06,0.79
|
||||
130,做空,2026-02-11 21:30:00,2026-02-12 03:30:00,1963.0,1943.01,2.24,50,0.0571,1.14,0.06,1.09
|
||||
131,做多,2026-02-12 03:30:00,2026-02-12 03:45:00,1943.01,1952.12,2.25,50,0.058,0.53,0.06,0.47
|
||||
132,做空,2026-02-12 03:45:00,2026-02-12 04:25:00,1952.12,1941.02,2.26,50,0.0578,0.64,0.06,0.59
|
||||
133,做多,2026-02-12 04:25:00,2026-02-12 05:20:00,1941.02,1968.22,2.26,50,0.0583,1.58,0.06,1.53
|
||||
134,做空,2026-02-12 05:20:00,2026-02-12 06:10:00,1968.22,1960.92,2.28,50,0.0578,0.42,0.06,0.37
|
||||
135,做多,2026-02-12 06:10:00,2026-02-12 08:05:00,1960.92,1951.09,2.28,50,0.0581,-0.57,0.06,-0.63
|
||||
136,做空,2026-02-12 08:05:00,2026-02-12 12:30:00,1951.09,1967.55,2.29,50,0.0586,-0.97,0.06,-1.02
|
||||
137,做多,2026-02-12 12:30:00,2026-02-12 14:10:00,1967.55,1970.2,2.28,50,0.0579,0.15,0.06,0.1
|
||||
138,做空,2026-02-12 14:10:00,2026-02-12 16:25:00,1970.2,1958.73,2.28,50,0.0578,0.66,0.06,0.61
|
||||
139,做多,2026-02-12 16:25:00,2026-02-12 17:10:00,1958.73,1968.27,2.28,50,0.0583,0.56,0.06,0.5
|
||||
140,做空,2026-02-12 17:10:00,2026-02-12 20:50:00,1968.27,1976.76,2.29,50,0.0581,-0.49,0.06,-0.55
|
||||
141,做多,2026-02-12 20:50:00,2026-02-12 21:30:00,1976.76,1985.8,2.28,50,0.0577,0.52,0.06,0.46
|
||||
142,做空,2026-02-12 21:30:00,2026-02-12 22:45:00,1985.8,1978.53,2.29,50,0.0575,0.42,0.06,0.36
|
||||
143,做多,2026-02-12 22:45:00,2026-02-13 01:35:00,1978.53,1920.11,2.29,50,0.0578,-3.38,0.06,-3.43
|
||||
144,做空,2026-02-13 01:35:00,2026-02-13 04:10:00,1920.11,1920.22,2.25,50,0.0587,-0.01,0.06,-0.06
|
||||
145,做多,2026-02-13 04:10:00,2026-02-13 06:30:00,1920.22,1927.46,2.25,50,0.0587,0.42,0.06,0.37
|
||||
146,做空,2026-02-13 06:30:00,2026-02-13 08:15:00,1927.46,1940.1,2.26,50,0.0585,-0.74,0.06,-0.8
|
||||
147,做多,2026-02-13 08:15:00,2026-02-13 09:05:00,1940.1,1941.5,2.26,50,0.0582,0.08,0.06,0.02
|
||||
148,做空,2026-02-13 09:05:00,2026-02-13 10:20:00,1941.5,1946.1,2.26,50,0.0582,-0.27,0.06,-0.32
|
||||
149,做多,2026-02-13 10:20:00,2026-02-13 10:50:00,1946.1,1947.9,2.25,50,0.0579,0.1,0.06,0.05
|
||||
150,做空,2026-02-13 10:50:00,2026-02-13 12:10:00,1947.9,1950.84,2.25,50,0.0579,-0.17,0.06,-0.23
|
||||
151,做多,2026-02-13 12:10:00,2026-02-13 12:25:00,1950.84,1949.6,2.25,50,0.0577,-0.07,0.06,-0.13
|
||||
152,做空,2026-02-13 12:25:00,2026-02-13 12:30:00,1949.6,1950.08,2.25,50,0.0577,-0.03,0.06,-0.08
|
||||
153,做多,2026-02-13 12:30:00,2026-02-13 16:20:00,1950.08,1939.99,2.25,50,0.0576,-0.58,0.06,-0.64
|
||||
154,做空,2026-02-13 16:20:00,2026-02-13 19:05:00,1939.99,1955.6,2.24,50,0.0578,-0.9,0.06,-0.96
|
||||
155,做多,2026-02-13 19:05:00,2026-02-13 20:25:00,1955.6,1961.63,2.23,50,0.057,0.34,0.06,0.29
|
||||
156,做空,2026-02-13 20:25:00,2026-02-13 21:05:00,1961.63,1957.39,2.23,50,0.0569,0.24,0.06,0.19
|
||||
157,做多,2026-02-13 21:05:00,2026-02-13 21:20:00,1957.39,1967.19,2.23,50,0.0571,0.56,0.06,0.5
|
||||
158,做空,2026-02-13 21:20:00,2026-02-14 02:00:00,1967.19,2056.73,2.24,50,0.0569,-5.1,0.06,-5.15
|
||||
159,做多,2026-02-14 02:00:00,2026-02-14 02:35:00,2056.73,2061.34,2.19,50,0.0532,0.25,0.05,0.19
|
||||
160,做空,2026-02-14 02:35:00,2026-02-14 04:15:00,2061.34,2049.81,2.19,50,0.0531,0.61,0.05,0.56
|
||||
161,做多,2026-02-14 04:15:00,2026-02-14 05:00:00,2049.81,2054.62,2.19,50,0.0535,0.26,0.05,0.2
|
||||
162,做空,2026-02-14 05:00:00,2026-02-14 07:35:00,2054.62,2047.52,2.19,50,0.0534,0.38,0.05,0.32
|
||||
163,做多,2026-02-14 07:35:00,2026-02-14 09:50:00,2047.52,2053.35,2.2,50,0.0537,0.31,0.06,0.26
|
||||
164,做空,2026-02-14 09:50:00,2026-02-14 09:55:00,2053.35,2053.37,2.22,50,0.054,-0.0,0.06,-0.06
|
||||
165,做多,2026-02-14 09:55:00,2026-02-14 11:25:00,2053.37,2050.56,2.22,50,0.0539,-0.15,0.06,-0.21
|
||||
166,做空,2026-02-14 11:25:00,2026-02-14 13:00:00,2050.56,2052.1,2.21,50,0.054,-0.08,0.06,-0.14
|
||||
167,做多,2026-02-14 13:00:00,2026-02-14 15:30:00,2052.1,2052.31,2.21,50,0.0539,0.01,0.06,-0.04
|
||||
168,做空,2026-02-14 15:30:00,2026-02-14 15:35:00,2052.31,2050.7,2.21,50,0.0538,0.09,0.06,0.03
|
||||
169,做多,2026-02-14 15:35:00,2026-02-14 15:50:00,2050.7,2057.65,2.21,50,0.0539,0.37,0.06,0.32
|
||||
170,做空,2026-02-14 15:50:00,2026-02-14 20:15:00,2057.65,2094.01,2.21,50,0.0538,-1.95,0.06,-2.01
|
||||
171,做多,2026-02-14 20:15:00,2026-02-14 22:20:00,2094.01,2069.5,2.19,50,0.0523,-1.28,0.05,-1.34
|
||||
172,做空,2026-02-14 22:20:00,2026-02-15 00:00:00,2069.5,2086.28,2.18,50,0.0526,-0.88,0.05,-0.94
|
||||
173,做多,2026-02-15 00:00:00,2026-02-15 02:20:00,2086.28,2082.08,2.17,50,0.052,-0.22,0.05,-0.27
|
||||
174,做空,2026-02-15 02:20:00,2026-02-15 03:15:00,2082.08,2084.26,2.16,50,0.052,-0.11,0.05,-0.17
|
||||
175,做多,2026-02-15 03:15:00,2026-02-15 03:30:00,2084.26,2085.58,2.16,50,0.0519,0.07,0.05,0.01
|
||||
176,做空,2026-02-15 03:30:00,2026-02-15 07:15:00,2085.58,2087.12,2.16,50,0.0518,-0.08,0.05,-0.13
|
||||
177,做多,2026-02-15 07:15:00,2026-02-15 10:05:00,2087.12,2058.92,2.16,50,0.0517,-1.46,0.05,-1.51
|
||||
178,做空,2026-02-15 10:05:00,2026-02-15 10:20:00,2058.92,2054.96,2.16,50,0.0524,0.21,0.05,0.15
|
||||
179,做多,2026-02-15 10:20:00,2026-02-15 12:05:00,2054.96,2072.91,2.16,50,0.0525,0.94,0.05,0.89
|
||||
180,做空,2026-02-15 12:05:00,2026-02-15 14:00:00,2072.91,2086.85,2.17,50,0.0523,-0.73,0.05,-0.78
|
||||
181,做多,2026-02-15 14:00:00,2026-02-15 14:35:00,2086.85,2090.16,2.16,50,0.0517,0.17,0.05,0.12
|
||||
182,做空,2026-02-15 14:35:00,2026-02-15 16:25:00,2090.16,2075.54,2.16,50,0.0517,0.76,0.05,0.7
|
||||
183,做多,2026-02-15 16:25:00,2026-02-15 20:20:00,2075.54,2062.81,2.17,50,0.0522,-0.66,0.05,-0.72
|
||||
184,做空,2026-02-15 20:20:00,2026-02-15 20:45:00,2062.81,2046.45,2.16,50,0.0523,0.86,0.05,0.8
|
||||
185,做多,2026-02-15 20:45:00,2026-02-15 22:30:00,2046.45,1999.25,2.17,50,0.0529,-2.5,0.05,-2.55
|
||||
186,做空,2026-02-15 22:30:00,2026-02-16 00:05:00,1999.25,1999.62,2.14,50,0.0535,-0.02,0.05,-0.07
|
||||
187,做多,2026-02-16 00:05:00,2026-02-16 05:30:00,1999.62,1959.09,2.14,50,0.0535,-2.17,0.05,-2.22
|
||||
188,做空,2026-02-16 05:30:00,2026-02-16 07:00:00,1959.09,1956.8,2.12,50,0.054,0.12,0.05,0.07
|
||||
189,做多,2026-02-16 07:00:00,2026-02-16 08:05:00,1956.8,1973.71,2.12,50,0.0541,0.91,0.05,0.86
|
||||
190,做空,2026-02-16 08:05:00,2026-02-16 10:20:00,1973.71,1958.9,2.14,50,0.0541,0.8,0.05,0.75
|
||||
191,做多,2026-02-16 10:20:00,2026-02-16 12:00:00,1958.9,1963.67,2.14,50,0.0547,0.26,0.05,0.21
|
||||
192,做空,2026-02-16 12:00:00,2026-02-16 19:05:00,1963.67,1973.75,2.14,50,0.0546,-0.55,0.05,-0.6
|
||||
193,做多,2026-02-16 19:05:00,2026-02-16 20:25:00,1973.75,1991.31,2.14,50,0.0542,0.95,0.05,0.9
|
||||
194,做空,2026-02-16 20:25:00,2026-02-16 21:25:00,1991.31,1976.1,2.15,50,0.0539,0.82,0.05,0.77
|
||||
195,做多,2026-02-16 21:25:00,2026-02-16 22:50:00,1976.1,1969.72,2.15,50,0.0545,-0.35,0.05,-0.4
|
||||
196,做空,2026-02-16 22:50:00,2026-02-16 23:30:00,1969.72,1940.59,2.15,50,0.0545,1.59,0.05,1.54
|
||||
197,做多,2026-02-16 23:30:00,2026-02-17 01:30:00,1940.59,1983.81,2.16,50,0.0557,2.41,0.06,2.35
|
||||
198,做空,2026-02-17 01:30:00,2026-02-17 02:35:00,1983.81,1974.99,2.19,50,0.0551,0.49,0.05,0.43
|
||||
199,做多,2026-02-17 02:35:00,2026-02-17 03:35:00,1974.99,1977.15,2.19,50,0.0555,0.12,0.05,0.06
|
||||
200,做空,2026-02-17 03:35:00,2026-02-17 06:45:00,1977.15,1991.2,2.19,50,0.0554,-0.78,0.06,-0.83
|
||||
201,做多,2026-02-17 06:45:00,2026-02-17 07:05:00,1991.2,1993.01,2.18,50,0.0548,0.1,0.05,0.04
|
||||
202,做空,2026-02-17 07:05:00,2026-02-17 10:00:00,1993.01,1986.61,2.18,50,0.0547,0.35,0.05,0.3
|
||||
203,做多,2026-02-17 10:00:00,2026-02-17 12:20:00,1986.61,1996.22,2.2,50,0.0553,0.53,0.06,0.48
|
||||
204,做空,2026-02-17 12:20:00,2026-02-17 13:15:00,1996.22,1975.63,2.2,50,0.0551,1.14,0.05,1.08
|
||||
205,做多,2026-02-17 13:15:00,2026-02-17 14:25:00,1975.63,1981.79,2.21,50,0.056,0.34,0.06,0.29
|
||||
206,做空,2026-02-17 14:25:00,2026-02-17 15:05:00,1981.79,1975.75,2.21,50,0.0558,0.34,0.06,0.28
|
||||
207,做多,2026-02-17 15:05:00,2026-02-17 18:00:00,1975.75,1974.07,2.22,50,0.0561,-0.09,0.06,-0.15
|
||||
208,做空,2026-02-17 18:00:00,2026-02-17 18:15:00,1974.07,1963.99,2.21,50,0.0561,0.57,0.06,0.51
|
||||
209,做多,2026-02-17 18:15:00,2026-02-17 19:00:00,1963.99,1966.66,2.22,50,0.0565,0.15,0.06,0.1
|
||||
210,做空,2026-02-17 19:00:00,2026-02-17 19:45:00,1966.66,1966.75,2.22,50,0.0564,-0.01,0.06,-0.06
|
||||
211,做多,2026-02-17 19:45:00,2026-02-17 20:05:00,1966.75,1973.21,2.22,50,0.0564,0.36,0.06,0.31
|
||||
212,做空,2026-02-17 20:05:00,2026-02-17 20:50:00,1973.21,1970.9,2.22,50,0.0563,0.13,0.06,0.07
|
||||
213,做多,2026-02-17 20:50:00,2026-02-17 21:10:00,1970.9,1979.05,2.22,50,0.0563,0.46,0.06,0.4
|
||||
214,做空,2026-02-17 21:10:00,2026-02-17 22:35:00,1979.05,1978.92,2.22,50,0.0562,0.01,0.06,-0.05
|
||||
215,做多,2026-02-17 22:35:00,2026-02-18 00:00:00,1978.92,1986.74,2.22,50,0.0562,0.44,0.06,0.38
|
||||
216,做空,2026-02-18 00:00:00,2026-02-18 01:10:00,1986.74,1964.67,2.23,50,0.056,1.24,0.06,1.18
|
||||
217,做多,2026-02-18 01:10:00,2026-02-18 02:20:00,1964.67,1986.33,2.24,50,0.0569,1.23,0.06,1.18
|
||||
218,做空,2026-02-18 02:20:00,2026-02-18 04:30:00,1986.33,1993.32,2.25,50,0.0566,-0.4,0.06,-0.45
|
||||
219,做多,2026-02-18 04:30:00,2026-02-18 04:40:00,1993.32,1997.94,2.24,50,0.0563,0.26,0.06,0.2
|
||||
220,做空,2026-02-18 04:40:00,2026-02-18 06:50:00,1997.94,1993.94,2.24,50,0.0562,0.22,0.06,0.17
|
||||
221,做多,2026-02-18 06:50:00,2026-02-18 11:25:00,1993.94,1993.01,2.25,50,0.0563,-0.05,0.06,-0.11
|
||||
222,做空,2026-02-18 11:25:00,2026-02-18 12:35:00,1993.01,1994.19,2.26,50,0.0568,-0.07,0.06,-0.12
|
||||
223,做多,2026-02-18 12:35:00,2026-02-18 14:20:00,1994.19,2001.76,2.26,50,0.0567,0.43,0.06,0.37
|
||||
224,做空,2026-02-18 14:20:00,2026-02-18 17:50:00,2001.76,2017.24,2.26,50,0.0566,-0.88,0.06,-0.93
|
||||
225,做多,2026-02-18 17:50:00,2026-02-18 22:30:00,2017.24,1967.63,2.25,50,0.0559,-2.77,0.05,-2.83
|
||||
226,做空,2026-02-18 22:30:00,2026-02-18 22:45:00,1967.63,1955.53,2.23,50,0.0566,0.68,0.06,0.63
|
||||
227,做多,2026-02-18 22:45:00,2026-02-18 23:05:00,1955.53,1983.75,2.23,50,0.0571,1.61,0.06,1.55
|
||||
228,做空,2026-02-18 23:05:00,2026-02-19 02:15:00,1983.75,1963.63,2.25,50,0.0566,1.14,0.06,1.08
|
||||
229,做多,2026-02-19 02:15:00,2026-02-19 04:30:00,1963.63,1947.9,2.26,50,0.0575,-0.9,0.06,-0.96
|
||||
230,做空,2026-02-19 04:30:00,2026-02-19 07:15:00,1947.9,1946.27,2.25,50,0.0577,0.09,0.06,0.04
|
||||
231,做多,2026-02-19 07:15:00,2026-02-19 07:25:00,1946.27,1947.6,2.25,50,0.0577,0.08,0.06,0.02
|
||||
232,做空,2026-02-19 07:25:00,2026-02-19 08:25:00,1947.6,1952.44,2.25,50,0.0577,-0.28,0.06,-0.34
|
||||
233,做多,2026-02-19 08:25:00,2026-02-19 09:10:00,1952.44,1969.01,2.25,50,0.0577,0.96,0.06,0.9
|
||||
234,做空,2026-02-19 09:10:00,2026-02-19 12:45:00,1969.01,1971.59,2.26,50,0.0574,-0.15,0.06,-0.2
|
||||
235,做多,2026-02-19 12:45:00,2026-02-19 14:05:00,1971.59,1971.53,2.26,50,0.0573,-0.0,0.06,-0.06
|
||||
236,做空,2026-02-19 14:05:00,2026-02-19 15:40:00,1971.53,1981.57,2.26,50,0.0573,-0.57,0.06,-0.63
|
||||
237,做多,2026-02-19 15:40:00,2026-02-19 17:20:00,1981.57,1977.7,2.25,50,0.0568,-0.22,0.06,-0.28
|
||||
238,做空,2026-02-19 17:20:00,2026-02-19 17:45:00,1977.7,1961.93,2.25,50,0.0568,0.9,0.06,0.84
|
||||
239,做多,2026-02-19 17:45:00,2026-02-19 22:50:00,1961.93,1939.99,2.26,50,0.0575,-1.26,0.06,-1.32
|
||||
240,做空,2026-02-19 22:50:00,2026-02-20 00:05:00,1939.99,1915.04,2.24,50,0.0578,1.44,0.06,1.39
|
||||
241,做多,2026-02-20 00:05:00,2026-02-20 01:15:00,1915.04,1941.03,2.26,50,0.0589,1.53,0.06,1.47
|
||||
242,做空,2026-02-20 01:15:00,2026-02-20 03:25:00,1941.03,1935.82,2.27,50,0.0585,0.3,0.06,0.25
|
||||
243,做多,2026-02-20 03:25:00,2026-02-20 04:45:00,1935.82,1947.16,2.27,50,0.0587,0.67,0.06,0.61
|
||||
244,做空,2026-02-20 04:45:00,2026-02-20 05:55:00,1947.16,1947.67,2.28,50,0.0585,-0.03,0.06,-0.09
|
||||
245,做多,2026-02-20 05:55:00,2026-02-20 07:00:00,1947.67,1943.15,2.28,50,0.0584,-0.26,0.06,-0.32
|
||||
246,做空,2026-02-20 07:00:00,2026-02-20 12:00:00,1943.15,1948.02,2.27,50,0.0585,-0.28,0.06,-0.34
|
||||
247,做多,2026-02-20 12:00:00,2026-02-20 13:30:00,1948.02,1960.28,2.28,50,0.0586,0.72,0.06,0.66
|
||||
248,做空,2026-02-20 13:30:00,2026-02-20 14:30:00,1960.28,1954.43,2.29,50,0.0584,0.34,0.06,0.28
|
||||
249,做多,2026-02-20 14:30:00,2026-02-20 15:15:00,1954.43,1959.51,2.29,50,0.0586,0.3,0.06,0.24
|
||||
250,做空,2026-02-20 15:15:00,2026-02-20 18:40:00,1959.51,1961.18,2.29,50,0.0585,-0.1,0.06,-0.16
|
||||
251,做多,2026-02-20 18:40:00,2026-02-20 20:50:00,1961.18,1946.59,2.29,50,0.0584,-0.85,0.06,-0.91
|
||||
252,做空,2026-02-20 20:50:00,2026-02-20 21:00:00,1946.59,1943.99,2.28,50,0.0586,0.15,0.06,0.1
|
||||
253,做多,2026-02-20 21:00:00,2026-02-20 22:30:00,1943.99,1944.3,2.28,50,0.0587,0.02,0.06,-0.04
|
||||
254,做空,2026-02-20 22:30:00,2026-02-21 06:10:00,1944.3,1964.49,2.28,50,0.0586,-1.18,0.06,-1.24
|
||||
255,做多,2026-02-21 06:10:00,2026-02-21 07:05:00,1964.49,1968.92,2.27,50,0.0577,0.26,0.06,0.2
|
||||
256,做空,2026-02-21 07:05:00,2026-02-21 08:45:00,1968.92,1963.92,2.27,50,0.0576,0.29,0.06,0.23
|
||||
257,做多,2026-02-21 08:45:00,2026-02-21 12:25:00,1963.92,1959.01,2.28,50,0.058,-0.29,0.06,-0.34
|
||||
258,做空,2026-02-21 12:25:00,2026-02-21 20:25:00,1959.01,1969.99,2.28,50,0.0581,-0.64,0.06,-0.7
|
||||
259,做多,2026-02-21 20:25:00,2026-02-21 22:05:00,1969.99,1981.03,2.27,50,0.0576,0.64,0.06,0.58
|
||||
260,做空,2026-02-21 22:05:00,2026-02-21 23:30:00,1981.03,1988.19,2.27,50,0.0574,-0.41,0.06,-0.47
|
||||
261,做多,2026-02-21 23:30:00,2026-02-21 23:40:00,1988.19,1989.55,2.27,50,0.057,0.08,0.06,0.02
|
||||
262,做空,2026-02-21 23:40:00,2026-02-22 00:00:00,1989.55,1979.46,2.27,50,0.057,0.58,0.06,0.52
|
||||
263,做多,2026-02-22 00:00:00,2026-02-22 01:40:00,1979.46,1988.74,2.27,50,0.0574,0.53,0.06,0.48
|
||||
264,做空,2026-02-22 01:40:00,2026-02-22 03:50:00,1988.74,1987.85,2.28,50,0.0572,0.05,0.06,-0.01
|
||||
265,做多,2026-02-22 03:50:00,2026-02-22 09:00:00,1987.85,1973.58,2.28,50,0.0573,-0.82,0.06,-0.87
|
||||
266,做空,2026-02-22 09:00:00,2026-02-22 11:15:00,1973.58,1968.26,2.28,50,0.0577,0.31,0.06,0.25
|
||||
267,做多,2026-02-22 11:15:00,2026-02-22 15:25:00,1968.26,1975.34,2.28,50,0.0579,0.41,0.06,0.35
|
||||
268,做空,2026-02-22 15:25:00,2026-02-22 16:20:00,1975.34,1973.39,2.28,50,0.0577,0.11,0.06,0.06
|
||||
269,做多,2026-02-22 16:20:00,2026-02-22 17:15:00,1973.39,1973.0,2.28,50,0.0578,-0.02,0.06,-0.08
|
||||
270,做空,2026-02-22 17:15:00,2026-02-22 20:00:00,1973.0,1976.79,2.28,50,0.0578,-0.22,0.06,-0.28
|
||||
271,做多,2026-02-22 20:00:00,2026-02-22 22:30:00,1976.79,1951.75,2.28,50,0.0576,-1.44,0.06,-1.5
|
||||
272,做空,2026-02-22 22:30:00,2026-02-23 01:30:00,1951.75,1935.57,2.26,50,0.0579,0.94,0.06,0.88
|
||||
273,做多,2026-02-23 01:30:00,2026-02-23 02:15:00,1935.57,1941.0,2.27,50,0.0586,0.32,0.06,0.26
|
||||
274,做空,2026-02-23 02:15:00,2026-02-23 02:35:00,1941.0,1940.45,2.27,50,0.0585,0.03,0.06,-0.02
|
||||
275,做多,2026-02-23 02:35:00,2026-02-23 02:50:00,1940.45,1942.01,2.27,50,0.0585,0.09,0.06,0.03
|
||||
276,做空,2026-02-23 02:50:00,2026-02-23 04:50:00,1942.01,1939.47,2.27,50,0.0584,0.15,0.06,0.09
|
||||
277,做多,2026-02-23 04:50:00,2026-02-23 05:35:00,1939.47,1949.72,2.27,50,0.0585,0.6,0.06,0.54
|
||||
278,做空,2026-02-23 05:35:00,2026-02-23 07:20:00,1949.72,1951.6,2.28,50,0.0584,-0.11,0.06,-0.17
|
||||
279,做多,2026-02-23 07:20:00,2026-02-23 07:55:00,1951.6,1957.01,2.27,50,0.0582,0.32,0.06,0.26
|
||||
280,做空,2026-02-23 07:55:00,2026-02-23 08:25:00,1957.01,1947.41,2.28,50,0.0581,0.56,0.06,0.5
|
||||
281,做多,2026-02-23 08:25:00,2026-02-23 11:05:00,1947.41,1866.1,2.29,50,0.0589,-4.79,0.05,-4.85
|
||||
282,做空,2026-02-23 11:05:00,2026-02-23 11:15:00,1866.1,1858.39,2.25,50,0.0602,0.46,0.06,0.41
|
||||
283,做多,2026-02-23 11:15:00,2026-02-23 13:15:00,1858.39,1866.46,2.25,50,0.0605,0.49,0.06,0.43
|
||||
284,做空,2026-02-23 13:15:00,2026-02-23 16:35:00,1866.46,1877.82,2.25,50,0.0604,-0.69,0.06,-0.74
|
||||
285,做多,2026-02-23 16:35:00,2026-02-23 17:10:00,1877.82,1884.54,2.25,50,0.0598,0.4,0.06,0.35
|
||||
286,做空,2026-02-23 17:10:00,2026-02-23 20:30:00,1884.54,1907.37,2.25,50,0.0596,-1.36,0.06,-1.42
|
||||
287,做多,2026-02-23 20:30:00,2026-02-23 20:35:00,1907.37,1919.57,2.23,50,0.0585,0.71,0.06,0.66
|
||||
288,做空,2026-02-23 20:35:00,2026-02-23 22:35:00,1919.57,1906.62,2.24,50,0.0583,0.76,0.06,0.7
|
||||
289,做多,2026-02-23 22:35:00,2026-02-24 10:30:00,1906.62,1849.89,2.25,50,0.0589,-3.34,0.05,-3.4
|
||||
290,做空,2026-02-24 10:30:00,2026-02-24 11:00:00,1849.89,1836.02,2.22,50,0.06,0.83,0.06,0.78
|
||||
291,做多,2026-02-24 11:00:00,2026-02-24 13:05:00,1836.02,1836.44,2.23,50,0.0607,0.03,0.06,-0.03
|
||||
292,做空,2026-02-24 13:05:00,2026-02-24 13:20:00,1836.44,1815.44,2.23,50,0.0606,1.27,0.06,1.22
|
||||
293,做多,2026-02-24 13:20:00,2026-02-24 16:30:00,1815.44,1832.52,2.24,50,0.0616,1.05,0.06,1.0
|
||||
294,做空,2026-02-24 16:30:00,2026-02-24 17:05:00,1832.52,1824.3,2.25,50,0.0613,0.5,0.06,0.45
|
||||
295,做多,2026-02-24 17:05:00,2026-02-24 20:10:00,1824.3,1826.47,2.25,50,0.0617,0.13,0.06,0.08
|
||||
296,做空,2026-02-24 20:10:00,2026-02-24 21:20:00,1826.47,1819.72,2.25,50,0.0616,0.42,0.06,0.36
|
||||
297,做多,2026-02-24 21:20:00,2026-02-24 22:35:00,1819.72,1821.38,2.25,50,0.062,0.1,0.06,0.05
|
||||
298,做空,2026-02-24 22:35:00,2026-02-25 02:10:00,1821.38,1846.04,2.25,50,0.0619,-1.53,0.06,-1.58
|
||||
299,做多,2026-02-25 02:10:00,2026-02-25 03:05:00,1846.04,1853.79,2.24,50,0.0606,0.47,0.06,0.41
|
||||
300,做空,2026-02-25 03:05:00,2026-02-25 05:00:00,1853.79,1850.16,2.24,50,0.0605,0.22,0.06,0.16
|
||||
301,做多,2026-02-25 05:00:00,2026-02-25 09:05:00,1850.16,1864.09,2.24,50,0.0606,0.84,0.06,0.79
|
||||
302,做空,2026-02-25 09:05:00,2026-02-25 12:00:00,1864.09,1900.0,2.26,50,0.0607,-2.18,0.06,-2.24
|
||||
303,做多,2026-02-25 12:00:00,2026-02-25 14:20:00,1900.0,1892.77,2.24,50,0.0589,-0.43,0.06,-0.48
|
||||
304,做空,2026-02-25 14:20:00,2026-02-25 14:50:00,1892.77,1885.31,2.23,50,0.059,0.44,0.06,0.38
|
||||
305,做多,2026-02-25 14:50:00,2026-02-25 16:20:00,1885.31,1896.51,2.24,50,0.0593,0.66,0.06,0.61
|
||||
306,做空,2026-02-25 16:20:00,2026-02-25 19:05:00,1896.51,1914.28,2.24,50,0.0591,-1.05,0.06,-1.11
|
||||
307,做多,2026-02-25 19:05:00,2026-02-25 19:10:00,1914.28,1914.26,2.23,50,0.0583,-0.0,0.06,-0.06
|
||||
308,做空,2026-02-25 19:10:00,2026-02-26 03:10:00,1914.26,2065.7,2.23,50,0.0583,-8.82,0.06,-8.88
|
||||
309,做多,2026-02-26 03:10:00,2026-02-26 04:50:00,2065.7,2077.16,2.14,50,0.0518,0.59,0.05,0.54
|
||||
310,做空,2026-02-26 04:50:00,2026-02-26 06:40:00,2077.16,2088.92,2.15,50,0.0516,-0.61,0.05,-0.66
|
||||
311,做多,2026-02-26 06:40:00,2026-02-26 10:45:00,2088.92,2048.37,2.14,50,0.0512,-2.08,0.05,-2.13
|
||||
312,做空,2026-02-26 10:45:00,2026-02-26 13:15:00,2048.37,2059.76,2.13,50,0.0519,-0.59,0.05,-0.64
|
||||
313,做多,2026-02-26 13:15:00,2026-02-26 14:05:00,2059.76,2070.3,2.12,50,0.0515,0.54,0.05,0.49
|
||||
314,做空,2026-02-26 14:05:00,2026-02-26 14:45:00,2070.3,2061.26,2.12,50,0.0513,0.46,0.05,0.41
|
||||
|
@@ -0,0 +1,37 @@
|
||||
period,std,train_final,train_ret_pct,train_trades,train_liq,test_final,test_ret_pct,test_trades,test_liq,score
|
||||
30,3.0,6.461292242669117e-12,-99.99999999999677,6251,2111,1.5236368612973373e-11,-99.99999999999238,5324,1148,1.5236368612973373e-11
|
||||
20,3.0,1.8100835126072174e-13,-99.99999999999991,8303,2213,2.004484456301478e-13,-99.9999999999999,7119,1125,2.004484456301478e-13
|
||||
30,2.8,2.4311483078671436e-12,-99.99999999999878,7043,2250,1.7667468163728375e-13,-99.99999999999991,6027,1207,1.7667468163728375e-13
|
||||
20,2.8,7.846644590273088e-17,-100.0,9405,2411,1.373663083431439e-15,-100.0,8162,1200,1.373663083431439e-15
|
||||
15,3.0,4.000972689149238e-14,-99.99999999999999,10176,2274,1.334121125924488e-15,-100.0,9020,1127,1.334121125924488e-15
|
||||
12,3.0,1.3648909498077833e-16,-100.0,12248,2312,3.221031658827695e-16,-100.0,10961,1111,3.221031658827695e-16
|
||||
30,2.5,3.5612711817081846e-19,-100.0,8364,2548,2.6039428085637916e-16,-100.0,7169,1309,2.6039428085637916e-16
|
||||
10,3.0,1.0851271143245777e-19,-100.0,14554,2331,1.5973234572926277e-17,-100.0,12954,1056,1.5973234572926277e-17
|
||||
15,2.8,1.0867209668553655e-17,-100.0,11611,2443,2.8298588113655214e-18,-100.0,10334,1169,2.8298588113655214e-18
|
||||
8,3.0,5.306932488644652e-21,-100.0,17958,2357,1.2736252312876604e-19,-100.0,16166,1010,1.2736252312876604e-19
|
||||
12,2.8,1.4286513547325967e-19,-100.0,13966,2448,1.0033977462584242e-19,-100.0,12480,1164,1.0033977462584242e-19
|
||||
20,2.5,2.2403774532126082e-23,-100.0,11128,2662,7.765130502770661e-20,-100.0,9730,1294,7.765130502770661e-20
|
||||
30,2.2,7.112452348296382e-24,-100.0,9746,2837,2.178522685356585e-20,-100.0,8376,1404,2.178522685356585e-20
|
||||
10,2.8,1.14378568397889e-22,-100.0,16467,2419,1.7504767423183517e-20,-100.0,14860,1099,1.7504767423183517e-20
|
||||
15,2.5,1.2889707168075324e-24,-100.0,13904,2665,7.701898585592486e-22,-100.0,12376,1244,7.701898585592486e-22
|
||||
30,2.0,3.3954467452863534e-30,-100.0,10737,3038,3.006982280285153e-23,-100.0,9277,1476,3.006982280285153e-23
|
||||
8,2.8,2.3911268173585217e-25,-100.0,20200,2424,2.6239693580748698e-23,-100.0,18347,1047,2.6239693580748698e-23
|
||||
12,2.5,1.5959390099076778e-26,-100.0,16840,2666,2.5122374088172532e-24,-100.0,15097,1197,2.5122374088172532e-24
|
||||
20,2.2,4.075155061653048e-30,-100.0,13056,2898,1.6217540014835198e-24,-100.0,11509,1387,1.6217540014835198e-24
|
||||
10,2.5,1.5239252240418153e-27,-100.0,19776,2602,3.478054992553642e-26,-100.0,17847,1143,3.478054992553642e-26
|
||||
30,1.8,2.905397760666862e-35,-100.0,11783,3196,1.4643221654306065e-26,-100.0,10238,1510,1.4643221654306065e-26
|
||||
20,2.0,4.5258883799074187e-35,-100.0,14558,3084,6.0778437333199835e-28,-100.0,12766,1425,6.0778437333199835e-28
|
||||
15,2.2,1.0473150457667376e-34,-100.0,16471,2949,4.616747557539696e-28,-100.0,14639,1329,4.616747557539696e-28
|
||||
8,2.5,3.728422330048161e-32,-100.0,24241,2572,8.443947733942594e-30,-100.0,22035,1088,8.443947733942594e-30
|
||||
12,2.2,4.023491430830127e-34,-100.0,19939,2849,2.0103723058079613e-31,-100.0,17925,1278,2.0103723058079613e-31
|
||||
15,2.0,1.5077333275255206e-39,-100.0,18290,3047,4.5852539168192905e-32,-100.0,16384,1379,4.5852539168192905e-32
|
||||
20,1.8,3.1358668307895184e-40,-100.0,16081,3234,3.528256253001935e-32,-100.0,14238,1477,3.528256253001935e-32
|
||||
10,2.2,9.818937063199508e-37,-100.0,23289,2808,8.301596164191992e-34,-100.0,21116,1192,8.301596164191992e-34
|
||||
12,2.0,2.89871510624932e-41,-100.0,22108,2997,5.7249833676044525e-36,-100.0,19972,1312,5.7249833676044525e-36
|
||||
15,1.8,1.9646377910410098e-43,-100.0,20241,3165,1.887622828901651e-36,-100.0,18203,1403,1.887622828901651e-36
|
||||
8,2.2,3.137207043844276e-39,-100.0,28429,2715,3.907836948794964e-37,-100.0,26080,1123,3.907836948794964e-37
|
||||
10,2.0,3.772919321721765e-43,-100.0,25796,2936,3.0387903785706536e-39,-100.0,23573,1242,3.0387903785706536e-39
|
||||
12,1.8,2.2809761615524126e-47,-100.0,24375,3136,2.3011372195381717e-40,-100.0,22137,1322,2.3011372195381717e-40
|
||||
8,2.0,1.0509234742751481e-45,-100.0,31437,2841,8.788965059420589e-44,-100.0,28899,1160,8.788965059420589e-44
|
||||
10,1.8,5.805887390677206e-50,-100.0,28616,3081,2.7972542140757193e-44,-100.0,26107,1254,2.7972542140757193e-44
|
||||
8,1.8,2.081454986276226e-52,-100.0,34477,2948,9.722792700824057e-50,-100.0,31739,1170,9.722792700824057e-50
|
||||
|
@@ -0,0 +1,37 @@
|
||||
period,std,train_final,train_ret_pct,train_trades,train_liq,test_final,test_ret_pct,test_trades,test_liq
|
||||
30,3.0,10.33503463017524,-94.83248268491238,6729,2627,9.105543803335324,-95.44722809833233,5622,1452
|
||||
30,2.8,5.776936552726516,-97.11153172363674,7595,2844,5.8310318500270775,-97.08448407498646,6321,1513
|
||||
20,3.0,2.8530376604538237,-98.57348116977309,8932,2894,3.117142538047551,-98.44142873097623,7487,1533
|
||||
30,2.5,3.3090997870703003,-98.34545010646485,8894,3101,2.9901743436510984,-98.50491282817445,7453,1604
|
||||
20,2.8,0.859787066661548,-99.57010646666923,10085,3122,1.9227920948602537,-99.03860395256987,8513,1595
|
||||
30,2.2,0.6281222070732229,-99.68593889646338,10267,3369,1.236067041291377,-99.38196647935432,8634,1668
|
||||
20,2.5,0.25278361222515633,-99.87360819388742,11847,3394,1.049877999265477,-99.47506100036726,10073,1644
|
||||
15,3.0,1.466920389212773,-99.26653980539362,10948,3115,0.9504725191291745,-99.52476374043542,9444,1587
|
||||
15,2.8,0.40768152859129914,-99.79615923570435,12417,3310,0.7301936713745412,-99.63490316431273,10761,1640
|
||||
30,2.0,0.27389542637526637,-99.86305228681236,11185,3489,0.5860341454411505,-99.70698292727943,9512,1716
|
||||
12,3.0,0.4596628661296959,-99.77016856693515,13093,3243,0.4599583255360801,-99.77002083723195,11385,1580
|
||||
15,2.5,0.07101870013743423,-99.96449064993128,14756,3554,0.27989601683829196,-99.86005199158086,12771,1662
|
||||
20,2.2,0.068694671965183,-99.96565266401741,13743,3599,0.2447384990957471,-99.87763075045213,11824,1712
|
||||
30,1.8,0.07356202139088691,-99.96321898930455,12192,3609,0.23106787386920916,-99.88446606306539,10474,1746
|
||||
12,2.8,0.20911756492338415,-99.8954412175383,14849,3399,0.2173258061277338,-99.89133709693613,12877,1605
|
||||
10,3.0,0.1284276762723427,-99.93578616186383,15455,3345,0.1658833559115693,-99.91705832204421,13421,1582
|
||||
20,2.0,0.027822496858016875,-99.98608875157099,15185,3723,0.10850768549118871,-99.9457461572544,13061,1728
|
||||
10,2.8,0.062411539565720396,-99.96879423021714,17473,3515,0.0858355994398584,-99.95708220028007,15299,1600
|
||||
12,2.5,0.0635800161079057,-99.96820999194605,17762,3624,0.07595434907945135,-99.96202282546028,15517,1641
|
||||
15,2.2,0.011211866028193341,-99.9943940669859,17256,3759,0.07346375074383373,-99.96326812462809,14996,1687
|
||||
20,1.8,0.010177972068216252,-99.99491101396589,16657,3813,0.041379392242463335,-99.97931030387876,14523,1765
|
||||
8,3.0,0.037529843697168386,-99.98123507815141,18948,3467,0.030619960044026544,-99.98469001997799,16661,1580
|
||||
15,2.0,0.004790098785046004,-99.99760495060748,19085,3851,0.0250058198917987,-99.9874970900541,16699,1703
|
||||
10,2.5,0.020080566762398937,-99.9899597166188,20810,3675,0.02154161161844521,-99.98922919419078,18304,1622
|
||||
12,2.2,0.006198215965126392,-99.99690089201744,20863,3802,0.01569234833017946,-99.9921538258349,18304,1675
|
||||
8,2.8,0.00916331137620061,-99.9954183443119,21278,3593,0.013446224481937236,-99.99327688775904,18831,1590
|
||||
15,1.8,0.00195636598029706,-99.99902181700985,20986,3912,0.007973883235858103,-99.99601305838208,18506,1711
|
||||
12,2.0,0.0012611903383017201,-99.99936940483084,22983,3884,0.0049442565518793904,-99.99752787172406,20318,1667
|
||||
10,2.2,0.0015631498325544685,-99.99921842508373,24294,3843,0.004016982771284942,-99.99799150861436,21533,1619
|
||||
8,2.5,0.0015805889869186715,-99.99920970550654,25383,3778,0.00222758185497439,-99.99888620907251,22550,1619
|
||||
12,1.8,0.0003285760597477184,-99.99983571197012,25197,3969,0.0014253657508011418,-99.9992873171246,22474,1670
|
||||
10,2.0,0.00030181924086439277,-99.99984909037957,26744,3905,0.0007558609511890611,-99.9996220695244,23966,1645
|
||||
8,2.2,0.00022388168465948394,-99.99988805915767,29572,3888,0.000283647480462369,-99.99985817625976,26546,1608
|
||||
10,1.8,0.00010484354042229784,-99.9999475782298,29476,3949,0.00015541841539480644,-99.9999222907923,26481,1640
|
||||
8,2.0,3.0427493228289115e-05,-99.99998478625339,32549,3962,3.787843338427551e-05,-99.99998106078331,29334,1613
|
||||
8,1.8,5.318861339787151e-06,-99.99999734056934,35502,3981,6.1348022466747185e-06,-99.99999693259888,32157,1599
|
||||
|
49
strategy/results/bb_5m_practical_upgrade_bandwidth_tune.csv
Normal file
49
strategy/results/bb_5m_practical_upgrade_bandwidth_tune.csv
Normal file
@@ -0,0 +1,49 @@
|
||||
bb_period,bb_std,cooldown,min_bw,final,ret,trades,liq,win,dd,sharpe,fee,rebate
|
||||
30,3.2,6,0.01,202.98777028457513,1.4938851422875672,2208,0,64.4927536231884,-2.2659000933991535,0.5747142550615898,4.492191078113778,4.042051704177064
|
||||
30,3.2,6,0.008,202.88007457111019,1.4400372855550927,2497,0,63.99679615538646,-2.3593132155964156,0.5474772340529435,5.077568757707738,4.568895760736814
|
||||
30,3.2,12,0.01,202.58279532236259,1.2913976611812927,2176,0,63.60294117647059,-2.590578505705281,0.49034397612249453,4.425821502882915,3.9823209224653042
|
||||
30,3.2,12,0.008,202.43724464440305,1.2186223222015258,2453,0,63.06563391765185,-2.6964621320131528,0.45661035313826664,4.984364752542757,4.4850138457153115
|
||||
30,3.2,6,0.005,202.2604553875168,1.1302276937583997,2848,0,63.55337078651685,-3.5097750900355322,0.4233881729734044,5.800483411417114,5.2195225693696905
|
||||
30,3.2,6,0.0,201.9035397473293,0.9517698736646452,2983,0,62.45390546429769,-3.6901419995414244,0.3554736578132862,6.071731305514356,5.463647284287156
|
||||
30,3.2,12,0.005,201.87948930618595,0.9397446530929727,2788,0,62.51793400286944,-3.7314549188814397,0.3459557408534809,5.673598716356395,5.1053271761221275
|
||||
30,3.2,24,0.008,201.81718023856013,0.9085901192800634,2321,0,60.83584661783714,-3.1850135601426643,0.3332848294762347,4.711163723354367,4.239135720345717
|
||||
40,3.2,24,0.008,201.7362421481199,0.8681210740599568,1762,0,61.80476730987514,-1.9330254703131686,0.33009880295284993,3.5617733962125127,3.2028717014335406
|
||||
30,3.2,24,0.01,201.69506662016363,0.8475333100818148,2071,0,61.41960405601159,-3.0289149936820934,0.31756756837299815,4.202969916048575,3.7817585189246183
|
||||
30,3.2,12,0.0,201.60362661159775,0.8018133057988733,2922,0,61.327857631759066,-3.88911319759859,0.2941026586132461,5.943783104874334,5.348494371558028
|
||||
30,3.0,6,0.01,201.5881617500534,0.7940808750266939,2543,0,63.429020841525755,-2.368575342977323,0.2998262616505584,5.151884495340698,4.633970942969105
|
||||
40,3.2,24,0.01,201.53527397642122,0.7676369882106115,1605,0,62.55451713395639,-1.9504615008019073,0.2907552932707512,3.2424316070919357,2.91546508291806
|
||||
30,3.0,6,0.008,201.359992187183,0.6799960935914982,2918,0,63.19396847155586,-2.027912276846223,0.2610014112678299,5.899172349883858,5.306536721796989
|
||||
30,3.0,12,0.01,201.3241380805589,0.662069040279448,2506,0,62.729449321628096,-2.8976334001800694,0.24838320050757742,5.080944389695803,4.570128417005312
|
||||
30,3.0,12,0.008,201.31165446949683,0.6558272347484149,2866,0,62.35170969993021,-2.494460658608773,0.24878271250544268,5.80043717869557,5.217675411997363
|
||||
30,3.0,24,0.01,201.26991592259085,0.6349579612954273,2368,0,61.02195945945946,-3.348407035056823,0.23124334375082511,4.807697212750294,4.324206690738638
|
||||
30,3.0,24,0.008,201.25444575369687,0.6272228768484354,2688,0,60.56547619047619,-3.1621600662850256,0.22981479221382087,5.449274512519768,4.901629784853851
|
||||
30,3.2,24,0.005,201.17465506334136,0.587327531670681,2627,0,60.22078416444614,-4.2867277356414775,0.21102822502134555,5.338402308340532,4.803653591872367
|
||||
40,3.2,6,0.008,201.0778775233752,0.5389387616876036,1853,0,63.680518078791145,-1.545875090009332,0.21018483710385255,3.730990845759943,3.3551758773915945
|
||||
40,3.2,24,0.005,201.05984222600543,0.5299211130027146,1924,0,61.018711018711016,-2.175922708147283,0.19495371215945767,3.885764208269912,3.494473381060668
|
||||
40,3.2,24,0.0,200.85259022124131,0.4262951106206571,1977,0,60.59686393525544,-2.2131317121589404,0.15572489459076294,3.9910079187965377,3.589195518538243
|
||||
40,3.2,6,0.01,200.74117229778386,0.3705861488919311,1680,0,63.988095238095234,-1.788489097899884,0.14388428114556331,3.3801026625472996,3.039379763592075
|
||||
40,3.2,6,0.005,200.6975214875542,0.3487607437771061,2038,0,63.297350343473994,-1.8348344987913379,0.1307282485158805,4.1020755008586685,3.689158017516957
|
||||
30,3.2,24,0.0,200.6742618681597,0.33713093407985184,2748,0,58.806404657933044,-4.526694095829043,0.12031876886338758,5.578810922296089,5.020023604160509
|
||||
40,3.2,12,0.008,200.65656048664087,0.32828024332043526,1824,0,62.88377192982456,-1.7544366504391178,0.12833478287726025,3.6720632612140545,3.3021471605391497
|
||||
30,3.0,6,0.005,200.51551216591736,0.2577560829586787,3377,0,62.51110453064851,-2.9778328420115088,0.09497684815116508,6.823545946251757,6.138485174444638
|
||||
40,3.2,6,0.0,200.44496962075274,0.2224848103763719,2097,0,62.994754411063425,-2.042148146654995,0.08158240969215196,4.218333320816779,3.79379346557969
|
||||
40,3.0,24,0.008,200.41889346236763,0.2094467311838173,2057,0,61.93485658726301,-2.473425069100074,0.07868630999290598,4.146171354749355,3.72884910922223
|
||||
30,3.0,12,0.005,200.35022974683667,0.17511487341833742,3300,0,61.36363636363637,-3.584345639913721,0.06306984952787358,6.672617704418062,6.002651107710117
|
||||
40,3.2,12,0.01,200.24642098781575,0.12321049390787665,1659,0,63.29113924050633,-2.2088172045713748,0.047913641900456855,3.3367725501172822,3.000389348021997
|
||||
40,3.2,12,0.005,200.22091496566105,0.11045748283052605,2002,0,62.38761238761239,-2.0783640787319086,0.03817994892546192,4.027940397396305,3.6224432772034887
|
||||
40,3.0,24,0.01,200.12568455038564,0.06284227519282126,1879,0,62.16072378924961,-2.6329610918170374,0.023564976494820568,3.787542396891309,3.4060828242510723
|
||||
40,3.0,6,0.008,200.0678037808892,0.03390189044459646,2194,0,63.947128532360985,-2.2038606611252476,0.01294800862092224,4.410398919734593,3.966658239689972
|
||||
30,3.0,6,0.0,200.00414940285927,0.002074701429634729,3569,0,61.58587839731017,-3.4138707553280483,-0.0006647490253754809,7.204083538326778,6.4809759087145915
|
||||
40,3.2,12,0.0,199.9609691102816,-0.019515444859194986,2060,0,61.99029126213592,-2.293284464503728,-0.012281258667209633,4.142089182262913,3.725180692979831
|
||||
30,3.0,12,0.0,199.86477350989745,-0.06761324505127675,3488,0,60.321100917431195,-3.9479783254082292,-0.026217988255613115,7.044972103443261,6.337776620729888
|
||||
30,3.0,24,0.005,199.8322173667805,-0.08389131660975124,3078,0,59.25925925925925,-4.517336088935309,-0.031095706303734948,6.227919385867038,5.602429614435114
|
||||
40,3.0,24,0.005,199.5939851399495,-0.20300743002525223,2287,0,60.690861390467866,-3.1641220863467083,-0.07962941557219835,4.605201690819581,4.141987512861499
|
||||
40,3.0,12,0.008,199.5739264063975,-0.21303679680124785,2148,0,63.17504655493482,-2.615052284973501,-0.08139777980329083,4.316235063292179,3.8819178516682813
|
||||
40,3.0,6,0.01,199.4783021660671,-0.2608489169664523,1988,0,63.581488933601605,-2.6165649578562693,-0.09950203972642017,3.991524078241081,3.5896750888907443
|
||||
40,3.0,24,0.0,199.34357556785355,-0.3282122160732257,2360,0,60.21186440677966,-3.3377613611040715,-0.1256995824626251,4.74929125388248,4.271670892552751
|
||||
30,3.0,24,0.0,199.30001953765344,-0.34999023117327965,3243,0,58.125192722787546,-4.896971344439777,-0.12506755033132605,6.553042403347132,5.89504751509868
|
||||
40,3.0,12,0.01,199.12086527405495,-0.4395673629725252,1956,0,62.985685071574636,-2.934702029502688,-0.16766517034426934,3.9282781540179963,3.532758588982499
|
||||
40,3.0,6,0.005,199.01319225044602,-0.49340387477698755,2458,0,62.9780309194467,-3.206770049240731,-0.19188065769564314,4.932566481122759,4.436623248761567
|
||||
40,3.0,6,0.0,198.65444873410513,-0.6727756329474346,2539,0,62.46553761323356,-3.483785802636902,-0.25943426479073867,5.091061673108702,4.579273159284268
|
||||
40,3.0,12,0.005,198.53430497909721,-0.7328475104513927,2400,0,62.041666666666664,-3.6063962830445178,-0.2822792363382157,4.814513695479092,4.33038262002996
|
||||
40,3.0,12,0.0,198.16460271518014,-0.9176986424099312,2480,0,61.41129032258065,-3.8946055152910333,-0.35154409034010436,4.970878228218944,4.47111508616677
|
||||
|
9
strategy/results/bb_5m_practical_upgrade_candidates.csv
Normal file
9
strategy/results/bb_5m_practical_upgrade_candidates.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
name,bb_period,bb_std,lev,trend_ema,cooldown_bars,stop_loss,take_profit,final,ret,trades,liq,win,dd,sharpe,fee,rebate
|
||||
D_trend288_cd12,30,3.0,1,288.0,12,0.0,0.0,199.86477350989745,-0.06761324505127675,3488,0,60.321100917431195,-3.9479783254082292,-0.026217988255613115,7.044972103443261,6.337776620729888
|
||||
B_trend288,30,3.0,1,288.0,0,0.0,0.0,199.7540264365565,-0.1229867817217496,3668,0,62.05016357688113,-3.996173585769327,-0.046036770219455056,7.41289979748533,6.668913917641575
|
||||
C_trend576,30,3.0,1,576.0,0,0.0,0.0,199.20628338025136,-0.39685830987431814,4143,0,61.18754525706011,-4.6188391069942725,-0.14008705265439372,8.355454097286774,7.515422312937967
|
||||
E_trend288_cd12_sl12_tp15,30,3.0,1,288.0,12,0.012,0.015,195.3494628170402,-2.3252685914798974,3710,0,52.129380053908356,-4.882606479135802,-1.4756369432482566,7.362551062011999,6.62365864234843
|
||||
F_trend288_cd6_sl10_tp20,30,3.0,1,288.0,6,0.01,0.02,195.3050328845755,-2.347483557712252,3796,0,48.840885142255004,-5.078860622065719,-1.5321092835282057,7.536365316666955,6.7800929289619924
|
||||
H_bb20_30_trend576_cd12,20,3.0,1,576.0,12,0.01,0.015,189.48915432155357,-5.255422839223215,6395,0,49.1164972634871,-10.60519250897687,-2.8074280977201473,12.531119081963354,11.272889176910006
|
||||
G_bb20_28_trend288_cd12,20,2.8,1,288.0,12,0.012,0.015,189.04763867132164,-5.476180664339182,6479,0,52.106806605957715,-11.116408258934996,-2.9900816266006194,12.667135948143327,11.395318795619543
|
||||
A_base_no_filter,30,3.0,1,,0,0.0,0.0,187.87751952363539,-6.061240238182307,8669,0,61.62187103472142,-12.334791284875877,-1.4020222751730407,16.98060303079724,15.274934432023217
|
||||
|
2193
strategy/results/bb_5m_practical_upgrade_daily.csv
Normal file
2193
strategy/results/bb_5m_practical_upgrade_daily.csv
Normal file
File diff suppressed because it is too large
Load Diff
3
strategy/results/bb_5m_practical_upgrade_summary.csv
Normal file
3
strategy/results/bb_5m_practical_upgrade_summary.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
label,final_equity,return_pct,trade_count,win_rate_pct,liq_count,max_drawdown,total_fee,total_rebate,sharpe
|
||||
"Baseline (BB30/3.0, no filters)",187.87751952363539,-6.061240238182307,8669,61.62187103472142,0,-12.334791284875877,16.98060303079724,15.274934432023217,-1.4020222751730407
|
||||
Practical (BB30/3.2 + EMA + BW + cooldown),202.98777028457513,1.4938851422875672,2208,64.4927536231884,0,-2.2659000933991535,4.492191078113778,4.042051704177064,0.5747142550615898
|
||||
|
BIN
strategy/results/bb_trade_d_plan_2020_2025.png
Normal file
BIN
strategy/results/bb_trade_d_plan_2020_2025.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
111
strategy/run_bb_15m_2020_2025.py
Normal file
111
strategy/run_bb_15m_2020_2025.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
BB(10, 2.5) 均值回归策略回测 — 15分钟K线 | 2020-2025 | 200U | 万五手续费 | 90%返佣次日8点到账
|
||||
"""
|
||||
import sys, time
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1]))
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
from pathlib import Path
|
||||
|
||||
from strategy.bb_backtest import BBConfig, run_bb_backtest
|
||||
from strategy.data_loader import load_klines
|
||||
|
||||
out_dir = Path(__file__).resolve().parent / "results"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# ============================================================
|
||||
# 加载 15 分钟 K 线数据 (2020-2025)
|
||||
# ============================================================
|
||||
YEARS = list(range(2020, 2026))
|
||||
data = {}
|
||||
|
||||
print("加载 15 分钟 K 线数据 (2020-2025)...")
|
||||
t0 = time.time()
|
||||
for y in YEARS:
|
||||
end_year = y + 1 if y < 2025 else 2026 # 2025 数据到 2026-01-01 前
|
||||
df = load_klines('15m', f'{y}-01-01', f'{end_year}-01-01')
|
||||
data[y] = df
|
||||
print(f" {y}: {len(df):>7,} 条 ({df.index[0]} ~ {df.index[-1]})")
|
||||
print(f"数据加载完成 ({time.time()-t0:.1f}s)\n")
|
||||
|
||||
# ============================================================
|
||||
# 配置: 200U | 万五手续费 | 90%返佣次日8点到账
|
||||
# ============================================================
|
||||
cfg = BBConfig(
|
||||
bb_period=10,
|
||||
bb_std=2.5,
|
||||
leverage=50,
|
||||
initial_capital=200.0,
|
||||
margin_pct=0.01, # 1% 权益/单
|
||||
max_daily_loss=50.0, # 固定值备用
|
||||
max_daily_loss_pct=0.05, # 日亏损上限 = 当日起始权益的 5%
|
||||
fee_rate=0.0005, # 万五 (0.05%) 开平仓各万五
|
||||
rebate_rate=0.0,
|
||||
rebate_pct=0.90, # 90% 手续费返佣
|
||||
rebate_hour_utc=0, # UTC 0点 = 北京时间早上8点到账
|
||||
# 强平
|
||||
liq_enabled=True,
|
||||
maint_margin_rate=0.005, # 0.5% 维持保证金率
|
||||
# 滑点
|
||||
slippage_pct=0.0005, # 0.05% 滑点
|
||||
# 市场容量限制
|
||||
max_notional=500000.0, # 单笔最大名义价值 50万U
|
||||
# 加仓
|
||||
pyramid_enabled=True,
|
||||
pyramid_step=0.01, # 递增加仓
|
||||
pyramid_max=3,
|
||||
)
|
||||
|
||||
# ============================================================
|
||||
# 运行回测 (滚仓: 200U 起,逐年累加不复位)
|
||||
# ============================================================
|
||||
df_full = pd.concat([data[y] for y in YEARS])
|
||||
r_full = run_bb_backtest(df_full, cfg)
|
||||
d_full = r_full.daily_stats
|
||||
eq_full = d_full["equity"].astype(float)
|
||||
pnl_full = d_full["pnl"].astype(float)
|
||||
eq_curve = r_full.equity_curve["equity"].dropna()
|
||||
|
||||
final_eq = float(eq_full.iloc[-1])
|
||||
ret_pct = (final_eq - 200) / 200 * 100
|
||||
dd_full = float((eq_full - eq_full.cummax()).min())
|
||||
sharpe_full = float(pnl_full.mean() / pnl_full.std()) * np.sqrt(365) if pnl_full.std() > 0 else 0
|
||||
win_full = sum(1 for t in r_full.trades if t.net_pnl > 0) / max(len(r_full.trades), 1) * 100
|
||||
|
||||
print("=" * 100)
|
||||
print(" BB(10, 2.5) 15分钟K线 | 200U 起滚仓 | 万五 fee | 90% 返佣 | 含强平+滑点+容量限制")
|
||||
print("=" * 100)
|
||||
liq_count = sum(1 for t in r_full.trades if t.fee == 0.0 and t.net_pnl < 0)
|
||||
print(f" 初始本金: 200U | 最终权益: {final_eq:,.0f}U | 收益率: {ret_pct:+,.1f}%")
|
||||
print(f" 交易次数: {len(r_full.trades)} | 胜率: {win_full:.1f}% | 强平次数: {liq_count} | 最大回撤: {dd_full:+,.0f}U")
|
||||
print(f" 总手续费: {r_full.total_fee:,.0f} | 总返佣: {r_full.total_rebate:,.0f} | Sharpe: {sharpe_full:.2f}")
|
||||
print("-" * 100)
|
||||
print(" 年末权益:")
|
||||
for y in YEARS:
|
||||
mask = eq_curve.index.year == y
|
||||
if mask.any():
|
||||
yr_eq = float(eq_curve.loc[mask].iloc[-1])
|
||||
print(f" {y} 年末: {yr_eq:,.0f}U")
|
||||
print("=" * 100)
|
||||
|
||||
# ============================================================
|
||||
# 生成权益曲线图 (对数坐标,滚仓复利)
|
||||
# ============================================================
|
||||
fig, ax = plt.subplots(1, 1, figsize=(14, 6), dpi=120)
|
||||
eq_ser = eq_curve
|
||||
days = (eq_ser.index - eq_ser.index[0]).total_seconds() / 86400
|
||||
ax.semilogy(days, eq_ser.values.clip(min=1), color="#2563eb", linewidth=1.2)
|
||||
ax.axhline(y=200, color="gray", linestyle="--", alpha=0.6)
|
||||
ax.set_title("BB(10, 2.5) 15min | 200U | 0.05% fee 90% rebate | 2020-2025", fontsize=12, fontweight="bold")
|
||||
ax.set_xlabel("Days")
|
||||
ax.set_ylabel("Equity (USDT, log scale)")
|
||||
ax.grid(True, alpha=0.3)
|
||||
|
||||
chart_path = out_dir / "bb_15m_200u_2020_2025.png"
|
||||
plt.savefig(chart_path, bbox_inches="tight")
|
||||
print(f"\n图表已保存: {chart_path}")
|
||||
323
strategy/run_bb_15m_2020_2025_conservative.py
Normal file
323
strategy/run_bb_15m_2020_2025_conservative.py
Normal file
@@ -0,0 +1,323 @@
|
||||
"""
|
||||
Conservative BB backtest for bb_trade-style logic.
|
||||
|
||||
Assumptions:
|
||||
1) Use 15m OHLC from 2020-01-01 to 2026-01-01 (exclusive).
|
||||
2) Bollinger band is computed from CLOSED bars (shifted by 1 bar).
|
||||
3) If bar i touches band, execute on bar i+1 open (no same-bar fill).
|
||||
4) Fee: 0.05% each side; rebate: 90% of daily fee, credited next day at 08:00 UTC+8 (UTC 00:00).
|
||||
5) Position sizing: 1% equity open, then +1%/+2%/+3% add ladder (max 3 adds).
|
||||
6) Leverage 50x; optional liquidation model enabled.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from strategy.data_loader import load_klines
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConservativeConfig:
|
||||
bb_period: int = 10
|
||||
bb_std: float = 2.5
|
||||
leverage: float = 50.0
|
||||
initial_capital: float = 200.0
|
||||
margin_pct: float = 0.01
|
||||
pyramid_step: float = 0.01
|
||||
pyramid_max: int = 3
|
||||
fee_rate: float = 0.0005
|
||||
rebate_pct: float = 0.90
|
||||
rebate_hour_utc: int = 0
|
||||
slippage_pct: float = 0.0005
|
||||
liq_enabled: bool = True
|
||||
maint_margin_rate: float = 0.005
|
||||
max_daily_loss: float = 50.0
|
||||
|
||||
|
||||
def bollinger_prev_close(close: pd.Series, period: int, n_std: float) -> tuple[np.ndarray, np.ndarray]:
|
||||
mid = close.rolling(period).mean().shift(1)
|
||||
std = close.rolling(period).std(ddof=0).shift(1)
|
||||
upper = (mid + n_std * std).to_numpy(dtype=float)
|
||||
lower = (mid - n_std * std).to_numpy(dtype=float)
|
||||
return upper, lower
|
||||
|
||||
|
||||
def run_conservative(df: pd.DataFrame, cfg: ConservativeConfig):
|
||||
arr_open = df["open"].to_numpy(dtype=float)
|
||||
arr_high = df["high"].to_numpy(dtype=float)
|
||||
arr_low = df["low"].to_numpy(dtype=float)
|
||||
arr_close = df["close"].to_numpy(dtype=float)
|
||||
idx = df.index
|
||||
n = len(df)
|
||||
|
||||
upper, lower = bollinger_prev_close(df["close"].astype(float), cfg.bb_period, cfg.bb_std)
|
||||
|
||||
balance = cfg.initial_capital
|
||||
position = 0 # +1 long, -1 short
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
pyramid_count = 0
|
||||
|
||||
total_fee = 0.0
|
||||
total_rebate = 0.0
|
||||
trades = 0
|
||||
win_trades = 0
|
||||
liq_count = 0
|
||||
|
||||
day_fees = {}
|
||||
current_day = None
|
||||
day_start_equity = cfg.initial_capital
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
rebate_applied_today = False
|
||||
|
||||
equity_arr = np.full(n, np.nan)
|
||||
position_arr = np.zeros(n)
|
||||
|
||||
def unrealised(price: float) -> float:
|
||||
if position == 0:
|
||||
return 0.0
|
||||
if position == 1:
|
||||
return entry_qty * (price - entry_price)
|
||||
return entry_qty * (entry_price - price)
|
||||
|
||||
def apply_open_slippage(side: int, price: float) -> float:
|
||||
# Buy higher, sell lower
|
||||
return price * (1 + cfg.slippage_pct) if side == 1 else price * (1 - cfg.slippage_pct)
|
||||
|
||||
def apply_close_slippage(side: int, price: float) -> float:
|
||||
# Close long = sell lower; close short = buy higher
|
||||
return price * (1 - cfg.slippage_pct) if side == 1 else price * (1 + cfg.slippage_pct)
|
||||
|
||||
def add_fee(ts: pd.Timestamp, fee: float):
|
||||
nonlocal total_fee
|
||||
total_fee += fee
|
||||
d = ts.date()
|
||||
day_fees[d] = day_fees.get(d, 0.0) + fee
|
||||
|
||||
def close_position(exec_price: float, exec_idx: int):
|
||||
nonlocal balance, position, entry_price, entry_qty, entry_margin, pyramid_count
|
||||
nonlocal trades, win_trades, day_pnl
|
||||
if position == 0:
|
||||
return
|
||||
|
||||
px = apply_close_slippage(position, exec_price)
|
||||
gross = entry_qty * (px - entry_price) if position == 1 else entry_qty * (entry_price - px)
|
||||
notional = entry_qty * px
|
||||
fee = notional * cfg.fee_rate
|
||||
net = gross - fee
|
||||
|
||||
balance += net
|
||||
add_fee(idx[exec_idx], fee)
|
||||
day_pnl += net
|
||||
trades += 1
|
||||
if net > 0:
|
||||
win_trades += 1
|
||||
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
pyramid_count = 0
|
||||
|
||||
def open_position(side: int, exec_price: float, exec_idx: int, is_add: bool = False):
|
||||
nonlocal balance, position, entry_price, entry_qty, entry_margin, pyramid_count
|
||||
nonlocal day_pnl
|
||||
px = apply_open_slippage(side, exec_price)
|
||||
eq = balance + unrealised(px)
|
||||
|
||||
if is_add:
|
||||
margin = eq * (cfg.margin_pct + cfg.pyramid_step * (pyramid_count + 1))
|
||||
else:
|
||||
margin = eq * cfg.margin_pct
|
||||
|
||||
margin = min(margin, balance * 0.95)
|
||||
if margin <= 0:
|
||||
return
|
||||
|
||||
notional = margin * cfg.leverage
|
||||
qty = notional / px
|
||||
fee = notional * cfg.fee_rate
|
||||
|
||||
balance -= fee
|
||||
add_fee(idx[exec_idx], fee)
|
||||
day_pnl -= fee
|
||||
|
||||
if is_add and position != 0:
|
||||
old_notional = entry_qty * entry_price
|
||||
new_notional = qty * px
|
||||
entry_qty += qty
|
||||
entry_price = (old_notional + new_notional) / entry_qty
|
||||
entry_margin += margin
|
||||
pyramid_count += 1
|
||||
else:
|
||||
position = side
|
||||
entry_price = px
|
||||
entry_qty = qty
|
||||
entry_margin = margin
|
||||
pyramid_count = 0
|
||||
|
||||
for i in range(n - 1):
|
||||
ts = idx[i]
|
||||
bar_day = ts.date()
|
||||
|
||||
if bar_day != current_day:
|
||||
current_day = bar_day
|
||||
day_start_equity = balance + unrealised(arr_close[i])
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
rebate_applied_today = False
|
||||
|
||||
if (not rebate_applied_today) and ts.hour >= cfg.rebate_hour_utc:
|
||||
prev_day = bar_day - pd.Timedelta(days=1)
|
||||
prev_fee = day_fees.get(prev_day, 0.0)
|
||||
if prev_fee > 0:
|
||||
rebate = prev_fee * cfg.rebate_pct
|
||||
balance += rebate
|
||||
total_rebate += rebate
|
||||
rebate_applied_today = True
|
||||
|
||||
if not day_stopped:
|
||||
if day_pnl + unrealised(arr_close[i]) <= -cfg.max_daily_loss:
|
||||
close_position(arr_open[i + 1], i + 1)
|
||||
day_stopped = True
|
||||
|
||||
if cfg.liq_enabled and position != 0 and entry_margin > 0:
|
||||
liq_threshold = 1.0 / cfg.leverage * (1 - cfg.maint_margin_rate)
|
||||
if position == 1:
|
||||
liq_price = entry_price * (1 - liq_threshold)
|
||||
if arr_low[i] <= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
pyramid_count = 0
|
||||
trades += 1
|
||||
liq_count += 1
|
||||
elif position == -1:
|
||||
liq_price = entry_price * (1 + liq_threshold)
|
||||
if arr_high[i] >= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
pyramid_count = 0
|
||||
trades += 1
|
||||
liq_count += 1
|
||||
|
||||
if day_stopped or np.isnan(upper[i]) or np.isnan(lower[i]):
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
equity_arr[i:] = 0.0
|
||||
position_arr[i:] = 0
|
||||
break
|
||||
continue
|
||||
|
||||
touched_upper = arr_high[i] >= upper[i]
|
||||
touched_lower = arr_low[i] <= lower[i]
|
||||
exec_px = arr_open[i + 1]
|
||||
|
||||
if touched_upper and touched_lower:
|
||||
pass
|
||||
elif touched_upper:
|
||||
if position == 1:
|
||||
close_position(exec_px, i + 1)
|
||||
if position == 0:
|
||||
open_position(-1, exec_px, i + 1, is_add=False)
|
||||
elif position == -1 and pyramid_count < cfg.pyramid_max:
|
||||
open_position(-1, exec_px, i + 1, is_add=True)
|
||||
elif touched_lower:
|
||||
if position == -1:
|
||||
close_position(exec_px, i + 1)
|
||||
if position == 0:
|
||||
open_position(1, exec_px, i + 1, is_add=False)
|
||||
elif position == 1 and pyramid_count < cfg.pyramid_max:
|
||||
open_position(1, exec_px, i + 1, is_add=True)
|
||||
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
equity_arr[i:] = 0.0
|
||||
position_arr[i:] = 0
|
||||
break
|
||||
|
||||
if position != 0 and balance > 0:
|
||||
close_position(arr_close[-1], n - 1)
|
||||
|
||||
equity_arr[-1] = balance
|
||||
position_arr[-1] = 0
|
||||
|
||||
eq_df = pd.DataFrame({"equity": equity_arr, "position": position_arr}, index=idx)
|
||||
daily = eq_df["equity"].resample("1D").last().dropna().to_frame("equity")
|
||||
daily["pnl"] = daily["equity"].diff().fillna(0.0)
|
||||
|
||||
return {
|
||||
"equity_curve": eq_df,
|
||||
"daily": daily,
|
||||
"final_equity": float(daily["equity"].iloc[-1]),
|
||||
"trade_count": int(trades),
|
||||
"win_rate": float(win_trades / max(trades, 1)),
|
||||
"liq_count": int(liq_count),
|
||||
"total_fee": float(total_fee),
|
||||
"total_rebate": float(total_rebate),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
df = load_klines("15m", "2020-01-01", "2026-01-01")
|
||||
cfg = ConservativeConfig()
|
||||
result = run_conservative(df, cfg)
|
||||
|
||||
daily = result["daily"]
|
||||
eq = daily["equity"].astype(float)
|
||||
pnl = daily["pnl"].astype(float)
|
||||
final_eq = float(eq.iloc[-1])
|
||||
ret_pct = (final_eq - cfg.initial_capital) / cfg.initial_capital * 100
|
||||
max_dd = float((eq - eq.cummax()).min()) if len(eq) else 0.0
|
||||
sharpe = float(pnl.mean() / pnl.std() * np.sqrt(365)) if pnl.std() > 0 else 0.0
|
||||
|
||||
print("=" * 110)
|
||||
print("Conservative BB(10,2.5) | 15m | 2020-2025 | 200U | fee 0.05% each side | 90% rebate next day 08:00")
|
||||
print("=" * 110)
|
||||
print(f"Final equity: {final_eq:.8f} U")
|
||||
print(f"Return: {ret_pct:+.2f}%")
|
||||
print(f"Trades: {result['trade_count']}")
|
||||
print(f"Win rate: {result['win_rate']*100:.2f}%")
|
||||
print(f"Liquidations: {result['liq_count']}")
|
||||
print(f"Max drawdown: {max_dd:.2f} U")
|
||||
print(f"Total fee: {result['total_fee']:.8f}")
|
||||
print(f"Total rebate: {result['total_rebate']:.8f}")
|
||||
print(f"Sharpe: {sharpe:.4f}")
|
||||
print("-" * 110)
|
||||
for year in range(2020, 2026):
|
||||
m = daily.index.year == year
|
||||
if m.any():
|
||||
print(f"{year} year-end equity: {float(daily.loc[m, 'equity'].iloc[-1]):.8f} U")
|
||||
print("=" * 110)
|
||||
|
||||
out_dir = Path(__file__).resolve().parent / "results"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
out_csv = out_dir / "bb_15m_2020_2025_conservative_daily.csv"
|
||||
daily.to_csv(out_csv)
|
||||
print(f"Saved daily equity: {out_csv}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
67
strategy/run_bb_202602_detail.py
Normal file
67
strategy/run_bb_202602_detail.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
bb_trade.py 策略回测 — 2026年2月,输出详细交易明细
|
||||
200U 本金 | 1% 仓位/单 | 万五手续费 | 90% 返佣次日8点到账
|
||||
按北京时间加载数据 (与交易所/网页显示一致)
|
||||
"""
|
||||
import sys
|
||||
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1]))
|
||||
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
|
||||
from strategy.bb_backtest import BBConfig, run_bb_backtest
|
||||
from strategy.data_loader import load_klines
|
||||
|
||||
out_dir = Path(__file__).resolve().parent / "results"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 按北京时间加载 2026-02-01 00:00 ~ 2026-03-01 00:00
|
||||
df = load_klines('5m', '2026-02-01', '2026-03-01', tz='Asia/Shanghai')
|
||||
|
||||
cfg = BBConfig(
|
||||
bb_period=10, bb_std=2.5, leverage=50, initial_capital=200.0,
|
||||
margin_pct=0.01, max_daily_loss=50.0, fee_rate=0.0005,
|
||||
rebate_pct=0.90, rebate_hour_utc=0, pyramid_enabled=False, # 不加仓
|
||||
pyramid_step=0.01, pyramid_max=3, slippage_pct=0.0, liq_enabled=True,
|
||||
cross_margin=True, # 全仓:仅权益<=0 时爆仓
|
||||
fill_at_close=True, # 真实成交:检测到信号后在 K 线收盘价成交
|
||||
)
|
||||
|
||||
r = run_bb_backtest(df, cfg)
|
||||
|
||||
# 数据库/回测使用 UTC,转为北京时间输出
|
||||
def to_beijing(ts):
|
||||
if hasattr(ts, 'tz_localize'):
|
||||
return ts.tz_localize('UTC').tz_convert('Asia/Shanghai').strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str(ts)[:19]
|
||||
|
||||
# 构建交易明细 DataFrame
|
||||
rows = []
|
||||
for i, t in enumerate(r.trades, 1):
|
||||
rows.append({
|
||||
"序号": i,
|
||||
"方向": "做多" if t.side == "long" else "做空",
|
||||
"开仓时间": to_beijing(t.entry_time),
|
||||
"平仓时间": to_beijing(t.exit_time),
|
||||
"开仓价": round(t.entry_price, 2),
|
||||
"平仓价": round(t.exit_price, 2),
|
||||
"保证金": round(t.margin, 2),
|
||||
"杠杆": t.leverage,
|
||||
"数量": round(t.qty, 4),
|
||||
"毛盈亏": round(t.gross_pnl, 2),
|
||||
"手续费": round(t.fee, 2),
|
||||
"净盈亏": round(t.net_pnl, 2),
|
||||
})
|
||||
|
||||
trade_df = pd.DataFrame(rows)
|
||||
|
||||
# 保存 CSV
|
||||
csv_path = out_dir / "bb_202602_trade_detail.csv"
|
||||
trade_df.to_csv(csv_path, index=False, encoding="utf-8-sig")
|
||||
print(f"交易明细已保存: {csv_path}")
|
||||
|
||||
# 打印到控制台
|
||||
print("\n" + "=" * 150)
|
||||
print(f" 交易明细 (共 {len(r.trades)} 笔)")
|
||||
print("=" * 150)
|
||||
print(trade_df.to_string(index=False))
|
||||
381
strategy/run_bb_5m_practical_upgrade.py
Normal file
381
strategy/run_bb_5m_practical_upgrade.py
Normal file
@@ -0,0 +1,381 @@
|
||||
"""
|
||||
Practical upgraded BB backtest on 5m ETH data (2020-2025).
|
||||
|
||||
Execution model (conservative):
|
||||
1) BB uses closed bars only (shift by 1 bar).
|
||||
2) Signal on bar i, execution at bar i+1 open.
|
||||
3) Fee = 0.05% each side, rebate = 90% next day at UTC 00:00 (UTC+8 08:00).
|
||||
4) Daily loss stop, liquidation, and slippage are enabled.
|
||||
|
||||
Compares:
|
||||
- Baseline: BB(30, 3.0), 1x, no trend filter.
|
||||
- Practical: BB(30, 3.2), 1x, EMA trend filter, BB width filter, cooldown.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from strategy.data_loader import load_klines
|
||||
|
||||
|
||||
@dataclass
|
||||
class PracticalConfig:
|
||||
bb_period: int = 30
|
||||
bb_std: float = 3.2
|
||||
leverage: float = 1.0
|
||||
initial_capital: float = 200.0
|
||||
margin_pct: float = 0.01
|
||||
fee_rate: float = 0.0005
|
||||
rebate_pct: float = 0.90
|
||||
rebate_hour_utc: int = 0
|
||||
slippage_pct: float = 0.0005
|
||||
liq_enabled: bool = True
|
||||
maint_margin_rate: float = 0.005
|
||||
max_daily_loss: float = 50.0
|
||||
|
||||
# Practical risk controls
|
||||
trend_ema_period: int = 288 # 288 * 5m = 24h EMA
|
||||
min_bandwidth: float = 0.01 # (upper-lower)/mid minimum
|
||||
cooldown_bars: int = 6 # 6 * 5m = 30 minutes
|
||||
|
||||
|
||||
def run_practical_backtest(df: pd.DataFrame, cfg: PracticalConfig):
|
||||
arr_open = df["open"].to_numpy(dtype=float)
|
||||
arr_high = df["high"].to_numpy(dtype=float)
|
||||
arr_low = df["low"].to_numpy(dtype=float)
|
||||
arr_close = df["close"].to_numpy(dtype=float)
|
||||
idx = df.index
|
||||
n = len(df)
|
||||
|
||||
close_s = df["close"].astype(float)
|
||||
mid = close_s.rolling(cfg.bb_period).mean().shift(1)
|
||||
std = close_s.rolling(cfg.bb_period).std(ddof=0).shift(1)
|
||||
upper_s = mid + cfg.bb_std * std
|
||||
lower_s = mid - cfg.bb_std * std
|
||||
bandwidth_s = (upper_s - lower_s) / mid
|
||||
|
||||
upper = upper_s.to_numpy(dtype=float)
|
||||
lower = lower_s.to_numpy(dtype=float)
|
||||
bandwidth = bandwidth_s.to_numpy(dtype=float)
|
||||
|
||||
if cfg.trend_ema_period > 0:
|
||||
trend_ema = close_s.ewm(span=cfg.trend_ema_period, adjust=False).mean().shift(1).to_numpy(dtype=float)
|
||||
else:
|
||||
trend_ema = np.full(n, np.nan)
|
||||
|
||||
balance = cfg.initial_capital
|
||||
position = 0 # +1 long, -1 short
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
|
||||
trades = 0
|
||||
win_trades = 0
|
||||
liq_count = 0
|
||||
total_fee = 0.0
|
||||
total_rebate = 0.0
|
||||
|
||||
current_day = None
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
rebate_applied_today = False
|
||||
next_trade_bar = 0
|
||||
day_fees = {}
|
||||
|
||||
equity_arr = np.full(n, np.nan)
|
||||
position_arr = np.zeros(n)
|
||||
|
||||
def unrealised(price: float) -> float:
|
||||
if position == 0:
|
||||
return 0.0
|
||||
if position == 1:
|
||||
return entry_qty * (price - entry_price)
|
||||
return entry_qty * (entry_price - price)
|
||||
|
||||
def apply_open_slippage(side: int, price: float) -> float:
|
||||
return price * (1 + cfg.slippage_pct) if side == 1 else price * (1 - cfg.slippage_pct)
|
||||
|
||||
def apply_close_slippage(side: int, price: float) -> float:
|
||||
return price * (1 - cfg.slippage_pct) if side == 1 else price * (1 + cfg.slippage_pct)
|
||||
|
||||
def add_fee(ts: pd.Timestamp, fee: float):
|
||||
nonlocal total_fee
|
||||
total_fee += fee
|
||||
d = ts.date()
|
||||
day_fees[d] = day_fees.get(d, 0.0) + fee
|
||||
|
||||
def close_position(exec_price: float, exec_idx: int):
|
||||
nonlocal balance, position, entry_price, entry_qty, entry_margin
|
||||
nonlocal trades, win_trades, day_pnl
|
||||
if position == 0:
|
||||
return
|
||||
|
||||
px = apply_close_slippage(position, exec_price)
|
||||
gross = entry_qty * (px - entry_price) if position == 1 else entry_qty * (entry_price - px)
|
||||
notional = entry_qty * px
|
||||
fee = notional * cfg.fee_rate
|
||||
net = gross - fee
|
||||
|
||||
balance += net
|
||||
add_fee(idx[exec_idx], fee)
|
||||
day_pnl += net
|
||||
trades += 1
|
||||
if net > 0:
|
||||
win_trades += 1
|
||||
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
|
||||
def open_position(side: int, exec_price: float, exec_idx: int):
|
||||
nonlocal balance, position, entry_price, entry_qty, entry_margin
|
||||
nonlocal day_pnl
|
||||
px = apply_open_slippage(side, exec_price)
|
||||
eq = balance + unrealised(px)
|
||||
margin = min(eq * cfg.margin_pct, balance * 0.95)
|
||||
if margin <= 0:
|
||||
return
|
||||
|
||||
notional = margin * cfg.leverage
|
||||
qty = notional / px
|
||||
fee = notional * cfg.fee_rate
|
||||
|
||||
balance -= fee
|
||||
add_fee(idx[exec_idx], fee)
|
||||
day_pnl -= fee
|
||||
|
||||
position = side
|
||||
entry_price = px
|
||||
entry_qty = qty
|
||||
entry_margin = margin
|
||||
|
||||
for i in range(n - 1):
|
||||
ts = idx[i]
|
||||
bar_day = ts.date()
|
||||
|
||||
if bar_day != current_day:
|
||||
current_day = bar_day
|
||||
day_pnl = 0.0
|
||||
day_stopped = False
|
||||
rebate_applied_today = False
|
||||
|
||||
# Fee rebate settlement (next day 08:00 UTC+8 = UTC 00:00)
|
||||
if (not rebate_applied_today) and ts.hour >= cfg.rebate_hour_utc:
|
||||
prev_day = bar_day - pd.Timedelta(days=1)
|
||||
prev_fee = day_fees.get(prev_day, 0.0)
|
||||
if prev_fee > 0:
|
||||
rebate = prev_fee * cfg.rebate_pct
|
||||
balance += rebate
|
||||
total_rebate += rebate
|
||||
rebate_applied_today = True
|
||||
|
||||
# Daily loss stop
|
||||
if not day_stopped and (day_pnl + unrealised(arr_close[i]) <= -cfg.max_daily_loss):
|
||||
close_position(arr_open[i + 1], i + 1)
|
||||
day_stopped = True
|
||||
|
||||
# Liquidation check
|
||||
if cfg.liq_enabled and position != 0 and entry_margin > 0:
|
||||
liq_threshold = 1.0 / cfg.leverage * (1 - cfg.maint_margin_rate)
|
||||
if position == 1:
|
||||
liq_price = entry_price * (1 - liq_threshold)
|
||||
if arr_low[i] <= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
trades += 1
|
||||
liq_count += 1
|
||||
else:
|
||||
liq_price = entry_price * (1 + liq_threshold)
|
||||
if arr_high[i] >= liq_price:
|
||||
balance -= entry_margin
|
||||
day_pnl -= entry_margin
|
||||
position = 0
|
||||
entry_price = 0.0
|
||||
entry_qty = 0.0
|
||||
entry_margin = 0.0
|
||||
trades += 1
|
||||
liq_count += 1
|
||||
|
||||
if (
|
||||
day_stopped
|
||||
or i < next_trade_bar
|
||||
or np.isnan(upper[i])
|
||||
or np.isnan(lower[i])
|
||||
or np.isnan(bandwidth[i])
|
||||
):
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
equity_arr[i:] = 0.0
|
||||
position_arr[i:] = 0
|
||||
break
|
||||
continue
|
||||
|
||||
if cfg.trend_ema_period > 0 and np.isnan(trend_ema[i]):
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
continue
|
||||
|
||||
if bandwidth[i] < cfg.min_bandwidth:
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
continue
|
||||
|
||||
touched_upper = arr_high[i] >= upper[i]
|
||||
touched_lower = arr_low[i] <= lower[i]
|
||||
exec_px = arr_open[i + 1]
|
||||
|
||||
if cfg.trend_ema_period > 0:
|
||||
long_ok = arr_close[i] > trend_ema[i]
|
||||
short_ok = arr_close[i] < trend_ema[i]
|
||||
else:
|
||||
long_ok = True
|
||||
short_ok = True
|
||||
|
||||
if touched_upper and touched_lower:
|
||||
pass
|
||||
elif touched_upper:
|
||||
if position == 1:
|
||||
close_position(exec_px, i + 1)
|
||||
next_trade_bar = max(next_trade_bar, i + 1 + cfg.cooldown_bars)
|
||||
if position == 0 and short_ok:
|
||||
open_position(-1, exec_px, i + 1)
|
||||
next_trade_bar = max(next_trade_bar, i + 1 + cfg.cooldown_bars)
|
||||
elif touched_lower:
|
||||
if position == -1:
|
||||
close_position(exec_px, i + 1)
|
||||
next_trade_bar = max(next_trade_bar, i + 1 + cfg.cooldown_bars)
|
||||
if position == 0 and long_ok:
|
||||
open_position(1, exec_px, i + 1)
|
||||
next_trade_bar = max(next_trade_bar, i + 1 + cfg.cooldown_bars)
|
||||
|
||||
equity_arr[i] = balance + unrealised(arr_close[i])
|
||||
position_arr[i] = position
|
||||
|
||||
if balance <= 0:
|
||||
balance = 0.0
|
||||
equity_arr[i:] = 0.0
|
||||
position_arr[i:] = 0
|
||||
break
|
||||
|
||||
if position != 0 and balance > 0:
|
||||
close_position(arr_close[-1], n - 1)
|
||||
|
||||
equity_arr[-1] = balance
|
||||
position_arr[-1] = 0
|
||||
|
||||
eq_df = pd.DataFrame({"equity": equity_arr, "position": position_arr}, index=idx)
|
||||
daily = eq_df["equity"].resample("1D").last().dropna().to_frame("equity")
|
||||
daily["pnl"] = daily["equity"].diff().fillna(0.0)
|
||||
|
||||
return {
|
||||
"equity_curve": eq_df,
|
||||
"daily": daily,
|
||||
"final_equity": float(daily["equity"].iloc[-1]),
|
||||
"trade_count": int(trades),
|
||||
"win_rate": float(win_trades / max(trades, 1)),
|
||||
"liq_count": int(liq_count),
|
||||
"total_fee": float(total_fee),
|
||||
"total_rebate": float(total_rebate),
|
||||
}
|
||||
|
||||
|
||||
def summarize(label: str, result: dict, initial_capital: float):
|
||||
daily = result["daily"]
|
||||
eq = daily["equity"].astype(float)
|
||||
pnl = daily["pnl"].astype(float)
|
||||
final_eq = float(eq.iloc[-1])
|
||||
ret_pct = (final_eq - initial_capital) / initial_capital * 100
|
||||
max_dd = float((eq - eq.cummax()).min()) if len(eq) else 0.0
|
||||
sharpe = float(pnl.mean() / pnl.std() * np.sqrt(365)) if pnl.std() > 0 else 0.0
|
||||
|
||||
print(f"[{label}]")
|
||||
print(f" Final equity: {final_eq:.6f} U")
|
||||
print(f" Return: {ret_pct:+.4f}%")
|
||||
print(f" Trades: {result['trade_count']} | Win rate: {result['win_rate']*100:.2f}% | Liquidations: {result['liq_count']}")
|
||||
print(f" Max drawdown: {max_dd:.6f} U | Sharpe: {sharpe:.4f}")
|
||||
print(f" Total fee: {result['total_fee']:.6f} | Total rebate: {result['total_rebate']:.6f}")
|
||||
print(" Year-end equity:")
|
||||
for year in range(2020, 2026):
|
||||
m = daily.index.year == year
|
||||
if m.any():
|
||||
print(f" {year}: {float(daily.loc[m, 'equity'].iloc[-1]):.6f} U")
|
||||
print()
|
||||
|
||||
return {
|
||||
"label": label,
|
||||
"final_equity": final_eq,
|
||||
"return_pct": ret_pct,
|
||||
"trade_count": result["trade_count"],
|
||||
"win_rate_pct": result["win_rate"] * 100,
|
||||
"liq_count": result["liq_count"],
|
||||
"max_drawdown": max_dd,
|
||||
"total_fee": result["total_fee"],
|
||||
"total_rebate": result["total_rebate"],
|
||||
"sharpe": sharpe,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
df = load_klines("5m", "2020-01-01", "2026-01-01")
|
||||
|
||||
baseline_cfg = PracticalConfig(
|
||||
bb_period=30,
|
||||
bb_std=3.0,
|
||||
leverage=1.0,
|
||||
trend_ema_period=0,
|
||||
min_bandwidth=0.0,
|
||||
cooldown_bars=0,
|
||||
)
|
||||
practical_cfg = PracticalConfig(
|
||||
bb_period=30,
|
||||
bb_std=3.2,
|
||||
leverage=1.0,
|
||||
trend_ema_period=288,
|
||||
min_bandwidth=0.01,
|
||||
cooldown_bars=6,
|
||||
)
|
||||
|
||||
print("=" * 118)
|
||||
print("Practical Upgrade Backtest | 5m | 2020-2025 | capital=200U | fee=0.05% each side | rebate=90% next day 08:00")
|
||||
print("=" * 118)
|
||||
print("Execution: signal at bar i, fill at bar i+1 open (conservative)")
|
||||
print()
|
||||
|
||||
baseline = run_practical_backtest(df, baseline_cfg)
|
||||
practical = run_practical_backtest(df, practical_cfg)
|
||||
|
||||
summary_rows = []
|
||||
summary_rows.append(summarize("Baseline (BB30/3.0, no filters)", baseline, baseline_cfg.initial_capital))
|
||||
summary_rows.append(summarize("Practical (BB30/3.2 + EMA + BW + cooldown)", practical, practical_cfg.initial_capital))
|
||||
|
||||
out_dir = Path(__file__).resolve().parent / "results"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
baseline_daily = baseline["daily"].rename(columns={"equity": "baseline_equity", "pnl": "baseline_pnl"})
|
||||
practical_daily = practical["daily"].rename(columns={"equity": "practical_equity", "pnl": "practical_pnl"})
|
||||
daily_compare = baseline_daily.join(practical_daily, how="outer")
|
||||
daily_compare.to_csv(out_dir / "bb_5m_practical_upgrade_daily.csv")
|
||||
|
||||
pd.DataFrame(summary_rows).to_csv(out_dir / "bb_5m_practical_upgrade_summary.csv", index=False)
|
||||
|
||||
print(f"Saved: {out_dir / 'bb_5m_practical_upgrade_daily.csv'}")
|
||||
print(f"Saved: {out_dir / 'bb_5m_practical_upgrade_summary.csv'}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
197
strategy/run_bb_trade_backtest.py
Normal file
197
strategy/run_bb_trade_backtest.py
Normal file
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
回测 bb_trade.py 的 D方案策略
|
||||
BB(10, 2.5) | 5分钟 | ETH | 50x | 递增加仓+1%/次 max=3
|
||||
200U 本金 | 每次开仓 1% 权益 | 开平仓手续费万五 | 返佣90%次日早8点到账
|
||||
"""
|
||||
import sys, time
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1]))
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
from pathlib import Path
|
||||
|
||||
from strategy.bb_backtest import BBConfig, run_bb_backtest
|
||||
from strategy.data_loader import load_klines
|
||||
|
||||
out_dir = Path(__file__).resolve().parent / "results"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# ============================================================
|
||||
# 加载数据 2020-2025
|
||||
# ============================================================
|
||||
YEARS = list(range(2020, 2026))
|
||||
|
||||
print("加载 5 分钟 K 线数据 (2020-2025)...")
|
||||
t0 = time.time()
|
||||
data = {}
|
||||
for y in YEARS:
|
||||
df = load_klines('5m', f'{y}-01-01', f'{y+1}-01-01')
|
||||
data[y] = df
|
||||
print(f" {y}: {len(df):>7,} 条 ({df.index[0]} ~ {df.index[-1]})")
|
||||
|
||||
# 合并全量数据用于连续回测
|
||||
df_all = pd.concat([data[y] for y in YEARS])
|
||||
df_all = df_all[~df_all.index.duplicated(keep='first')].sort_index()
|
||||
print(f" 合计: {len(df_all):>7,} 条 ({df_all.index[0]} ~ {df_all.index[-1]})")
|
||||
print(f"数据加载完成 ({time.time()-t0:.1f}s)\n")
|
||||
|
||||
# ============================================================
|
||||
# 配置 — 完全匹配 bb_trade.py D方案
|
||||
# ============================================================
|
||||
cfg = BBConfig(
|
||||
bb_period=10,
|
||||
bb_std=2.5,
|
||||
leverage=50,
|
||||
initial_capital=200.0,
|
||||
margin_pct=0.01, # 1% 权益/单
|
||||
max_daily_loss=50.0,
|
||||
fee_rate=0.0005, # 万五 (0.05%) 每侧 (开+平各收一次)
|
||||
rebate_rate=0.0, # 无即时返佣
|
||||
rebate_pct=0.90, # 90% 手续费次日返还
|
||||
rebate_hour_utc=0, # UTC 0点 = 北京时间早上8点
|
||||
pyramid_enabled=True,
|
||||
pyramid_step=0.01, # 递增加仓 +1%/次
|
||||
pyramid_max=3, # 最多加仓3次
|
||||
slippage_pct=0.0, # 回测不加滑点 (实盘浏览器市价单有滑点)
|
||||
liq_enabled=True,
|
||||
stop_loss_pct=0.0,
|
||||
)
|
||||
|
||||
# ============================================================
|
||||
# 1) 逐年回测 (每年独立 200U 起步)
|
||||
# ============================================================
|
||||
print("=" * 100)
|
||||
print(" 【逐年独立回测】每年独立 200U 本金")
|
||||
print(f" BB({cfg.bb_period}, {cfg.bb_std}) | {cfg.leverage}x | 开仓={cfg.margin_pct:.0%}权益 | "
|
||||
f"手续费={cfg.fee_rate:.4%}/侧 | 返佣={cfg.rebate_pct:.0%}次日8点")
|
||||
print("=" * 100)
|
||||
print(f" {'年份':>6s} {'最终权益':>10s} {'收益率':>8s} {'日均PnL':>8s} {'交易次数':>8s} {'胜率':>6s} "
|
||||
f"{'最大回撤':>10s} {'回撤%':>8s} {'总手续费':>10s} {'总返佣':>10s} {'净手续费':>10s} {'Sharpe':>7s}")
|
||||
print("-" * 130)
|
||||
|
||||
year_results = {}
|
||||
for y in YEARS:
|
||||
r = run_bb_backtest(data[y], cfg)
|
||||
year_results[y] = r
|
||||
|
||||
d = r.daily_stats
|
||||
pnl = d["pnl"].astype(float)
|
||||
eq = d["equity"].astype(float)
|
||||
peak = eq.cummax()
|
||||
dd = float((eq - peak).min())
|
||||
dd_pct = dd / float(peak[eq - peak == dd].iloc[0]) * 100 if dd < 0 else 0
|
||||
final_eq = float(eq.iloc[-1])
|
||||
ret_pct = (final_eq - cfg.initial_capital) / cfg.initial_capital * 100
|
||||
n_trades = len(r.trades)
|
||||
win_rate = sum(1 for t in r.trades if t.net_pnl > 0) / max(n_trades, 1) * 100
|
||||
avg_daily = float(pnl.mean())
|
||||
sharpe = float(pnl.mean() / pnl.std()) * np.sqrt(365) if pnl.std() > 0 else 0
|
||||
net_fee = r.total_fee - r.total_rebate
|
||||
|
||||
print(f" {y:>6d} {final_eq:>10.1f} {ret_pct:>+7.1f}% {avg_daily:>+7.2f}U "
|
||||
f"{n_trades:>8d} {win_rate:>5.1f}% {dd:>+10.1f} {dd_pct:>+7.1f}% "
|
||||
f"{r.total_fee:>10.1f} {r.total_rebate:>10.1f} {net_fee:>10.1f} {sharpe:>7.2f}")
|
||||
|
||||
print()
|
||||
|
||||
# ============================================================
|
||||
# 2) 连续回测 (2020-2025 一次性跑,资金连续滚动)
|
||||
# ============================================================
|
||||
print("=" * 100)
|
||||
print(" 【连续回测】2020-2025 资金滚动,200U 起步")
|
||||
print("=" * 100)
|
||||
|
||||
r_all = run_bb_backtest(df_all, cfg)
|
||||
|
||||
d_all = r_all.daily_stats
|
||||
pnl_all = d_all["pnl"].astype(float)
|
||||
eq_all = d_all["equity"].astype(float)
|
||||
peak_all = eq_all.cummax()
|
||||
dd_all = float((eq_all - peak_all).min())
|
||||
dd_pct_all = dd_all / float(peak_all[eq_all - peak_all == dd_all].iloc[0]) * 100 if dd_all < 0 else 0
|
||||
final_eq_all = float(eq_all.iloc[-1])
|
||||
ret_pct_all = (final_eq_all - cfg.initial_capital) / cfg.initial_capital * 100
|
||||
n_trades_all = len(r_all.trades)
|
||||
win_rate_all = sum(1 for t in r_all.trades if t.net_pnl > 0) / max(n_trades_all, 1) * 100
|
||||
avg_daily_all = float(pnl_all.mean())
|
||||
sharpe_all = float(pnl_all.mean() / pnl_all.std()) * np.sqrt(365) if pnl_all.std() > 0 else 0
|
||||
net_fee_all = r_all.total_fee - r_all.total_rebate
|
||||
|
||||
print(f" 初始资金: {cfg.initial_capital:.0f} U")
|
||||
print(f" 最终权益: {final_eq_all:.1f} U")
|
||||
print(f" 总收益率: {ret_pct_all:+.1f}%")
|
||||
print(f" 日均 PnL: {avg_daily_all:+.2f} U")
|
||||
print(f" 交易次数: {n_trades_all}")
|
||||
print(f" 胜率: {win_rate_all:.1f}%")
|
||||
print(f" 最大回撤: {dd_all:+.1f} U ({dd_pct_all:+.1f}%)")
|
||||
print(f" 总手续费: {r_all.total_fee:.1f} U")
|
||||
print(f" 总返佣: {r_all.total_rebate:.1f} U")
|
||||
print(f" 净手续费: {net_fee_all:.1f} U")
|
||||
print(f" Sharpe: {sharpe_all:.2f}")
|
||||
print()
|
||||
|
||||
# 按年统计连续回测中的表现
|
||||
print(" 连续回测逐年切片:")
|
||||
print(f" {'年份':>6s} {'年初权益':>10s} {'年末权益':>10s} {'年收益':>10s} {'年收益率':>8s}")
|
||||
print("-" * 60)
|
||||
for y in YEARS:
|
||||
mask = (eq_all.index >= f'{y}-01-01') & (eq_all.index < f'{y+1}-01-01')
|
||||
if mask.sum() == 0:
|
||||
continue
|
||||
eq_year = eq_all[mask]
|
||||
start_eq = float(eq_year.iloc[0])
|
||||
end_eq = float(eq_year.iloc[-1])
|
||||
yr_ret = end_eq - start_eq
|
||||
yr_pct = yr_ret / start_eq * 100
|
||||
print(f" {y:>6d} {start_eq:>10.1f} {end_eq:>10.1f} {yr_ret:>+10.1f} {yr_pct:>+7.1f}%")
|
||||
print()
|
||||
|
||||
# ============================================================
|
||||
# 图表
|
||||
# ============================================================
|
||||
fig, axes = plt.subplots(3, 1, figsize=(18, 18), dpi=120)
|
||||
|
||||
# 图1: 逐年独立回测权益曲线
|
||||
ax1 = axes[0]
|
||||
colors = plt.cm.tab10(np.linspace(0, 1, len(YEARS)))
|
||||
for i, y in enumerate(YEARS):
|
||||
r = year_results[y]
|
||||
eq = r.equity_curve["equity"].dropna()
|
||||
days = (eq.index - eq.index[0]).total_seconds() / 86400
|
||||
ax1.plot(days, eq.values, label=f"{y}", color=colors[i], linewidth=0.8)
|
||||
ax1.set_title(f"BB(10,2.5) D方案 逐年独立回测 (200U起步)", fontsize=13, fontweight="bold")
|
||||
ax1.set_xlabel("天数")
|
||||
ax1.set_ylabel("权益 (USDT)")
|
||||
ax1.axhline(y=200, color="gray", linestyle="--", alpha=0.5, label="本金200U")
|
||||
ax1.legend(loc="upper left", fontsize=9)
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
# 图2: 连续回测权益曲线
|
||||
ax2 = axes[1]
|
||||
eq_curve = r_all.equity_curve["equity"].dropna()
|
||||
ax2.plot(eq_curve.index, eq_curve.values, color="steelblue", linewidth=0.6)
|
||||
ax2.set_title(f"BB(10,2.5) D方案 连续回测 2020-2025 (200U→{final_eq_all:.0f}U)", fontsize=13, fontweight="bold")
|
||||
ax2.set_xlabel("日期")
|
||||
ax2.set_ylabel("权益 (USDT)")
|
||||
ax2.axhline(y=200, color="gray", linestyle="--", alpha=0.5)
|
||||
ax2.grid(True, alpha=0.3)
|
||||
|
||||
# 图3: 连续回测日PnL
|
||||
ax3 = axes[2]
|
||||
daily_pnl = r_all.daily_stats["pnl"].astype(float)
|
||||
colors_pnl = ['green' if x >= 0 else 'red' for x in daily_pnl.values]
|
||||
ax3.bar(daily_pnl.index, daily_pnl.values, color=colors_pnl, width=1, alpha=0.7)
|
||||
ax3.set_title("日 PnL 分布", fontsize=13, fontweight="bold")
|
||||
ax3.set_xlabel("日期")
|
||||
ax3.set_ylabel("PnL (USDT)")
|
||||
ax3.axhline(y=0, color="black", linewidth=0.5)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
chart_path = out_dir / "bb_trade_d_plan_2020_2025.png"
|
||||
plt.savefig(chart_path, bbox_inches="tight")
|
||||
print(f"图表已保存: {chart_path}")
|
||||
Reference in New Issue
Block a user