1、trend + hawks 策略

This commit is contained in:
2025-09-24 23:14:14 +08:00
parent bc93a547f0
commit f43a6b2822
33 changed files with 20646 additions and 1609 deletions

View File

@@ -1,55 +0,0 @@
from datetime import timedelta
from src.analysis.result_analyzer import ResultAnalyzer
# 导入 TqsdkEngine而不是原来的 BacktestEngine
from src.indicators.indicators import RSI, HistoricalRange, BollingerBandwidth
from src.tqsdk_real_engine import TqsdkEngine
# 导入你的策略类
from src.strategies.OpenTwoFactorStrategy import SimpleLimitBuyStrategyLong, SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategy
from tqsdk import TqApi, TqBacktest, TqAuth, TqKq, TqAccount
# --- 配置参数 ---
# Tqsdk 的本地数据文件路径,注意 Tqsdk 要求文件名为 KQ_m@交易所_品种名_周期.csv
# 主力合约的 symbol
symbol = 'KQ.m@CZCE.MA'
strategy_parameters = {
'main_symbol': 'MA', # 根据您的数据文件中的品种名称调整
'trade_volume': 2,
'lag': 7,
# 'range_factor': 1.8, # 示例值,需要通过网格搜索优化
# 'profit_factor': 2.8, # 示例值
# 'range_factor': 1.6, # 示例值,需要通过网格搜索优化
# 'profit_factor': 2.1, # 示例值
'range_factor_l': 1.8, # 示例值,需要通过网格搜索优化
'profit_factor_l': 2.8, # 示例值
'range_factor_s': 1.6, # 示例值,需要通过网格搜索优化
'profit_factor_s': 2.1, # 示例值
'max_position': 10,
'enable_log': True,
'stop_loss_points': 20,
'use_indicator': True,
# 'indicator': HistoricalRange(11, 25, 20),
# 'indicator': BollingerBandwidth(window=20, nbdev=2.0, down_bound=1.9, up_bound=3.25),
'indicator_l': HistoricalRange(11, 25, 20),
'indicator_s': BollingerBandwidth(window=20, nbdev=2.0, down_bound=1.9, up_bound=3.25),
}
# api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
api = TqApi(TqAccount('H宏源期货', '903308830', 'lzr520102'), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# --- 1. 初始化回测引擎并运行 ---
print("\n初始化 Tqsdk 回测引擎...")
engine = TqsdkEngine(
strategy_class=SimpleLimitBuyStrategy,
strategy_params=strategy_parameters,
api=api,
symbol=symbol,
duration_seconds=60 * 60,
roll_over_mode=True, # 启用换月模式检测
history_length=50,
close_bar_delta=timedelta(minutes=58)
)
engine.run() # 这是一个同步方法,内部会运行 asyncio 循环

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,180 @@
import numpy as np
import talib
from typing import Optional, Dict, Any, List, Tuple, Union
from src.algo.TrendLine import calculate_latest_trendline_values
# 假设这些是你项目中的基础模块
from src.core_data import Bar, Order
from src.indicators.base_indicators import Indicator
from src.indicators.indicators import Empty
from src.strategies.base_strategy import Strategy
class TrendlineBreakoutStrategy(Strategy):
"""
趋势线突破策略 V3 (优化版):
1. 策略逻辑与 V2 相同,但趋势线计算被重构为一个独立的、
高性能的辅助方法。
2. 该方法只计算最新的趋势线值,避免不必要的数组生成。
开仓信号:
- 做多: 上一根收盘价上穿下趋势线
- 做空: 上一根收盘价下穿上趋势线
平仓逻辑:
- 采用 ATR 滑动止损 (Trailing Stop)。
"""
def __init__(
self,
context: Any,
main_symbol: str,
trendline_n: int = 50,
trade_volume: int = 1,
order_direction: Optional[List[str]] = None,
atr_period: int = 14,
atr_multiplier: float = 1.0,
enable_log: bool = True,
indicators: Union[Indicator, List[Indicator]] = None,
):
super().__init__(context, main_symbol, enable_log)
self.main_symbol = main_symbol
self.trendline_n = trendline_n
self.trade_volume = trade_volume
self.order_direction = order_direction or ["BUY", "SELL"]
self.atr_period = atr_period
self.atr_multiplier = atr_multiplier
self.pos_meta: Dict[str, Dict[str, Any]] = {}
if indicators is None:
indicators = [Empty(), Empty()]
self.indicators = indicators
if self.trendline_n < 3:
raise ValueError("trendline_n 必须大于或等于 3")
log_message = (
f"TrendlineBreakoutStrategy (V3 Optimized) 初始化:\n"
f"交易标的={self.main_symbol}, 交易量={self.trade_volume}\n"
f"趋势线周期={self.trendline_n}, ATR周期={self.atr_period}, ATR倍数={self.atr_multiplier}"
)
self.log(log_message)
def _calculate_atr(self, bar_history: List[Bar]) -> Optional[float]:
# (此函数与上一版本完全相同,保持不变)
if len(bar_history) < self.atr_period + 1: return None
highs = np.array([b.high for b in bar_history])
lows = np.array([b.low for b in bar_history])
closes = np.array([b.close for b in bar_history])
atr = talib.ATR(highs, lows, closes, timeperiod=self.atr_period)
return atr[-1] if not np.isnan(atr[-1]) else None
def on_init(self):
super().on_init()
self.pos_meta.clear()
def on_open_bar(self, open_price: float, symbol: str):
bar_history = self.get_bar_history()
min_bars_required = self.trendline_n + 2
if len(bar_history) < min_bars_required:
return
self.cancel_all_pending_orders(symbol)
pos = self.get_current_positions().get(symbol, 0)
# 1. 优先处理平仓逻辑 (逻辑不变)
meta = self.pos_meta.get(symbol)
if meta and pos != 0:
current_atr = self._calculate_atr(bar_history[:-1])
if current_atr:
trailing_stop = meta['trailing_stop']
direction = meta['direction']
last_close = bar_history[-1].close
if direction == "BUY":
new_stop_level = last_close - current_atr * self.atr_multiplier
trailing_stop = max(trailing_stop, new_stop_level)
else: # SELL
new_stop_level = last_close + current_atr * self.atr_multiplier
trailing_stop = min(trailing_stop, new_stop_level)
self.pos_meta[symbol]['trailing_stop'] = trailing_stop
if (direction == "BUY" and open_price <= trailing_stop) or \
(direction == "SELL" and open_price >= trailing_stop):
self.log(f"ATR滑动止损触发: 价格 {open_price:.2f} 触及止损位 {trailing_stop:.2f}")
self.send_market_order("CLOSE_LONG" if direction == "BUY" else "CLOSE_SHORT", abs(pos))
del self.pos_meta[symbol]
return
# 2. 开仓逻辑 (调用优化后的方法)
if pos == 0:
prices_for_trendline = np.array([b.close for b in bar_history[-self.trendline_n - 1:-1]])
# --- 调用新的独立方法 ---
trendline_val_upper, trendline_val_lower = calculate_latest_trendline_values(prices_for_trendline)
if trendline_val_upper is None or trendline_val_lower is None:
return # 无法计算趋势线,跳过
prev_close = bar_history[-2].close
last_close = bar_history[-1].close
current_atr = self._calculate_atr(bar_history[:-1])
if not current_atr:
return
if "BUY" in self.order_direction and last_close > trendline_val_upper and self.indicators[0].is_condition_met(*self.get_indicator_tuple()):
self.log(f"做多信号: Close({last_close:.2f}) 上穿下趋势线({trendline_val_upper:.2f})")
self.send_open_order("BUY", open_price, self.trade_volume, current_atr)
elif "SELL" in self.order_direction and last_close < trendline_val_lower and self.indicators[1].is_condition_met(*self.get_indicator_tuple()):
self.log(f"做空信号: Close({last_close:.2f}) 下穿上趋势线({trendline_val_lower:.2f})")
self.send_open_order("SELL", open_price, self.trade_volume, current_atr)
# is_met = self.indicators[0].is_condition_met(*self.get_indicator_tuple())
# if "BUY" in self.order_direction and last_close > trendline_val_upper and is_met:
# self.log(f"做多信号: Close({last_close:.2f}) 上穿下趋势线({trendline_val_upper:.2f})")
# self.send_open_order("BUY", open_price, self.trade_volume, current_atr)
#
# elif "SELL" in self.order_direction and last_close < trendline_val_lower and is_met:
# self.log(f"做空信号: Close({last_close:.2f}) 下穿上趋势线({trendline_val_lower:.2f})")
# self.send_open_order("SELL", open_price, self.trade_volume, current_atr)
# prob = self.indicators[0].get_latest_value(*self.get_indicator_tuple())
# if "BUY" in self.order_direction and last_close > trendline_val_upper:
# if prob is None or prob[0] < prob[1]:
# self.log(f"做多信号: Close({last_close:.2f}) 上穿下趋势线({trendline_val_upper:.2f})")
# self.send_open_order("BUY", open_price, self.trade_volume, current_atr)
#
# elif "SELL" in self.order_direction and last_close < trendline_val_lower:
# if prob is None or prob[2] < prob[3]:
# self.log(f"做空信号: Close({last_close:.2f}) 下穿上趋势线({trendline_val_lower:.2f})")
# self.send_open_order("SELL", open_price, self.trade_volume, current_atr)
# send_open_order, send_market_order, on_rollover 等方法与上一版本完全相同,保持不变
def send_open_order(self, direction: str, entry_price: float, volume: int, current_atr: float):
if direction == "BUY":
initial_stop = entry_price - current_atr * self.atr_multiplier
else:
initial_stop = entry_price + current_atr * self.atr_multiplier
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order_direction = "BUY" if direction == "BUY" else "SELL"
order = Order(id=order_id, symbol=self.symbol, direction=order_direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="OPEN")
self.send_order(order)
self.pos_meta[self.symbol] = {"direction": direction, "volume": volume, "entry_price": entry_price,
"trailing_stop": initial_stop}
self.log(
f"发送开仓订单: {direction} {volume}手 @ Market Price (执行价约 {entry_price:.2f}), 初始ATR止损位: {initial_stop:.2f}")
def send_market_order(self, direction: str, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="CLOSE")
self.send_order(order)
self.log(f"发送平仓订单: {direction} {volume}手 @ Market Price")
def on_rollover(self, old_symbol: str, new_symbol: str):
super().on_rollover(old_symbol, new_symbol)
self.cancel_all_pending_orders(new_symbol)
self.pos_meta.clear()

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,58 +0,0 @@
from datetime import timedelta
from src.analysis.result_analyzer import ResultAnalyzer
# 导入 TqsdkEngine而不是原来的 BacktestEngine
from src.indicators.indicators import RSI, HistoricalRange, BollingerBandwidth
from src.tqsdk_real_engine import TqsdkEngine
# 导入你的策略类
from src.strategies.OpenTwoFactorStrategy import SimpleLimitBuyStrategyLong, SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategy
from tqsdk import TqApi, TqBacktest, TqAuth, TqKq, TqAccount
# --- 配置参数 ---
# Tqsdk 的本地数据文件路径,注意 Tqsdk 要求文件名为 KQ_m@交易所_品种名_周期.csv
# 主力合约的 symbol
symbol = "KQ.m@CZCE.SA"
strategy_parameters = {
'main_symbol': "SA", # 根据您的数据文件中的品种名称调整
'trade_volume': 1,
# 'lag': 7,
# 'lag': 1,
# 'range_factor': 1.6, # 示例值,需要通过网格搜索优化
# 'profit_factor': 2.4, # 示例值
# 'range_factor': 2.5, # 示例值,需要通过网格搜索优化
# 'profit_factor': 4.5, # 示例值
'range_factor_l': 1.6, # 示例值,需要通过网格搜索优化
'profit_factor_l': 2.4, # 示例值
'range_factor_s': 2.5, # 示例值,需要通过网格搜索优化
'profit_factor_s': 4.5, # 示例值
'max_position': 10,
'enable_log': True,
'stop_loss_points': 10,
'use_indicator': True,
# 'indicator': RSI(window=25, down_bound=47, up_bound=67),
# 'indicator': BollingerBandwidth(window=10, nbdev=1.5, down_bound=2.5, up_bound=6),
'indicator_l': RSI(window=25, down_bound=47, up_bound=67),
'indicator_s': BollingerBandwidth(window=10, nbdev=1.5, down_bound=2.5, up_bound=6),
'lag_l': 7,
'lag_s': 1,
}
# api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
api = TqApi(TqAccount('H宏源期货', '903308830', 'lzr520102'), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# --- 1. 初始化回测引擎并运行 ---
print("\n初始化 Tqsdk 回测引擎...")
engine = TqsdkEngine(
strategy_class=SimpleLimitBuyStrategy,
strategy_params=strategy_parameters,
api=api,
symbol=symbol,
duration_seconds=60 * 60,
roll_over_mode=True, # 启用换月模式检测
history_length=300,
close_bar_delta=timedelta(minutes=58)
)
engine.run() # 这是一个同步方法,内部会运行 asyncio 循环

View File

@@ -1,59 +0,0 @@
from datetime import timedelta
from src.analysis.result_analyzer import ResultAnalyzer
# 导入 TqsdkEngine而不是原来的 BacktestEngine
from src.indicators.indicators import RSI, HistoricalRange, BollingerBandwidth, NormalizedATR
from src.tqsdk_real_engine import TqsdkEngine
# 导入你的策略类
from src.strategies.OpenTwoFactorStrategy import SimpleLimitBuyStrategyLong, SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategy
from tqsdk import TqApi, TqBacktest, TqAuth, TqKq, TqAccount
# --- 配置参数 ---
# Tqsdk 的本地数据文件路径,注意 Tqsdk 要求文件名为 KQ_m@交易所_品种名_周期.csv
# 主力合约的 symbol
symbol = "KQ.m@SHFE.fu"
strategy_parameters = {
'main_symbol': "fu", # 根据您的数据文件中的品种名称调整
'trade_volume': 3,
'lag': 7,
# 'lag': 7,
# 'range_factor': 0.7, # 示例值,需要通过网格搜索优化
# 'profit_factor': 0.3, # 示例值
# 'range_factor': 1.9, # 示例值,需要通过网格搜索优化
# 'profit_factor': 0.2, # 示例值
'range_factor_l': 0.7, # 示例值,需要通过网格搜索优化
'profit_factor_l': 0.3, # 示例值
'range_factor_s': 1.9, # 示例值,需要通过网格搜索优化
'profit_factor_s': 0.2, # 示例值
'max_position': 10,
'enable_log': True,
'stop_loss_points': 20,
'use_indicator': True,
# 'indicator': HistoricalRange(shift_window=0, down_bound=5, up_bound=20),
# 'indicator': RSI(window=5, down_bound=40, up_bound=70),
# 'indicator': HistoricalRange(shift_window=0, down_bound=20, up_bound=100),
'indicator_l': HistoricalRange(shift_window=0, down_bound=5, up_bound=20),
'indicator_s': HistoricalRange(shift_window=0, down_bound=20, up_bound=100),
# 'lag_l': 1,
# 'lag_s': 7,
}
# api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
api = TqApi(TqAccount('H宏源期货', '903308830', 'lzr520102'), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# --- 1. 初始化回测引擎并运行 ---
print("\n初始化 Tqsdk 回测引擎...")
engine = TqsdkEngine(
strategy_class=SimpleLimitBuyStrategy,
strategy_params=strategy_parameters,
api=api,
symbol=symbol,
duration_seconds=60 * 60,
roll_over_mode=True, # 启用换月模式检测
history_length=50,
close_bar_delta=timedelta(minutes=58)
)
engine.run() # 这是一个同步方法,内部会运行 asyncio 循环

View File

@@ -1,55 +0,0 @@
from datetime import timedelta
from src.analysis.result_analyzer import ResultAnalyzer
# 导入 TqsdkEngine而不是原来的 BacktestEngine
from src.indicators.indicators import RSI, HistoricalRange
from src.tqsdk_real_engine import TqsdkEngine
# 导入你的策略类
from src.strategies.OpenTwoFactorStrategy import SimpleLimitBuyStrategyLong, SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategy
from tqsdk import TqApi, TqBacktest, TqAuth, TqKq, TqAccount
# --- 配置参数 ---
# Tqsdk 的本地数据文件路径,注意 Tqsdk 要求文件名为 KQ_m@交易所_品种名_周期.csv
# 主力合约的 symbol
main_symbol = "KQ.m@DCE.jm"
strategy_parameters = {
'symbol': 'jm', # 根据您的数据文件中的品种名称调整
'trade_volume': 1,
'lag': 1,
# 'range_factor': 1.3, # 示例值,需要通过网格搜索优化
# 'profit_factor': 4.8, # 示例值
# 'range_factor': 1.1, # 示例值,需要通过网格搜索优化
# 'profit_factor': 4.9, # 示例值
'range_factor_l': 1.3, # 示例值,需要通过网格搜索优化
'profit_factor_l': 4.8, # 示例值
'range_factor_s': 1.1, # 示例值,需要通过网格搜索优化
'profit_factor_s': 4.9, # 示例值
'max_position': 10,
'enable_log': True,
'stop_loss_points': 20,
'use_indicator': True,
# 'indicator': RSI(5, 63, 95),
# 'indicator': RSI(5, 5, 25),
'indicator_l': RSI(5, 63, 95),
'indicator_s': RSI(5, 0, 100),
}
# api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
api = TqApi(TqAccount('H宏源期货', '903308830', 'lzr520102'), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# --- 1. 初始化回测引擎并运行 ---
print("\n初始化 Tqsdk 回测引擎...")
engine = TqsdkEngine(
strategy_class=SimpleLimitBuyStrategy,
strategy_params=strategy_parameters,
api=api,
symbol=main_symbol,
duration_seconds=60 * 60,
roll_over_mode=True, # 启用换月模式检测
history_length=50,
close_bar_delta=timedelta(minutes=58)
)
engine.run() # 这是一个同步方法,内部会运行 asyncio 循环

View File

@@ -1,58 +0,0 @@
from datetime import timedelta
from src.analysis.result_analyzer import ResultAnalyzer
# 导入 TqsdkEngine而不是原来的 BacktestEngine
from src.indicators.indicators import RSI, HistoricalRange, BollingerBandwidth, NormalizedATR
from src.tqsdk_real_engine import TqsdkEngine
# 导入你的策略类
from src.strategies.OpenTwoFactorStrategy import SimpleLimitBuyStrategyLong, SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategy
from tqsdk import TqApi, TqBacktest, TqAuth, TqKq, TqAccount
# --- 配置参数 ---
# Tqsdk 的本地数据文件路径,注意 Tqsdk 要求文件名为 KQ_m@交易所_品种名_周期.csv
# 主力合约的 symbol
symbol = "KQ.m@SHFE.rb"
strategy_parameters = {
'main_symbol': 'rb', # 根据您的数据文件中的品种名称调整
'trade_volume': 2,
# 'lag': 1,
# 'lag': 7,
# 'range_factor': 2.1, # 示例值,需要通过网格搜索优化
# 'profit_factor': 1.6, # 示例值
# 'range_factor': 0.2, # 示例值,需要通过网格搜索优化
# 'profit_factor': 3.8, # 示例值
'range_factor_l': 2.1, # 示例值,需要通过网格搜索优化
'profit_factor_l': 1.6, # 示例值
'range_factor_s': 0.2, # 示例值,需要通过网格搜索优化
'profit_factor_s': 3.8, # 示例值
'max_position': 10,
'enable_log': True,
'stop_loss_points': 20,
'use_indicator': True,
# 'indicator': RSI(14, 44, 70),
# 'indicator': NormalizedATR(window=5, down_bound=0.62, up_bound=0.76),
'indicator_l': RSI(14, 44, 70),
'indicator_s': NormalizedATR(window=5, down_bound=0.62, up_bound=0.76),
'lag_l': 1,
'lag_s': 7,
}
# api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
api = TqApi(TqAccount('H宏源期货', '903308830', 'lzr520102'), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# --- 1. 初始化回测引擎并运行 ---
print("\n初始化 Tqsdk 回测引擎...")
engine = TqsdkEngine(
strategy_class=SimpleLimitBuyStrategy,
strategy_params=strategy_parameters,
api=api,
symbol=symbol,
duration_seconds=60 * 60,
roll_over_mode=True, # 启用换月模式检测
history_length=50,
close_bar_delta=timedelta(minutes=58)
)
engine.run() # 这是一个同步方法,内部会运行 asyncio 循环