tqsdk实盘

This commit is contained in:
2025-07-10 15:07:31 +08:00
parent 4c243a4b47
commit 5de1a43b02
26 changed files with 12462 additions and 17535 deletions

View File

@@ -0,0 +1,829 @@
# src/strategies/simple_limit_buy_strategy.py
from tkinter import N
import numpy as np
from src.indicators.indicators import RSI, HistoricalRange
from .base_strategy import Strategy
from ..core_data import Bar, Order
from typing import Optional, Dict, Any
from collections import deque
class SimpleLimitBuyStrategyLong(Strategy):
"""
一个基于当前K线Open、前1根和前7根K线Range计算优势价格进行限价买入的策略。
具备以下特点:
- 每根K线开始时取消上一根K线未成交的订单。
- 最多只能有一个开仓挂单和一个持仓。
- 包含简单的止损和止盈逻辑。
"""
def __init__(
self,
context: Any,
symbol: str,
enable_log: bool,
trade_volume: int,
range_factor: float,
profit_factor: float,
max_position: int,
stop_loss_points: float = 10, # 新增:止损点数
take_profit_points: float = 10,
use_indicator: bool = False,
): # 新增:止盈点数
"""
初始化策略。
Args:
context: 模拟器实例。
symbol (str): 交易合约代码。
trade_volume (int): 单笔交易量。
range_factor (float): 前1根K线Range的权重因子用于从Open价向下偏移。
profit_factor (float): 前7根K线Range的权重因子用于从Open价向下偏移。
max_position (int): 最大持仓量此处为1因为只允许一个持仓
stop_loss_points (float): 止损点数(例如,亏损达到此点数则止损)。
take_profit_points (float): 止盈点数(例如,盈利达到此点数则止盈)。
"""
super().__init__(context, symbol, enable_log)
self.trade_volume = trade_volume
self.range_factor = range_factor
self.profit_factor = profit_factor
self.max_position = max_position # 理论上这里应为1
self.stop_loss_points = stop_loss_points
self.take_profit_points = take_profit_points
self.use_indicator = use_indicator
self.order_id_counter = 0
self._last_order_id: Optional[str] = None # 用于跟踪上一根K线发出的订单ID
self.log(
f"策略初始化: symbol={self.symbol}, trade_volume={self.trade_volume}, "
f"range_factor={self.range_factor}, "
f"profit_factor={self.profit_factor}, "
f"max_position={self.max_position}, "
f"止损点={self.stop_loss_points}, 止盈点={self.take_profit_points}"
)
def on_init(self):
super().on_init()
count = self.cancel_all_pending_orders()
self.log(f'取消{count}笔订单')
def on_open_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
"""
每当新的K线数据到来时调用。
Args:
bar (Bar): 当前的K线数据对象。
next_bar_open (Optional[float]): 下一根K线的开盘价此处策略未使用。
"""
current_datetime = bar.datetime # 获取当前K线时间
self.symbol = bar.symbol
# --- 1. 撤销上一根K线未成交的订单 ---
# 检查是否记录了上一笔订单ID并且该订单仍然在待处理列表中
if self._last_order_id:
pending_orders = self.get_pending_orders()
if self._last_order_id in pending_orders:
success = self.cancel_order(
self._last_order_id
) # 直接调用基类的取消方法
if success:
self.log(
f"[{current_datetime}] 策略: 成功撤销上一根K线未成交订单 {self._last_order_id}"
)
else:
self.log(
f"[{current_datetime}] 策略: 尝试撤销订单 {self._last_order_id} 失败(可能已成交或不存在)"
)
# 无论撤销成功与否,既然我们尝试了撤销,就清除记录
self._last_order_id = None
# else:
# self.log(f"[{current_datetime}] 策略: 无上一根K线未成交订单需要撤销。")
# 2. 更新K线历史
trade_volume = self.trade_volume
# 获取当前持仓和未决订单(在取消之后获取,确保是最新的状态)
current_positions = self.get_current_positions()
current_pos_volume = current_positions.get(self.symbol, 0)
pending_orders_after_cancel = (
self.get_pending_orders()
) # 再次获取,此时应已取消旧订单
range_1_ago = None
range_7_ago = None
bar_history = self.get_bar_history()
if len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
# 计算历史 K 线的 Range
range_1_ago = bar_1_ago.high - bar_1_ago.low
range_7_ago = bar_7_ago.high - bar_7_ago.low
# for i in range(1, 9, 1):
# print(bar_history[-i].datetime)
# --- 3. 平仓逻辑 (止损/止盈) ---
# 只有当有持仓时才考虑平仓
if (
current_pos_volume > 0 and range_1_ago is not None
): # 假设只做多,所以持仓量 > 0
avg_entry_price = self.get_average_position_price(self.symbol)
if avg_entry_price is not None:
pnl_per_unit = (
bar.open - avg_entry_price
) # 当前浮动盈亏(以收盘价计算)
self.log(
f"[{current_datetime}] 止盈信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {self.take_profit_points:.2f}"
)
# 止盈条件
if pnl_per_unit >= range_1_ago * self.profit_factor:
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_LONG",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# 止损条件
elif pnl_per_unit <= -self.stop_loss_points:
self.log(
f"[{current_datetime}] 止损信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {-self.stop_loss_points:.2f}"
)
# 发送市价卖出订单平仓,确保立即成交
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_LONG",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# --- 4. 开仓逻辑 (只考虑做多 BUY 方向) ---
# 只有在没有持仓 (current_pos_volume == 0) 且没有待处理订单 (not pending_orders_after_cancel)
# 且K线历史足够长时才考虑开仓
# rsi = RSI(5).get_latest_value(np.array(self.get_price_history('close')), None, None, None, None)
indicator_value = HistoricalRange(21).get_latest_value(
None,
None,
np.array(self.get_price_history("high")),
np.array(self.get_price_history("low")),
None,
)
if (
current_pos_volume == 0
and range_1_ago is not None
and (not self.use_indicator or 10 < indicator_value < 25)
):
# if current_pos_volume == 0 and range_1_ago is not None:
# 根据策略逻辑计算目标买入价格
# 目标买入价 = 当前K线Open - (前1根Range * 因子1 + 前7根Range * 因子2)
self.log(bar.open, range_1_ago * self.range_factor)
target_buy_price = bar.open - (range_1_ago * self.range_factor)
# 确保目标买入价格有效,例如不能是负数
target_buy_price = max(0.01, target_buy_price)
self.log(
f"[{current_datetime}] 开多仓信号 - 当前Open={bar.open:.2f}, "
f"前1Range={range_1_ago:.2f}, "
f"计算目标买入价={target_buy_price:.2f}"
)
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="BUY",
volume=trade_volume,
price_type="LIMIT",
limit_price=target_buy_price,
submitted_time=bar.datetime,
)
new_order = self.send_order(order)
# 记录下这个订单的ID以便在下一根K线开始时进行撤销
if new_order:
self._last_order_id = new_order.id
self.log(
f"[{current_datetime}] 策略: 发送限价买入订单 {self._last_order_id} @ {target_buy_price:.2f}"
)
else:
self.log(f"[{current_datetime}] 策略: 发送订单失败。")
# else:
# self.log(f"[{current_datetime}] 不满足开仓条件:持仓={current_pos_volume}, 待处理订单={len(pending_orders_after_cancel)}, K线历史长度={len(bar_history)}")
def on_close_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
self.cancel_all_pending_orders()
def on_rollover(self, old_symbol: str, new_symbol: str):
"""
在合约换月时清空历史K线数据和上次订单ID避免使用旧合约数据进行计算。
"""
super().on_rollover(old_symbol, new_symbol) # 调用基类方法打印日志
self._last_order_id = None # 清空上次订单ID因为旧合约订单已取消
self.log(f"换月完成清空历史K线数据和上次订单ID准备新合约交易。")
class SimpleLimitBuyStrategyShort(Strategy):
"""
一个基于当前K线Open、前1根和前7根K线Range计算优势价格进行限价买入的策略。
具备以下特点:
- 每根K线开始时取消上一根K线未成交的订单。
- 最多只能有一个开仓挂单和一个持仓。
- 包含简单的止损和止盈逻辑。
"""
def __init__(
self,
context: Any,
symbol: str,
enable_log: bool,
trade_volume: int,
range_factor: float,
profit_factor: float,
max_position: int,
stop_loss_points: float = 10, # 新增:止损点数
take_profit_points: float = 10,
use_indicator: bool = False,
): # 新增:止盈点数
"""
初始化策略。
Args:
context: 模拟器实例。
symbol (str): 交易合约代码。
trade_volume (int): 单笔交易量。
range_factor (float): 前1根K线Range的权重因子用于从Open价向下偏移。
profit_factor (float): 前7根K线Range的权重因子用于从Open价向下偏移。
max_position (int): 最大持仓量此处为1因为只允许一个持仓
stop_loss_points (float): 止损点数(例如,亏损达到此点数则止损)。
take_profit_points (float): 止盈点数(例如,盈利达到此点数则止盈)。
"""
super().__init__(context, symbol, enable_log)
self.trade_volume = trade_volume
self.range_factor = range_factor
self.profit_factor = profit_factor
self.max_position = max_position # 理论上这里应为1
self.stop_loss_points = stop_loss_points
self.take_profit_points = take_profit_points
self.use_indicator = use_indicator
self.order_id_counter = 0
self._last_order_id: Optional[str] = None # 用于跟踪上一根K线发出的订单ID
self.log(
f"策略初始化: symbol={self.symbol}, trade_volume={self.trade_volume}, "
f"range_factor={self.range_factor}, "
f"profit_factor={self.profit_factor}, "
f"max_position={self.max_position}, "
f"止损点={self.stop_loss_points}, 止盈点={self.take_profit_points}"
)
def on_open_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
"""
每当新的K线数据到来时调用。
Args:
bar (Bar): 当前的K线数据对象。
next_bar_open (Optional[float]): 下一根K线的开盘价此处策略未使用。
"""
current_datetime = bar.datetime # 获取当前K线时间
self.symbol = bar.symbol
# --- 1. 撤销上一根K线未成交的订单 ---
# 检查是否记录了上一笔订单ID并且该订单仍然在待处理列表中
if self._last_order_id:
pending_orders = self.get_pending_orders()
if self._last_order_id in pending_orders:
success = self.cancel_order(
self._last_order_id
) # 直接调用基类的取消方法
if success:
self.log(
f"[{current_datetime}] 策略: 成功撤销上一根K线未成交订单 {self._last_order_id}"
)
else:
self.log(
f"[{current_datetime}] 策略: 尝试撤销订单 {self._last_order_id} 失败(可能已成交或不存在)"
)
# 无论撤销成功与否,既然我们尝试了撤销,就清除记录
self._last_order_id = None
# else:
# self.log(f"[{current_datetime}] 策略: 无上一根K线未成交订单需要撤销。")
# 2. 更新K线历史
trade_volume = self.trade_volume
# 获取当前持仓和未决订单(在取消之后获取,确保是最新的状态)
current_positions = self.get_current_positions()
current_pos_volume = current_positions.get(self.symbol, 0)
pending_orders_after_cancel = (
self.get_pending_orders()
) # 再次获取,此时应已取消旧订单
range_1_ago = None
range_7_ago = None
bar_history = self.get_bar_history()
if len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
# 计算历史 K 线的 Range
range_1_ago = bar_1_ago.high - bar_1_ago.low
range_7_ago = bar_7_ago.high - bar_7_ago.low
# --- 3. 平仓逻辑 (止损/止盈) ---
# 只有当有持仓时才考虑平仓
if (
current_pos_volume < 0 and range_1_ago is not None
): # 假设只做多,所以持仓量 > 0
avg_entry_price = self.get_average_position_price(self.symbol)
if avg_entry_price is not None:
pnl_per_unit = (
avg_entry_price - bar.open
) # 当前浮动盈亏(以收盘价计算)
self.log(
f"[{current_datetime}] 止盈信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {self.take_profit_points:.2f}"
)
# 止盈条件
if pnl_per_unit >= range_1_ago * self.profit_factor:
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_SHORT",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# 止损条件
elif pnl_per_unit <= -self.stop_loss_points:
self.log(
f"[{current_datetime}] 止损信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {-self.stop_loss_points:.2f}"
)
# 发送市价卖出订单平仓,确保立即成交
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_SHORT",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# --- 4. 开仓逻辑 (只考虑做多 BUY 方向) ---
# 只有在没有持仓 (current_pos_volume == 0) 且没有待处理订单 (not pending_orders_after_cancel)
# 且K线历史足够长时才考虑开仓
# rsi = RSI(5).get_latest_value(np.array(self.get_price_history('close')), None, None, None, None)
indicator_value = RSI(5).get_latest_value(np.array(self.get_price_history('close')), None, None, None, None)
if (
current_pos_volume == 0
and range_1_ago is not None
and (not self.use_indicator or 20 < indicator_value < 60)
):
# 根据策略逻辑计算目标买入价格
# 目标买入价 = 当前K线Open - (前1根Range * 因子1 + 前7根Range * 因子2)
self.log(bar.open, range_1_ago * self.range_factor)
target_buy_price = bar.open + (range_1_ago * self.range_factor)
# 确保目标买入价格有效,例如不能是负数
target_buy_price = max(0.01, target_buy_price)
self.log(
f"[{current_datetime}] 开多仓信号 - 当前Open={bar.open:.2f}, "
f"前1Range={range_1_ago:.2f}, "
f"计算目标买入价={target_buy_price:.2f}"
)
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="SELL",
volume=trade_volume,
price_type="LIMIT",
limit_price=target_buy_price,
submitted_time=bar.datetime,
)
new_order = self.send_order(order)
# 记录下这个订单的ID以便在下一根K线开始时进行撤销
if new_order:
self._last_order_id = new_order.id
self.log(
f"[{current_datetime}] 策略: 发送限价买入订单 {self._last_order_id} @ {target_buy_price:.2f}"
)
else:
self.log(f"[{current_datetime}] 策略: 发送订单失败。")
# else:
# self.log(f"[{current_datetime}] 不满足开仓条件:持仓={current_pos_volume}, 待处理订单={len(pending_orders_after_cancel)}, K线历史长度={len(bar_history)}")
def on_close_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
self.cancel_all_pending_orders()
def on_rollover(self, old_symbol: str, new_symbol: str):
"""
在合约换月时清空历史K线数据和上次订单ID避免使用旧合约数据进行计算。
"""
super().on_rollover(old_symbol, new_symbol) # 调用基类方法打印日志
self._last_order_id = None # 清空上次订单ID因为旧合约订单已取消
self.log(f"换月完成清空历史K线数据和上次订单ID准备新合约交易。")
class SimpleLimitBuyStrategy(Strategy):
"""
一个基于当前K线Open、前1根和前7根K线Range计算优势价格进行限价买入的策略。
具备以下特点:
- 每根K线开始时取消上一根K线未成交的订单。
- 最多只能有一个开仓挂单和一个持仓。
- 包含简单的止损和止盈逻辑。
"""
def __init__(
self,
context: Any,
symbol: str,
enable_log: bool,
trade_volume: int,
range_factor_l: float,
profit_factor_l: float,
range_factor_s: float,
profit_factor_s: float,
max_position: int,
stop_loss_points: float = 10, # 新增:止损点数
take_profit_points: float = 10,
use_indicator: bool = False,
): # 新增:止盈点数
"""
初始化策略。
Args:
context: 模拟器实例。
symbol (str): 交易合约代码。
trade_volume (int): 单笔交易量。
range_factor (float): 前1根K线Range的权重因子用于从Open价向下偏移。
profit_factor (float): 前7根K线Range的权重因子用于从Open价向下偏移。
max_position (int): 最大持仓量此处为1因为只允许一个持仓
stop_loss_points (float): 止损点数(例如,亏损达到此点数则止损)。
take_profit_points (float): 止盈点数(例如,盈利达到此点数则止盈)。
"""
super().__init__(context, symbol, enable_log)
self.trade_volume = trade_volume
self.range_factor_l = range_factor_l
self.profit_factor_l = profit_factor_l
self.range_factor_s = range_factor_s
self.profit_factor_s = profit_factor_s
self.max_position = max_position # 理论上这里应为1
self.stop_loss_points = stop_loss_points
self.take_profit_points = take_profit_points
self.use_indicator = use_indicator
self.order_id_counter = 0
self._last_order_id: Optional[str] = None # 用于跟踪上一根K线发出的订单ID
self.log(
f"策略初始化: symbol={self.symbol}, trade_volume={self.trade_volume}, "
f"range_factor_l={self.range_factor_l}, "
f"profit_factor_l={self.profit_factor_l}, "
f"range_factor_s={self.range_factor_s}, "
f"profit_factor_s={self.profit_factor_s}, "
f"max_position={self.max_position}, "
f"止损点={self.stop_loss_points}, 止盈点={self.take_profit_points}"
)
def on_open_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
"""
每当新的K线数据到来时调用。
Args:
bar (Bar): 当前的K线数据对象。
next_bar_open (Optional[float]): 下一根K线的开盘价此处策略未使用。
"""
current_datetime = bar.datetime # 获取当前K线时间
self.symbol = bar.symbol
# --- 1. 撤销上一根K线未成交的订单 ---
# 检查是否记录了上一笔订单ID并且该订单仍然在待处理列表中
if self._last_order_id:
pending_orders = self.get_pending_orders()
if self._last_order_id in pending_orders:
success = self.cancel_order(
self._last_order_id
) # 直接调用基类的取消方法
if success:
self.log(
f"[{current_datetime}] 策略: 成功撤销上一根K线未成交订单 {self._last_order_id}"
)
else:
self.log(
f"[{current_datetime}] 策略: 尝试撤销订单 {self._last_order_id} 失败(可能已成交或不存在)"
)
# 无论撤销成功与否,既然我们尝试了撤销,就清除记录
self._last_order_id = None
# else:
# self.log(f"[{current_datetime}] 策略: 无上一根K线未成交订单需要撤销。")
# 2. 更新K线历史
trade_volume = self.trade_volume
# 获取当前持仓和未决订单(在取消之后获取,确保是最新的状态)
current_positions = self.get_current_positions()
current_pos_volume = current_positions.get(self.symbol, 0)
pending_orders_after_cancel = (
self.get_pending_orders()
) # 再次获取,此时应已取消旧订单
range_1_ago = None
range_7_ago = None
bar_history = self.get_bar_history()
if len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
# 计算历史 K 线的 Range
range_1_ago = bar_1_ago.high - bar_1_ago.low
range_7_ago = bar_7_ago.high - bar_7_ago.low
# --- 3. 平仓逻辑 (止损/止盈) ---
# 只有当有持仓时才考虑平仓
if (
current_pos_volume < 0 and range_1_ago is not None
): # 假设只做多,所以持仓量 > 0
avg_entry_price = self.get_average_position_price(self.symbol)
if avg_entry_price is not None:
pnl_per_unit = (
avg_entry_price - bar.open
) # 当前浮动盈亏(以收盘价计算)
self.log(
f"[{current_datetime}] 止盈信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {self.take_profit_points:.2f}"
)
# 止盈条件
if pnl_per_unit >= range_1_ago * self.profit_factor_s:
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_SHORT",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# 止损条件
elif pnl_per_unit <= -self.stop_loss_points:
self.log(
f"[{current_datetime}] 止损信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {-self.stop_loss_points:.2f}"
)
# 发送市价卖出订单平仓,确保立即成交
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_SHORT",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
if (
current_pos_volume > 0 and range_1_ago is not None
): # 假设只做多,所以持仓量 > 0
avg_entry_price = self.get_average_position_price(self.symbol)
if avg_entry_price is not None:
pnl_per_unit = (
bar.open - avg_entry_price
) # 当前浮动盈亏(以收盘价计算)
self.log(
f"[{current_datetime}] 止盈信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {self.take_profit_points:.2f}"
)
# 止盈条件
if pnl_per_unit >= range_1_ago * self.profit_factor_l:
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_LONG",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# 止损条件
elif pnl_per_unit <= -self.stop_loss_points:
self.log(
f"[{current_datetime}] 止损信号 - PnL per unit: {pnl_per_unit:.2f}, 目标: {-self.stop_loss_points:.2f}"
)
# 发送市价卖出订单平仓,确保立即成交
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="CLOSE_LONG",
volume=trade_volume,
price_type="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime,
offset="CLOSE",
)
trade = self.send_order(order)
return # 平仓后本K线不再进行开仓判断
# --- 4. 开仓逻辑 (只考虑做多 BUY 方向) ---
# 只有在没有持仓 (current_pos_volume == 0) 且没有待处理订单 (not pending_orders_after_cancel)
# 且K线历史足够长时才考虑开仓
if (
current_pos_volume == 0
and range_1_ago is not None
):
indicator_value = HistoricalRange(21).get_latest_value(
None,
None,
np.array(self.get_price_history("high")),
np.array(self.get_price_history("low")),
None,
)
if (not self.use_indicator or 10 < indicator_value < 25):
# 根据策略逻辑计算目标买入价格
# 目标买入价 = 当前K线Open - (前1根Range * 因子1 + 前7根Range * 因子2)
self.log(bar.open, range_1_ago * self.range_factor_l)
target_buy_price = bar.open - (range_1_ago * self.range_factor_l)
# 确保目标买入价格有效,例如不能是负数
target_buy_price = max(0.01, target_buy_price)
self.log(
f"[{current_datetime}] 开多仓信号 - 当前Open={bar.open:.2f}, "
f"前1Range={range_1_ago:.2f}, "
f"计算目标买入价={target_buy_price:.2f}"
)
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="BUY",
volume=trade_volume,
price_type="LIMIT",
limit_price=target_buy_price,
submitted_time=bar.datetime,
)
new_order = self.send_order(order)
# 记录下这个订单的ID以便在下一根K线开始时进行撤销
if new_order:
self._last_order_id = new_order.id
self.log(
f"[{current_datetime}] 策略: 发送限价买入订单 {self._last_order_id} @ {target_buy_price:.2f}"
)
else:
self.log(f"[{current_datetime}] 策略: 发送订单失败。")
indicator_value = RSI(5).get_latest_value(np.array(self.get_price_history('close')), None, None, None, None)
if (not self.use_indicator or 20 < indicator_value < 60):
# 根据策略逻辑计算目标买入价格
# 目标买入价 = 当前K线Open - (前1根Range * 因子1 + 前7根Range * 因子2)
self.log(bar.open, range_1_ago * self.range_factor_s)
target_buy_price = bar.open + (range_1_ago * self.range_factor_s)
# 确保目标买入价格有效,例如不能是负数
target_buy_price = max(0.01, target_buy_price)
self.log(
f"[{current_datetime}] 开多仓信号 - 当前Open={bar.open:.2f}, "
f"前1Range={range_1_ago:.2f}, "
f"计算目标买入价={target_buy_price:.2f}"
)
order_id = f"{self.symbol}_BUY_{bar.datetime.strftime('%Y%m%d%H%M%S')}_{self.order_id_counter}"
self.order_id_counter += 1
# 创建一个限价多单
order = Order(
id=order_id,
symbol=self.symbol,
direction="SELL",
volume=trade_volume,
price_type="LIMIT",
limit_price=target_buy_price,
submitted_time=bar.datetime,
)
new_order = self.send_order(order)
# 记录下这个订单的ID以便在下一根K线开始时进行撤销
if new_order:
self._last_order_id = new_order.id
self.log(
f"[{current_datetime}] 策略: 发送限价买入订单 {self._last_order_id} @ {target_buy_price:.2f}"
)
else:
self.log(f"[{current_datetime}] 策略: 发送订单失败。")
# else:
# self.log(f"[{current_datetime}] 不满足开仓条件:持仓={current_pos_volume}, 待处理订单={len(pending_orders_after_cancel)}, K线历史长度={len(bar_history)}")
def on_close_bar(self, bar: Bar, next_bar_open: Optional[float] = None):
self.cancel_all_pending_orders()
def on_rollover(self, old_symbol: str, new_symbol: str):
"""
在合约换月时清空历史K线数据和上次订单ID避免使用旧合约数据进行计算。
"""
super().on_rollover(old_symbol, new_symbol) # 调用基类方法打印日志
self._last_order_id = None # 清空上次订单ID因为旧合约订单已取消
self.log(f"换月完成清空历史K线数据和上次订单ID准备新合约交易。")

