4.5 CCI • CCI 顺势指标探索
一、CCI指标简介与构造
顺势指标CCI由唐纳德拉姆伯特所创,是通过测量股价的波动是否已超出其正常范围,来预测股价变化趋势的技术分析指标。计算方法参考《技术指标系列(五)——CCI的顺势而为 》。
下面描绘出CCI与股价时序图走势
defcci(stock,start_date,end_date,windows):#设置股票,起始时间,以及CCI指标多少日import pandasas pdimport numpyas npfrom CAL.PyCALimport * Alpha =0.015 eq_TP = {} eq_MATP = {} eq_meanDev = {} eq_CCI = {} cal = Calendar('China.SSE') windows ='-'+str(windows)+'B' start_date = Date.strptime(start_date,"%Y%m%d") end_date = Date.strptime(end_date,"%Y%m%d") timeLength = cal.bizDatesList(start_date, end_date)for iin xrange(len(timeLength)): begin_date = cal.advanceDate(timeLength[i],windows,BizDayConvention.Unadjusted) begin_date =begin_date.strftime("%Y%m%d") timeLength[i] = timeLength[i].strftime("%Y%m%d") eq_static = DataAPI.MktEqudAdjGet(secID=stock,beginDate=begin_date,endDate=timeLength[i],field=['secID','highestPrice','lowestPrice','closePrice'],pandas="1")for stkin stock:try: eq_TP[stk] = np.array(eq_static[eq_static['secID'] == stk].mean(axis=1)) eq_MATP[stk] = sum(eq_TP[stk])/len(eq_TP[stk]) eq_meanDev[stk] = sum(abs(eq_TP[stk] - eq_MATP[stk]))/len(eq_TP[stk]) eq_CCI[stk].append((eq_TP[stk][-1] - eq_MATP[stk])/(Alpha * eq_meanDev[stk]))except: eq_CCI[stk] = [] Date = pd.DataFrame(timeLength) eq_CCI = pd.DataFrame(eq_CCI) cciSeries = pd.concat([Date,eq_CCI],axis =1) cciSeries.columns = ['Date','CCI']return cciSeriesdefcci_price_Plot(stock,start_date,end_date,windows): cciSeries = cci(stock,start_date,end_date,windows) closePrice = DataAPI.MktEqudAdjGet(secID=stock,beginDate=start_date,endDate=end_date,field=['closePrice'],pandas="1") table = pd.merge(cciSeries,closePrice, left_index=True, right_index=True, how ='inner')return tableimport pandasas pdimport numpyas npfrom CAL.PyCALimport *cal = Calendar('China.SSE')table = cci_price_Plot(['600000.XSHG'],'20080531','20150901',30)#绘制浦发银行的CCI与股价对比图tableDate = table.set_index('Date')tableDate.plot(figsize=(20,8),subplots =1)array([<matplotlib.axes.AxesSubplot object at0x60037d0>, <matplotlib.axes.AxesSubplot object at0x602fa90>], dtype=object)
二、CCI指标简单应用
选取CCI处于100和150之间,开始处于上涨趋势的股票。关于windows,我们用quick_backtest做一个简单的优化
defcci(account,N=20): Alpha =0.015 eq_TP = {} eq_MATP = {} eq_meanDev = {} eq_CCI = {} eq_highPrice = account.get_attribute_history('highPrice',N) eq_closePrice = account.get_attribute_history('closePrice',N) eq_lowPrice = account.get_attribute_history('lowPrice',N)for stkin account.universe: eq_TP[stk] = (eq_highPrice[stk] + eq_closePrice[stk] + eq_lowPrice[stk])/3 eq_MATP[stk] = sum(eq_TP[stk])/len(eq_TP[stk]) eq_meanDev[stk] = sum(abs(eq_TP[stk] - eq_MATP[stk]))/len(eq_TP[stk]) eq_CCI[stk] = (eq_TP[stk][-1] - eq_MATP[stk])/(Alpha * eq_meanDev[stk])return eq_CCIstart ='2010-08-01'# 回测起始时间end ='2014-08-01'# 回测结束时间benchmark ='HS300'# 策略参考标准universe = set_universe('HS300')# 证券池,支持股票和基金capital_base =100000# 起始资金freq ='d'# 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测refresh_rate =20# 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟sim_params = quartz.sim_condition.env.SimulationParameters(start, end, benchmark, universe, capital_base)idxmap_all, data_all = quartz.sim_condition.data_generator.get_daily_data(sim_params)from CAL.PyCALimport *import pandasas pdimport numpyas npdefinitialize(account):# 初始化虚拟账户状态passdefhandle_data(account):# 每个交易日的买入卖出指令 eq_CCI = cci(account,window) buylist = []for stkin account.universe:try:if eq_CCI[stk] >100and eq_CCI[stk] <150: buylist.append(stk)except:passfor stkin account.valid_secpos: order_to(stk,0)for stkin buylist[:]:if stknotin account.universeor account.referencePrice[stk] ==0or np.isnan(account.referencePrice[stk]): bulist.remove(stk)for stkin buylist: order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))print'window annualized_return sharpe max_drawdown'for windowin range(10,100,5): strategy = quartz.sim_condition.strategy.TradingStrategy(initialize, handle_data) bt_test, acct = quartz.quick_backtest(sim_params, strategy, idxmap_all, data_all,refresh_rate = refresh_rate) perf = quartz.perf_parse(bt_test, acct)print' {0:2d} {1:>7.4f} {2:>7.4f} {3:>7.4f}'.format(window, perf['annualized_return'], perf['sharpe'], perf['max_drawdown']) window annualized_return sharpe max_drawdown100.0186-0.06100.416115-0.0367-0.28180.5448200.07530.17340.4531250.0268-0.02540.309830-0.0440-0.31980.5640350.04810.05990.4794400.11170.32700.4057450.06190.11760.235350-0.0425-0.34420.4226550.0227-0.05770.3355600.05130.05400.4461650.08600.19690.2304700.04340.02180.3005750.0126-0.11760.3672800.08910.20840.3728850.10020.25540.2971900.07680.16870.2710950.0243-0.05880.3461from CAL.PyCALimport *import pandasas pdimport numpyas npstart ='2010-08-01'# 回测起始时间end ='2014-08-01'# 回测结束时间benchmark ='HS300'# 策略参考标准universe = set_universe('HS300')# 证券池,支持股票和基金capital_base =100000# 起始资金freq ='d'# 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测refresh_rate =20# 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟definitialize(account):# 初始化虚拟账户状态passdefhandle_data(account):# 每个交易日的买入卖出指令 eq_CCI = cci(account,85) buylist = []for stkin account.universe:try:if eq_CCI[stk] >100and eq_CCI[stk] <150: buylist.append(stk)except:passfor stkin account.valid_secpos: order_to(stk,0)for stkin buylist[:]:if stknotin account.universeor account.referencePrice[stk] ==0or np.isnan(account.referencePrice[stk]): bulist.remove(stk)for stkin buylist: order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))
样本外测试
from CAL.PyCALimport *import pandasas pdimport numpyas npstart ='2014-08-01'# 回测起始时间end ='2015-08-01'# 回测结束时间benchmark ='HS300'# 策略参考标准universe = set_universe('HS300')# 证券池,支持股票和基金capital_base =100000# 起始资金freq ='d'# 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测refresh_rate =20# 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟definitialize(account):# 初始化虚拟账户状态passdefhandle_data(account):# 每个交易日的买入卖出指令 eq_CCI = cci(account,85) buylist = []for stkin account.universe:try:if eq_CCI[stk] >100and eq_CCI[stk] <150: buylist.append(stk)except:passfor stkin account.valid_secpos: order_to(stk,0)for stkin buylist[:]:if stknotin account.universeor account.referencePrice[stk] ==0or np.isnan(account.referencePrice[stk]): bulist.remove(stk)for stkin buylist: order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))