美国量化基金与金融科技服务商(及特色券商)系列研究报告之三
美国 Quantopian 金融科技服务商解析
———— 著名零售端金融服务商
华鑫证券私募基金研究中心
一、概要
公司简介: Quantopian是一家2011年由金融技术企业家John Fawcett成立于美国波士顿的对冲基金服务商,对那些不熟悉从事这些活动的公司内部运作的人来说,对冲基金和专有算法股票交易的世界似乎是模糊、复杂甚至危险的,而公司思想是可以从任何人(不仅是高薪交易员)那里获取交易算法,打着“人人都可以成为Quant(金融工程师/宽客)”的旗号,吸引和鼓励了来自全世界的用户在其算法交易平台上开发和测试自己的投资算法交易策略来买卖证券。公司已经建立了一种商业模型,将以资本形式的投资者需求与以众包策略形式的算法供应联系起来,并且以众包模式基金进行股票交易。创始人曾于2008年以2800万美元的现金和股票出售了一家金融科技软件公司。
客户群:坚持走"群众化路线"。它瞄准的并非投资领域的顶级专业人士,而是量化投资行业的新手。自2013起,Quantopian上的用户量数量逐年翻倍,从10000个用户快速扩张,到2016年已经拥有来自世界180个国家的8万用户在其平台上开发和测试自己的交易算法,到2020年3月用户量倍数级增长,拥有来自190个国家超过30万用户,平台累计进行了超过1200万次回测。
团队:Quantopian的成员由190多个国家的金融专业人士,科学家,开发者和学生构成,主要管理者9人。创始人John Fawcett现后服务于波士顿基金和基金服务软件开发商Tamale和ADVENT,在成立公司时有12年相关工作经验。
公司发展状况:Quantopian在算法交易平台领域发展的风生水起,2014年底是获得了1500万美元的B轮融资,而当时Quantopian仅有20位员工,随后经从Bessemer Venture Partners和Andreessen Horowitz等大型投资机构获得4880万美元的融资。如此大的声势让Quantopian入选了2014年福布斯美国最有前景的公司之列,随后公司接连入选The Forbes Fintech 50。
二. 公司业务布局及发展路径
2.1. 公司业务范围及模式
Quanntopian是一个众包量化投资平台,众包(Crowdsourcing)是由美国《连线》杂志的记者Jeff Howe在2006年6月提出的,它是指一个公司或机构把过去由员工执行的工作任务,以自由自愿的形式外包给非特定的大众网络的做法。公司为算法投资者提供市场数据和基于Python语言的策略开发平台,用户可在平台上涉及交易算法,开发策略,对策略进行回撤和调优。公司于2011年在美国成立,主营业务主要分为三块:
(1) 策略开发和交易:策略基础开发和回测服务有两项功能。一个是教育平台,公司与MIT斯隆管理学院合作,提供在Quantopian上开发算法交易策略的学习资料;一个是Research平台提供海量日历史数据,数据覆盖25个国家股票、ETF、ADR标的,数据类型包括价格、收益率,公司基本面、股票情绪、宏观经济指标等50多个维度数据集,数据更新到前一个交易日,最早可追溯到2002年的美国和2004年的其他国家,代码编写栏和可视化数据分析工具帮助开发和回测算法的有效性。上述涉及功能均免费,公司与盈透证券合作,平台上开发的策略可以接入盈透账户进行实时交易。
(2) 社区交流,其社区在Github上开源,供用户讨论代码、分享数据等。
(3) 竞赛和基金投资,Quantopian为用户提交想法提供了激励和竞赛,设置常规化的算法比赛,任何作者都可以将其代码绑定到他们的银行帐户并进行交易,基于10多项结构和风险筛选项找出风险较小的高收益策略,包括(1)低风险;(2)市场beta在-0.3和0.3之间;(3)夏普比率始终超过1.0的风险状况下获得一致的收益;(4)活跃的投资组合,每年的目标周转率是12和500次;(5)与其他选定作者的相关性较低;(6)基于市场趋势和经济驱动力的战略意图,通过每日现金奖励来激励开发者。然后该公司通过评估算法六个月,如果回测和现场模拟证明成功,挑选部分算法,募集基金进行投资,公司可以将资金用于交易公司或其有限合伙人(目前为Point72 Ventures)的资金,公司对选中的每个算法的投资额大约为10万美元到300万美元;在这种情况下,作者将获得全部回报的一部分,同时作者拥有其算法的IP。截至2017年10月,Quantopian已经从100,000个用户,500,000个算法中,各投资十万元以上的资金给其中的三个算法,和策略研发者共享策略投资收益。同时,平台会收取一定的管理费用,而算法作者也从基金收益中获取大约10%作为回报。不过,尽管Quantopian在2016年对算法的投资回报高达40%,但由于公司尚未开展外部资产管理业务,投资所用资金均来自自有资产。因此,当Quantopian在未来真正引入外部资金时,必将面临更为严峻的监管压力.
2.2. 业务发展路径
典型的对冲基金业务模型依赖于高薪和聪明的分析师来创建一套有限的策略和算法,用于交易从有限合伙人那里筹集的资金。对冲基金通常收取2%的管理费和20%的正回报。而公司通过打造一个免费的策略开发平台吸引全世界最优秀的人才来编写开发算法,模型对具有Internet访问和基本编码技能的任何人开放访问权限,从而大大降低了测试和创建交易模型的障碍,吸引了大批客户使用其平台工具开发交易算法。公司利用众包策略、极低的劳动力成本(几乎为零)和不同的费用结构以及开放的创新渠道来突破原有行业模式,从而从根本上改变了金融和技术领域的经济驱动力。此外,交易产品更难以保持专有性,因为任何人都可以使用相同的可用数据来建立相似或相同的交易模型,以对市场情况进行压力测试。在这种模型下,使用新算法进行实验的可变成本接近于零;在传统的对冲基金中,公司可能需要大量投资于交易策略,并证明其成功,才能够从有限合伙人那里筹集资金。
Quantopian在扩展产品方面具有优势。该公司可以进一步使广泛筹资,或者将培训和投资用于最杰出的算法开发人员上。最后,该公司可以充当对冲基金的招聘工具。
三、具体产品介绍
(一)产品主要核心模块
1. 数据源
公司拥有2002年以来直到最近完成的交易日的美国股票和美国期货的分钟级历史记录数据,甚至包括不再交易的股票和ETF。提供该分钟内的开盘价,收盘价,高价,低价和交易量,每晚收市更新。而美国期货数据库包含72种期货,涵盖了商品,利率,股票和货币期货等种类。每周5天(美国东部时间周日下午6点-周五下午6点)可获得这些期货的24小时数据。有的数据集都是以时间点形式,连续发送,这对于回测准确性非常重要,避免算法因为遗漏破产和其他重要事件而产生过于乐观的结果,形成回测偏差。
具体来说,在算法仿真过程中,权拓点使用交易价格,这意味着当用户的算法要求特定资产的价格时,它会在仿真时获得该资产的价格。对于期货,交易价格是从电子贸易数据得出的。当用户的算法要求提供历史股价或交易量数据时,将根据当前模拟日期的拆分,合并和股息进行调整。换句话说,如果用户的算法要求一个历史价格窗口,并且该窗口中间有一个拆分,则该窗口的第一部分将针对拆分进行调整。进行此调整是为了使用户的算法可以使用窗口中的值进行有意义的计算。
Quantopian还提供免费的基本数据访问。平台引入Morningstar的数据包括600多个衡量公司财务业绩的指标,这些指标均来自其公开文件。此数据最常见的用途是筛选出用于算法的证券子集。通常在算法的交易逻辑中使用基本指标。除了定价和基本数据外,公司还提供大量合作伙伴数据集。组合各种数据集中发现的信号是创建高质量算法的有力方法。可用的数据集包括诸如情绪分析之类的市场指标,以及诸如临床试验数据之类的行业特定指标。每个数据集都有一组有限的免费数据。完整的数据集可以按需购买,按月收费。
自助数据部分允许用户将自己的时间序列csv数据上传到Quantopian。为了准确地在pipeline中表示用户的数据并避免前瞻性偏差,将按照类似于Quantopian Partner Data的时间点性质来收集,存储和显示用户的数据。
2. 研究环境
对于大多数人来说,编写一个好的算法最困难的部分是找到想法或定价“优势”。研究平台是进行此类研究和分析的地方。在研究平台上,用户可以访问Quantopian的所有数据价格,数量,公司基本面以及合作伙伴数据集,包括情感数据,收益日历等。同时可以将回测或实时算法的结果加载到研究中,分析结果并与其他算法的性能进行比较,帮助改进算法。
3. IDE和回测
在IDE(交互式开发环境)中,用户可以编写算法,按“ Build”将帮助检查用户算法的代码是否存在语法错误,然后开始进行运行回测,回测数自动保存并且可以访问以供将来分析。
4. 样本外测试
在书面交易中,用户的算法通过获取实时市场数据(但有15分钟的延迟)模拟投资组合对进行交易。对于任何算法来说,这都是一个很好的测试。如果在算法开发过程中过度拟合,那么测试器将发现问题所在。其背后的订单履行逻辑与常规回测逻辑一致,包括滑点模型。不过此项功能目前仅适用于美国股票类资产交易。
5. 隐私保护
Quantopian非常重视隐私和安全性。内部生成的所有交易算法和回测结果均归用户所有,可以选择与社区共享知识产权,或者选择授予Quantopian权限以查看代码以进行故障排除。除特殊情况(例如保护平台的安全性)外,未经用户的允许,平台将不会访问用户的算法。具体来说,平台的安全层包括:Quantopian应用程序的SSL加密,安全的websocket通信以获取回测数据,以及在将所有交易算法和其他专有信息写入的数据库之前,先对其进行加密。
(二)产品使用手册
交易算法
交易算法(trading algorithm)是用计算机来定义一组买卖资产规则的程序。大多的交易算法都是基于历史数据和数学/统计模型来做决策的。在Quantopian研究环境中有完整的美股数据可供客户使用。在 Quantopian主页,通过 Research --> Notebooks 就可以创建一个 Jupyter Notebook 环境来运行 Python代码。
编写交易算法的第一步是找到可以建立策略基础的经济或统计关系。为此,可以使用Quantopian的研究环境访问和分析平台中可用的历史数据集。研究环境Jupyter Notebook允许用户以称为“单元”的单元运行Python代码。例如,以下代码绘制了苹果公司(AAPL)的每日收盘价,以及其20天和50天移动平均线:
要使用上面的代码副本并将其粘贴到Research中的新笔记本中,进入研究模式后,按Shift + Enter键即可运行单元格。输出应如下所示:
数据探索
从2002年到最近完成的交易日,研究部提供实用程序功能来查询8000多种美国股票的价格,数量和回报数据。这些函数获取资产(或资产列表)以及开始和结束日期,并返回按日期索引的pandas 系列(或 DataFrame)。定以需要研究的时间段,并使用returns函数来查询APL的数据:
替代数据
除了定价和数量数据外,Quantopian还集成了许多其他数据集,包括公司基本面,股票情绪分析和共识估计等。用户可以在Quantopian的Data Reference中找到完整的数据集列表。例如PsychSignal的StockTwits Trader Mood数据集。PsychSignal的数据集根据金融通讯平台Stocktwits上发布的消息的总体情绪,每天为股票分配牛市和熊市得分。用户可以从检查stocktwits数据集中的消息量和情绪得分(牛市减去熊市)列开始 。使用Quantopian的Pipeline API查询数据来访问和分析Research中的数据。
探索数据集时,可尝试查找可能用作交易策略基础的模式。例如,上图显示了每日收益与股票交易消息量之间的一些匹配峰值,并且在某些情况下,收益的峰值方向与APL的情绪得分方向一致。
Pipeline API
Pipeline API是用于资产数据的横截面分析的强大工具。它使用户能够为多个数据输入定义一组计算,并一次分析大量资产。Pipeline API的一些常见用法包括:
? 根据过滤规则选择资产
? 根据评分功能对资产进行排名
? 计算投资组合分配
首先,导入Pipeline类并创建一个返回空Pipeline的函数。将Pipeline定义放入函数中可以帮助用户随着Pipeline复杂性的增加而事情井井有条。在Research和IDE之间传输数据Pipeline时,这特别有用。
将输出添加到Pipeline中,用户需要包括对数据集的引用,并指定用户要对该数据进行的计算。例如,用户将添加对USEquityPricing数据集中的close列的引用。然后,用户可以将输出定义为该列中的最新值,如下所示:
Pipeline API还提供了许多内置计算,其中一些是在数据的尾随窗口上计算的。例如,以下代码导入Psychsignal的 stocktwits数据集,并将输出定义为其bull_minus_bear列的3天移动平均线:
制定策略的重要部分是定义在投资组合中交易的资产集。用户通常将这组资产称为用户的交易范围。交易范围应尽可能大,同时还要排除不适合用户投资组合的资产。例如,用户可能要排除流动性不足或难以交易的问题,Quantopian的QTradableStocksUS提供了这一特征。用户可以使用Pipeline构造函数的screen参数将QTradableStocksUS设置为用户的交易领域:
#从quantopian 导入Pipeline类和数据集。Pipeline进口Pipeline从quantopian 。Pipeline。数据导入USEquityPricing 从quantopian 。Pipeline。数据。心理信号进口库存
#从Quantopian 导入内置的移动平均值计算。Pipeline。因素导入SimpleMovingAverage
#从Quantopian 导入内置的交易Universe 。Pipeline。实验进口QTradableStocksUS
def make_pipeline ():#创建对用户交易世界的引用
base_universe = QTradableStocksUS ()
#获取最新收盘价
close_price = USEquityPricing 。关闭。最新
#3计算天的平均bull_minus_bear分数
sentiment_score = SimpleMovingAverage (
输入= [ stocktwits 。bull_minus_bear ],
window_length = 3 ,)
#包含close_price和#sentiment_score的返回Pipeline,其中将用户的交易范围作为屏幕返回Pipeline(
列= { 'close_price' :close_price ,'sentiment_score' :sentiment_score ,},
screen = base_universe ,)
现在,用户的Pipeline定义已经完成,用户可以使用run_pipeline在特定时间段内执行它 。输出将是按日期和资产索引的pandas DataFrame,其列对应于用户添加到Pipeline定义中的输出:
#从quantopian 导入run_pipeline方法。研究导入run_pipeline
#执行make_pipeline创建的Pipeline#start_date 和end_date之间的
pipeline_output = run_pipeline (
make_pipeline (),
start_date = '2013-01-01' ,
end_date = '2013-12-31' )
#显示最后10行
pipeline_output 。尾巴(10 )
策略定义
既然用户已经了解了如何在Quantopian中访问和操纵数据,那么让用户为多空权益策略构建一条数据Pipeline。通常,多头-空头股票策略包括对资产彼此之间的相对价值进行建模,然后押注用户有信心将在价值上增加(多头)并减少(空头)的资产组合。当多套高价值资产和低价值资产之间的收益差增加时,多空股票策略便会获利。多空股票策略的质量完全取决于其基础排名模型的质量。在本教程中,用户将为策略使用简单的排名架构:
策略:用户将3天平均情绪得分高的资产视为高价值,并将3天平均情绪得分低的资产视为低价值。
策略分析
用户可以使用SimpleMovingAverage和 stocktwits的bull_minus_bear数据定义以上策略,类似于用户在之前创建的Pipeline:
#从Quantopian 导入Pipeline。Pipeline进口Pipeline从quantopian 。Pipeline。数据。psychsignal 进口stocktwits
从quantopian 。Pipeline。因素从量子视点导入SimpleMovingAverage 。Pipeline。实验进口QTradableStocksUS
#Pipeline定义def make_pipeline ():
base_universe = QTradableStocksUS ()
sentiment_score = SimpleMovingAverage (
输入= [ stocktwits 。bull_minus_bear ],
window_length = 3 ,)
return Pipeline (
列= { 'sentiment_score' :sentiment_score ,},
screen = base_universe
)
为简单起见,用户将仅分析由sentiment_score排名的前350名和后350名股票 。用户可以使用sentiment_score输出的top和bottom方法 为这些集合创建Pipeline过滤器 ,并使用|组合它们。 运算符以获取结果。然后,通过使用&运算符获取过滤器和用户的工作空间之间的交集,用户将删除可交易范围之外的所有内容 :
#从Quantopian 导入Pipeline。Pipeline进口Pipeline从quantopian 。Pipeline。数据。psychsignal 进口stocktwits
从quantopian 。Pipeline。因素从量子视点导入SimpleMovingAverage 。Pipeline。实验进口QTradableStocksUS
#Pipeline定义def make_pipeline ():
base_universe = QTradableStocksUS ()
sentiment_score = SimpleMovingAverage (
输入= [ stocktwits 。bull_minus_bear ],
window_length = 3 ,)
#顶级350和底部350个创建过滤器根据他们的情感计数#资产
top_bottom_scores = (
sentiment_score 。顶(350 )| sentiment_score 。底部(350 ))
return Pipeline (
column = { 'sentiment_score' :sentiment_score ,},#将屏幕设置为用户的过滤器#和交易Universe
屏幕之间的交点=(
base_universe
&top_bottom_scores
))
接下来,让用户在要分析的时间内执行Pipeline。这大约需要1分钟。
#从quantopian 导入run_pipeline方法。研究导入run_pipeline
#指定时间范围来评估
period_start = “2013-01-01”
period_end = “2016年1月1日”
#在评估期内执行Pipeline
pipeline_output = run_pipeline (
make_pipeline (),
start_date = period_start ,
end_date = period_end
)
除了Pipeline的数据外,用户还需要此期间存在的所有资产的定价数据。用户可以轻松地从Pipeline输出的索引中获取这些资产的列表,并将该列表传递给 价格以获取所需的定价数据:
#进口价格从Quantopian开始起作用。研究进口价格
#从Pipeline输出
asset_list = pipeline_output 获取唯一资产列表。索引。级别[ 1 ]。唯一()
#查询#评估期内存在的所有资产的定价数据
asset_prices = 价格(
asset_list ,
start = period_start ,end = period_end
)
现在,用户可以使用Quantopian的开源因素分析工具 Alphalens来测试用户选择策略的质量。首先,让用户使用get_clean_factor_and_forward_returns结合用户的因子和定价数据 。此函数将因子数据分类为分位数,并计算多个持有期间内每种证券的正向收益。用户将因子数据分为2个分位数(上半部分和下半部分),并使用1、5和10天的持有期:
#导入Alphalens 以al 形式导入alphalens
#根据情感得分
factor_data = al 获取资产远期收益和分位数分类。实用程序。get_clean_factor_and_forward_returns (
因子= pipeline_output [ 'sentiment_score' ],
价格= asset_prices ,
位数= 2 ,
周期=(1 ,5 ,10 ), )
#显示前5行
factor_data 。头(5 )
使用这种格式的数据可以使用户使用Alphalens的多种分析和绘图工具。让用户从整个期间的分位数来看平均收益率开始。因为用户的目标是建立多空策略,所以用户希望看到较低分位数(1)的收益为负,而较高分位数(2)的收益为正:
#通过系数分位数
mean_return_by_q ,std_err_by_q = al 计算平均值回报。表现。mean_return_by_quantile (factor_data )
#在评估时间范围
a1 内按分位数和持有期#绘制平均收益。密谋。plot_quantile_returns_bar (
mean_return_by_q 。申请(
人。utils的。rate_of_return ,
轴= 0 ,
ARGS =('1D' ,)) );
用户还可以使用以下代码绘制持有期为5天的因子加权多空组合的累计收益:
将pandas 导入为pd
#计算因子加权的多空组合收益
ls_factor_returns = al 。表现。factor_returns (factor_data )
#绘制5天持有期
al的累计收益。密谋。plot_cumulative_returns (ls_factor_returns [ '5D' ],'5D' ,频率= PD 。TSERIES 。偏移。BDAY ());
上图显示了一个大的下行期,该分析尚未考虑交易成本或市场影响。这不是一个非常有前途的策略。在这一点上,用户确实应该使用Alphalens进行更深入的分析,然后迭代用户的战略构想。但是,出于本教程的考虑,让用户继续用户的策略。
定义并测试了策略后,让用户使用它来构建和测试多空权益算法。本教程的其余部分将介绍Algorithm API,并将在交互式开发环境(IDE)中进行。
算法API和核心功能
下一步将使用Quantopian的Algorithm API为用户的交易算法构建基本结构。Algorithm API提供的功能可促进订单调度和执行,并允许用户初始化和管理算法中的参数。
让用户看一下将在算法中使用的一些核心功能:
初始化(上下文)
当用户的算法开始运行并且需要上下文作为输入时,initialize会被调用一次 。任何参数初始化和一次性启动逻辑都应放在此处。
context是用于在整个仿真过程中维持状态的增强Python 字典,可以在用户算法的不同部分中引用。用户希望在函数调用之间保留的所有变量都应存储在上下文中, 而不要使用全局变量。可以使用点表示法(context.some_attribute)访问和初始化上下文变量。
before_trading_start
市场开盘前每天调用一次before_trading_start,并且需要 上下文和数据作为输入。 上下文是从相同参考字典 初始化,并且数据是一个对象,存储若干API函数,使用户能够查找当前或历史的价格及成交量数据任何资产。
before_trading_start也是用户获取Pipeline输出的地方,并在将结果数据用于投资组合构建之前对其进行任何预处理。
schedule_function(func,day_rule,time_rule)
在Quantopian上,算法可以在NYSE交易日历之后的常规交易日东部时间9:30 AM-4PM之间进行股票交易。 schedule_function允许用户在指定的日期和时间执行自定义函数。例如,用户可以安排一个函数来在每周第一天的市场开放时重新平衡投资组合,如下所示:
schedule_function (
重新平衡,
date_rule = date_rules 。week_start (),
time_rule = time_rules 。market_open () )
调度函数应在initialize中完成,并且使用此方法调度的自定义函数需要将上下文和数据作为参数。有关可用的date_rules和time_rules的完整列表,
接下来,让用户为用户的交易算法构建一个框架。现在,用户将使算法跟踪模拟中经过的天数,并根据日期和时间记录不同的消息。
#导入算法API 导入量子视线。算法的算法中
def initialize (context ):#初始化算法参数
context 。day_count = 0
上下文。daily_message = “第{}天”。
情境。weekly_message = “该进行一些交易了!”
#安排重新平衡功能
算法。schedule_function (
重新平衡,
date_rule = ALGO 。date_rules 。week_start (),
time_rule = ALGO 。time_rules 。market_open () )
高清before_trading_start (背景下,数据): #执行任何日常行动是必要发生的一个交易时段开始之前#
的上下文。day_count + = 1个
日志。信息(背景。daily_message ,情境。DAY_COUNT )
def rebalance (上下文,数据):#执行rebalance逻辑
日志。信息(背景。weekly_message )
现在,用户已经有了交易算法的基本结构,让用户将创建的数据Pipeline添加到算法中。
算法中的数据处理
下一步将是将用户在Research中内置的数据Pipeline集成到用户的算法中。与Research的一个重要区别是,在回测期间,随着模拟的进行,用户的Pipeline每天都会执行,因此用户不需要包括start_date和end_date参数。
为了在算法中使用用户的数据Pipeline,第一步是在算法的初始化函数中添加对其的引用 。这是使用attach_pipeline方法完成的 ,该方法需要两个输入:对Pipeline对象的引用 (用户使用make_pipeline构造 ),以及用于标识它的String名称。
#导入算法API 导入量子视线。算法的算法中
def initialize (context ):#将Pipeline附加到算法
algo 。attach_pipeline (
make_pipeline (),'data_pipe' )
#安排重新平衡功能
算法。schedule_function (
重新平衡,
date_rule = ALGO 。date_rules 。week_start (),
time_rule = ALGO 。time_rules 。market_open () )
def before_trading_start (context ,data ):通过
def 重新平衡(上下文,数据):通过
如上所述,用户的Pipeline将在每天开放市场之前处理数据流并生成输出。用户可以使用pipeline_output函数在before_trading_start中获得Pipeline的输出,该函数采用在initialize中指定的Pipeline名称 ,并返回由Pipeline生成的pandas DataFrame。现在,用户可以使用重新平衡功能记录Pipeline输出中的前10行。
#导入算法API 导入量子视线。算法的算法中
def initialize (context ):#将Pipeline附加到算法
algo 。attach_pipeline (
make_pipeline (),'data_pipe' )
#安排重新平衡功能
算法。schedule_function (
重新平衡,
date_rule = ALGO 。date_rules 。week_start (),
time_rule = ALGO 。time_rules 。market_open () )
def before_trading_start (上下文,数据):#获取Pipeline输出,并将其存储在上下文
context中。pipeline_data = 算法。pipeline_output ('data_pipe' )
def rebalance (上下文,数据):#显示Pipeline输出
日志的前10行#。信息(背景。pipeline_data 。头(10 ))
现在,让用户将在Research中内置的make_pipeline函数添加到算法中。与其像用户分析时那样限制资产的数量,用户的算法应该考虑交易环境中受到投资者情感因素影响的所有资产。为此,用户可以使用sentiment_score输出的notnull方法 创建一个过滤器,并使用&运算符将其与可交易Universe相交 :
#导入算法API 导入量子视线。算法的算法中
#从Quantopian 导入Pipeline。Pipeline进口Pipeline从quantopian 。Pipeline。数据。psychsignal 进口stocktwits
从quantopian 。Pipeline。因素从量子视点导入SimpleMovingAverage 。Pipeline。筛选器导入QTradableStocksUS
def initialize (context ):#将Pipeline附加到算法
algo 。attach_pipeline (
make_pipeline (),'data_pipe' )
#安排重新平衡功能
算法。schedule_function (
重新平衡,
date_rule = ALGO 。date_rules 。week_start (),
time_rule = ALGO 。time_rules 。market_open () )
def before_trading_start (上下文,数据):#获取Pipeline输出,并将其存储在上下文
context中。pipeline_data = 算法。pipeline_output ('data_pipe' )
def rebalance (上下文,数据):#显示Pipeline输出
日志的前10行#。信息(背景。pipeline_data 。头(10 ))
#Pipeline定义def make_pipeline ():
base_universe = QTradableStocksUS ()
sentiment_score = SimpleMovingAverage (
输入= [ stocktwits 。bull_minus_bear ],
window_length = 3 ,)
return Pipeline (
列= { 'sentiment_score' :sentiment_score ,},
屏幕=(
base_universe
&sentiment_score 。notnull ()))
现在,用户的算法每天都会选择一种可交易的资产范围,并产生可用于确定投资组合中资产分配的alpha分数。
投资组合管理
现在该定义算法将如何使用Pipeline生成的alpha分数来重新平衡其投资组合了。用户的目标是找到一个目标投资组合,该投资组合可以在保持由一组规则或约束定义的特定结构的同时,根据alpha分数最大化回报。这通常称为 投资组合优化问题。Quantopian的Optimize API使用户可以轻松地将Pipeline的输出转化为目标和一组约束。然后,用户可以使用 order_optimal_portfolio将当前投资组合转换为满足用户规格的目标投资组合。
第一步是定义一个目标。用户将使用 MaximizeAlpha,它将尝试将资本分配给与其alpha分数成比例的资产。
#导入Optimize API模块导入Quantopian 。优化的选择
def rebalance (上下文,数据):#从Pipeline输出
alpha = context中检索alpha 。pipeline_data 。情感分数
如果不是alpha 。空:#创建MaximizeAlpha目标
target = opt 。MaximizeAlpha (alpha )
接下来,用户需要指定用户希望目标投资组合满足的约束列表。让用户从在initialize中定义一些阈值开始 ,并将它们存储在用户的上下文变量中:
#约束参数
context 。max_leverage = 1.0
上下文。max_pos_size = 0.015
上下文。max_turnover = 0.95
现在,用户可以使用上面定义的阈值指定重新平衡的约束条件:
#导入Optimize API模块导入Quantopian 。优化的选择
def rebalance (上下文,数据):#从Pipeline输出
alpha = context中检索alpha 。pipeline_data 。情感分数
如果不是alpha 。空:#创建MaximizeAlpha目标
target = opt 。MaximizeAlpha (alpha )
#创建位置大小约束
constrain_pos_size = opt 。PositionConcentration 。with_equal_bounds (- 背景。max_pos_size ,
情境。max_pos_size
)
#限制目标投资组合的杠杆率
max_leverage = opt 。MaxGrossExposure (上下文。max_leverage )
#确保长书和短书#的大小大致相同
dollar_neutral = opt 。美元中性()
#限制投资组合周转率
max_turnover = opt 。MaxTurnover (上下文。max_turnover )
最后,用户可以将目标和约束列表传递给 order_optimal_portfolio以计算目标投资组合,并发出将当前投资组合转换为最佳状态所需的订单:
#导入算法API 导入量子视线。算法的算法中
#Import Optimize API 导入Quantopian 。优化的选择
def rebalance (上下文,数据):#从Pipeline输出
alpha = context中检索alpha 。pipeline_data 。情感分数
如果不是alpha 。空:#创建MaximizeAlpha目标
target = opt 。MaximizeAlpha (alpha )
#创建位置大小约束
constrain_pos_size = opt 。PositionConcentration 。with_equal_bounds (- 背景。max_pos_size ,
情境。max_pos_size
)
#限制目标投资组合的杠杆率
max_leverage = opt 。MaxGrossExposure (上下文。max_leverage )
#确保长书和短书#的大小大致相同
dollar_neutral = opt 。美元中性()
#限制投资组合周转率
max_turnover = opt 。MaxTurnover (上下文。max_turnover )
#使用目标#和约束
算法列表重新平衡投资组合。order_optimal_portfolio (
目标= 目标,
约束= [
constrain_pos_size ,
max_leverage ,
dollar_neutral ,
max_turnover ,] )
风险管理
除了对目标投资组合的结构设置限制之外,用户还将希望将其暴露于可能影响其绩效的常见风险因素中。例如,由于股票twitter情绪数据的瞬态特性 以及用户意图利用情绪得分峰值的意图,用户的算法可能会面临短期逆转风险。
用户将使用Quantopian的风险模型来管理投资组合中常见风险因素的敞口。风险模型计算资产面临16种不同风险因素的风险:11种行业因素和5种风格因素(包括短期反转)。用户可以使用Risk_loading_pipeline函数轻松地在用户的算法中访问此数据,该 函数返回一个数据Pipeline,该Pipeline为Risk Model中的每个因子生成一列输出。
与用户的数据Pipeline类似,用户将需要将风险数据Pipeline附加到用户的算法上,并提供一个名称来标识它。然后,用户可以在before_trading_start中获取其输出,并将其 存储在 context中:
#导入算法API 导入量子视线。算法的算法中
#从Quantopian 导入Risk API方法。Pipeline。实验性进口risk_loading_pipeline
def initialize (context ):#约束参数
context 。max_leverage = 1.0
上下文。max_pos_size = 0.015
上下文。max_turnover = 0.95
#附加数据Pipeline
算法。attach_pipeline (
make_pipeline (),'data_pipe' )
algo 。attach_pipeline (
risk_loading_pipeline (),'risk_pipe' )
#安排重新平衡功能
算法。schedule_function (
重新平衡,
ALGO 。date_rules 。week_start (),
算法中。time_rules 。market_open (), )
def before_trading_start (上下文,数据):#获取Pipeline输出,并将其存储在上下文
context中。pipeline_data = 算法。pipeline_output ('data_pipe' )
情境。risk_factor_betas = algo 。pipeline_output ('risk_pipe' )
下一步是将RiskModelExposure约束添加到投资组合优化逻辑中。该约束条件采用了风险模型生成的数据,并限制了用户目标投资组合对模型中包含的每个因素的总体敞口。
#限制目标投资组合的风险敞口#默认情况下,最大行业敞口设置为#0.2,最大样式敞口设置为0.4
factor_risk_constraints = opt 。实验的。RiskModelExposure (
背景。risk_factor_betas ,
版本= 选择。最新)
最后,以下算法涵盖了用户的策略和投资组合构建逻辑,并准备进行回测。克隆算法后,通过单击IDE右上角的“运行完整回测”来运行完整回测。
#导入算法API 导入量子视线。算法的算法中
#Import Optimize API 导入Quantopian 。优化的选择
#从Quantopian 导入Pipeline。Pipeline进口Pipeline从quantopian 。Pipeline。数据。psychsignal 进口stocktwits
从quantopian 。Pipeline。因素导入SimpleMovingAverage
#从quantopian 导入内置的Universe和Risk API方法。Pipeline。过滤器导入QTradableStocksUS 从quantopian 。Pipeline。实验性进口risk_loading_pipeline
def initialize (context ):#约束参数
context 。max_leverage = 1.0
上下文。max_pos_size = 0.015
上下文。max_turnover = 0.95
#附加数据Pipeline
算法。attach_pipeline (
make_pipeline (),'data_pipe' )
algo 。attach_pipeline (
risk_loading_pipeline (),'risk_pipe' )
#安排重新平衡功能
算法。schedule_function (
重新平衡,
ALGO 。date_rules 。week_start (),
算法中。time_rules 。market_open (), )
def before_trading_start (上下文,数据):#获取Pipeline输出,并将其存储在上下文
context中。pipeline_data = 算法。pipeline_output ('data_pipe' )
情境。risk_factor_betas = algo 。pipeline_output ('risk_pipe' )
#Pipeline定义def make_pipeline ():
sentiment_score = SimpleMovingAverage (
输入= [ stocktwits 。bull_minus_bear ],
window_length = 3 ,
掩模= QTradableStocksUS () )
返回Pipeline(
列= { 'sentiment_score' :sentiment_score ,},
屏幕= sentiment_score 。NOTNULL () )
ef rebalance (上下文,数据):#从Pipeline输出
alpha = context中检索alpha 。pipeline_data 。情感分数
如果不是alpha 。空:#创建MaximizeAlpha目标
target = opt 。MaximizeAlpha (alpha )
#创建位置大小约束
constrain_pos_size = opt 。PositionConcentration 。with_equal_bounds (- 背景。max_pos_size ,
情境。max_pos_size
)
#限制目标投资组合的杠杆率
max_leverage = opt 。MaxGrossExposure (上下文。max_leverage )
#确保长书和短书#的大小大致相同
dollar_neutral = opt 。美元中性()
#限制投资组合周转率
max_turnover = opt 。MaxTurnover (上下文。max_turnover )
#限制目标投资组合的风险敞口#默认情况下,最大行业敞口设置为#0.2,最大样式敞口设置为0.4
factor_risk_constraints = opt 。实验的。RiskModelExposure (
背景。risk_factor_betas ,
版本= 选择。最新)
#使用目标#和约束
算法列表重新平衡投资组合。order_optimal_portfolio (
客观= 客观,
约束= [
constrain_pos_size ,
max_Leverage ,
dollar_neutral ,
max_turnover ,
factor_risk_constraints ,] )
回测分析
回测完成后,单击“笔记本”选项卡。
这将显示带有以下代码的研究笔记本:
bt = get_backtest ('5a4e4faec73c4e44f218170a' )
bt 。create_full_tear_sheet ()
注意:笔记本中的字母数字字符串将不同于上面显示的字符串。该字符串是用户的回测在Quantopian中的唯一标识符。也可以在完整的回测结果页面的URL中找到它。
执行此单元格(Shift + Enter)会将用户的回测生成的数据加载到研究笔记本中,并使用它来创建 Pyfolio撕纸。Pyfolio是Quantopian用于投资组合和风险分析的开源工具。它提供了许多可视化工具,旨在帮助用户更好地了解算法的行为以及随着时间的推移所面临的风险。例如,下图显示了用户的投资组合随时间推移的市场滚动风险。用户要构建多头-空头股票交易算法的原因之一是要保持与市场的低相关性,因此用户希望该图在整个回测期间始终保持在0附近。
Pyfolio的另一个有趣的部分是性能归因部分。下图使用Quantopian的风险模型来说明可以将多少收益归因于用户的策略,以及其中多少来自共同的风险因素。
用户可以从上面看到,用户投资组合的大部分总收益来自特定收益。这表明算法的性能并非来自于常见风险因素,这是一件好事。
四、公司优势和不足
公司同行业可比标的主要有Quantconnect,Numerai WorldQuant的WebSim。这些平台也选择了走"群众化"之路,为用户提供包括略编写、回测等方面的服务。不同之处在于,WorldQuant专注于更为基础的量化投资分析。其中,杰出的算法作者还有机会成为平台的兼职研究顾问。目前,该平台兼职顾问人数已经超过500,相当于WorldQuant的正式员工数量。其它平台提供策略研发环境的经营方式不同,Numerai提供的是一个协作平台。它的独特之处还在于其以众包解决问题的方式更能代表“群体工作”。
自从2015年开始我国量化基金市场开始崛起,量化投资受关注度迅速上升,量化基金的技术服务也收到了关注,各类基于A股的算法交易开发平台纷纷出现,最早成立的一批公司例如优矿、聚宽等,都是模仿Quantopian的业务模式,基于Quantopian的Zipline开源量化交易库进行二次开发。
相比于服务于机构类客户的算法和策略开发平台,因为这些公司运用C++语言开发策略,Quantopian策略开发和回测速度不如这类公司,从技术角度,相比于现在为机构类客户提供服务的金融科技供应商而言,其在技术和数据角度不足明显。
不仅如此,线上策略开发不可避免的存在策略及数据保密性的问题。并且目前策略尚不能支持公司大规模持续性获得盈利,2018 年Quantopian公司CEO离职时表示2017年4月推出的基金收益率远未达到预期,众包基金远低于预期的收益率也使得作为资金方的对冲基金投资较为谨慎,一家对冲基金对Quantopian算法分配高达2.5亿美元的投资资金,与之曾管理高达130亿美元的总净资产相比,这是一个明显的下降。
华鑫证券私募基金研究中心课题组联系人:
周韬雄 课题组研究员
电话:021- 54967619
邮箱:zhoutx@cfsc.com.cn
蔺钰尧 课题组研究员
电话:021-54967852
邮箱:linyy@cfsc.com.cn