178 lines
7.9 KiB
Python
178 lines
7.9 KiB
Python
|
|
import numpy as np
|
|||
|
|
import pandas as pd
|
|||
|
|
from typing import Optional, Dict, Any, List
|
|||
|
|
|
|||
|
|
# 假设这些是你项目中的模块
|
|||
|
|
from src.core_data import Bar, Order
|
|||
|
|
from src.strategies.base_strategy import Strategy
|
|||
|
|
from src.algo.TrendLine import calculate_latest_trendline_values
|
|||
|
|
from src.algo.HawksProcess import calculate_hawkes_bands
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TrendlineHawkesStrategy(Strategy):
|
|||
|
|
"""
|
|||
|
|
趋势线与霍克斯过程双重确认策略 (V2 - 支持逻辑反转):
|
|||
|
|
|
|||
|
|
入场信号 (双重确认):
|
|||
|
|
1. 趋势线事件: 收盘价突破上轨(标准模式做多)或下轨(标准模式做空)。
|
|||
|
|
2. 霍克斯确认: 同时,成交量霍克斯强度必须高于其近期高位分位数。
|
|||
|
|
|
|||
|
|
出场逻辑 (基于霍克斯过程):
|
|||
|
|
- 当成交量霍克斯强度从高位回落至近期低位分位数以下时,平仓。
|
|||
|
|
|
|||
|
|
逻辑反转 (`reverse_logic=True`):
|
|||
|
|
- 趋势线突破上轨时,开【空】仓。
|
|||
|
|
- 趋势线突破下轨时,开【多】仓。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(
|
|||
|
|
self,
|
|||
|
|
context: Any,
|
|||
|
|
main_symbol: str,
|
|||
|
|
trade_volume: int = 1,
|
|||
|
|
order_direction: Optional[List[str]] = None,
|
|||
|
|
# --- 新增: 逻辑反转开关 ---
|
|||
|
|
reverse_logic: bool = False,
|
|||
|
|
# --- 趋势线参数 ---
|
|||
|
|
trendline_n: int = 50,
|
|||
|
|
# --- 霍克斯过程参数 ---
|
|||
|
|
hawkes_kappa: float = 0.1,
|
|||
|
|
hawkes_lookback: int = 50,
|
|||
|
|
hawkes_entry_percent: float = 0.95,
|
|||
|
|
hawkes_exit_percent: float = 0.50,
|
|||
|
|
enable_log: bool = True,
|
|||
|
|
):
|
|||
|
|
super().__init__(context, main_symbol, enable_log)
|
|||
|
|
self.main_symbol = main_symbol
|
|||
|
|
self.trade_volume = trade_volume
|
|||
|
|
self.order_direction = order_direction or ["BUY", "SELL"]
|
|||
|
|
|
|||
|
|
# --- 新增 ---
|
|||
|
|
self.reverse_logic = reverse_logic
|
|||
|
|
|
|||
|
|
self.trendline_n = trendline_n
|
|||
|
|
self.hawkes_kappa = hawkes_kappa
|
|||
|
|
self.hawkes_lookback = hawkes_lookback
|
|||
|
|
self.hawkes_entry_percent = hawkes_entry_percent
|
|||
|
|
self.hawkes_exit_percent = hawkes_exit_percent
|
|||
|
|
|
|||
|
|
self.pos_meta: Dict[str, Dict[str, Any]] = {}
|
|||
|
|
|
|||
|
|
if self.trendline_n < 3:
|
|||
|
|
raise ValueError("trendline_n 必须大于或等于 3")
|
|||
|
|
|
|||
|
|
log_message = (
|
|||
|
|
f"TrendlineHawkesStrategy 初始化:\n"
|
|||
|
|
f"【逻辑模式】: {'反转 (Reversal)' if self.reverse_logic else '标准 (Breakout)'}\n"
|
|||
|
|
f"趋势线周期={self.trendline_n}\n"
|
|||
|
|
f"霍克斯参数: kappa={self.hawkes_kappa}, lookback={self.hawkes_lookback}, "
|
|||
|
|
f"entry_pct={self.hawkes_entry_percent}, exit_pct={self.hawkes_exit_percent}"
|
|||
|
|
)
|
|||
|
|
self.log(log_message)
|
|||
|
|
|
|||
|
|
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 = max(self.trendline_n + 2, self.hawkes_lookback + 2)
|
|||
|
|
if len(bar_history) < min_bars_required:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.cancel_all_pending_orders(symbol)
|
|||
|
|
pos = self.get_current_positions().get(symbol, 0)
|
|||
|
|
|
|||
|
|
# --- 数据准备 (与之前相同) ---
|
|||
|
|
close_prices = np.array([b.close for b in bar_history])
|
|||
|
|
volume_series = pd.Series(
|
|||
|
|
[b.volume for b in bar_history],
|
|||
|
|
index=pd.to_datetime([b.datetime for b in bar_history])
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
vol_hawkes, hawkes_upper_band, hawkes_lower_band = calculate_hawkes_bands(
|
|||
|
|
volume_series, self.hawkes_lookback, self.hawkes_kappa,
|
|||
|
|
self.hawkes_entry_percent, self.hawkes_exit_percent
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
latest_hawkes_value = vol_hawkes.iloc[-1]
|
|||
|
|
latest_hawkes_upper = hawkes_upper_band.iloc[-1]
|
|||
|
|
latest_hawkes_lower = hawkes_lower_band.iloc[-1]
|
|||
|
|
|
|||
|
|
# 1. 优先处理平仓逻辑 (逻辑保持不变)
|
|||
|
|
meta = self.pos_meta.get(symbol)
|
|||
|
|
if meta and pos != 0:
|
|||
|
|
if latest_hawkes_value < latest_hawkes_lower:
|
|||
|
|
self.log(f"霍克斯出场信号: 强度({latest_hawkes_value:.2f}) < 阈值({latest_hawkes_lower:.2f})")
|
|||
|
|
self.send_market_order("CLOSE_LONG" if meta['direction'] == "BUY" else "CLOSE_SHORT", abs(pos))
|
|||
|
|
del self.pos_meta[symbol]
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 2. 开仓逻辑 (加入反转判断)
|
|||
|
|
if pos == 0:
|
|||
|
|
prices_for_trendline = close_prices[-self.trendline_n - 1:-1]
|
|||
|
|
trend_upper, trend_lower = calculate_latest_trendline_values(prices_for_trendline)
|
|||
|
|
|
|||
|
|
if trend_upper is None or trend_lower is None:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
prev_close = bar_history[-2].close
|
|||
|
|
last_close = bar_history[-1].close
|
|||
|
|
|
|||
|
|
# --- a) 定义基础的突破【事件】 ---
|
|||
|
|
upper_break_event = last_close > trend_upper and prev_close < trend_upper
|
|||
|
|
lower_break_event = last_close < trend_lower and prev_close > trend_lower
|
|||
|
|
|
|||
|
|
# --- b) 定义霍克斯【确认】---
|
|||
|
|
hawkes_confirmation = latest_hawkes_value > latest_hawkes_upper
|
|||
|
|
|
|||
|
|
# 只有当基础事件和霍克斯确认都发生时,才考虑开仓
|
|||
|
|
if hawkes_confirmation and (upper_break_event or lower_break_event):
|
|||
|
|
|
|||
|
|
# --- c) 【核心修改】根据 reverse_logic 决定最终交易方向 ---
|
|||
|
|
trade_direction = None
|
|||
|
|
|
|||
|
|
if upper_break_event: # 价格向上突破上轨
|
|||
|
|
# 标准模式:做多 (动量)
|
|||
|
|
# 反转模式:做空 (力竭反转)
|
|||
|
|
trade_direction = "SELL" if self.reverse_logic else "BUY"
|
|||
|
|
|
|||
|
|
elif lower_break_event: # 价格向下突破下轨
|
|||
|
|
# 标准模式:做空 (动量)
|
|||
|
|
# 反转模式:做多 (恐慌探底反转)
|
|||
|
|
trade_direction = "BUY" if self.reverse_logic else "SELL"
|
|||
|
|
|
|||
|
|
# d) 执行交易
|
|||
|
|
if trade_direction and trade_direction in self.order_direction:
|
|||
|
|
event_type = "向上突破" if upper_break_event else "向下突破"
|
|||
|
|
logic_type = "反转" if self.reverse_logic else "标准"
|
|||
|
|
self.log(
|
|||
|
|
f"{logic_type}模式 {trade_direction} 信号: "
|
|||
|
|
f"价格{event_type} & 霍克斯强度({latest_hawkes_value:.2f}) > 阈值({latest_hawkes_upper:.2f})"
|
|||
|
|
)
|
|||
|
|
self.send_open_order(trade_direction, open_price, self.trade_volume)
|
|||
|
|
|
|||
|
|
# send_open_order, send_market_order, on_rollover 等方法保持不变
|
|||
|
|
def send_open_order(self, direction: str, entry_price: float, volume: int):
|
|||
|
|
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}
|
|||
|
|
self.log(f"发送开仓订单: {direction} {volume}手 @ Market Price (执行价约 {entry_price:.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()
|