量化研究--高频日内网格T0策略研究
量化研究--高频日内网格T0策略研究
文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途
我写了800多行完成了这个框架,后面就只需要把T0算法放入模块就可以很方便
这个框架是我专门研究的高频T0模块,支持自定义算法交易,支持自定义函数,详细的教程
量化研究--高频日内网格T0策略研究https://mp.weixin.qq.com/s/DfnisJCXXs7cuds-lJRadQ
先看一下这个模块的原理,在看怎么样设置实盘,策略的模块的配置参数
策略的算法
策略的原理
一、策略原理深度分析
这是一个基于价格百分比波动来触发交易的条件单式网格策略。它不同于传统的、在固定价位设置无数网格线的网格策略,它只在特定的条件(涨跌幅)被触发时,才会建议进行一次买卖操作。
其核心逻辑可以概括为:
-
确定一个基准价格(
base_price
):这是计算当前涨跌幅的锚点。策略会非常智能地根据历史交易记录来确定这个价格,这是该策略的关键所在。 -
计算当前相对于基准价的涨跌幅(
zdf
):zdf = (当前价 - 基准价) / 基准价 * 100
。 -
根据涨跌幅与阈值的比较,发出交易信号:
-
卖出信号(
return 'sell'
):当zdf >= x1
(例如 0.8%) 时。 -
买入信号(
return 'buy'
):当zdf <= x2
(例如 -1%) 时。 -
无信号(
return ''
):当zdf
介于x2
和x1
之间时。
-
基准价(base_price
)的确定逻辑(策略的灵魂):
这是该策略最精妙的部分,它决定了策略是“一次性”还是“可循环”的。代码中的 if self.log.shape[0]>0
分支详细处理了这一点:
-
首次运行(无任何历史日志记录):
-
检查是否有该股票的买入订单(
check_buy_order
)。这可能是系统里挂的限价单。 -
如果有,则以订单价格作为
base_price
。这意味着策略会追踪你这个挂单的成本。 -
如果没有,则使用股票的昨日收盘价(
lastClose
) 作为base_price
。
-
-
非首次运行(已有该策略的历史交易日志):
-
它会从日志(
log
)中筛选出同名策略对同一只股票的操作记录。 -
如果找到记录:则取最近一次操作的触发价格(
pre_price
) 作为新的基准价。这是策略能够循环运作的关键。例如,第一次基准价是10元,涨到10.08元(+0.8%)卖出后,下一次的基准价就变成了10.08元。如果价格又从10.08元跌到9.98元(约-1%),就会触发买入。 -
如果没找到记录(例如是另一只股票):则逻辑与“首次运行”相同,检查订单或使用昨日收盘价。
-
简单比喻:这个策略像一个会自动重置起跑线的运动员。每次到达终点(触发交易)后,它就把新的起点(基准价)设在上一次终点的地方,然后开始新一轮的奔跑(监测涨跌幅)。
二、策略特点
-
高频与分时:参数
x1
和x2
设置得很小(0.8% 和 -1%),旨在捕捉盘中分时图上的微小波动,符合“高频”和“分时”的特性。适合波动较大、交易活跃的标的。 -
条件单式(非连续网格):它不像传统网格那样布满买入卖出线,而是在一个动态移动的基准点上下设置一个“买入条件单”和一个“卖出条件单”。只有条件满足时才触发,每次只操作一次。
-
动态基准调整:其核心特点是基准价会根据上一次交易成果动态调整,这使得策略能适应价格的趋势性移动,避免在单边上涨或下跌市场中迅速失效。
-
依赖订单状态:策略与订单系统(
check_buy_order
)有耦合,说明它可能被设计为与一个实际的交易执行系统协同工作,不仅可以处理已成交的订单,还能处理挂单。 -
风险控制:
-
优点:由于基准价动态上移,在上涨趋势中,卖出价会不断抬高,能锁定利润。
-
缺点:在下跌趋势中,买入价也会不断下移,虽然每次买入的成本都比前一次低,但如果遇到长期阴跌,会导致持续买入而被套较深。参数设置中的 “保留底仓” 和 “持有值” 就是为了控制这个风险,限制买入的总金额。
-
-
虚拟单功能:参数中“是否生成买入/卖出虚拟单子”表明,该策略可能主要用于模拟或信号生成,真正的下单操作由其他资金管理模块处理。
三、策略参数设置解析
{
"函数名称": "conditional_single_time_sharing_grid(name='固定高频分时网格',x1=0.8,x2=-1)",
"是否开启": "是",
"资金模型": "金额",
"卖出值": 200,
"买入值": 200,
"持有值": 600,
"保留底仓": 0,
"是否生成买入虚拟单子": "是",
"是否生成卖出虚拟单子": "否"
}
-
x1=0.8, x2=-1:策略的核心参数,定义了网格的宽度。卖出阈值(0.8%)小于买入阈值(1%)的绝对值,这种不对称设置可能是为了在震荡中略微赚取差价(高卖低买),并给下跌留出更多空间。
-
资金模型:金额:意味着接下来的值都是固定金额,而不是股票数量。
-
卖出值:200:每次触发卖出信号时,卖出200元市值的股票。
-
买入值:200:每次触发买入信号时,买入200元市值的股票。
-
持有值:600:该策略对这只股票的目标最大持仓市值是600元。这是一个重要的风险控制参数。
-
保留底仓:0:当策略需要卖出时,允许全部卖出,不保留底仓。如果设置为100,那么即使触发卖出,也会至少保留100元市值的股票不动。
-
是否生成买入/卖出虚拟单子:这 likely 是一个模拟盘或信号测试功能。"生成买入虚拟单子"为“是”,意味着当发出
buy
信号时,系统会记录一个虚拟的买入订单,以便后续计算基准价。“卖出虚拟单子”为“否”,可能意味着卖出操作会直接调用真实交易接口或另一种日志方式。
策略的实盘设置,我没有开启的模块不要动,我在测试加入其他的控制算法,设置账户
设置记录文件路径,这个路径可以自己随便建立一个excel表输入路径就可以
建议和我的统一设置西蒙斯高频日内算法交易框架5.xlsx
设置股票池,建议先自定义运行,不要选择持股,持股会加载账户的全部持股分析
设置自定义股票,名字,股票代码一一对应
开启算法参数,其他的模块先不动,我明天给策略的运行图
设置网格参数x1,上涨卖出单元格,x2下跌买入单元格
设置交易金额,可以保留底仓
点击运行测试一下
没有问题挂模型交易就可以
点击运行就可以
日志输出
交易记录
策略日志不要随便情况文件里面保存的记录数据
下单的结果
策略的委托
自定义因子计算框架
class user_def_trader_func:def __init__(self,c,stock='512480.SH',tick='',hist='',other_data=''):'''自定义交易函数'''self.tick=tickself.hist=histself.other_data=other_dataself.log=pd.read_excel(r'{}'.format(c.path))self.trader_date=str(datetime.now())[:10]self.now_date=datetime.now()self.stock=stockif self.log.shape[0]>0:self.log=self.log[['证券代码','模块名称','交易日','触发时间','交易类型','交易数量','触发价格','投资备注','交易状态']]self.log=self.log.sort_values(by='触发时间',ascending=True)self.log=self.log[self.log['交易日']==self.trader_date]else:self.log=pd.DataFrame()self.c=cdef conditional_single_time_sharing_grid(self,name='固定高频分时网格',x1=0.8,x2=-1):tick=self.histstock=self.stockbase_price=tick['lastClose'].tolist()[-1]price=tick['lastPrice'].tolist()[-1]close_list=tick['lastPrice'].tolist()if self.log.shape[0]>0:self.log['证券代码']=self.log['证券代码'].astype(str)log=self.log[self.log['模块名称']==name]log=log[log['证券代码']==stock]if log.shape[0]>0:pre_price=log['触发价格'].tolist()[-1]zdf=((price-pre_price)/pre_price)*100else:order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricezdf=((price-base_price)/base_price)*100else:order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricezdf=((price-base_price)/base_price)*100if zdf>=x1:print('{} 模块{} 卖出{} 目前涨跌幅{} 大于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x1))return 'sell'elif zdf<=x2:print('{} 模块{} 买入{} 目前涨跌幅{} 小于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x2))return 'buy'else:print('{} 模块{} 不符合交易{} 目前涨跌幅{} 在{}到{}期间 '.format(self.now_date,name,stock,zdf,x2,x1))return ''def symmetric_grid_trading(self,name='对称高频分时网格',x1=0.8,x2=-1):'''对称高频分时网格'''tick=self.histstock=self.stockbase_price=tick['lastClose'].tolist()[-1]price=tick['lastPrice'].tolist()[-1]close_list=tick['lastPrice'].tolist()if self.log.shape[0]>0:self.log['证券代码']=self.log['证券代码'].astype(str)log=self.log[self.log['模块名称']==name]log=log[log['证券代码']==stock]if log.shape[0]>0:pre_price=log['触发价格'].tolist()[-1]zdf=((price-pre_price)/pre_price)*100shift_trader_type=log['交易类型'].tolist()[-1]else:order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricezdf=((price-base_price)/base_price)*100shift_trader_type=''else:order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricezdf=((price-base_price)/base_price)*100shift_trader_type=''if zdf>=x1 and shift_trader_type=='buy':print('{} 上一笔买入模块{} 卖出{} 目前涨跌幅{} 大于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x1))return 'sell'elif zdf<=x2 and shift_trader_type=='sell':print('{}上一笔卖出 模块{} 买入{} 目前涨跌幅{} 小于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x2))return 'buy'if zdf>=x1 :print('{}上一笔没有买入委托 模块{} 卖出{} 目前涨跌幅{} 大于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x1))return 'sell'elif zdf<=x2 :print('{} 上一笔没有卖出委托模块{} 买入{} 目前涨跌幅{} 小于目前标涨跌幅{} '.format(self.now_date,name,stock,zdf,x2))return 'buy'else:print('{} 模块{} 不符合交易{} 目前涨跌幅{} 在{}到{}期间 '.format(self.now_date,name,stock,zdf,x2,x1))return ''def sell_on_the_rally(self,name='冲高回落卖出',x1=3,x2=-1):'''冲高回落卖出x1 冲高启动计算最低涨跌幅x2 回落涨跌幅'''stock=self.stocktick=self.histbase_price=tick['lastClose'].tolist()[-1]stock=self.stockif self.log.shape[0]>0:self.log['证券代码']=self.log['证券代码'].astype(str)log=self.log[self.log['模块名称']==name]log=log[log['证券代码']==stock]if log.shape[0]>0:pre_price=log['触发价格'].tolist()[-1]#触发时间shift_date=log['触发时间'].tolist()[-1]shift_date=str(shift_date).split('.')[0].replace('-','').replace(' ','').replace(':','')shift_date=int(shift_date)tick=tick[tick['date_1']>=shift_date]close_list=tick['lastPrice'].tolist()price=close_list[-1]#最大值max_value=max(close_list)else:close_list=tick['lastPrice'].tolist()price=close_list[-1]order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricepre_price=base_price#最大值max_value=max(close_list)else:close_list=tick['lastPrice'].tolist()price=close_list[-1]order_stats,order_price=check_buy_order(self.c,stock=stock)if order_stats==True:base_price=order_priceelse:base_price=base_pricepre_price=base_price#最大值max_value=max(close_list)#最大涨跌幅max_zdf=((max_value-pre_price)/pre_price)*100#回落的涨跌幅last_zdf=((price-max_value)/max_value)*100if max_zdf>=x1 and last_zdf<=x2:print('{} {} 冲高{} 大于{} 回落{}大于{} 卖出'.format(stock,name,max_zdf,x1,last_zdf,x2))return 'sell'else:print('{} {} 冲高{} {} 回落{} {} 等待卖出'.format(stock,name,max_zdf,x1,last_zdf,x2))return ''