理查马文价值导向选股法则(年化 34%,附代码)

引言

理查和马文是华尔街著名的财务分析专家,二人合作研究愈30年,在业界有着很高的声望,现在均任罗根资产管理公司投资经理。他们二人都是格雷厄姆和巴菲特的追随者,奉行价值投资的理念,本篇将要介绍的理查&马文价值导向选股法则正是两人价值投资理念的集中体现。

策略思路

理查和马文是价值投资的拥护者,在投资组合选股中,尤其重视分红率高且稳定的公司。二人于1980年代开始合作研究关系,曾先后于核心财务公司(CoreStates Financial)、伯恩财务集团合作进行投资方面的研究。之后二人正式开始以价值投资方式进行投资组合管理,其投资业绩始终保持在同类资产管理公司的前列。其策略主要从五个角度对股票提出要求:

一、股票具备一定的市值规模;

二、股票具有一定的分红收益;

三、公司的财务状况要求健康;

四、股票具备合理的估值;

五、公司有充足的现金流。

从这五个角度出发,我们给出选股的六个指标:

1.市值
2.市盈率
3.股息收益率
4.股息率相对全市场水平
5.资产负债率
6.每股现金流净额

这六个指标共同构建了选股准则,行程了理查马文价值导向选股法则。这五条准则非常清晰明确,均为可直接量化实现的准则。每条准则具有明确的量化描述和判断条件,除个别部分需对中国市场调整外,我们的回测将严格按照这六条准则复制,不存在需主观判断而不能量化的准则。

策略细节

归纳理查马文价值投资策略初始版本,可以大致总结策略衡量的五个方面:

(1)用总市值来要求目标公司具备一定的公司规模;

(2)用股息收益率来衡量股票的分红水平,保证价值投资者能够获得一定的分红收益。

(3)用资产负债率来衡量公司的偿债能力和财务结构,保证买入的投资标的具备足够强大的资产负债表;

(4)用市盈率来衡量股票的估值,要求买入的投资标的足够“便宜”,具有合理的估值;

(5)用每股现金流量保证目标公司具有较为充足的现金水平。

其价值选股标准也主要围绕着这三个方面,具体为:

  1. 罗伯·瑞克超额现金流选股法则的通用版本:

a)总市值大于等于市场平均值
b)股息率大于等于市场平均值的1.5倍
c)最近一期资产负债率小于市场均值
d)最近一年市盈率小于市场平均值
e)最近一年每股现金流量为正值且大于市场平均值
f)姑息率最高的前10家

策略实现

为了比较长期价值投资的效果,我们进行了3次回测,回测时长分别为1年,5年,10年。

(1)理查马文价值导向选股法则

投资标的:A股
调仓周期:60天
回测时间:2016.01.01~2017.01.01
回测时长:1年

收益曲线

收益归因

业绩分析

从回测结果看,该价值选股策略取得了10%以上的超额收益。表现强于大盘。该策略有一定的选股效果。

(2)理查马文价值导向选股法则

投资标的:A股
调仓周期:60天
回测时间:2014.01.01~2017.01.01
回测时长:3年

收益曲线

收益归因

业绩分析

当回测时间延长到三年,我们发现该策略的成果更加优异。年化收益率达到了36.7%。观察收益曲线,可以发现该策略在大盘下跌时依然取得了一段不错的收益。这表明该策略对价值股的选取一定程度上减轻了熊市带来的影响。

(3)理查马文价值导向选股法则

投资标的:A股
调仓周期:60天
回测时间:2007.01.01~2017.01.01
回测时长:10年

收益曲线

收益归因

业绩分析

在10年期的回测中,该策略表现比较一般,远逊与其在3年期回测中的表现。这可能是因为A股特有的小市值因素造成的。由于壳资源的价值和其他原因,A股市场长期以来一直偏向小市值风格,而这一风格在近几年发生了变化,单纯的小市值难以取得过人的成绩。而我们的策略更偏向于寻找市值较大的公司,也因此该策略在小市值有效的十年期表现不佳,而在一年、三年回测时间段有所表现。

小结

