4.5 CCI • CCI 顺势指标探索

来源:https://uqer.io/community/share/55f28179f9f06c1ea681fa40

一、CCI指标简介与构造

顺势指标CCI由唐纳德拉姆伯特所创,是通过测量股价的波动是否已超出其正常范围,来预测股价变化趋势的技术分析指标。计算方法参考《技术指标系列(五)——CCI的顺势而为 》

下面描绘出CCI与股价时序图走势

  1. def cci(stock,start_date,end_date,windows): #设置股票,起始时间,以及CCI指标多少日
  2. import pandas as pd
  3. import numpy as np
  4. from CAL.PyCAL import *
  5. Alpha = 0.015
  6. eq_TP = {}
  7. eq_MATP = {}
  8. eq_meanDev = {}
  9. eq_CCI = {}
  10. cal = Calendar('China.SSE')
  11. windows = '-'+str(windows)+'B'
  12. start_date = Date.strptime(start_date,"%Y%m%d")
  13. end_date = Date.strptime(end_date,"%Y%m%d")
  14. timeLength = cal.bizDatesList(start_date, end_date)
  15. for i in xrange(len(timeLength)):
  16. begin_date = cal.advanceDate(timeLength[i],windows,BizDayConvention.Unadjusted)
  17. begin_date =begin_date.strftime("%Y%m%d")
  18. timeLength[i] = timeLength[i].strftime("%Y%m%d")
  19. eq_static = DataAPI.MktEqudAdjGet(secID=stock,beginDate=begin_date,endDate=timeLength[i],field=['secID','highestPrice','lowestPrice','closePrice'],pandas="1")
  20. for stk in stock:
  21. try:
  22. eq_TP[stk] = np.array(eq_static[eq_static['secID'] == stk].mean(axis=1))
  23. eq_MATP[stk] = sum(eq_TP[stk])/len(eq_TP[stk])
  24. eq_meanDev[stk] = sum(abs(eq_TP[stk] - eq_MATP[stk]))/len(eq_TP[stk])
  25. eq_CCI[stk].append((eq_TP[stk][-1] - eq_MATP[stk])/(Alpha * eq_meanDev[stk]))
  26. except:
  27. eq_CCI[stk] = []
  28. Date = pd.DataFrame(timeLength)
  29. eq_CCI = pd.DataFrame(eq_CCI)
  30. cciSeries = pd.concat([Date,eq_CCI],axis =1)
  31. cciSeries.columns = ['Date','CCI']
  32. return cciSeries
  33. def cci_price_Plot(stock,start_date,end_date,windows):
  34. cciSeries = cci(stock,start_date,end_date,windows)
  35. closePrice = DataAPI.MktEqudAdjGet(secID=stock,beginDate=start_date,endDate=end_date,field=['closePrice'],pandas="1")
  36. table = pd.merge(cciSeries,closePrice, left_index=True, right_index=True, how = 'inner')
  37. return table
  1. import pandas as pd
  2. import numpy as np
  3. from CAL.PyCAL import *
  4. cal = Calendar('China.SSE')
  5. table = cci_price_Plot(['600000.XSHG'],'20080531','20150901',30) #绘制浦发银行的CCI与股价对比图
  6. tableDate = table.set_index('Date')
  7. tableDate.plot(figsize=(20,8),subplots = 1)
  8. array([<matplotlib.axes.AxesSubplot object at 0x60037d0>,
  9. <matplotlib.axes.AxesSubplot object at 0x602fa90>], dtype=object)

4.5 CCI • CCI 顺势指标探索 - 图1

二、CCI指标简单应用

