1 # 根据缺口的模式选股买股票
2 '''
3 --------------------------------------------
4 1、总体回测前要做的事情
5 initialize(context)
6 1.1、设置策略参数 ----> 全局常量
7 1.2、设置中间变量 ----> 全局变量
8 1.3、设置回测条件 ----> JoinQuant额外需要的
9 2、每天开盘前选股策略 (下面策略,发现这种股,不容错过)
10 2.1、设置手续费
11 2.2、设置可行股票池,比如过滤当日停牌股票
12 2.3、筛选上市满一年的全部A股
13 2.4、筛选上市发生向上缺口的时点
14 定义为:今日最低价>昨日最高价,删除涨停的个股
15 涨幅>5%
16 2.5、筛选前期盘整阶段,比如20-30个交易日,最高价-最低价/最低价<15%或者标准差较少的
17 2.6、缺口当日成交量 > 前20个交易日平均成交量的50%,也就是15倍以上。
18 3、每天交易时
19 3.1、买入/卖出信号判断
20 3.2、执行买入/卖出的操作
21 4、每天收盘
22 无
23
24 --------------------------------------------
25 关于什么时候卖?
26 策略有三,第一个就是设置止盈位。也就是不需要追求最高点卖出。
27 比如你设置一个从最近高点下滑3%(比例自调)的位置作为卖出点。
28 第二个就是利用技术分析,看重要的压力位,一方面是均线系统的压力,
29 要看的是日线,周线月线,周期越大,压力越强,其次是前期的高点,
30 密集成交区,这个区域是深度套牢区,因此可以暂时止盈。
31 还有就是识技术指标的图,比如看MACD顶背离,这个比较准,KDJ超卖等等。
32 建议多去分析大盘,80%的股票和大盘会保存一样走势,大盘触顶,个股一般也好不到哪去。
33 第三就是关注基本面,同行对比,分析当前的股价的PE,以及与同行业的公司来看,
34 比如营业总收入排第几,净利润排第几,收入增速排第几,它的总市值排在第几。
35 如果基本面排在行业第10,但是市值排在第一,这就表示高估了。可以择机止盈。
36
37 '''
38
39
40 #
41 import jqdata
42 import pandas as pd
43 import datetime as dt
44 import time
45
46 '''
47 ================================================================================
48 总体回测前
49 ================================================================================
50 '''
51 # 初始化函数,设定基准等等
52 def initialize(context):
53 print '初始化方法'
54 set_params() # 设置策略常量
55 set_variables() # 设置中间变量
56 set_backtest() # 设置回测条件
57 print '--------------------------------------'
58
59 #1
60 #设置策略参数
61 def set_params():
62 print '设置策略参数'
63 g.tc = 15 # 调仓天数
64 g.num_stocks = 10 # 每次调仓选取的最大股票数量
65
66 #2
67 #设置中间变量
68 def set_variables():
69 print '设置中间变量'
70 g.t = 0 # 记录回测运行的天数
71 g.if_trade = False # 当天是否交易
72
73 #3
74 #设置回测条件
75 def set_backtest():
76 print '设置回测条件'
77
78 # 设定沪深300作为基准,就是基准收益
79 set_benchmark('000300.XSHG')
80
81
82 # 开启动态复权模式(真实价格)
83 set_option('use_real_price', True)
84 # 输出内容到日志 log.info()
85 log.info('初始函数开始运行且全局只运行一次')
86 # 过滤掉order系列API产生的比error级别低的log
87 # log.set_level('order', 'error')
88
89 ### 股票相关设定 ###
90 # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
91 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
92
93 ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
94 # 开盘前运行
95 run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
96 # 开盘时运行
97 run_daily(market_open, time='every_bar', reference_security='000300.XSHG')
98 # 收盘后运行
99 run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
100
101 log.set_level('order','error') # 设置报错等级
102
103 '''
104 ================================================================================
105 每天开盘前
106 ================================================================================
107 2、每天开盘前选股策略 (下面策略,发现这种股,不容错过)
108 2.1、设置手续费
109 2.2、设置可行股票池,比如过滤当日停牌股票
110 2.3、筛选上市满一年的全部A股
111 2.4、筛选上市发生向上缺口的时点
112 定义为:今日最低价>昨日最高价,删除涨停的个股
113 涨幅>5%
114 2.5、筛选前期盘整阶段,比如20-30个交易日,最高价-最低价/最低价<15%或者标准差较少的
115 2.6、缺口当日成交量 > 前20个交易日平均成交量的50%,也就是15倍以上。
116 '''
117 ## 开盘前运行函数
118 def before_market_open(context):
119 # 输出运行时间
120 log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
121
122 print '----每天开盘前要做的事情----'
123
124 set_slip_fee(context) # 设置滑点与手续费
125 # g.stocks=get_index_stocks('000300.XSHG') # 设置沪深300为初始股票池
126 g.stocks=get_index_stocks('000002.XSHG') # 设置000002.XSHG全部上市A股
127 # 设置可行股票池
128 g.feasible_stocks = set_feasible_stocks(g.stocks,context)
129
130
131 # 给微信发送消息(添加模拟交易,并绑定微信生效)
132 # send_message('美好的一天~')
133
134 # 要操作的股票:平安银行(g.为全局变量)
135 # g.security = '000001.XSHE'
136
137 #
138 # 设置可行股票池:过滤掉当日停牌的股票
139 # 输入:initial_stocks为list类型,表示初始股票池; context(见API)
140 # 输出:unsuspened_stocks为list类型,表示当日未停牌的股票池,即:可行股票池
141 def set_feasible_stocks(initial_stocks,context):
142 # 判断初始股票池的股票是否停牌,返回list
143 # print '设置可行股票池:过滤掉当日停牌的股票',context.current_dt.day
144 # print '当前时期%10s' %(context.current_dt.strftime("%Y-%m-%d"))
145 paused_info = []# 存储对应股票是否停牌的信息数组
146 liste_Date_info = []# 存储对应的上市时间
147 # 在股票基本信息表 - STK_STOCKINFO能找到
148 stock_info = get_all_securities(['stock']);
149
150
151 # get_current_data ♠ - 获取当前时间数据
152 current_data = get_current_data()
153 print '打印--',initial_stocks
154 print '再打印--当前时间数据对象返回是空的',current_data
155
156 for i in initial_stocks:
157 # i是遍历出来的每个股票的代码
158 # 然后paused是判断这个股票是否停牌,False表示没有停牌
159 paused_info.append(current_data[i].paused)
160
161 # print '获取所有股票数据',stock_info[i].start_date
162 # 如何获取上市满一年的股票
163 # 先获取所有股票数据 .start_data
164 # print '当前时期:%10s--股票上市时期:%10s' %(context.current_dt.strftime("%Y-%m-%d"),stock_info.at[i,'start_date'])
165 # print '当前时期:%10s--股票上市时期' %((stock_info.at[i,'start_date']-context.current_dt).days)
166 # 存储上市时间是否满一年,如果满一年为YES
167 isGoPublicOneYear = calculate_goPublick_OneYear(context.current_dt.strftime("%Y-%m-%d"),str(stock_info.at[i,'start_date']))
168 liste_Date_info.append(isGoPublicOneYear)
169 if isGoPublicOneYear == False:
170 print '上市不满一年的股票%10s:%10s' %(i,stock_info.at[i,'display_name'])
171
172
173 df_paused_public_info = pd.DataFrame({'paused_info':paused_info,'liste_Date_info':liste_Date_info},index = initial_stocks)
174 # print 'df_paused_public_info:\n',df_paused_public_info
175 unsuspened_stocks = list(df_paused_public_info.index[(df_paused_public_info.paused_info == False) and (df_paused_public_info.liste_Date_info == True)])
176
177 # print '最后获得的index',unsuspened_stocks
178
179
180
181
182 return unsuspened_stocks
183
184 # 计算当天交易时间是否为上市时间满一年
185 def calculate_goPublick_OneYear(currentTime,goPublicTime):
186 currentTimeDate = time.strptime(currentTime,"%Y-%m-%d")
187 y,m,d = currentTimeDate[0:3]
188
189 goPublicTimeDate = time.strptime(goPublicTime,"%Y-%m-%d")
190 y2,m2,d2 = goPublicTimeDate[0:3]
191
192 # print (dt.datetime(y,m,d)-dt.datetime(y2,m2,d2)).days
193
194 if ((dt.datetime(y,m,d)-dt.datetime(y2,m2,d2)).days)>366:
195 return True
196 else:
197 return False
198
199
200 #5
201 # 根据不同的时间段设置滑点与手续费
202 # 输入:context(见API)
203 # 输出:none
204 def set_slip_fee(context):
205 print '根据不同的时间段设置滑点与手续费'
206 # 将滑点设置为0
207 set_slippage(FixedSlippage(0))
208 # 根据不同的时间段设置手续费
209 print '根据不同的时间段设置手续费'
210 dt=context.current_dt
211 if dt>datetime.datetime(2013,1, 1):
212 set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
213
214 elif dt>datetime.datetime(2011,1, 1):
215 set_commission(PerTrade(buy_cost=0.001, sell_cost=0.002, min_cost=5))
216
217 elif dt>datetime.datetime(2009,1, 1):
218 set_commission(PerTrade(buy_cost=0.002, sell_cost=0.003, min_cost=5))
219 else:
220 set_commission(PerTrade(buy_cost=0.003, sell_cost=0.004, min_cost=5))
221
222
223 '''
224 ================================================================================
225 每天交易时
226 ================================================================================
227 '''
228 ## 开盘时运行函数
229 def market_open(context):
230 log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
231 security = g.security
232 # 获取股票的收盘价
233 close_data = attribute_history(security, 5, '1d', ['close'])
234 # 取得过去五天的平均价格
235 MA5 = close_data['close'].mean()
236 # 取得上一时间点价格
237 current_price = close_data['close'][-1]
238 # 取得当前的现金
239 cash = context.portfolio.available_cash
240
241 # 如果上一时间点价格高出五天平均价1%, 则全仓买入
242 if current_price > 1.01*MA5:
243 # 记录这次买入
244 log.info("价格高于均价 1%%, 买入 %s" % (security))
245 # 用所有 cash 买入股票
246 # order_value(security, cash)
247 # 如果上一时间点价格低于五天平均价, 则空仓卖出
248 elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0:
249 # 记录这次卖出
250 log.info("价格低于均价, 卖出 %s" % (security))
251 # 卖出所有股票,使这只股票的最终持有量为0
252 # order_target(security, 0)
253
254 '''
255 ================================================================================
256 每天收盘后
257 ================================================================================
258 '''
259
260 ## 收盘后运行函数
261 def after_market_close(context):
262 log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
263 #得到当天所有成交记录
264 trades = get_trades()
265 for _trade in trades.values():
266 log.info('成交记录:'+str(_trade))
267 log.info('一天结束')
268 log.info('##############################################################')