理查&马文价值导向选股法则是理查和马文价值投资理念的集中体现。其从五个角度对投资标的进行要求,分别是足够的公司规模,合理的估值,健康的财务状况,一定的分红水平和相对充足的现金流。围绕这五个角度,提出了 6 个具体的选股准则,用总市值,要求目标公司具备足够的公司规模;市盈率衡量估值水平,要求股票的价格尽量“便宜”;用资产负债率限制公司的财务杠杆,要求企业具备健康的财务状况;用股息率来衡量收益水平,要求满足一定的分红收益;用每股现金流衡量公司的现金流水平,要求目标公司具备一定的现金流量。

从我们的回测结果来看,理查&马文价值导向选股法则表现并不稳定,在中国市场还不具备很强的实用性,非常值得我们沿着这六条准则所体现的思路作进一步的优化和探索。

但需要说明的是,目前我们所测试的选股法则并不能算成熟的策略,仍有不足。 其一、策略相对基准的 相对强弱波动较大,仅在 2008 年到 2010 年、2013 年后体现出明显的相对优势, 而在其他 5 年间没有体现出稳定的相对优势;其二、策略持股个数波动略大,易造成 交易执行的问题。当股票个数过少时,隐藏的风险和波动性加大。

我们再次提出四个简单的优化建议: 一是吸收理查&马文价值导向选股法则中的投资思维,在原有基础上扩展筛选股的考查纬度、或者调整具体的考核指标,进一步优化考察指标的参数;二是对选股数量和行业分布进行调整,利用分散化投资和行业中性的优势来避免策略的大幅波动,减少策略中明显不足的最大回撤指标;三适当对持股数量进行挑战,利用分散化投资的优势来平稳策略的表现。

关于回测平台、历史数据,可以在这里下载:http://www.***链接失效或指向广告已经被屏蔽***.com/# /introduce
这个平台的数据都是经过清洗的,而且策略不会外露,有保密系统,还是比较安全的。
想学习更多量化策略,也可以来这里看看:http://www.***链接失效或指向广告已经被屏蔽***.com/# /lzClass
想学习更多关于量化投资策略相关内容的,可以关注微信:量化投资与金融科技(微信号:QuantumFintech)
微信二维码:

Code

-- coding:utf-8 --

from CloudQuant import SDKCoreEngine # 导入量子金服SDK
from CloudQuant import AssetType
from CloudQuant import QuoteCycle
import numpy as np
import pandas as pd

np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 100000000,
'startDate': 20140101,
'endDate': 20170101,
'cycle': QuoteCycle.D,
'strategyName': '理查马文',
'feeRate': 0.001,
'feeLimit': 5,
'stampTaxRate': 0.001,
'dealByVolume': True
}

HOLDING_PERIOD=60

def initial(sdk):
sdk.setGlobal('c',0)

def initPerDay(sdk):
**pass

def strategy(sdk):
count=sdk.getGlobal('c')
if **count==0:
TCAP=sdk.getFactorData('LZ_CN_STKA_VAL_A_TCAP')[-1] # 总市值
PE = sdk.getFactorData('LZ_CN_STKA_VAL_PE')[-1] # PE
PC = sdk.getFactorData('LZ_CN_STKA_VAL_PC')[-1] # 市现率
D2A=sdk.getFactorData('LZ_CN_STKA_FIN_IND_DEBTTOASTS')[-1] # 资产负债率
PPD=sdk.getFactorData('LZ_CN_STKA_VAL_PPD')[-1] # 股价/每股派息
DR=1/PPD # 股息率
ST = sdk.getFactorData('LZ_CN_STKA_SLCIND_ST_FLAG')[-1] # ST
STOP = sdk.getFactorData('LZ_CN_STKA_SLCIND_STOP_FLAG')[-1] # 停牌
stock_list = sdk.getStockList()
stock_list = np.array(stock_list)

condition_TCAP=TCAP>=np.nanmean(TCAP)
condition_DR=DR>=np.nanmean(DR)*1.5
condition_D2A = D2A  0:
            order = [stock, price, volume, 1]
            buy_orders.append(order)
**if **buy_orders:
    sdk.makeOrders(buy_orders)
    sdk.sdklog(

-- coding:utf-8 --

from CloudQuant import SDKCoreEngine # 导入量子金服SDK
from CloudQuant import AssetType
from CloudQuant import QuoteCycle
import numpy as np
import pandas as pd

np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 100000000,
'startDate': 20140101,
'endDate': 20170101,
'cycle': QuoteCycle.D,
'strategyName': '理查马文',
'feeRate': 0.001,
'feeLimit': 5,
'stampTaxRate': 0.001,
'dealByVolume': True
}

