当前位置: 首页 > news >正文

量化交易:公司基本面的量化

公司的基本面因素一直具备滞后性,令基本面的量化出现巨大困难。而从上市公司的基本面因素来看,一般只有每个季度的公布期才会有财务指标的更新,而这种财务指标的滞后性对股票表现是否有影响呢?如何去规避基本面滞后产生的风险呢?下面我们将重点介绍量化交易在公司基本面分析上的应用,即平时常说的 基本面量化(Quantamental)。

反映公司经营优劣的指标

首先我们简单介绍下可能运用在量化策略上的基本面指标,相信大部分投资者都对上市公司的基本面有一定的了解,上市公司的基本面情况总是同公司业绩相关,而衡量业绩的主要基本面指标有每股收益、净资产收益率、主营业务收入等等。

而上市公司财务指标又常常存在相关的性质,比如每股收益和主营业务收入和产品毛利率相关,所以当我们把一堆财务指标放在一起统计可能就会产生相关性问题,从而降低了模型对市场走势的解释程度。因此,如何选出合适的独立性指标就成为我们进行财务指标量化模型设计的基础。

那么怎样的财务指标会较真实的反映上市公司的经营优劣呢?

  • 具有延续性的财务指标,比如近三年净利润增速,这一个指标把3年的净利润增速平均起来,这种增长性具备一定的长期特征;

  • 与现金流相关的指标,由于涉及真实的资金往来,现金流能够比较真实反映上市公司的经营状况。

每股现金流量/每股业绩

每股现金流量比每股盈余更能显示从事资本性支出及支付股利的能力。每股现金流量通常比每股盈余要高,这是因为公司正常经营活动所产生的净现金流量还会包括一些从利润中扣除出去但又不影响现金流出的费用调整项目,如折旧费等。但每股现金流量也有可能低于每股盈余。一家公司的每股现金流量越高,说明这家公司的每股普通股在一个会计年度内所赚得的现金流量越多;反之,则表示每股普通股所赚得的现金流量越少。

而每股现金流量常常与上市公司的业绩、总股本相关,所以用每股现金流量/每股业绩来衡量上市公司的现金流动情况,比单纯用每股盈余更为合理。

净资产收益率

净资产收益率又称股东权益收益率,是净利润与平均股东权益的百分比,是公司税后利润除以净资产得到的百分比率,该指标反映股东权益的收益水平,用以衡量公司运用自有资本的效率。指标值越高,说明投资带来的收益越高。

净资产收益率通过净资金去计量每年上市公司收益的百分比,净资产收益率比每股净利润,资产收益率等更合理的衡量归于于股东的上市公司权益的增值速度。

销售毛利率

销售毛利率,表示每一元销售收入扣除销售成本后,有多少钱可以用于各项期间费用和形成盈利。 销售毛利率是企业销售净利率的最初基础,没有足够大的毛利率便不能盈利。

在分析企业主营业务的盈利空间和变化趋势时,销售毛利率是一个重要指标。该指标的优点在于可以对企业某一主要产品或主要业务的盈利状况进行分析,这对于判断企业核心竞争力的变化趋势及其企业成长性极有帮助。

基本面量化的具体实现

  • 确定三个财务因子为销售毛利率、净资产收益率、每股现金流量/每股业绩

  • 通过features数据接口获取全市场3000多家上市公司的财务数据

  • 单独筛选每个财务因子前500的上市公司

  • 最终确定三个因子都能排在前500的股票篮子

  • 买入该股票篮子,等权重买入

  • 一个月换仓一次,买入新确定的股票篮子

回测结果:

从策略结果来看,年化收益26.9%,应该超过了大部分公募基金,虽然回撤很大,但细心地伙伴可以看出是发生在15年股灾期间和16年熔断期间,如果配合择时模型,想必效果会更好。尤其是值得注意的是,该策略在17年还取得了稳定正收益。本例子只作为如何使用财务数据进行基本面量化的样例策略,便于大家能够快速上手开发策略。

策略案例 

数据准备函数

def prepare(context):# 确定起始时间start_date = context.start_date# 确定结束时间end_date = context.end_dateinstruments = context.instrumentsfields = ['fs_gross_profit_margin_0', 'fs_roe_0', 'fs_free_cash_flow_0', 'fs_net_profit_0']raw_data = D.features(instruments, start_date, end_date, fields)raw_data['cash_flow/profit'] = raw_data['fs_free_cash_flow_0'] / raw_data['fs_net_profit_0']context.daily_buy_stock = pd.DataFrame(raw_data.groupby('date').apply(seek_stock))def seek_stock(df):ahead_f1 = set(df.sort_values('fs_roe_0',ascending=False)['instrument'][:500])ahead_f2 = set(df.sort_values('fs_gross_profit_margin_0',ascending=False)['instrument'][:500])ahead_f3 = set(df.sort_values('cash_flow/profit',ascending=False)['instrument'][:500])return list(ahead_f1 & ahead_f2 & ahead_f3)

