这一篇做的是多因子选股篇,结合具体策略来说,说的不好还请大家多多指正。
前言
选股思路来自于前些日子看的一本书《超级成长股》,全篇就讲了两个因子:市销率跟市研率(市值跟研发费用)。
作为翻版小市值收益曲线还是可以的。
选用的是市销率+净利润增长率+营业收入增长率三个因子,先选出市销率最低的30只股票,然后用净利润增长率+营业收入进行等权打分,选出分最高的前十只股票,在优矿平台上实现。
策略部分
选用的语言是Python,这里导入的是3个包,numpy、pandas是python自带的,CAL是优矿自己集成的库
- import numpy as npimport pandas as pdfrom CAL.PyCAL import *
每一个策略都要有确定回测的区间、相对的基准、股票池、初始资金、策略执行的频率以及佣金
- start = '2014-01-01'end = '2016-01-01' benchmark = 'HS300' # 基准为HS300指数 universe = DynamicUniverse('HS300') # HS300动态股票池capital_base = 100000000refresh_rate = 5 commission = Commission(buycost=0.0003, sellcost=0.0003, unit='perValue') # 设置手续费
导入上交所日历、定义三个因子
- # 日期处理cal = Calendar('China.SSE') # 导入上海证券交易所交易日历,Cal是优矿自己集成的包# 定义因子名称,市销率、净利润增长率、营业收入增长率factor_name = ['PS','NetProfitGrowRate','OperatingRevenueGrowRate']
- def initialize(account): # 初始化虚拟账户状态 pass
策略逻辑部分:
def handle_data(account): # 每个交易日的买入卖出指令
设定股票池
- today = account.current_date # 当前交易日 yesterday = cal.advanceDate(today, '-1B') # 前一个交易日,B: 工作日,M:月,W:周,Y:年 yesterday_str = yesterday.strftime('%Y%m%d') # 日期类型转化为字符串 valid_uni = DataAPI.IdxConsGet(ticker=u"399300",intoDate=yesterday_str,field=['consID'],pandas="1")['consID'].tolist() # 前一交易日HS300(399300)成分股列表 valid_uni = [s for s in account.universe if s in valid_uni]
- Factor_PS = DataAPI.MktStockFactorsOneDayGet(tradeDate=yesterday_str,secID=valid_uni,field=['secID','PS'],pandas="1") Factor_PS.set_index('secID',inplace=True)
- sec_list = Factor_PS.sort('PS')[0:30].index.tolist()
- Factor = DataAPI.MktStockFactorsOneDayGet(tradeDate=yesterday_str,secID=sec_list,field=['secID','NetProfitGrowRate','OperatingRevenueGrowRate'],pandas="1") Factor.set_index('secID',inplace=True)
- #净利润增长率NetProfitGrowRate Factor_NetProfitGrowRate = Factor['NetProfitGrowRate'].dropna().to_dict() #dropna()跟to_dict() 是python pandas中的两个函数,在这里的意思是把值为空的剔除掉 signal_NetProfitGrowRate = standardize(winsorize(Factor_NetProfitGrowRate)) # 因子处理:去极值、标准化,去掉极大极小值,让因子之间可加减
# 营业收入增长率OperatingRevenueGrowRate,处理方法同上
- Factor_OperatingRevenueGrowRate = Factor['OperatingRevenueGrowRate'].dropna().to_dict() signal_OperatingRevenueGrowRate = standardize(winsorize(Factor_OperatingRevenueGrowRate))
- # 按净利润增长率和营业收入增长率等权打分 Total_Score = pd.DataFrame(index=Factor.index, columns=['NetProfitGrowRate','OperatingRevenueGrowRate'], data=0) Total_Score['NetProfitGrowRate'][signal_NetProfitGrowRate.keys()] = signal_NetProfitGrowRate.values() Total_Score['OperatingRevenueGrowRate'][signal_OperatingRevenueGrowRate.keys()] = signal_OperatingRevenueGrowRate.values() Total_Score['total_score'] = np.dot(Total_Score, np.array([0.5, 0.5])) # 综合两个因子的大小,等权求和评分
买入列表
buylist = Total_Score.sort('total_score').tail(10).index.tolist() # 选出评分最高的10只股票
- buylist = {s: 0 for s in buylist}
for s in account.valid_secpos.keys():
- if s not in buylist: order_to(s, 0) each_buymoney= account.reference_portfolio_value / len(buylist) #将投资组合的价值平分为len(buylist)份,等份买 for s in buylist: if s in account.security_position: #如果待买入股票已经持有,则不进行买入,否者就需要计算买入的头寸并下单 continue amount= each_buymoney / account.reference_price[s] # account.reference_price 意思是获取可买入证券前一日收盘价 order(s, amount)