HOLDING_PERIOD=60

def initial(sdk):
sdk.setGlobal('c',0)

def initPerDay(sdk):
**pass

def strategy(sdk):
count=sdk.getGlobal('c')
if **count==0:
TCAP=sdk.getFactorData('LZ_CN_STKA_VAL_A_TCAP')[-1] # 总市值
PE = sdk.getFactorData('LZ_CN_STKA_VAL_PE')[-1] # PE
PC = sdk.getFactorData('LZ_CN_STKA_VAL_PC')[-1] # 市现率
D2A=sdk.getFactorData('LZ_CN_STKA_FIN_IND_DEBTTOASTS')[-1] # 资产负债率
PPD=sdk.getFactorData('LZ_CN_STKA_VAL_PPD')[-1] # 股价/每股派息
DR=1/PPD # 股息率
ST = sdk.getFactorData('LZ_CN_STKA_SLCIND_ST_FLAG')[-1] # ST
STOP = sdk.getFactorData('LZ_CN_STKA_SLCIND_STOP_FLAG')[-1] # 停牌
stock_list = sdk.getStockList()
stock_list = np.array(stock_list)

condition_TCAP=TCAP>=np.nanmean(TCAP)
condition_DR=DR>=np.nanmean(DR)*1.5
condition_D2A = D2A  0:
            order = [stock, price, volume, 1]
            buy_orders.append(order)
**if **buy_orders:
    sdk.makeOrders(buy_orders)
    sdk.sdklog("------------------------------------------")
    sdk.sdklog(sdk.getNowDate(),"DATE")
    sdk.sdklog(buy_orders,'BUY')

def run_all():
config['initial'] = initial
config['strategy'] = strategy
config['preparePerDay'] = initPerDay

启动SDK

SDKCoreEngine(**config).run()

if name == 'main':
run_all()

-- coding:utf-8 --

from CloudQuant import SDKCoreEngine # 导入量子金服SDK
from CloudQuant import AssetType
from CloudQuant import QuoteCycle
import numpy as np
import pandas as pd

np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 100000000,
'startDate': 20140101,
'endDate': 20170101,
'cycle': QuoteCycle.D,
'strategyName': '理查马文',
'feeRate': 0.001,
'feeLimit': 5,
'stampTaxRate': 0.001,
'dealByVolume': True
}

HOLDING_PERIOD=60

def initial(sdk):
sdk.setGlobal('c',0)

def initPerDay(sdk):
**pass

def strategy(sdk):
count=sdk.getGlobal('c')
if **count==0:
TCAP=sdk.getFactorData('LZ_CN_STKA_VAL_A_TCAP')[-1] # 总市值
PE = sdk.getFactorData('LZ_CN_STKA_VAL_PE')[-1] # PE
PC = sdk.getFactorData('LZ_CN_STKA_VAL_PC')[-1] # 市现率
D2A=sdk.getFactorData('LZ_CN_STKA_FIN_IND_DEBTTOASTS')[-1] # 资产负债率
PPD=sdk.getFactorData('LZ_CN_STKA_VAL_PPD')[-1] # 股价/每股派息
DR=1/PPD # 股息率
ST = sdk.getFactorData('LZ_CN_STKA_SLCIND_ST_FLAG')[-1] # ST
STOP = sdk.getFactorData('LZ_CN_STKA_SLCIND_STOP_FLAG')[-1] # 停牌
stock_list = sdk.getStockList()
stock_list = np.array(stock_list)

condition_TCAP=TCAP>=np.nanmean(TCAP)
condition_DR=DR>=np.nanmean(DR)*1.5
condition_D2A = D2A  0:
            order = [stock, price, volume, 1]
            buy_orders.append(order)
**if **buy_orders:
    sdk.makeOrders(buy_orders)
    sdk.sdklog(

关键字:量化选股, 量化策略, 量化投资, 量化交易


风险提示及免责条款

市场有风险,投资需谨慎。本文不构成个人投资建议,也未考虑到个别用户特殊的投资目标、财务状况或需要。用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部