Files
NewQuant/src/strategies/simple_limit_buy_strategy.py

126 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# src/strategies/simple_limit_buy_strategy.py (修改部分)
from typing import Dict, Any, Optional
import pandas as pd
# 导入 Strategy 抽象基类
from .base_strategy import Strategy
# 导入核心数据类
from ..core_data import Bar, Order, Trade
class TestStrategy(Strategy):
"""
一个简单的限价买入策略:
在每根Bar线上如果当前没有持仓且没有待处理的买入订单则尝试下一个限价多单。
如果在当前Bar之前有未成交的买入订单则撤销该订单。
确保在任意时间点,最多只有一笔限价买入订单在市场中。
"""
def __init__(self, context: Any, **parameters: Any): # context 类型提示可以为 BacktestContext
super().__init__(context, **parameters)
self.trade_volume = 1
self.order_id_counter = 0
self.limit_price_factor = parameters.get('limit_price_factor', 0.999) # 限价因子
self.max_position = parameters.get('max_position', self.trade_volume) # 最大持仓量
self._last_order_id: Optional[str] = None # 跟踪上一根Bar发出的订单ID
self._current_long_position: int = 0 # 策略内部维护的当前持仓
def on_init(self):
super().on_init()
# 确保初始状态正确
self._last_order_id = None
self._current_long_position = 0 # 或者从模拟器获取初始持仓
def on_trade(self, trade: Trade):
"""
当模拟器成功执行一笔交易时调用。
更新策略内部持仓状态。
"""
super().on_trade(trade) # 调用父类方法
# 简单起见这里假设只交易self.symbol
if trade.symbol == self.symbol:
if trade.direction == "BUY":
self._current_long_position += trade.volume
elif trade.direction == "SELL": # 可能是平多或开空
self._current_long_position -= trade.volume # 卖出量为正值,所以是减
# 如果成交的是我们之前提交的订单清空_last_order_id
if self._last_order_id == trade.order_id:
self._last_order_id = None
# 打印当前持仓
# print(f"[{trade.fill_time}] 策略内部持仓更新: {self.symbol} -> {self._current_long_position}")
def on_bar(self, bar: Bar):
"""
每接收到一根Bar时执行策略逻辑。
"""
current_portfolio_value = self.context.get_account_cash()
# print(f"[{bar.datetime}] Strategy processing Bar. Current close price: {bar.close:.2f}. Current Portfolio Value: {current_portfolio_value:.2f}")
# 1. 撤销上一根K线未成交的订单
if self._last_order_id:
# 检查这个订单是否仍然在待处理订单列表中
pending_orders = self.get_pending_orders() # 直接访问模拟器或者通过context提供接口
if self._last_order_id in pending_orders:
success = self.cancel_order(self._last_order_id)
# 这里发送的“撤单订单”会被simulator的send_order处理并调用simulator.cancel_order
if success: # simulator.send_order返回Trade或None这里我们用一个特殊处理
# Simulator的send_order返回的是Trade如果实现撤单最好Simulator的cancel_order返回bool
print(f"[{bar.datetime}] 策略: 成功撤销上一根K线未成交订单 {self._last_order_id}")
else:
print(f"[{bar.datetime}] 策略: 尝试撤销订单 {self._last_order_id} 失败(可能已成交或不存在)")
# 无论撤销成功与否,既然我们尝试了撤销,就清除记录
self._last_order_id = None
else:
# 订单不在待处理列表中,说明它可能已经成交了 (在on_trade中已处理)
# 或者在上一根K线已经被取消/过期
self._last_order_id = None # 清理状态
# print(f"[{bar.datetime}] 订单 {self._last_order_id} 不在待处理列表,无需撤销。")
# 2. 判断是否需要下单
# 如果当前没有多头持仓,并且没有待处理的买入订单
# (注: _last_order_id被清除后_last_order_id为None表示当前没有待处理的我们发出的买单)
current_positions = self.context.get_current_positions()
self._current_long_position = current_positions.get(self.symbol, 0) # 从模拟器获取最新持仓
if self._current_long_position == 0 and self._last_order_id is None: # 确保只有一笔买单
# 计算限价价格
limit_price = bar.open * self.limit_price_factor
trade_volume = self.trade_volume
# 生成唯一的订单ID
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="MARKET",
# limit_price=limit_price,
submitted_time=bar.datetime
)
# 通过上下文发送订单
# trade = self.send_order(order)
# if trade:
# print(
# f"[{bar.datetime}] 策略: 发送并立即成交限价买单 {trade.volume} 股 (open:{bar.open}, close:{bar.close}) (订单ID: {order.id})")
# # 如果立即成交_last_order_id 仍然保持 None
# else:
# # 如果未立即成交将订单ID记录下来以便下一根Bar撤销
# self._last_order_id = order.id
# print(
# f"[{bar.datetime}] 策略: 发送限价买单 {trade_volume} 股 @ {limit_price:.2f} (未成交订单ID: {order.id} 已挂单)")
order = self.send_order(order)
if order:
print(f"[{bar.datetime}]发送订单 {order.id}, direction {order.direction}")
else:
# print(f"[{bar.datetime}] 策略: 当前已有持仓或有未成交订单,不重复下单。")
pass