策略逻辑主体函数

# 回测参数设置,initialize函数只运行一次
def initialize(context):# 手续费设置context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5)) # 调仓规则(每月的第一天调仓)context.schedule_function(rebalance, date_rule=date_rules.month_start(days_offset=0)) # handle_data函数会每天运行一次
def handle_data(context,data):pass# 换仓函数
def rebalance(context, data):# 当前的日期date = data.current_dt.strftime('%Y-%m-%d')# 根据日期获取调仓需要买入的股票的列表stock_to_buy = list(context.daily_buy_stock.ix[date][0])# 通过positions对象,使用列表生成式的方法获取目前持仓的股票列表stock_hold_now = [equity.symbol for equity in context.portfolio.positions]# 继续持有的股票:调仓时,如果买入的股票已经存在于目前的持仓里,那么应继续持有no_need_to_sell = [i for i in stock_hold_now if i in stock_to_buy]# 需要卖出的股票stock_to_sell = [i for i in stock_hold_now if i not in no_need_to_sell]# 卖出for stock in stock_to_sell:# 如果该股票停牌,则没法成交。因此需要用can_trade方法检查下该股票的状态# 如果返回真值,则可以正常下单,否则会出错# 因为stock是字符串格式,我们用symbol方法将其转化成平台可以接受的形式:Equity格式if data.can_trade(context.symbol(stock)):# order_target_percent是平台的一个下单接口,表明下单使得该股票的权重为0,#   即卖出全部股票,可参考回测文档context.order_target_percent(context.symbol(stock), 0)# 如果当天没有买入的股票,就返回if len(stock_to_buy) == 0:return# 等权重买入 weight =  1 / len(stock_to_buy)# 买入for stock in stock_to_buy:if data.can_trade(context.symbol(stock)):# 下单使得某只股票的持仓权重达到weight,因为# weight大于0,因此是等权重买入context.order_target_percent(context.symbol(stock), weight)

策略回测接口

# 策略运行调用函数
m=M.trade.v2( instruments=D.instruments(market='CN_STOCK_A'),start_date='2013-01-01', end_date='2017-05-01',prepare=prepare, # 在实盘或模拟交易,每天会更新数据,因此必须传入数据准备函数# 必须传入initialize,只在第一天运行initialize=initialize,# 必须传入handle_data,每个交易日都会运行handle_data=handle_data,# 买入以开盘价成交order_price_field_buy='open',# 卖出也以开盘价成交order_price_field_sell='open',# 策略本金capital_base=1000000,# 比较基准:沪深300benchmark='000300.INDX',m_deps='quantamental'
)

相关文章:

  • pytorch 安装 2023年
  • 【咖啡品牌分析】Google Maps数据采集咖啡市场数据分析区域分析热度分布分析数据抓取瑞幸星巴克
  • Hoppscotch:开源 API 开发工具,快捷实用 | 开源日报 No.77
  • Polygon zkEVM的Dragon Fruit和Inca Berry升级
  • Python------列表 集合 字典 推导式(本文以 集合为主)
  • 编译智能合约以及前端交互工具库(Web3项目一实战之三)
  • 视频怎么做成二维码?在线教学视频码的制作技巧
  • FISCO BCOS 3.0【02】配置和使用系统自带的控制台
  • MFC 对话框
  • C语言——冒泡排序
  • 从服务器端获取人脸数据,在本地检测特征,并将特征发送给服务器
  • ubuntu20中安装cmake-gui
  • 计算机毕业设计 基于SpringBoot的车辆网位置信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 【Rust】快速教程——从hola,mundo到所有权
  • 为什么Transformer模型中使用Layer Normalization(Layer Norm)而不是Batch Normalization(BN)
  • @jsonView过滤属性
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【译】理解JavaScript:new 关键字
  • 〔开发系列〕一次关于小程序开发的深度总结
  • 3.7、@ResponseBody 和 @RestController
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • Codepen 每日精选(2018-3-25)
  • download使用浅析
  • gulp 教程
  • js中的正则表达式入门
  • node和express搭建代理服务器(源码)
  • rabbitmq延迟消息示例
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • vue-router 实现分析
  • vue总结
  • Zepto.js源码学习之二
  • 安卓应用性能调试和优化经验分享
  • 将回调地狱按在地上摩擦的Promise
  • 那些年我们用过的显示性能指标
  • 算法---两个栈实现一个队列
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 因为阿里,他们成了“杭漂”
  • 最近的计划
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • 积累各种好的链接
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • 正则表达式-基础知识Review
  • #NOIP 2014# day.1 T2 联合权值
  • #微信小程序:微信小程序常见的配置传旨
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (5)STL算法之复制
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (pojstep1.3.1)1017(构造法模拟)
  • (超详细)语音信号处理之特征提取
  • (二)c52学习之旅-简单了解单片机
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (附源码)ssm捐赠救助系统 毕业设计 060945