请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化平台 帖子:3351382 新帖:1

对【量化课堂】CAPM+APT多因子模型的几点改进

特朗普对头发表于:5 月 10 日 05:11回复(1)


最近研究了一下这个利用财报基本面数据寻找alpha的策略,发现还是有比较高的信息率的,在没有任何对冲的情况下,也能在不同的时期有所表现,且整体强于基准,不过在查看代码实现的时候,发现了以下几个问题,对代码进行了相应的修改,算是bug fix吧,希望对大家有参考价值。

潜在问题如下:
1)基本面数据不同lag没变化的问题,用LD来动态往前找基本面数据。每次循环得到一个新的LD,因为他是本次pubdata的前一天,用这个日期去query会查到前一次的财务数据,以此往前推。

for i in stocks:    # 获得前一个交易日的日期(因为当前交易日你是不知道当前收盘价的)D=getDay(dateStr,-1)LD=D #LD用来拿上一次的财报alpha = []    # 一个循环,对每一个财务季度进行获取因子for j in range(0,lags):        # 查询财务因子的语句q = query(indicator,valuation).filter(indicator.code.in_([i]))        # f_temp=get_fundamentals(q,D)f_temp=get_fundamentals(q,LD) #这里原来的code有个问题,D在循环里没变化,所以改用LDrow_name=i '_lag' str(j)        #先判定是否上市,如果上市,才将其装入if len(f_temp)>0:            #如果能取到数据,说明已经上市f_temp=f_temp[cols2]f_temp.index=[row_name]table_factors.ix[[row_name],cols2]=f_temp            #得到本期财报的披露日期向前推一个日期:LD=getDay(table_factors['pubDate'][row_name],-1)r=getAlpha(i,LD,D,g.rf)[0]table_factors.ix[[row_name],['alpha']]=rtable_factors=table_factors.dropna() #把没有alpha的值都drop了# print(table_factors)return table_factors

2)基本面数据标准化处理。修改方法是使用sklearn的标准化函数来对factor进行标准化处理。原因是线性回归这种函数是通过计算和优化残差距离来拟合的,如果factor不在一个scale范围内,可能会使有些factor对结果的影响大,有些小,另外标准化也会加快算法的收敛速度,有利于数值计算。

# 判断是否调仓日,如果是调仓日,则进行调仓操作if g.if_trade:    # 获得今天的日期的字符串todayStr=str(context.current_dt)[0:10]print(todayStr)    # 获得当前股票对应季度的对应财务因子数据,数据类型为dataframefactors_table=getDS(g.all_stocks,todayStr,g.lag)    # 计算回归系数    # factor没有归一化可能会有点问题。。)scaler = StandardScaler()factors_table_new = scaler.fit_transform(factors_table[g.factors])    # print(factors_table)weights=linreg(factors_table_new,factors_table[['alpha']])# 获得当前的因子current_factors=getOriginalFactors(g.factors,todayStr)    # print(type(current_factors))    #这里也要对因子做归一化处理    # current_factors_new = scaler.transform(current_factors)current_factors_new = pd.DataFrame(scaler.transform(current_factors),index=current_factors.index, columns=current_factors.columns)print((current_factors_new))    # 计算调仓信号toBuy = get_signal(context,current_factors_new, weights)print(toBuy)    # 执行调仓buy_and_sell(context, toBuy)    # 调仓指令归于“否”g.if_trade = False

3)调整factor,选择相对比率,去除绝对数值的factor,比如eps和adjusted_profit。因为绝对数值的scale太大,和公司体量有关,不能说大的就一定好,比较并不公平。相对比率则比较客观,比如roe高的企业,优秀的概率则高一些。

修改如下:

g.factors=[#'eps',   #'adjusted_profit', #数字最大,也不是相对数值去掉,试试看!   'inc_return',           'roa',           'roe',           'net_profit_margin',           'gross_profit_margin',           'operation_profit_to_total_revenue',           'ga_expense_to_total_revenue',           'goods_sale_and_service_to_revenue',           'inc_total_revenue_year_on_year',           'inc_total_revenue_annual',           'inc_operation_profit_year_on_year',           'inc_operation_profit_annual']

4)股票购买数量由10调整到g.N,原来默认的20其实没有作用。原文代码里用10控制最大的选股数,但是本意是20个最多,所以改了下控制参数,就可以了。资金量大的时候可以更加分散化。

NoB=0for i in range(0,g.N):if points[i]>0:
        NoB =1#if NoB>10 #为什么只买10只股票,还是只考虑10个point为正的股票,改成用g.N控制个数if NoB>g.N:   
    NoB = g.N 
toBuy=array(points.index[0:NoB])return toBuy

改进空间:
如果要做成真正的量化策略,还可以进一步调整和加入以下部分:
1)解决财报日期和交易日期发布不匹配,LD和D之间时间长度不稳定的问题。我把调仓时间改成21天了,所以给策略一个自己纠正的机会,一定程度缓解了这个问题。不过应该有更好的改进方法。
2)股指期货对冲。可变成纯alpha策略,毕竟策略考虑的是alpha。
3)风险控制。策略波动率比基准还大,明显有改进空间。
4)仓位控制。牛市涨的还行,熊市跌的也快,如果加入仓位控制,应该会更好一些。

全部回复

0/140

量化课程

    移动端课程