View File

@@ -159,11 +159,11 @@ class SimpleLimitBuyStrategyLong(Strategy):
# 只有在没有持仓 (current_pos_volume == 0) 且没有待处理订单 (not pending_orders_after_cancel)
# 且K线历史足够长时才考虑开仓
bar_history = self.get_bar_history()
if current_pos_volume == 0 and len(bar_history) > 10:
if current_pos_volume == 0 and len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-2]
bar_7_ago = bar_history[-8]
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
# 计算历史 K 线的 Range
range_1_ago = bar_1_ago.high - bar_1_ago.low
@@ -387,11 +387,11 @@ class SimpleLimitBuyStrategyShort(Strategy):
# 只有在没有持仓 (current_pos_volume == 0) 且没有待处理订单 (not pending_orders_after_cancel)
# 且K线历史足够长时才考虑开仓
bar_history = self.get_bar_history()
if current_pos_volume == 0 and len(bar_history) > 10:
if current_pos_volume == 0 and len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-2]
bar_7_ago = bar_history[-8]
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
# 计算历史 K 线的 Range
range_1_ago = bar_1_ago.high - bar_1_ago.low
@@ -660,11 +660,11 @@ class SimpleLimitBuyStrategy(Strategy):
return # 平仓后本K线不再进行开仓判断
bar_history = self.get_bar_history()
if current_pos_volume == 0 and len(bar_history) > 10:
if current_pos_volume == 0 and len(bar_history) > 16:
# 获取前1根K线 (倒数第二根) 和前7根K线 (队列中最老的一根)
bar_1_ago = bar_history[-2]
bar_7_ago = bar_history[-8]
bar_1_ago = bar_history[-8]
bar_7_ago = bar_history[-15]
print(bar_1_ago, bar_7_ago)

