strategy_1.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. # 克隆自聚宽文章:https://www.joinquant.com/post/53374
  2. # 标题:机位有限,实盘策略送人
  3. # 作者:韶华不负
  4. # 导入函数库
  5. from jqdata import *
  6. from six import BytesIO
  7. from jqlib.technical_analysis import *
  8. from jqfactor import get_factor_values
  9. import numpy as np
  10. import pandas as pd
  11. import time
  12. # 初始化函数,设定基准等等
  13. def after_code_changed(context):
  14. # 输出内容到日志 log.info()
  15. log.info('初始函数开始运行且全局只运行一次')
  16. unschedule_all()
  17. # 过滤掉order系列API产生的比error级别低的log
  18. # log.set_level('order', 'error')
  19. set_params() #1 设置策略参数
  20. set_variables() #2 设置中间变量
  21. set_backtest() #3 设置回测条件
  22. disable_cache()
  23. ### 股票相关设定 ###
  24. # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
  25. set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
  26. ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
  27. # 开盘前运行
  28. run_daily(before_market_open, time='6:00')
  29. # 竞价时运行
  30. run_daily(call_auction, time='09:25:15')
  31. # 开盘时运行-测试不同的买入时间
  32. #run_daily(market_open, time='09:45')
  33. # 收盘时运行
  34. run_daily(market_run, time='14:55')
  35. # 收盘后运行
  36. #run_daily(after_market_close, time='20:00')
  37. # 收盘后运行
  38. #run_daily(after_market_analysis, time='21:00')
  39. #1 设置策略参数
  40. def set_params():
  41. #设置全局参数
  42. g.index ='all' #all-zz-300-500-1000,single-个股信号诊断
  43. g.code = '000679.XSHE'
  44. g.switch = 10 #1-低位首板低开,2-首阳倒挂,10-两者合并
  45. #池1-低板低开
  46. #买前量价过滤
  47. g.check_dura_1 =5 #默认是20,可以测试10-60
  48. g.pre_rise_1 = 1.1 #前期(20天)的涨幅上限,10等同不设限
  49. g.optimz_control = 1 #0-默认不控制,1-采用板型过滤
  50. g.volume_control_1 = 2 #0-默认不控制,1-周期放量控制,2-周期倍量控制,3,倍量控制(相对昨日),4-放量(240-0.9)加倍量(20-5)的最佳回测叠加
  51. g.volume_period_1 = 20 #放量控制周期,240-120-90-60
  52. g.volume_ratio_1 = 5 #放量控制和周期最高量的比值,0.9/0.8
  53. #竞价面
  54. g.auction_open_highlimit_1 = 0.98 #竞价开盘上限,999-不设限
  55. g.auction_open_lowlimit_1 = 0 #竞价开盘下限,0-不设限,1-相当于高开
  56. g.begin_times = ' 09:24:55'
  57. g.end_times = ' 09:25:10'
  58. #池2-低板倒挂
  59. g.check_dura_2 =20 #默认是20,可以测试10-60
  60. g.pre_rise_2 = 1.1 #前期(20天)的涨幅上限,10等同不设限
  61. g.strong_limit = 1.06 #D日的涨幅下限
  62. g.trap_limit = 1.06 #D1日的高开套下限
  63. g.filt_type = 'S' #进行二次择优,B-基本面,V-量价面,S-静态(流通盘)
  64. g.cirm_up = 45 #流通盘过滤上线,9999-不设限
  65. g.volume_control_2 = 2 #0-默认不控制,1-周期放量控制,2-周期倍量控制,3,倍量控制(相对昨日),4-放量(240-0.9)加倍量(20-5)的最佳回测叠加
  66. g.volume_period_2 = 20 #放量控制周期,240-120-90-60
  67. g.volume_ratio_2 = 5 #放量控制和周期最高量的比值,0.9/0.8
  68. #竞价面
  69. g.auction_open_highlimit_2 = 0.98 #竞价开盘上限,999-不设限;设定低开更有效
  70. g.auction_turn_highlimit_2 = 0 #竞价开盘下限,0-不设限,1-相当于高开
  71. #2 设置中间变量
  72. def set_variables():
  73. #暂时未用,测试用全池
  74. g.stocknum = 0 #持仓数,0-代表全取,2/4/8,因为地板倒和低板低各取1
  75. #3 设置回测条件
  76. def set_backtest():
  77. ## 设定g.index作为基准
  78. if g.index == 'all':
  79. set_benchmark('000001.XSHG')
  80. elif g.index == 'single':
  81. set_benchmark(g.code)
  82. else:
  83. set_benchmark(g.index)
  84. # 开启动态复权模式(真实价格)
  85. set_option('use_real_price', True)
  86. set_option("avoid_future_data", True)
  87. #显示所有列
  88. pd.set_option('display.max_columns', None)
  89. #显示所有行
  90. pd.set_option('display.max_rows', None)
  91. log.set_level('order', 'error') # 设置报错等级
  92. ## 开盘前运行函数
  93. def before_market_open(context):
  94. log.info('----------------------------------------------------------------')
  95. log.info('------------------------美好的一天开始了------------------------')
  96. log.info('----------------------------------------------------------------')
  97. # 输出运行时间
  98. log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
  99. #0,预置全局参数
  100. today_date = context.current_dt.date()
  101. lastd_date = context.previous_date
  102. befor_date = get_trade_days(end_date=today_date, count=3)[0]
  103. all_data = get_current_data()
  104. g.pool_1 = []
  105. g.pool_2 = []
  106. num1,num2,num3,num4,num5,num6=0,0,0,0,0,0 #用于过程追踪
  107. #0,构建基准指数票池,三去+去新
  108. start_time = time.time()
  109. if g.index =='all':
  110. stocklist = list(get_all_securities(['stock']).index) #取all
  111. elif g.index == 'zz':
  112. stocklist = get_index_stocks('000300.XSHG', date = None) + get_index_stocks('000905.XSHG', date = None) + get_index_stocks('000852.XSHG', date = None)
  113. elif g.index =='single':
  114. stocklist = [g.code] #个股信号诊断
  115. else:
  116. stocklist = get_index_stocks(g.index, date = None)
  117. num1 = len(stocklist)
  118. stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].paused]
  119. stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].is_st]
  120. stocklist = [stockcode for stockcode in stocklist if'退' not in all_data[stockcode].name]
  121. stocklist = [stockcode for stockcode in stocklist if stockcode[0:3] != '688']
  122. stocklist = [stockcode for stockcode in stocklist if (today_date-get_security_info(stockcode).start_date).days>20]
  123. #stocklist = [stockcode for stockcode in stocklist if stockcode[0:1] == '3'] #专为3字头
  124. num2 = len(stocklist)
  125. end_time = time.time()
  126. print('Step0,基准%s,原始%d只,四去后共%d只,构建耗时:%.1f 秒' % (g.index,num1,num2,end_time-start_time))
  127. if g.switch ==1 or g.switch ==10:
  128. #1.1,池1过滤
  129. start_time = time.time()
  130. list_201 = get_up_filter_jiang(context,stocklist,lastd_date,1,1,0)
  131. list_201 = get_up_filter_jiang(context,list_201,lastd_date,20,1,0)
  132. num3 = len(list_201)
  133. end_time = time.time()
  134. print('Step1.1,%d日首板共%d只,相对位置过滤共%d只,构建耗时:%.1f 秒' % (20,num3,len(list_201),end_time-start_time))
  135. log.info(list_201)
  136. #2.1,池1优化
  137. start_time = time.time()
  138. list_201 = get_rise_filter(context,list_201,lastd_date,g.check_dura_1,g.pre_rise_1,-1)
  139. if g.optimz_control !=0:
  140. g.pool_1 = get_up_optimize_filter(context,list_201)
  141. num4 = len(g.pool_1)
  142. else:
  143. g.pool_1 = list_201
  144. if g.volume_control_1 !=0:
  145. g.pool_1 = get_highvolume_filter(context,g.pool_1,g.volume_control_1,g.volume_period_1,g.volume_ratio_1)
  146. else:
  147. g.pool_1 = list_201
  148. end_time = time.time()
  149. print('Step2.1,涨幅限制%.2f共%d只,板型优化共%d只,量能控制共%d只,构建耗时:%.1f 秒' % (g.pre_rise_1,len(list_201),num4,len(g.pool_1),end_time-start_time))
  150. log.info('地板待选:%s' % g.pool_1)
  151. if g.switch ==2 or g.switch ==10:
  152. #1.2,低位票(ROC20<1.1),D日穿线大阳(7点以上)或涨停后,D1日高开套人(开0点上下落7点以上)+不能反包D日,
  153. start_time = time.time()
  154. list_66 = get_rise_filter(context,stocklist,lastd_date,g.check_dura_2,g.pre_rise_2,-1)
  155. num3 = len(list_66)
  156. list_66 = get_rainbow_strong_filter(context,list_66,befor_date,g.strong_limit)
  157. num4 = len(list_66)
  158. list_66 = get_trap_filter(context,list_66,lastd_date,g.trap_limit)
  159. end_time = time.time()
  160. print('Step1.21,周期涨幅低于%.2f共%d只,前日%.2f强势共%d只,昨日发套%.2f共%d只,构建耗时:%.1f 秒' % (g.pre_rise_2,num3,g.strong_limit,num4,g.trap_limit,len(list_66),end_time-start_time))
  161. log.info(list_66)
  162. if g.volume_control_2 !=0:
  163. list_66 = get_highvolume_filter(context,list_66,g.volume_control_2,g.volume_period_2,g.volume_ratio_2)
  164. end_time = time.time()
  165. print('Step1.22,量能控制共%d只,构建耗时:%.1f 秒' % (len(list_66),end_time-start_time))
  166. log.info(list_66)
  167. #2.2,从基本面,量价面进行择优
  168. start_time = time.time()
  169. if g.filt_type !=False:
  170. g.pool_2 = get_trap_optimize_filter(context,list_66,lastd_date,g.filt_type)
  171. end_time = time.time()
  172. print('Step2.2,%s择优共%d只,构建耗时:%.1f 秒' % (g.filt_type,len(g.pool_2),end_time-start_time))
  173. log.info('半岛待选:%s' % g.pool_2)
  174. def call_auction(context):
  175. log.info('函数运行时间(Call_auction):'+str(context.current_dt.time()))
  176. open_list=[]
  177. current_data = get_current_data()
  178. today_date = context.current_dt.date()
  179. lastd_date = context.previous_date
  180. g.buy_list=[]
  181. if len(g.pool_2) !=0:
  182. df_trap= pd.DataFrame(columns=['code','price','open','turn'])
  183. df_auction = get_call_auction(g.pool_2,start_date=today_date,end_date=today_date,fields=['time','current','volume','money'])
  184. for i in range(len(df_auction)):
  185. stockcode = df_auction.code.values[i]
  186. price = df_auction.current.values[i]
  187. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['close','high'],count=5)
  188. open = price/df_price.close[-1]
  189. turn = price/df_price.high[-1]
  190. df_trap = df_trap.append({'code': stockcode,'price': price,'open': open,'turn': turn}, ignore_index=True)
  191. df_trap = df_trap[(df_trap.open < g.auction_open_highlimit_2)] #竞开过滤
  192. df_trap.sort_values(by='turn', ascending=True, inplace=True)
  193. turn_list = list(df_trap.code)[:round(0.5*len(g.pool_2))] #发版
  194. g.buy_list = turn_list
  195. if len(g.pool_1) !=0:
  196. df_auction = get_call_auction(g.pool_1,start_date=today_date,end_date=today_date,fields=['time','current','volume','money'])
  197. for i in range(len(df_auction)):
  198. stockcode = df_auction.code.values[i]
  199. price = df_auction.current.values[i]
  200. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['close'],count=5)
  201. if (price/df_price.close[-1] <g.auction_open_highlimit_1) and (price/df_price.close[-1] >g.auction_open_lowlimit_1):
  202. g.buy_list.append(stockcode)
  203. if len(g.buy_list) ==0:
  204. #if len(g.buy_list) <=1: #测试
  205. log.info('今日无买信')
  206. return
  207. else:
  208. log.info('*****今日买信共%d只*****:' % len(g.buy_list))
  209. log.info(g.buy_list)
  210. #因信号收集屏蔽,回测打开
  211. total_value = context.portfolio.total_value
  212. buy_cash = round(0.5*total_value/len(g.buy_list))
  213. for stockcode in g.buy_list:
  214. if stockcode in list(context.portfolio.positions.keys()):
  215. continue
  216. buy_stock(context,stockcode,buy_cash)
  217. return
  218. ## 开盘时运行函数
  219. def market_open(context):
  220. log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
  221. today_date = context.current_dt.date()
  222. lastd_date = context.previous_date
  223. current_data = get_current_data()
  224. if len(g.buy_list) ==0:
  225. log.info('今日无买信')
  226. return
  227. else:
  228. log.info('*****今日买信共%d只*****:' % len(g.buy_list))
  229. log.info(g.buy_list)
  230. total_value = context.portfolio.total_value
  231. buy_cash = 0.5*total_value/len(g.buy_list)
  232. for stockcode in g.buy_list:
  233. if stockcode in list(context.portfolio.positions.keys()):
  234. continue
  235. buy_stock(context,stockcode,buy_cash)
  236. ## 收盘时运行函数
  237. def market_run(context):
  238. log.info('函数运行时间(market_close):'+str(context.current_dt.time()))
  239. today_date = context.current_dt.date()
  240. lastd_date = context.previous_date
  241. current_data = get_current_data()
  242. #尾盘只卖
  243. hour = context.current_dt.hour
  244. minute = context.current_dt.minute
  245. for stockcode in context.portfolio.positions:
  246. if current_data[stockcode].paused == True:
  247. continue
  248. if context.portfolio.positions[stockcode].closeable_amount ==0:
  249. continue
  250. #非停出
  251. if current_data[stockcode].last_price != current_data[stockcode].high_limit:
  252. log.info('非涨停即出%s' % stockcode)
  253. sell_stock(context,stockcode,0)
  254. continue
  255. ## 收盘后运行函数
  256. def after_market_close(context):
  257. log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
  258. g.trade_days = g.trade_days +1
  259. log.info(g.trade_days)
  260. log.info(g.open_num,g.open_nums_days)
  261. log.info(g.turn_num,g.turn_nums_days)
  262. """
  263. ---------------------------------函数定义-主要策略-----------------------------------------------
  264. """
  265. #周期涨跌幅(1/-1)过滤
  266. def get_rise_filter(context, stocklist, check_date, check_duration,rise_level,direction):
  267. # 输出运行时间
  268. log.info('-函数运行时间(get_rise_filter):'+str(context.current_dt.time()))
  269. poollist =[]
  270. if len(stocklist)==0:
  271. log.info("输入为空")
  272. return poollist
  273. by_date = get_trade_days(end_date=check_date, count=check_duration)[0]
  274. h = get_price(security=stocklist, end_date=check_date, frequency='1d', fields=['close','paused'], count=check_duration, panel=False)
  275. if direction == -1:
  276. temp = h.groupby('code')['close'].apply(lambda x: x.values[-1]/x.values[-check_duration] <rise_level)
  277. elif direction == 1:
  278. temp = h.groupby('code')['close'].apply(lambda x: x.values[-1]/x.values[-check_duration] >rise_level)
  279. poollist = temp[temp].index.tolist()
  280. return poollist
  281. #蒋的方法,N天M涨停过滤
  282. def get_up_filter_jiang(context,stocklist,check_date,check_duration,up_num,direction):
  283. # 输出运行时间
  284. log.info('-函数运行时间(get_up_filter_jiang):'+str(context.current_dt.time()))
  285. #0,预置,今天是D日
  286. all_data = get_current_data()
  287. poollist=[]
  288. if len(stocklist)==0:
  289. log.info("输入为空")
  290. return poollist
  291. # 交易日历
  292. trd_days = get_trade_days(end_date=check_date, count=check_duration) # array[datetime.date]
  293. s_trd_days = pd.Series(range(len(trd_days)), index=trd_days) # Series[index:交易日期,value:第几个交易日]
  294. back_date = trd_days[0]
  295. #2,形态过滤,一月内两次以上涨停(盘中过10%也算)
  296. start_time = time.time()
  297. # 取数
  298. df_price = get_price(stocklist,end_date=check_date,frequency='1d',fields=['pre_close','open','close','high','high_limit','low_limit','paused']
  299. ,skip_paused=False,fq='pre',count=check_duration,panel=False,fill_paused=True)
  300. # 过滤出涨停的股票,按time索引
  301. df_up = df_price[(df_price.close == df_price.high_limit) & (df_price.paused == 0)].set_index('time')
  302. # 标注出df_up中的time对应的是第几个交易日(ith)
  303. df_up['ith'] = s_trd_days
  304. code_set = set(df_up.code.values)
  305. if direction ==1:
  306. poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) > up_num))]
  307. elif direction ==-1:
  308. poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) < up_num))]
  309. else:
  310. poollist =[stockcode for stockcode in code_set if ((len(df_up[df_up.code ==stockcode]) == up_num))]
  311. end_time = time.time()
  312. #log.info('---%d天(%s--%s)%d次涨停过滤出%d只标的,构建耗时:%.1f 秒' % (check_duration,back_date,check_date,up_num,len(poollist),end_time-start_time))
  313. #log.info(poollist)
  314. return poollist
  315. #根据定义的选股条件选股
  316. def get_rainbow_strong_filter(context,stocklist,check_date,strong_limit):
  317. log.info('-函数运行时间(get_rainbow_strong_filter):'+str(context.current_dt.time()))
  318. all_data = get_current_data()
  319. poollist=[]
  320. if len(stocklist)==0:
  321. log.info("输入为空")
  322. return poollist
  323. # 取数
  324. df_price = get_price(stocklist,end_date=check_date,frequency='1d',fields=['pre_close','open','close','low','high','high_limit','low_limit','paused']
  325. ,skip_paused=False,fq='pre',count=1,panel=False,fill_paused=True)
  326. df_up = df_price[(df_price.close > df_price.open) & (df_price.close == df_price.high_limit) & (df_price.paused == 0)]
  327. up_list = df_up.code.values.tolist()
  328. print('---涨停板过滤后共%d只' % len(up_list))
  329. #排除一字板
  330. df_strong = df_price[(df_price.close != df_price.high_limit) & (df_price.close > strong_limit*df_price.pre_close) & (df_price.paused == 0)]
  331. strong_list = df_strong.code.values.tolist()
  332. print('---大阳过滤后共%d只' % len(strong_list))
  333. MA5 = MA(strong_list, check_date=check_date, timeperiod=5)
  334. MA10 = MA(strong_list, check_date=check_date, timeperiod=10)
  335. MA20 = MA(strong_list, check_date=check_date, timeperiod=20)
  336. strong_list = [stockcode for stockcode in strong_list if ((df_price[df_price.code == stockcode].low.values < MA5[stockcode] and df_price[df_price.code == stockcode
  337. ].close.values > MA5[stockcode]) or (df_price[df_price.code == stockcode].low.values < MA10[stockcode] and df_price[df_price.code == stockcode].close.values > MA10[
  338. stockcode]) or (df_price[df_price.code == stockcode].low.values < MA20[stockcode] and df_price[df_price.code == stockcode].close.values > MA20[stockcode]))]
  339. print('---均线过滤后共%d只' % len(strong_list))
  340. poollist = list(set(up_list+strong_list))
  341. print('---合并后共%d只' % len(poollist))
  342. return poollist
  343. #根据定义的选股条件选股
  344. #D1日高开套人(开0点上下落7点以上)+不能反包D日
  345. def get_trap_filter(context,stocklist,check_date,trap_limit):
  346. log.info('-函数运行时间(get_trap_filter):'+str(context.current_dt.time()))
  347. all_data = get_current_data()
  348. poollist=[]
  349. if len(stocklist)==0:
  350. log.info("输入为空")
  351. return poollist
  352. # 取数
  353. df_price = get_price(stocklist,end_date=check_date,frequency='1d',fields=['pre_close','open','close','low','high','high_limit','low_limit','paused']
  354. ,skip_paused=False,fq='pre',count=1,panel=False,fill_paused=True)
  355. df_trap = df_price[(df_price.open > df_price.pre_close) & (df_price.open > df_price.close) & (df_price.high/df_price.close >trap_limit) & (df_price.close/df_price.pre_close >0.93)]
  356. poollist = df_trap.code.values.tolist()
  357. return poollist
  358. #针对输入进行基本面/量价面的过滤择优
  359. def get_trap_optimize_filter(context,stocklist,check_date,filt_type):
  360. log.info('-函数运行时间(get_trap_optimize_filter):'+str(context.current_dt.time()))
  361. all_data = get_current_data()
  362. poollist=[]
  363. if len(stocklist)==0:
  364. log.info("输入为空")
  365. return stocklist
  366. #静态,流通盘<40
  367. if filt_type =="S":
  368. df_value = get_valuation(stocklist, end_date=check_date, count=1, fields=['circulating_market_cap']) #先新后老
  369. df_value = df_value.dropna()
  370. #df_value.sort_values(by='circulating_market_cap', ascending=True, inplace=True)
  371. #cirm_list = list(df_value.code)[:int(0.6*len(stocklist))]
  372. poollist = list(df_value[df_value.circulating_market_cap < g.cirm_up].code) #绝对
  373. elif filt_type == 'A':
  374. df_value = get_valuation(stocklist, end_date=check_date, count=1, fields=['circulating_market_cap']) #先新后老
  375. df_value = df_value.dropna()
  376. poollist = list(df_value[df_value.circulating_market_cap < g.cirm_up].code) #绝对
  377. df_money = get_money_flow(poollist, end_date=check_date, count=1, fields=['sec_code','date','net_pct_main'])
  378. poollist = list(df_money[df_money.net_pct_main <-1].sec_code)
  379. return poollist
  380. #去除T日是一字/T字/尾盘封板弱
  381. def get_up_optimize_filter(context,stocklist):
  382. log.info('-函数运行时间(get_up_optimize_filter):'+str(context.current_dt.time()))
  383. today_date = context.current_dt.date()
  384. lastd_date = context.previous_date
  385. all_data = get_current_data()
  386. poollist =[]
  387. if len(stocklist)==0:
  388. log.info("输入为空")
  389. return poollist
  390. #其他条件,在循环中过滤
  391. for stockcode in stocklist:
  392. #过滤掉一字板,T字板;
  393. df_lastd = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['open','close','high','high_limit','low_limit'],count=1)
  394. if (df_lastd['open'][0] == df_lastd['high_limit'][0] and df_lastd['close'][0] == df_lastd['high_limit'][0]):
  395. continue
  396. #过滤掉尾盘封板弱的;
  397. df_last30 = get_bars(stockcode, count=60, unit='1m', fields=['open','close','high','low'],include_now=True,df=True)
  398. if (df_last30['low'][:].min() != df_lastd['high_limit'][0]) & (df_last30['high'][:].max() == df_lastd['high_limit'][0]):
  399. continue
  400. """
  401. df_value = get_valuation(stockcode, end_date=lastd_date, count=1, fields=['circulating_market_cap','pe_ratio','pb_ratio']) #先新后老
  402. if len(df_value) ==0 or df_value['pe_ratio'].values[0] <0: #存在数据缺失
  403. continue
  404. """
  405. poollist.append(stockcode)
  406. return poollist
  407. ##过滤N天内M倍最高量,X-买入前量能过滤,1X-为持仓的量能过滤
  408. def get_highvolume_filter(context,stocklist,control_mode,check_dura,volume_ratio):
  409. log.info('-函数运行时间(get_highvolume_filter):'+str(context.current_dt.time()))
  410. lastd_date = context.previous_date
  411. poollist =[]
  412. if len(stocklist)==0:
  413. log.info("输入为空")
  414. return poollist
  415. for stockcode in stocklist:
  416. if control_mode ==1:
  417. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura)
  418. if df_price['volume'][-1] > volume_ratio*df_price['volume'].max():
  419. continue
  420. poollist.append(stockcode)
  421. elif control_mode ==2:
  422. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura)
  423. if df_price['volume'][-1] > volume_ratio*df_price['volume'].mean():
  424. continue
  425. poollist.append(stockcode)
  426. elif control_mode ==3:
  427. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=check_dura)
  428. if df_price['volume'][-1] > volume_ratio*df_price['volume'][-2]:
  429. continue
  430. poollist.append(stockcode)
  431. elif control_mode ==4:
  432. df_price = get_price(stockcode,end_date=lastd_date,frequency='daily',fields=['volume'],count=240)
  433. if df_price['volume'][-1] > 0.9*df_price['volume'].max():
  434. continue
  435. if df_price['volume'][-1] > 5*df_price['volume'][-20:].mean():
  436. continue
  437. poollist.append(stockcode)
  438. print('---量能控制%d-%d天放%.1f量过滤后共%d只' % (control_mode,check_dura,volume_ratio,len(poollist)))
  439. return poollist
  440. #按比例过滤
  441. def get_factor_filter_list(context,stock_list,jqfactor,sort,p1,p2):
  442. yesterday = context.previous_date
  443. score_list = get_factor_values(stock_list, jqfactor, end_date=yesterday, count=1)[jqfactor].iloc[0].tolist()
  444. df = pd.DataFrame(columns=['code','score'])
  445. df['code'] = stock_list
  446. df['score'] = score_list
  447. df = df.dropna()
  448. df.sort_values(by='score', ascending=sort, inplace=True)
  449. filter_list = list(df.code)[int(p1*len(stock_list)):int(p2*len(stock_list))]
  450. return filter_list
  451. """
  452. ---------------------------------函数定义-辅助函数-----------------------------------------------
  453. """
  454. ##买入函数
  455. def buy_stock(context,stockcode,cash):
  456. today_date = context.current_dt.date()
  457. current_data = get_current_data()
  458. if stockcode[0:2] == '68':
  459. last_price = current_data[stockcode].last_price
  460. if order_target_value(stockcode,cash,MarketOrderStyle(1.1*last_price)) != None: #科创板需要设定限值
  461. log.info('%s买入%s' % (today_date,stockcode))
  462. else:
  463. if order_target_value(stockcode, cash) != None:
  464. log.info('%s买入%s' % (today_date,stockcode))
  465. ##卖出函数
  466. def sell_stock(context,stockcode,cash):
  467. today_date = context.current_dt.date()
  468. current_data = get_current_data()
  469. if stockcode[0:2] == '68':
  470. last_price = current_data[stockcode].last_price
  471. if order_target_value(stockcode,cash,MarketOrderStyle(0.9*last_price)) != None: #科创板需要设定限值
  472. log.info('%s卖出%s' % (today_date,stockcode))
  473. else:
  474. if order_target_value(stockcode,cash) != None:
  475. log.info('%s卖出%s' % (today_date,stockcode))