This commit is contained in:
27942
2026-02-01 19:50:32 +08:00
parent c2e6d6d78d
commit b5d4f6dfdc
10 changed files with 82 additions and 7652 deletions

View File

@@ -41,6 +41,57 @@ from models.mexc import Mexc30
# ========================= 工具函数 =========================
# 交易对的最小价格单位tick size配置
# 格式:交易对符号 -> 最小单位
TICK_SIZE_MAP = {
'SOLUSDT': 0.01,
'BTCUSDT': 0.1,
'ETHUSDT': 0.01,
'BNBUSDT': 0.01,
# 可以根据需要添加更多交易对
}
# 默认最小单位(如果交易对不在配置中)
DEFAULT_TICK_SIZE = 0.01
def get_tick_size(symbol: str) -> float:
"""
获取交易对的最小价格单位
:param symbol: 交易对符号,如 'SOLUSDT'
:return: 最小单位,如 0.01
"""
return TICK_SIZE_MAP.get(symbol.upper(), DEFAULT_TICK_SIZE)
def adjust_price_for_trade(price: float, direction: str, symbol: str = 'SOLUSDT') -> float:
"""
根据交易方向调整价格,考虑买卖价差
买入(开多/平空):价格 + tick_size
卖出(开空/平多):价格 - tick_size
:param price: 原始价格K线开盘价或收盘价
:param direction: 交易方向,'long' 表示买入,'short' 表示卖出
:param symbol: 交易对符号,用于获取最小单位
:return: 调整后的价格
"""
tick_size = get_tick_size(symbol)
if direction == 'long':
# 买入:价格 + tick_size
adjusted = price + tick_size
elif direction == 'short':
# 卖出:价格 - tick_size
adjusted = price - tick_size
else:
# 未知方向,返回原价
adjusted = price
# 确保价格不会为负
return max(adjusted, tick_size)
def is_bullish(c): # 阳线
return float(c['close']) > float(c['open'])
@@ -109,7 +160,7 @@ def get_data_by_date(model, date_str: str):
# ========================= 回测逻辑 =========================
def backtest_15m_trend_optimized(dates: List[str]):
def backtest_15m_trend_optimized(dates: List[str], symbol: str = 'SOLUSDT'):
"""
回测策略逻辑:
1. 开仓条件信号出现时下一根K线开盘价开仓
@@ -182,7 +233,9 @@ def backtest_15m_trend_optimized(dates: List[str]):
if current_position is None:
if direction:
# 信号出现prev和curr形成信号在下一根K线next_bar的开盘价开仓
entry_price = float(next_bar['open'])
# 应用买卖价差:买入(开多)时价格+0.01,卖出(开空)时价格-0.01
raw_price = float(next_bar['open'])
entry_price = adjust_price_for_trade(raw_price, direction, symbol)
current_position = {
'direction': direction,
'signal': stats[signal_key]['name'],
@@ -192,7 +245,7 @@ def backtest_15m_trend_optimized(dates: List[str]):
}
consecutive_opposite_count = 0 # 重置连续反色计数
stats[signal_key]['count'] += 1
logger.debug(f"开仓: {stats[signal_key]['name']} {'做多' if direction == 'long' else '做空'} @ {entry_price:.2f}")
logger.debug(f"开仓: {stats[signal_key]['name']} {'做多' if direction == 'long' else '做空'} @ {entry_price:.2f} (原始价格: {raw_price:.2f})")
idx += 1
continue
@@ -203,7 +256,11 @@ def backtest_15m_trend_optimized(dates: List[str]):
# 1. 反向信号 -> 下一根K线开盘价平仓并反手开仓
# 策略:遇到反向信号(如持有多单时遇到阴包阳),平仓并反手开仓
if direction and direction != pos_dir:
exit_price = float(next_bar['open'])
# 平仓:持有多单时卖出(价格-0.01),持有空单时买入(价格+0.01
raw_exit_price = float(next_bar['open'])
exit_direction = 'short' if pos_dir == 'long' else 'long' # 平仓方向与持仓方向相反
exit_price = adjust_price_for_trade(raw_exit_price, exit_direction, symbol)
diff = (exit_price - current_position['entry_price']) if pos_dir == 'long' else (
current_position['entry_price'] - exit_price)
trades.append({
@@ -218,17 +275,19 @@ def backtest_15m_trend_optimized(dates: List[str]):
stats[pos_sig_key]['total_profit'] += diff
if diff > 0: stats[pos_sig_key]['wins'] += 1
# 反手开仓下一根K线开盘价
# 反手开仓下一根K线开盘价,应用买卖价差
raw_entry_price = float(next_bar['open'])
entry_price = adjust_price_for_trade(raw_entry_price, direction, symbol)
current_position = {
'direction': direction,
'signal': stats[signal_key]['name'],
'signal_key': signal_key,
'entry_price': exit_price,
'entry_price': entry_price,
'entry_time': next_bar['id']
}
consecutive_opposite_count = 0 # 重置连续反色计数
stats[signal_key]['count'] += 1
logger.debug(f"反向信号反手: 平{'做多' if pos_dir == 'long' else '做空'} @ {exit_price:.2f}, 开{'做多' if direction == 'long' else '做空'}")
logger.debug(f"反向信号反手: 平{'做多' if pos_dir == 'long' else '做空'} @ {exit_price:.2f} (原始: {raw_exit_price:.2f}), 开{'做多' if direction == 'long' else '做空'} @ {entry_price:.2f} (原始: {raw_entry_price:.2f})")
idx += 1
continue
@@ -240,7 +299,9 @@ def backtest_15m_trend_optimized(dates: List[str]):
# 如果已经连续两根阴线下一根K线开盘价平仓
if consecutive_opposite_count >= 2:
logger.debug(f"平仓: 做多遇到连续两根阴线")
exit_price = float(next_bar['open'])
# 平多单:卖出,价格 - 0.01
raw_exit_price = float(next_bar['open'])
exit_price = adjust_price_for_trade(raw_exit_price, 'short', symbol)
diff = exit_price - current_position['entry_price']
trades.append({
'entry_time': datetime.datetime.fromtimestamp(current_position['entry_time'] / 1000),
@@ -268,7 +329,9 @@ def backtest_15m_trend_optimized(dates: List[str]):
# 如果已经连续两根阳线下一根K线开盘价平仓
if consecutive_opposite_count >= 2:
logger.debug(f"平仓: 做空遇到连续两根阳线")
exit_price = float(next_bar['open'])
# 平空单:买入,价格 + 0.01
raw_exit_price = float(next_bar['open'])
exit_price = adjust_price_for_trade(raw_exit_price, 'long', symbol)
diff = current_position['entry_price'] - exit_price
trades.append({
'entry_time': datetime.datetime.fromtimestamp(current_position['entry_time'] / 1000),
@@ -305,8 +368,12 @@ def backtest_15m_trend_optimized(dates: List[str]):
# 尾仓:最后一根收盘价平仓
if current_position:
last = all_data[-1]
exit_price = float(last['close'])
pos_dir = current_position['direction']
# 平仓:持有多单时卖出(价格-0.01),持有空单时买入(价格+0.01
raw_exit_price = float(last['close'])
exit_direction = 'short' if pos_dir == 'long' else 'long' # 平仓方向与持仓方向相反
exit_price = adjust_price_for_trade(raw_exit_price, exit_direction, symbol)
diff = (exit_price - current_position['entry_price']) if pos_dir == 'long' else (
current_position['entry_price'] - exit_price)
trades.append({
@@ -346,7 +413,9 @@ if __name__ == '__main__':
print(dates)
# dates = [f"2025-09-{i}" for i in range(1, 32)]
trades, stats = backtest_15m_trend_optimized(dates)
# 指定交易对符号,用于获取正确的最小价格单位
symbol = 'SOLUSDT'
trades, stats = backtest_15m_trend_optimized(dates, symbol=symbol)
logger.info("===== 每笔交易详情 =====")