View File

@@ -33,6 +33,7 @@ class Strategy(ABC):
self.symbol = symbol # 策略操作的合约Symbol
self.params = params
self.enable_log = enable_log
self.trading = False
def on_init(self):
"""
@@ -78,6 +79,9 @@ class Strategy(ABC):
发送订单的辅助方法。
会在 BaseStrategy 内部构建 Order 对象,并通过 context 转发给模拟器。
"""
if not self.trading:
return None
if self.context.is_rollover_bar:
self.log(f"当前是换月K线禁止开仓订单")
return None
@@ -103,16 +107,24 @@ class Strategy(ABC):
取消指定ID的订单。
通过 context 调用模拟器的 cancel_order 方法。
"""
if not self.trading:
return False
return self.context.cancel_order(order_id)
def cancel_all_pending_orders(self) -> int:
"""取消当前策略的未决订单仅限于当前策略关注的Symbol。"""
# 注意:在换月模式下,引擎会自动取消旧合约的挂单,这里是策略主动取消
if not self.trading:
return 0
pending_orders = self.get_pending_orders()
cancelled_count = 0
# orders_to_cancel = [
# order.id for order in pending_orders.values() if order.symbol == self.symbol
# ]
orders_to_cancel = [
order.id for order in pending_orders.values() if order.symbol == self.symbol
order.id for order in pending_orders.values()
]
for order_id in orders_to_cancel:
if self.cancel_order(order_id):
@@ -179,3 +191,7 @@ class Strategy(ABC):
def get_bar_history(self):
return self.context.get_bar_history()
def get_price_history(self, key: str):
return self.context.get_price_history(key)