本人对白马股的定义如下:
第一条件:筛选投资回报率ROIC五年以上都超过10%的公司
第二条件:自由资金流强劲,有息负债率低
第三条件:行业地位高、上下游议价能力强、运营资本低的的企业。这条量化起来有点儿“玄学”,暂时用“毛利率高”作为代理指标吧。
回测效果如下:
核心选股代码:
def select_stock(context):
start_date = dt.datetime.today().date()-dt.timedelta(days=1)
stk = get_index_stocks('000300.XSHG')+get_index_stocks('000905.XSHG')+get_index_stocks('399006.XSHE')
stk=list(set(stk))
stk2= list(get_fundamentals(query(
valuation.code,
).filter(
valuation.code.in_(stk),
balance.equities_parent_company_owners > 0,
balance.retained_profit>0,
valuation.pe_ratio>0,
), date=start_date).code.values)
def delete_st(stocks,begin_date):
st_data=get_extras('is_st',stocks, count = 1,end_date=begin_date)
stockList = [stock for stock in stocks if not st_data[stock][0]]
return stockList
def delete_stop(stocks,beginDate,n=365*3):
stockList=[]
beginDate = datetime.datetime.strptime(beginDate, "%Y-%m-%d")
for stock in stocks:
start_date=get_security_info(stock).start_date
if start_date<(beginDate-datetime.timedelta(days=n)).date():
stockList.append(stock)
return stockList
def get_jq_factor(date,feasible_stocks,jqfactors_list):
factor_data = get_factor_values(securities=feasible_stocks,
factors=jqfactors_list,count=1, end_date=date )
df_jq_factor=pd.DataFrame(index=feasible_stocks)
for i in factor_data.keys():
df_jq_factor[i]=factor_data[i].iloc[0,:]
return df_jq_factor
stk = delete_st(stk2,start_date)
one_year_ago = start_date - datetime.timedelta(days=365)
two_year_ago = start_date - datetime.timedelta(days=365*2)
three_year_ago = start_date - datetime.timedelta(days=365*3)
four_year_ago = start_date - datetime.timedelta(days=365*4)
#1、5年roic均值>0.1
ikun_1= pd.DataFrame(index=stk)
ikun_1['roic1']=get_jq_factor(start_date,stk,'roic_ttm').dropna()
ikun_1['roic2']=get_jq_factor(one_year_ago,stk,'roic_ttm').dropna()
ikun_1['roic3']=get_jq_factor(two_year_ago,stk,'roic_ttm').dropna()
ikun_1['roic4']=get_jq_factor(three_year_ago,stk,'roic_ttm').dropna()
ikun_1['roic5']=get_jq_factor(four_year_ago,stk,'roic_ttm').dropna()
ikun_1=ikun_1.dropna()
ikun_1['roic_mean']=ikun_1.mean(axis=1)
ikun_11=list(ikun_1[ikun_1.roic_mean>=0.1].index)
# 2、自由现金流强劲、有息负债率低(不喜欢大量负债、重资产)
#free cash flow/total__assets高 非流动资产/总资产低, 有息负债率低
# 3、排除行业地位不高,上下游议价能力差,运营资本高
#用毛利率高借代 行业地位高(可能不准确??), 净运营资本低高
ikun_f = get_history_fundamentals(ikun_11,
[income.operating_revenue,
income.operating_cost,
balance.total_current_assets,
balance.total_current_liability,
cash_flow.net_operate_cash_flow,
cash_flow.fix_intan_other_asset_acqui_cash,
balance.total_assets,
balance.total_non_current_assets,
],
watch_date=start_date, count=4).dropna() # 连续的6个季度
ikun_f['fcf']=ikun_f['net_operate_cash_flow']-ikun_f['fix_intan_other_asset_acqui_cash']
ikun_total_current_assets=ikun_f.groupby('code')['total_current_assets'].mean()
ikun_total_current_liability=ikun_f.groupby('code')['total_current_liability'].mean()
ikun_operating_revenue=ikun_f.groupby('code')['operating_revenue'].sum()
ikun_operating_cost=ikun_f.groupby('code')['operating_cost'].sum()
ikun_total_assets=ikun_f.groupby('code')['total_assets'].mean()
ikun_total_non_current_assets=ikun_f.groupby('code')['total_non_current_assets'].mean()
ikun_fcf=ikun_f.groupby('code')['fcf'].sum()
ikun_2= pd.DataFrame(index=ikun_11)
ikun_2['fcfsum']=ikun_fcf/ikun_total_assets
ikun_2['f_l']=get_jq_factor(start_date,ikun_11,'financial_liability').dropna()
ikun_2['a']=ikun_total_assets
ikun_2['d_a']=-ikun_2['f_l']/ikun_2['a']
del ikun_2['a']
del ikun_2['f_l']
ikun_2['fix_asset']=-ikun_total_non_current_assets/ikun_total_assets
ikun_3= pd.DataFrame(index=ikun_11)
ikun_3['gpm']=(ikun_operating_revenue-ikun_operating_cost)/ikun_operating_revenue
ikun_3['net working capital']=(ikun_total_current_liability-ikun_total_current_assets)/ikun_total_assets
ikun_2=ikun_2.dropna()
ikun_2=ikun_2.rank(ascending=True)
ikun_2_v = np.sum(preprocessing.scale(ikun_2),axis=1)
ikun_2_v1=preprocessing.scale(ikun_2_v )
ikun_2_i = ikun_2.index.tolist()
ikun_end2 = pd.DataFrame({'code':ikun_2_i,'ikun2':ikun_2_v1}).set_index('code')
ikun_3=ikun_3.dropna()
ikun_3=ikun_3.rank(ascending=True)
ikun_3_v = np.sum(preprocessing.scale(ikun_3),axis=1)
ikun_3_v1=preprocessing.scale(ikun_3_v )
ikun_3_i = ikun_3.index.tolist()
ikun_end3 = pd.DataFrame({'code':ikun_3_i,'ikun3':ikun_3_v1}).set_index('code')
ikun_score = pd.merge(ikun_end3,ikun_end2,on=['code'])
ikun_score_v = np.sum(ikun_score.dropna(),axis=1)
ikun_score_v1=preprocessing.scale(ikun_score_v)
ikun_score_i = ikun_score.dropna().index.tolist()
ikun_score1= pd.DataFrame({'code':ikun_score_i,'score':ikun_score_v1}).set_index('code')
ikun_score1=ikun_score1.sort_values(by='score',ascending=False).head(2*g.buy_stock_count)
def get_pb(x):
q = query(
valuation.pb_ratio,
).filter(
valuation.code == x
)
return get_fundamentals(q,start_date)['pb_ratio'].item()
def get_marketcap(x):
q = query(
valuation.market_cap,
).filter(
valuation.code == x
)
return get_fundamentals(q,start_date)['market_cap'].item()
ikun_score1['value'] = ikun_score1.index.map(get_marketcap)
result = list(ikun_score1.sort_values(by ='value',ascending=False).head(g.buy_stock_count).index)
return result
行业地位高、上下游议价能力强、运营资本低的的企业,这个条件可能需要找找别的更好的指标,纯毛利率其实是会选出白酒等高毛利的品类,但是白酒在这一两年表现并不佳,因此寻找更恰当的指标可以提高泛化性能。
如果你喜欢小木屋分享的内容,请关注小木屋哦。关注小木屋后回复【电子书】可获取小木屋入门量化的硬核书籍呢。