嗯,用户让我写一个vn.py框架的策略,选股逻辑和买卖条件都挺详细的。首先,我需要理解每个条件的具体含义,然后考虑如何在vn.py中实现。
首先,选股逻辑有两个部分。第一部分是筛选昨日首次涨停,排除前两日有涨停的股票,追求首板后次日连板。这里要注意的是,首次涨停意味着昨天是第一个涨停,而前两天没有涨停过。可能需要计算过去三天的涨停情况,确定昨天涨停,而前两日没有。
第二部分是昨日盘中触及涨停但未封板的股票,次日通过集合竞价强度验证。这时候需要判断股票昨天最高价达到了涨停价,但收盘价没有封住涨停。可能需要计算涨停价,然后比较最高价和收盘价。
买入条件方面,成交额、均价涨幅、流通市值、集合竞价放量这些都需要处理。成交额在5到202亿之间,均价涨幅超过7%,流通市值70到520亿。集合竞价的成交量要大于前日的3%。另外,前四日涨幅小于18%,昨日均价跌幅小于4%,集合竞价高开在0.98到1.07倍前收盘价。这些条件都需要在策略中逐一实现。
卖出规则有两个情况:如果未封板且有浮盈,就在11:25前卖出;另一个是在14:50前,跌破MA5则止损,否则止盈。需要处理时间判断和指标计算,比如MA5的计算,以及是否封板的判断。
接下来考虑vn.py的结构。vn.py的策略通常继承自CtaTemplate,包含on_init初始化,on_start启动,on_stop停止,on_tick处理tick数据,on_bar处理K线。但选股策略可能需要用到选股函数,或者使用定时任务每天执行选股逻辑。
可能需要使用到历史数据,比如获取前三天的涨停情况。这里可能需要访问历史K线数据,比如使用历史管理器或者直接通过数据库查询。但vn.py中可能需要通过load_bar来加载历史数据,但选股可能需要多只股票的数据,这里可能需要处理多标的的数据,这可能比较复杂,因为vn.py主要是为单标的设计的CTA策略,多标的可能需要结合其他模块,比如PortfolioStrategy。
不过用户可能希望的是一个单一的策略,可能需要在策略中维护一个股票池,然后每天处理这些股票的数据。或者可能需要使用到选股模块,比如定时每天收盘后筛选符合条件的股票,然后在次日进行交易。
另外,处理涨停的判断需要注意不同的股票有不同的涨停幅度,比如普通股票是10%,ST是5%,创业板、科创板可能不同。这里可能需要获取股票的前收盘价,然后计算涨停价。或者可能需要使用到股票的涨跌停价格,如果数据源中有的话。
对于时间处理,比如在集合竞价阶段检查条件,或者在特定时间执行卖出操作。需要处理时间判断,比如在9:25检查集合竞价数据,或者在11:25前执行卖出。
关于数据频率,可能需要日线数据来判断涨停情况,以及分钟或tick数据来处理实时交易信号。但vn.py的策略通常基于K线数据,所以可能需要日线、分钟线结合。
实现时可能需要:
在策略初始化时加载历史日线数据,或者每天收盘后分析前几天的数据,筛选符合条件的股票。
在交易日开始时,对筛选出的股票进行监控,检查集合竞价的条件。
在满足买入条件时,发送订单。
在交易时间内监控卖出条件,如价格是否封板、浮盈情况,以及时间条件。
可能的难点包括:
多股票处理:vn.py的CtaTemplate通常是针对单一合约的,处理多股票可能需要多个实例或者使用组合策略模块。
历史数据获取:需要访问多只股票的历史日线数据来判断涨停情况,可能需要预先加载或查询数据库。
实时数据监控:需要同时监控多个股票的实时数据,如集合竞价的成交量和价格。
涨停价的计算:需要准确计算每个股票的涨停价,考虑ST、新股等因素。
时间判断:策略需要在特定时间执行操作,比如11:25前卖出,这需要准确处理时间戳。
可能的解决方案:
使用vn.py的PortfolioStrategy模块,或者创建多个策略实例,每个实例处理一个股票。
在策略中使用定时任务,比如每天收盘后运行选股函数,筛选出符合条件的股票列表,然后在次日进行监控。
使用历史管理器加载多日的数据,计算涨停情况。
对于实时数据,在on_bar或on_tick中处理,但需要区分不同股票的数据。
另外,用户的条件中有一些指标需要详细处理,比如均价涨幅>7%,这里的均价可能是指当日的成交均价,或者开盘价?需要明确。同样,集合竞价的放量是相比前日的成交量,需要计算前日成交量,然后比较集合竞价的成交量是否超过3%。
可能还需要处理集合竞价的数据,比如在9:25获取集合竞价的成交量和价格,作为买入条件的判断依据。
对于卖出规则,浮盈情况下在11:25前卖出,需要判断当前持仓是否有盈利,并且当前时间是否早于11:25。另一个是14:50前根据MA5判断止损或止盈。需要计算MA5的值,并检查当前价格是否跌破。
在代码结构上,可能需要:
在策略的on_init中加载足够的历史数据来计算指标,比如MA5。
在on_start中,每天初始化选股列表。
在on_bar中处理每个新K线的生成,比如日线结束时筛选股票,或者在分钟线中检查卖出条件。
可能需要使用到定时器,比如每天9:35执行选股,或者在特定时间检查卖出条件。
总之,这个策略需要综合处理多股票、历史数据筛选、实时条件判断以及时间驱动的交易动作。在vn.py中实现可能需要结合多个模块,并且可能需要一定的扩展,因为原生的CtaTemplate可能不太适合多标的情况。不过用户可能希望的是一个示例代码框架,所以可以给出一个基于CtaTemplate的结构,并在其中处理多股票的逻辑,或者指出需要结合组合策略模块。
以下是一个基于vn.py框架的策略示例,实现了您描述的选股逻辑和交易规则。请注意这需要根据您的数据接口和交易环境进行调整:
from vnpy.app.cta_strategy import (
CtaTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
EngineType
)
from vnpy.trader.constant import Status, Interval
import pandas as pd
import numpy as np
class BreakStrategy(CtaTemplate):
author = "AI Trader"
parameters = [
"capital",
"position_ratio",
"volume_ratio_threshold",
"ma_window"
]
variables = [
"target_list",
"current_positions"
]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg_daily = BarGenerator(self.on_bar, interval=Interval.DAILY)
self.am_daily = ArrayManager(40) # 保留40天数据
self.target_list = [] # 候选股票池
self.current_positions = {} # 当前持仓
# 参数设置
self.capital = 1000000
self.position_ratio = 0.2
self.volume_ratio_threshold = 0.03
self.ma_window = 5
def on_init(self):
self.load_bar(40) # 加载40天数据
def on_start(self):
self.put_event()
def on_stop(self):
self.put_event()
def filter_stocks(self):
"""每日选股逻辑"""
# 获取历史数据
history = self.am_daily.snapshot
# 条件1:昨日首次涨停
cond1 = (
(history['close'].iloc[-1] == history['high_limit'].iloc[-1]) & # 昨日涨停
(history['close'].iloc[-2] < history['high_limit'].iloc[-2]) & # 前日未涨停
(history['close'].iloc[-3] < history['high_limit'].iloc[-3]) # 大前日未涨停
)
# 条件2:昨日触板未封
cond2 = (
(history['high'].iloc[-1] == history['high_limit'].iloc[-1]) & # 最高价达到涨停
(history['close'].iloc[-1] < history['high_limit'].iloc[-1]) # 未封住涨停
)
# 综合筛选
selected = history[cond1 | cond2]
# 其他过滤条件
filtered = selected[
(selected['turnover'].between(5e8, 2.02e9)) & # 成交额
(selected['float_mv'].between(7e9, 5.2e10)) & # 流通市值
(selected['pre_4d_pct'] < 0.18) & # 前四日涨幅
(selected['last_close']*0.96 < selected['avg_price']) # 昨日均价跌幅
]
self.target_list = filtered.index.tolist()
def on_tick(self, tick: TickData):
# 处理集合竞价数据
if tick.datetime.time().hour == 9 and tick.datetime.time().minute == 25:
self.check_auction(tick)
# 执行卖出逻辑
self.execute_sell(tick)
def check_auction(self, tick):
"""集合竞价验证"""
for symbol in self.target_list:
# 获取前日收盘价
pre_close = self.am_daily.close[-2]
# 高开验证
open_ratio = tick.open_price / pre_close
if not (0.98 <= open_ratio <= 1.07):
continue
# 放量验证
auction_volume = tick.volume
pre_volume = self.am_daily.volume[-2]
if auction_volume < pre_volume * 1.03:
continue
# 执行买入
target_price = tick.open_price * 1.01 # 略高挂单
self.buy(symbol, target_price, self.capital*self.position_ratio)
def execute_sell(self, tick):
"""执行卖出规则"""
if tick.datetime.time() < time(11,25):
if self.check_floating_profit() and not self.is_limit_up(tick):
self.sell(tick)
elif tick.datetime.time() < time(14,50):
ma5 = self.am.close[-5:].mean()
if tick.last_price < ma5:
self.sell(tick, stop=True)
else:
self.sell(tick, profit=True)
def is_limit_up(self, tick):
"""判断是否涨停"""
return abs(tick.last_price - tick.limit_up) < 1e-5
def check_floating_profit(self):
"""检查浮动盈亏"""
return self.pos > 0 and (self.last_price/self.avg_cost - 1) > 0
def on_bar(self, bar: BarData):
self.bg_daily.update_bar(bar)
self.am_daily.update_bar(bar)
# 每日收盘后执行选股
if bar.datetime.time() == time(15,0):
self.filter_stocks()
self.put_event()
def notify_order(self, order: OrderData):
"""处理订单回报"""
if order.status == Status.ALLTRADED:
if order.direction == Direction.LONG:
self.current_positions[order.vt_symbol] = {
'entry_price': order.price,
'position': order.volume
}
self.put_event()
# 策略参数配置示例
strategy_setting = {
"capital": 1000000,
"position_ratio": 0.2,
"volume_ratio_threshold": 0.03,
"ma_window": 5
}
需要特别注意的几个关键点:
- 数据要求:
- 需要获取股票的每日涨停价数据(high_limit)
- 需要流通市值(float_mv)、成交额(turnover)等字段
需要前4日涨幅(pre_4d_pct)等衍生指标
功能扩展建议:
# 在ArrayManager中增加以下指标计算 class EnhancedArrayManager(ArrayManager): def __init__(self, size=100): super().__init__(size) def update_bar(self, bar: BarData): super().update_bar(bar) # 计算4日涨幅 if self.size >= 5: self.pre_4d_pct = (self.close[-1]/self.close[-5] - 1) * 100 # 计算均价指标 self.avg_price = self.turnover[-1]/self.volume[-1] if self.volume[-1] > 0 else 0
实际使用前需要:
- 验证各交易所的涨跌停计算规则
- 完善异常处理机制
- 增加风险控制模块
- 根据实际数据接口调整字段名称
- 优化订单执行逻辑(当前为简化示例)
建议先用历史数据进行充分回测,再逐步实盘验证。需要注意不同市场(A股/港股/美股)的涨跌停规则差异,本策略主要针对A股市场设计。