选取CCI处于100和150之间,开始处于上涨趋势的股票。关于windows,我们用quick_backtest做一个简单的优化

  1. def cci(account,N=20):
  2. Alpha = 0.015
  3. eq_TP = {}
  4. eq_MATP = {}
  5. eq_meanDev = {}
  6. eq_CCI = {}
  7. eq_highPrice = account.get_attribute_history('highPrice',N)
  8. eq_closePrice = account.get_attribute_history('closePrice',N)
  9. eq_lowPrice = account.get_attribute_history('lowPrice',N)
  10. for stk in account.universe:
  11. eq_TP[stk] = (eq_highPrice[stk] + eq_closePrice[stk] + eq_lowPrice[stk])/3
  12. eq_MATP[stk] = sum(eq_TP[stk])/len(eq_TP[stk])
  13. eq_meanDev[stk] = sum(abs(eq_TP[stk] - eq_MATP[stk]))/len(eq_TP[stk])
  14. eq_CCI[stk] = (eq_TP[stk][-1] - eq_MATP[stk])/(Alpha * eq_meanDev[stk])
  15. return eq_CCI
  1. start = '2010-08-01' # 回测起始时间
  2. end = '2014-08-01' # 回测结束时间
  3. benchmark = 'HS300' # 策略参考标准
  4. universe = set_universe('HS300') # 证券池,支持股票和基金
  5. capital_base = 100000 # 起始资金
  6. freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
  7. refresh_rate = 20 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
  8. sim_params = quartz.sim_condition.env.SimulationParameters(start, end, benchmark, universe, capital_base)
  9. idxmap_all, data_all = quartz.sim_condition.data_generator.get_daily_data(sim_params)
  1. from CAL.PyCAL import *
  2. import pandas as pd
  3. import numpy as np
  4. def initialize(account): # 初始化虚拟账户状态
  5. pass
  6. def handle_data(account): # 每个交易日的买入卖出指令
  7. eq_CCI = cci(account,window)
  8. buylist = []
  9. for stk in account.universe:
  10. try:
  11. if eq_CCI[stk] > 100 and eq_CCI[stk] < 150:
  12. buylist.append(stk)
  13. except:
  14. pass
  15. for stk in account.valid_secpos:
  16. order_to(stk, 0)
  17. for stk in buylist[:]:
  18. if stk not in account.universe or account.referencePrice[stk] == 0 or np.isnan(account.referencePrice[stk]):
  19. bulist.remove(stk)
  20. for stk in buylist:
  21. order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))
  22. print 'window annualized_return sharpe max_drawdown'
  23. for window in range(10, 100, 5):
  24. strategy = quartz.sim_condition.strategy.TradingStrategy(initialize, handle_data)
  25. bt_test, acct = quartz.quick_backtest(sim_params, strategy, idxmap_all, data_all,refresh_rate = refresh_rate)
  26. perf = quartz.perf_parse(bt_test, acct)
  27. print ' {0:2d} {1:>7.4f} {2:>7.4f} {3:>7.4f}'.format(window, perf['annualized_return'], perf['sharpe'], perf['max_drawdown'])
  28. window annualized_return sharpe max_drawdown
  29. 10 0.0186 -0.0610 0.4161
  30. 15 -0.0367 -0.2818 0.5448
  31. 20 0.0753 0.1734 0.4531
  32. 25 0.0268 -0.0254 0.3098
  33. 30 -0.0440 -0.3198 0.5640
  34. 35 0.0481 0.0599 0.4794
  35. 40 0.1117 0.3270 0.4057
  36. 45 0.0619 0.1176 0.2353
  37. 50 -0.0425 -0.3442 0.4226
  38. 55 0.0227 -0.0577 0.3355
  39. 60 0.0513 0.0540 0.4461
  40. 65 0.0860 0.1969 0.2304
  41. 70 0.0434 0.0218 0.3005
  42. 75 0.0126 -0.1176 0.3672
  43. 80 0.0891 0.2084 0.3728
  44. 85 0.1002 0.2554 0.2971
  45. 90 0.0768 0.1687 0.2710
  46. 95 0.0243 -0.0588 0.3461
  1. from CAL.PyCAL import *
  2. import pandas as pd
  3. import numpy as np
  4. start = '2010-08-01' # 回测起始时间
  5. end = '2014-08-01' # 回测结束时间
  6. benchmark = 'HS300' # 策略参考标准
  7. universe = set_universe('HS300') # 证券池,支持股票和基金
  8. capital_base = 100000 # 起始资金
  9. freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
  10. refresh_rate = 20 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
  11. def initialize(account): # 初始化虚拟账户状态
  12. pass
  13. def handle_data(account): # 每个交易日的买入卖出指令
  14. eq_CCI = cci(account,85)
  15. buylist = []
  16. for stk in account.universe:
  17. try:
  18. if eq_CCI[stk] > 100 and eq_CCI[stk] < 150:
  19. buylist.append(stk)
  20. except:
  21. pass
  22. for stk in account.valid_secpos:
  23. order_to(stk, 0)
  24. for stk in buylist[:]:
  25. if stk not in account.universe or account.referencePrice[stk] == 0 or np.isnan(account.referencePrice[stk]):
  26. bulist.remove(stk)
  27. for stk in buylist:
  28. order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))

4.5 CCI • CCI 顺势指标探索 - 图2

样本外测试

  1. from CAL.PyCAL import *
  2. import pandas as pd
  3. import numpy as np
  4. start = '2014-08-01' # 回测起始时间
  5. end = '2015-08-01' # 回测结束时间
  6. benchmark = 'HS300' # 策略参考标准
  7. universe = set_universe('HS300') # 证券池,支持股票和基金
  8. capital_base = 100000 # 起始资金
  9. freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
  10. refresh_rate = 20 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
  11. def initialize(account): # 初始化虚拟账户状态
  12. pass
  13. def handle_data(account): # 每个交易日的买入卖出指令
  14. eq_CCI = cci(account,85)
  15. buylist = []
  16. for stk in account.universe:
  17. try:
  18. if eq_CCI[stk] > 100 and eq_CCI[stk] < 150:
  19. buylist.append(stk)
  20. except:
  21. pass
  22. for stk in account.valid_secpos:
  23. order_to(stk, 0)
  24. for stk in buylist[:]:
  25. if stk not in account.universe or account.referencePrice[stk] == 0 or np.isnan(account.referencePrice[stk]):
  26. bulist.remove(stk)
  27. for stk in buylist:
  28. order(stk, account.referencePortfolioValue/account.referencePrice[stk]/len(buylist))

4.5 CCI • CCI 顺势指标探索 - 图3