量化学习平台
文章
市场宽度
背离图
登录
注册
韶华研究之十八 首板低开201系列
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问请到原文和作者交流讨论。 # 原文网址克隆自聚宽文章:https://www.joinquant.com/post/44907 # 标题:韶华研究之十八,201系列 # 作者:韶华不负 ##策略介绍 ##思路,采取N天M涨停,结合人气前排,和2N天涨幅限制,再观察低开高开的收益区分 ##2.10,信号收集分析后,采取201,5-2/3两种类型的优化过滤,按20日涨幅升序排序,取竞价低开的 ##竞价符合条件后买入,次日开盘如果收益大于1.05卖出,否则等尾盘非停即出 ##2.11 对比尾卖/五刻卖/分钟卖,尾卖最好,因为图的是再板的超额利益 ##2.12,信号收集分析后,采取201,低开低涨类型,半仓轮动 ##2.12,采用201低位首板低开上,次日尾盘不板卖的策略,并发布 ##23/3/18,加入放量倍量过滤,回测显示20天5倍量胜率相对高效果更好,发布 ##23/7/22,卖出加入量能控制,回测显示120D0.9V效果最好,发布 # 回测时间需要选择为 分钟 # 导入函数库 from jqdata import * from kuanke.wizard import * #不能和technical_analysis共存 from six import BytesIO from jqlib.technical_analysis import * from jqfactor import get_factor_values from sklearn.linear_model import LinearRegression import numpy as np import pandas as pd import time # 初始化函数,设定基准等等 def after_code_changed(context): # 输出内容到日志 log.info() log.info('初始函数开始运行且全局只运行一次') unschedule_all() # 过滤掉order系列API产生的比error级别低的log # log.set_level('order', 'error') set_params() #1 设置策略参数 set_variables() #2 设置中间变量 set_backtest() #3 设置回测条件 ### 股票相关设定 ### # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的) # 开盘前运行 run_daily(before_market_open, time='7:00') # 竞价时运行 run_daily(call_auction, time='09:26') # 开盘时运行 #run_daily(market_run, time='09:30') #run_daily(market_run, time='10:30') #run_daily(market_run, time='13:30') run_daily(market_run, time='14:55') # 收盘后运行 #run_daily(after_market_close, time='20:00') # 收盘后运行 #run_daily(after_market_analysis, time='21:00') #1 设置策略参数 def set_params(): #设置全局参数 g.index ='all' #all-zz-300-500-1000 g.auction_open_highlimit = 0.985 #竞价开盘上限 g.auction_open_lowlimit = 0.945 #竞价开盘下限 g.profit_line = 1.05 #盘中的止盈门槛 #买前量能过滤参数 g.volume_control = 2 #0-默认不控制,1-周期放量控制,2-周期倍量控制,3,倍量控制(相对昨日),4-放量(240-0.9)加倍量(20-5)的最佳回测叠加 g.volume_period = 20 #放量控制周期,240-120-90-60 g.volume_ratio = 5 #放量控制和周期最高量的比值,0.9/0.8 #持仓量能过滤参数 g.sell_mode = 0 #0-默认尾盘非板卖,11-T日天量(240),12-T日倍量(相对周期),13-T日倍量(相对D日) g.sell_vol_period = 120 #放量控制周期,240-120-90-60 g.sell_vol_ratio = 0.9 #放量控制和周期最高量的比值,0.9/0.8 #2 设置中间变量 def set_variables(): #暂时未用,测试用全池 g.stocknum = 0 #持仓数,0-代表全取 g.poolnum = 1*g.stocknum #参考池数 #3 设置回测条件 def set_backtest(): ## 设定g.index作为基准 if g.index == 'all': set_benchmark('000001.XSHG') else: set_benchmark(g.index) # 开启动态复权模式(真实价格) set_option('use_real_price', True) #set_option("avoid_future_data", True) #显示所有列 pd.set_option('display.max_columns', None) #显示所有行 pd.set_option('display.max_rows', None) log.set_level('order', 'error') # 设置报错等级 ## 开盘前运行函数 def before_market_open(context): # 输出运行时间 log.info('函数运行时间(before_market_open):'+str(context.current_dt.time())) #0,预置全局参数 today_date = context.current_dt.date() lastd_date = context.previous_date befor_date = get_trade_days(end_date=today_date, count=3)[0] all_data = get_current_data() g.poolist = [] g.sell_list =[] num1,num2,num3,num4,num5,num6=0,0,0,0,0,0 #用于过程追踪 #1,构建基准指数票池,三去+去新 start_time = time.time() if g.index =='all': stocklist = list(get_all_securities(['stock']).index) #取all elif g.index == 'zz': stocklist = get_index_stocks('000300.XSHG', date = None) + get_index_stocks('000905.XSHG', date = None) + get_index_stocks('000852.XSHG', date = None) else: stocklist = get_index_stocks(g.index, date = None) num1 = len(stocklist) stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].paused] stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].is_st] stocklist = [stockcode for stockcode in stocklist if'退' not in all_data[stockcode].name] stocklist = [stockcode for stockcode in stocklist if stockcode[0:3] != '688'] stocklist = [stockcode for stockcode in stocklist if (today_date-get_security_info(stockcode).start_date).days>365] num2 = len(stocklist) end_time = time.time() print('Step0,基准%s,原始%d只,四去后共%d只,构建耗时:%.1f 秒' % (g.index,num1,num2,end_time-start_time)) #N天M次涨停过滤,20-1,5-2,5-3,5-4,5-5 start_time = time.time() poollist = get_up_filter_jiang(context,stocklist,lastd_date,1,1,0) list_201 = get_up_filter_jiang(context,poollist,lastd_date,20,1,0) g.poollist = optimize_filter(context,list_201,'L') end_time = time.time() print('Step0,N天M次涨停过滤共%d只,板型过滤共%d只,构建耗时:%.1f 秒' % (len(list_201),len(g.poollist),end_time-start_time)) log.info(g.poollist) #增加天量/爆量过滤 if g.volume_control !=0: g.poollist = get_highvolume_filter(context,g.poollist,g.volume_control,g.volume_period,g.volume_ratio) log.info(g.poollist) #stock_analysis(context,list_201) #增加持仓股的量能卖出控制 if g.sell_mode !=0 and len(context.portfolio.positions) !=0: stocklist = list(context.portfolio.positions) g.sell_list = get_highvolume_filter(context,stocklist,g.sell_mode,g.sell_vol_period,g.sell_vol_ratio) log.info('今日早盘卖出:') log.info(g.sell_list) def call_auction(context): log.info('函数运行时间(Call_auction):'+str(context.current_dt.time())) current_data = get_current_data() today_date = context.current_dt.date() lastd_date = context.previous_date buy_list=[] df_auction = get_call_auction(g.poollist,start_date=today_date,end_date=today_date,fields=['time','current','volume','money']) if len(g.sell_list) ==0: log.info('今日早盘无卖信') else: for stockcode in context.portfolio.positions: if current_data[stockcode].paused == True: continue if (stockcode in g.sell_list):# and (stockcode not in g.buylist): sell_stock(context, stockcode,0) for i in range(len(df_auction)): stockcode = df_auction.code.values[i] price = df_auction.current.values[i] df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['close'],count=5) if price/df_price.close[-1] <g.auction_open_highlimit and price/df_price.close[-1] >g.auction_open_lowlimit: buy_list.append(stockcode) if len(buy_list) ==0: log.info('今日无买信') return else: log.info('今日买信共%d只:' % len(buy_list)) log.info(buy_list) total_value = context.portfolio.total_value buy_cash = 0.5*total_value/len(buy_list) for stockcode in buy_list: if stockcode in list(context.portfolio.positions.keys()): continue buy_stock(context,stockcode,buy_cash) return """ #按bar运行 def handle_data(context,data): #log.info('函数运行时间(market_open_bar):'+str(context.current_dt.time())) today_date = context.current_dt.date() lastd_date = context.previous_date current_data = get_current_data() #判断票池和仓位,全为空则轮空 if len(context.portfolio.positions) ==0: log.info('空仓,今天休息') return #判断仓位,若持仓则挂卖单 for stockcode in context.portfolio.positions: if current_data[stockcode].paused == True: continue if context.portfolio.positions[stockcode].closeable_amount ==0: continue #止盈出 cost = context.portfolio.positions[stockcode].avg_cost price = current_data[stockcode].last_price if price/cost > g.profit_line: log.info('止盈即出%s' % stockcode) sell_stock(context,stockcode,0) #14:55执行平仓 hour = context.current_dt.hour minute = context.current_dt.minute if hour == 14 and minute == 55: for stockcode in context.portfolio.positions: if current_data[stockcode].paused == True: continue if context.portfolio.positions[stockcode].closeable_amount ==0: continue log.info('尾盘平出%s' % stockcode) sell_stock(context,stockcode,0) """ ## 收盘时运行函数 def market_run(context): log.info('函数运行时间(market_close):'+str(context.current_dt.time())) today_date = context.current_dt.date() lastd_date = context.previous_date current_data = get_current_data() #尾盘只卖 hour = context.current_dt.hour minute = context.current_dt.minute for stockcode in context.portfolio.positions: if current_data[stockcode].paused == True: continue if context.portfolio.positions[stockcode].closeable_amount ==0: continue """ #止盈出 cost = context.portfolio.positions[stockcode].avg_cost price = current_data[stockcode].last_price if price/cost > g.profit_line and hour !=14: log.info('止盈即出%s' % stockcode) sell_stock(context,stockcode,0) elif hour == 14: log.info('尾盘即出%s' % stockcode) sell_stock(context,stockcode,0) else: log.info('%s留到尾盘' % stockcode) """ #非停出 if current_data[stockcode].last_price != current_data[stockcode].high_limit: log.info('非涨停即出%s' % stockcode) sell_stock(context,stockcode,0) continue ## 收盘后运行函数 def after_market_close(context): log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time()))) today_date = context.current_dt.date() last_date = context.previous_date """ ---------------------------------函数定义-主要策略----------------------------------------------- """ #蒋的方法,N天M涨停过滤 def get_up_filter_jiang(context,stocklist,check_date,check_duration,up_num,direction): # 输出运行时间 log.info('函数运行时间(get_up_filter_jiang):'+str(context.current_dt.time())) #0,预置,今天是D日 all_data = get_current_data() poollist=[] # 交易日历 trd_days = get_trade_days(end_date=check_date, count=check_duration) # array[datetime.date] s_trd_days = pd.Series(range(len(trd_days)), index=trd_days) # Series[index:交易日期,value:第几个交易日] back_date = trd_days[0] #2,形态过滤,一月内两次以上涨停(盘中过10%也算) start_time = time.time() # 取数 df_price = get_price(stocklist,end_date=check_date,frequency='1d',fields=['pre_close','open','close','high','high_limit','low_limit','paused'] ,skip_paused=False,fq='pre',count=check_duration,panel=False,fill_paused=True) # 过滤出涨停的股票,按time索引 df_up = df_price[(df_price.close == df_price.high_limit) & (df_price.paused == 0)].set_index('time') # 标注出df_up中的time对应的是第几个交易日(ith) df_up['ith'] = s_trd_days code_set = set(df_up.code.values) if direction ==1: poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) > up_num))] elif direction ==-1: poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) < up_num))] else: poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) == up_num))] end_time = time.time() log.info('---%d天(%s--%s)%d次涨停过滤出%d只标的,构建耗时:%.1f 秒' % (check_duration,back_date,check_date,up_num,len(poollist),end_time-start_time)) #log.info(poollist) return poollist #对1-m板后的形态过滤,1和m是针对20-22年的过滤方案,l-是针对18-22年的一板过滤方案 #去除T日是一字/T字/尾盘封板弱 def optimize_filter(context,stocklist,filt_type): today_date = context.current_dt.date() lastd_date = context.previous_date all_data = get_current_data() poollist =[] #其他条件,在循环中过滤 for stockcode in stocklist: #过滤掉一字板,T字板; df_lastd = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['open','close','high','high_limit','low_limit'],count=1) if (df_lastd['open'][0] == df_lastd['high_limit'][0] and df_lastd['close'][0] == df_lastd['high_limit'][0]): continue #过滤掉尾盘封板弱的; df_last30 = get_bars(stockcode, count=60, unit='1m', fields=['open','close','high','low'],include_now=True,df=True) if (df_last30['low'][:].min() != df_lastd['high_limit'][0]) & (df_last30['high'][:].max() == df_lastd['high_limit'][0]): continue df_value = get_valuation(stockcode, end_date=lastd_date, count=1, fields=['circulating_market_cap']) #先新后老 cirm_cap = df_value['circulating_market_cap'].values[0] df_price = get_price(stockcode,end_date=lastd_date,frequency='1d',fields=['open','close','high','low','paused','volume'],skip_paused=False,fq='pre',count=20,panel=False,fill_paused=True) change_5 = df_price['close'][-1]/df_price['close'][-5] change_20 = df_price['close'][-1]/df_price['close'].values.min() vol_lvs20 = df_price['volume'][-1]/df_price['volume'].values.mean() if filt_type == 1: if all_data[stockcode].last_price >8 and change_20 <1.3 and vol_lvs20 <4: poollist.append(stockcode) elif filt_type =='M': if all_data[stockcode].last_price >15 and cirm_cap <50: poollist.append(stockcode) elif filt_type =='L': if change_5 <1.1: poollist.append(stockcode) return poollist ##过滤N天内M倍最高量,X-买入前量能过滤,1X-为持仓的量能过滤 def get_highvolume_filter(context,stocklist,control_mode,check_dura,volume_ratio): lastd_date = context.previous_date poollist =[] for stockcode in stocklist: if control_mode ==1: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] > volume_ratio*df_price['volume'].max(): continue poollist.append(stockcode) elif control_mode ==2: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] > volume_ratio*df_price['volume'].mean(): continue poollist.append(stockcode) elif control_mode ==3: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] > volume_ratio*df_price['volume'][-2]: continue poollist.append(stockcode) elif control_mode ==4: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=240) if df_price['volume'][-1] > 0.9*df_price['volume'].max(): continue if df_price['volume'][-1] > 5*df_price['volume'][-20:].mean(): continue poollist.append(stockcode) elif control_mode ==11: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] < volume_ratio*df_price['volume'].max(): continue poollist.append(stockcode) elif control_mode ==12: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] < volume_ratio*df_price['volume'].mean(): continue poollist.append(stockcode) elif control_mode ==13: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura) if df_price['volume'][-1] < volume_ratio*df_price['volume'][-2]: continue poollist.append(stockcode) elif control_mode ==14: df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=240) if df_price['volume'][-1] < 0.9*df_price['volume'].max(): continue if df_price['volume'][-1] < 5*df_price['volume'][-20:].mean(): continue poollist.append(stockcode) print('---量能控制%d-%d天放%.1f量过滤后共%d只' % (control_mode,check_dura,volume_ratio,len(poollist))) return poollist """ ---------------------------------函数定义-次要过滤----------------------------------------------- """ """ ---------------------------------函数定义-辅助函数----------------------------------------------- """ ##买入函数 def buy_stock(context,stockcode,cash): today_date = context.current_dt.date() current_data = get_current_data() if stockcode[0:3] == '688': last_price = current_data[stockcode].last_price if order_target_value(stockcode,cash,MarketOrderStyle(1.1*last_price)) != None: #科创板需要设定限值 log.info('%s买入%s' % (today_date,stockcode)) else: if order_target_value(stockcode, cash) != None: log.info('%s买入%s' % (today_date,stockcode)) ##卖出函数 def sell_stock(context,stockcode,cash): today_date = context.current_dt.date() current_data = get_current_data() if stockcode[0:3] == '688': last_price = current_data[stockcode].last_price if order_target_value(stockcode,cash,MarketOrderStyle(0.9*last_price)) != None: #科创板需要设定限值 log.info('%s卖出%s' % (today_date,stockcode)) else: if order_target_value(stockcode,cash) != None: log.info('%s卖出%s' % (today_date,stockcode)) ##个股盘中分析信后的未来走势,带未来 def stock_analysis(context,stocklist): today_date = context.current_dt.date() lastd_date = context.previous_date all_data = get_current_data() #pop = CYF(stocklist, check_date=lastd_date, N=20) for stockcode in stocklist: stockname = get_security_info(stockcode).display_name df_value = get_valuation(stockcode, end_date=lastd_date, count=1, fields=['circulating_market_cap']) #先新后老 cirm_cap = df_value['circulating_market_cap'].values[0] df_price = get_price(stockcode,end_date=lastd_date,frequency='1d',fields=['open','close','high','low','paused','volume'],skip_paused=False,fq='pre',count=20,panel=False,fill_paused=True) change_5 = df_price['close'][-1]/df_price['close'][-5] change_20 = df_price['close'][-1]/df_price['close'][0] change_5v20 = change_5/change_20 vol_lvs5 = df_price['volume'][-1]/df_price['volume'][-5:].mean() vol_5vs20 = df_price['volume'][-5:].mean()/df_price['volume'].values.mean() df_money = get_money_flow(stockcode, end_date=lastd_date, count=2, fields=['net_amount_main']) #先新后老 #存在昨日负流入或为零的状况 net_main_lbvsb = (df_money['net_amount_main'].values[0]-df_money['net_amount_main'].values[-1])/df_money['net_amount_main'].values[0] #看未来1-5日的涨跌幅 fut_date_list = get_trade_days(start_date = today_date,end_date = '2022-02-11') if len(fut_date_list) >=5: fut5_date = get_trade_days(start_date= today_date)[4] next_date = get_trade_days(start_date= today_date)[1] else: fut5_date = get_trade_days(start_date= today_date)[-1] next_date = get_trade_days(start_date= today_date)[1] future5_price = get_price(stockcode, start_date=today_date, end_date=fut5_date, frequency='daily', fields=['open','close','high','low']) next_price = get_price(stockcode, start_date=today_date, end_date=next_date, frequency='daily', fields=['pre_close','open','close','high','low','avg']) price_D = next_price['open'].values[0] #今天9:30买入 catch = price_D/next_price['pre_close'].values[0] d2_open = next_price['open'].values[-1]/price_D d2_avg = next_price['avg'].values[-1]/next_price['avg'].values[0] d2_close = next_price['close'].values[-1]/price_D d5_close = future5_price['close'].values[-1]/price_D write_file('201.csv', str('%s,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.3f,%.2f,%.2f,%.2f,%.2f\n' % (today_date,stockcode,stockname,cirm_cap,change_5 ,change_20,change_5v20,vol_lvs5,vol_5vs20,net_main_lbvsb,price_D,catch,d2_open,d2_close,d2_avg,d5_close)),append = True) ```
文章分类
关于作者
水滴
注册时间: