Quantopian教程系列四

Writing a Contest Algorithm

本教程将:
给一个概述的quant竞赛和它是如何工作的(第一课)。

  • 浏览竞赛算法所需的每个标准(课程2-10)。
  • 就如何编写或修改算法以满足竞赛标准提供指导(课程2-10)。
  • 向您展示如何测试您的算法是否符合竞赛标准(第十一课)。

本教程不会:
教你如何研究和实现一种quant策略(为此,你应该参考入门教程)。

lession 1 introduction

Contest Overview

  • 这个比赛每天都会给写在quant上的顶级定量交易算法颁发现金奖励。该竞赛旨在评估具有代表性的多空股票策略。因此,contest算法需要具有一定的结构属性。本教程将简要介绍contest如何工作,然后介绍每个必需的结构属性,并提供如何满足这些需求的指导。

标准

  • 为了参加比赛,算法需要满足一组特殊的标准。这些标准用于选择具有代表性的多空股票策略。算法需要具备以下属性才能参加比赛:

1.正回报。
2.利用0.8倍- 1.1倍之间的杠杆。
3.比较低的头寸集中度。
4.beta-to-SPY很低。
5.中等换手率。
6.多头和空头头寸。
7.在流动性好的股票之间交易。
8.行业风险敞口低。
9.对风格风险的低暴露。
10.使用优化API下订单。

  • 有关所需标准的所有细节,请参阅比赛的官方规则。本教程的第11课有一个笔记本,您可以使用它来查看您的backtest是否通过了所有的竞赛标准。
    竞赛标准在2年的回测中被检查,并且每天重新检查你的算法在竞赛中的表现。如果你的算法在任何时候都不符合一个或多个条件,它将从竞赛中退出。如果您的算法被取消,您可以修改它,使它满足所有的条件,然后重新提交它。
    本教程后面将更详细地讨论和解释每个标准。每节课都集中讨论其中的一个需求,并提供如何编写满足每个标准的算法的建议。

提交一个算法

  • 要参加比赛,你需要编写一个算法,运行一个完整的backtest,然后点击’ enter contest '。在参加比赛后,您的算法将被回测从2年前直到最近的交易日。比赛标准将在2年内进行测试。如果你的算法通过了所有的标准,它将在下一个交易日后被评分和排名,并出现在排行榜上。如果你的算法没有达到任何一个标准,你将会收到一封电子邮件,告诉你你的项目被撤回了,连同你的特定标准都失败了。

得分及排名

  • 满足所有结构标准的竞赛算法在每个交易日之后根据分数进行排名。算法的得分是基于它的样本外收益和波动性。算法获得了高回报和低波动性的高分。
  • 算法提交后的每一天,算法的日收益除以跟踪的63个交易日的波动率,计算波动率调整日收益(VADR)。该算法的分数是该算法提交竞赛以来的vadr之和。
  • 在每个交易日结束时,参与者根据他们提交的最高分进行排名。每天排名前十的参与者将获得现金奖励。

lesson 2 Order with Optimize API

要求是什么?

  • 您的算法需要使用order_optimal_portfolio函数下所有订单。这是优化API的核心功能,也是在quant上将投资组合从一种状态移动到另一种状态的最佳方法。比赛中不允许使用quantapi中的其他排序方法。

为什么需要它?

  • order_optimal_portfolio函数是我们内部实时交易基础结构中支持的惟一一个订购函数。每个接收到分配的人都必须更新该算法以使用优化API。我们正在引导社区在流程的一开始就使用优化API,而不是在最后才使用它。这将使模拟成为一个更好的预测交易性能。

你怎样才能满足这个要求呢?

入门教程的第7课教你如何使用order_optimal_portfolio下订单。通读这一课是学习order_optimal_portfolio基础知识的最佳方法。为了满足这个需求,您需要使用order_optimal_portfolio将您的投资组合从一个状态移动到另一个状态。

lesson 3 Liquid Universe

要求是什么?

  • 你的算法必须只投资于QTradableStocksUS资产池(简称QTU)的股票。

为什么需要它?

  • 你的战略体系是它的基础。您希望资产池尽可能大,但是只包含与平台功能相匹配的资产。对于quant,这意味着我们可以可靠地找到数据的资产,适合我们的风险管理,我们可以在一个多算法的投资组合中使用,我们可以以合理的交易成本进行交易。QTradableStocksUS是满足这些quant需求的最大的资产池。此外,QTradableStocksUS的所有组成部分都包含在风险模型中。

你怎样才能满足这个要求呢?

  • 使用 QTradableStocksUS pipeline 过滤器作为你的基础。通常,这可以通过简单地在pipeline中设置screen=QTradableStocksUS来实现(如果您不熟悉pipeline,请参阅管道教程)。如果您计算了管道外的资产权重/预期阿尔法,那么在将股票传递给order_optimal_portfolio之前,您可能需要检查您想要订购的股票是否在QTU中。有一些宽松内建的竞赛要求-竞赛算法在技术上要求有至少95%的资本投资于股票的QTU,所以你有一些时间来调整你的投资组合,如果你的算法持有的股票跌出了QTU。
  • 下面是一个提供QTradableStocksUS示例:
from quantopian.pipeline import Pipeline
from quantopian.pipeline.experimental import QTradableStocksUS

def make_pipeline():

    return Pipeline(
        columns={
            # Your pipeline columns go here.
        },
        screen=QTradableStocksUS()
    )
  • 注意,有多种方法可以使用pipeline过滤器,如QTradableStocksUS。有时将其作为筛选提供是合适的,有时可能需要将其作为掩码提供给另一个pipeline术语。要了解有关过滤器和pieline的更多信息,请参阅pipeline教程。

lesson 4 Position Concentration

要求是什么?

  • 你的算法不能在任何一项资产上投资超过其资本基础的5%。

为什么需要它?

  • 在任何一种资产上投资过多,都会使算法暴露于头寸风险。如果你的大部分资本投资于一项资产,而该资产的价格发生显著变化,那么你的投资组合的价值也会发生显著变化。通过对大量资产进行几笔规模较小的投资,可以降低资产大幅缩水的风险。

你怎样才能满足这个要求呢?

  • 当您调用order_optimal_portfolio时,包含一个PositionConcentration约束。例如,你可以像这样定义1%的头寸集中度:
import quantopian.algorithm as algo
import quantopian.optimize as opt

MAX_SHORT_POSITION_SIZE = 0.01  # 1%
MAX_LONG_POSITION_SIZE = 0.01   # 1%

# Define the position concentration constraint.
constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
    -MAX_SHORT_POSITION_SIZE,
    MAX_LONG_POSITION_SIZE,
)

# Supply the constraint to order_optimal_portfolio.
algo.order_optimal_portfolio(
    objective=my_objective, #Fill in with your objective function.
    constraints=[
        constrain_pos_size,
    ],
)
  • 即使头寸集中度限制是5%,在您的算法中设置一个较低的限制也是一个好主意。价格波动可能导致您的算法暂时持有超过您指定的限制的头寸。通过留下一个缓冲,你大大减少了超过5%的竞争限制的几率(以及你的头寸风险!)

lesson 5 Long/Short

要求是什么?

  • 您的算法的净美元风险敞口不能超过10%。这意味着一个竞赛算法的多头和空头不能有超过10%的差异(以总资本基数的10%衡量)。如果你的算法投入了100%的资本,无论是多头投资还是空头投资都不能超过投资的55%。

为什么需要它?

  • 横断式的多空股票策略旨在押注资产相对于全球其它资产的预期价值。如果股票A预计将上升10%,股票B预计将上升5%,横断面的策略可能会打开一个在股票多头A和空头股票B,押注A的价格股票价格将增加超过股票B .因此,横断面,多空股票策略不应该偏见在多或空的方向。由于竞赛是为这些类型的策略选择,因此需要多空的平衡。
    要了解更多有关横截面、多空股票策略的信息,请参阅本讲座。

你怎样才能满足这个要求呢?

  • 在调用order_optimal_portfolio时包含一个与美元无关的约束。下面是一个美元中性约束的例子:
import quantopian.algorithm as algo
import quantopian.optimize as opt

# Define the dollar neutral constraint.
dollar_neutral = opt.DollarNeutral()

# Supply the constraint to order_optimal_portfolio.
algo.order_optimal_portfolio(
    objective=my_objective, #Fill in with your objective function.
    constraints=[
        dollar_neutral,
    ],
)
  • 即使有了美元中性约束,你的多、空投资组合的规模也可能略有不同。这是由你持有的投资组合的价格波动造成的。例如,如果你所有的多头头寸都升值了,而你的空头头寸保持不变,那么你的多头头寸的价值就会增加。只要你的持仓集中度较低(你的投资分散在许多资产上),并且你经常进行再平衡(每两周一次或更频繁),美元中性的约束应该会使你保持在10%的净敞口限制之下。

lesson 6 Turnover

要求是什么?

  • 你的算法必须有5%-65%的日均成交量,在63个交易日的滚动窗口中计算。周转率范围从0-200%(200%意味着你的资本完全从一套资产转移到另一套资产)。这意味着在一个竞赛算法中的头寸平均保持约3-40天。

为什么需要它?

  • 5%的下限之所以存在,是因为交易(“押注”)频率较低的算法需要更多时间来评估其性能。一个算法的交易频率越高,它积累大量样本外交易的速度就越快。营业额的下限要求算法做出积极的决策。
    目前,风险模型不支持平均持仓时间不超过2-3天的算法。风险模型不能准确地评估日内交易量较大的算法。同时,高周转率会导致更高的交易成本,所以避免高周转率通常是一个好主意。

你怎样才能满足这个要求呢?

  • 决定成交量的算法有两个组成部分:阿尔法信号的波动性和交易频率。
    在研究阶段,你应该使用 alphalens 来确定你的阿尔法信号的波动性。对于比赛,你应该选择一个预测周期为3-40天的因子。
  • 一旦你有了一个合适的预测范围的信号,你就可以通过你的算法的再平衡计划来进一步控制你的营业额。竞赛算法应该使用schedule_function以每天或每周的频率进行交易。你的算法的准确交易频率应该取决于你预期的持有期。你应该尝试不同的交易频率,用Pyfolio分析你的回测的成交量。举个例子,你可以使用下面的代码来安排一个 my_rebalance 函数每天运行:
def initialize(context):
    # Schedule our reblance function to run every day, 45 minutes after
    # market open.
    schedule_function(
        func=my_rebalance,  
        date_rule=date_rules.every_day(),  
        time_rule=time_rules.market_open(hours=0,minutes=45)
    )

def my_rebalance(context, data):
    # Ordering/rebalance logic goes here.

lesson 7 leverage

要求是什么?

  • 您的算法必须保持在0.8x 1.1x总杠杆之间,在每天结束时检查。这意味着你的算法需要在任何时候都投入80%到110%的名义资本。例如,如果资本基础为1000万美元,500万美元投资于多头,500万美元投资于空头,那么杠杆率将达到1倍(100%投资),并满足竞赛的要求。

为什么需要它?

  • 杠杆率的上限是一个标准化的过程,这样竞争算法就可以在相同的投资资本规模上进行评估。下限已经到位,因此contest算法始终保持对美国股票的投资,而不是在一段时间内持有现金。这与我们的分配过程是一致的。
    此外,杠杆率在一天结束时进行检查,这意味着算法必须在一夜之间保持其头寸。这是必要的,因为当前版本的quantrisk模型被设计用来衡量至少在一个市场接近休市期间持有的头寸的风险敞口。

你怎样才能满足这个要求呢?

  • 为了控制算法的最大影响,您应该在调用order_optimal_portfolio时提供MaxGrossExposure约束。下面是一个使用MaxGrossExposure约束调用order_optimal_portfolio以使投资组合的杠杆率保持在1倍的例子:
import quantopian.algorithm as algo
import quantopian.optimize as opt

MAX_GROSS_LEVERAGE = 1.0  # 1x

# Define the max leverage constraint.
constrain_gross_leverage = opt.MaxGrossExposure(MAX_GROSS_LEVERAGE)

# Supply the constraint to order_optimal_portfolio.
algo.order_optimal_portfolio(
    objective=my_objective, #Fill in with your objective function.
    constraints=[
        constrain_gross_leverage,
    ],
)
  • 即使使用MaxGrossExposure约束,您的算法的投资组合的杠杆率也可能超过1倍。这有几个原因。上下文最大1.1倍杠杆被设计用来提供一个缓冲区,这样算法可以投资1x,而不会因为偶尔超过1x而被取消资格。通过持有大量资产可以进一步缓解杠杆率的波动。
  • 为了满足最小的杠杆需求,您必须提供一个目标函数,其中包含大量的股票到order_optimal_portfolio。与杠杆的上限不同,下限不能用约束来控制。将一个目标函数传递给order_optimal_portfolio,该函数覆盖大量资产(大多数情况下为100个或更多),这将使优化API有机会在投资其所有资本时找到满足所有提供的约束的投资组合。

lesson 8 Beta-to-SPY

要求是什么?

你的算法不能与市场相关。具体来说,你的算法必须有一个绝对beta-to-SPY低于0.3。

为什么需要它?

一个算法需要有低的市场风险,以使它有资格分配审议。如果你的算法与股票市场的其他部分相关,那么这个算法提供的质量与购买市场指数没有什么不同。因此,这场竞赛要求算法保持市场中立。

你怎样才能满足这个要求呢?

要编写一个市场中性策略,你需要确保你的阿尔法信号与市场不相关。根据定义,阿尔法因素应该独立于市场整体运行。如果你的阿尔法信号是市场中立的,你的算法应该能够使用由阿尔法信号决定的权向量的最大化阿尔法目标。
另一种控制算法的beta-to-SPY的方法是使用历史上每个资产的beta-to-SPY为order_optimal_portfolio提供FactorExposure约束。然而,这种方法基于一个重要的假设,即组合我们投资组合中每种资产的历史 beta -to- spy 是一个很好的预测明天我们投资组合回报 beta-to- spy 的指标。这并不一定适用于所有的算法,所以它可能不适用于特定的策略。下面是一个FactorExposure的例子,它使用的是历史上每项资产的beta-to-SPY值:

import quantopian.algorithm as algo
import quantopian.optimize as opt

from quantopian.pipeline import Pipeline
from quantopian.pipeline.factors import SimpleBeta

def initialize(context):
    # Define the beta-to-SPY factor in Pipeline.
    beta = SimpleBeta(
                    target=sid(8554),
                    regression_length=260,
                    )

    pipe = Pipeline(
        columns={
            'beta': beta,
        },
        screen=beta.notnull(),
    )
    algo.attach_pipeline(pipe, 'pipe')

def before_trading_start(context, data):
    # Get the pipeline data every day.
    context.pipeline_data = algo.pipeline_output('pipe')

def do_portfolio_construction(context, data):
    pipeline_data = context.pipeline_data

    # Define the beta constraint to be +/- 0.05 beta-to-SPY based 
    # on historical per-asset beta.
    beta_neutral = opt.FactorExposure(
        pipeline_data[['beta']],
        min_exposures={'beta': -0.05},
        max_exposures={'beta': 0.05},
    )

    # Supply the constraint to order_optimal_portfolio.
    algo.order_optimal_portfolio(
        objective=my_objective, #Fill in with your objective function.
        constraints=[
            beta_neutral,
        ],
    )

lesson 9 Risk Model Exposure

要求是什么?

  • 你的算法对每个行业的风险敞口必须小于20%,这是根据quantrisk模型定义的。风险模型分为11个部分:
  1. 基本材料
  2. 技术
  3. 房地产
  4. 能源
  5. 通信服务
  6. 卫生保健
  7. 金融服务
  8. 周期性消费
  9. 工业
  10. 防御性消费
  11. 公用事业公司
  • 在quantrisk模型中,你的算法对每种风格因素的暴露程度也必须低于40%。风险模型中有5个风格因素:
  1. 大小
  2. 价值
  3. 趋势
  4. 短期逆转
  5. 波动
  • 在quantrisk模型中,风险因素的暴露量被测量为63个交易日滚动窗口的平均净暴露量。每天,每个部门的滚动平均净风险敞口必须在-20%到20%之间,而每个风格因素的滚动平均净风险敞口必须在-40%到40%之间。如果您的算法过度暴露于任何行业或风格因子,它将没有资格在竞赛中运行。

为什么需要它?

  • 风险模型的定义是对市场的一种特殊看法。quantrisk模型的目的是识别特定的风险敞口,这是quant的投资者客户所期望的。比赛的目标之一是激励算法的建设,可以考虑分配。将风险模型中的因素保持在较低水平,可以让你的算法与quant的分配过程保持一致。

你怎样才能满足这个要求呢?

  • 有两种方法可以限制你Quantopian Risk Model。第一种方法是构造一个独立于任何行业或风格因子的阿尔法因子。这通常是在研究阶段分析你的阿尔法因子的特性时完成的。
  • 限制你暴露在quantrisk模型中的风险因子的另一种方法是向order_optimal_portfolio提供约束。您可以使用risk_loading_pipeline来获取每个资产的历史风险因素风险敞口。然后,您可以通过向order_optimal_portfolio提供RiskModelExposure约束来根据这些历史风险来约束您的投资组合。
  • 下面是一个示例算法,它将投资组合限制在默认的暴露限制内(每个行业18%,每个风格36%):
import quantopian.algorithm as algo
import quantopian.optimize as opt

from quantopian.pipeline.experimental import risk_loading_pipeline  

def initialize(context):
    # Attach the risk loading pipeline to our algorithm.
    algo.attach_pipeline(risk_loading_pipeline(), 'risk_loading_pipeline')

def before_trading_start(context, data):
    # Get the risk loading data every day.
    context.risk_loading_pipeline = pipeline_output('risk_loading_pipeline')

def place_orders(context, data):  
    # Constrain our risk exposures. We're using version 0 of the default bounds
    # which constrain our portfolio to 18% exposure to each sector and 36% to
    # each style factor.
    constrain_sector_style_risk = opt.experimental.RiskModelExposure(  
        risk_model_loadings=context.risk_loading_pipeline,  
        version=0,
    )

    # Supply the constraint to order_optimal_portfolio.
    algo.order_optimal_portfolio(  
        objective=my_objective,  #Fill in with your objective function.
        constraints=[constrain_sector_style_risk],  
    )
  • 每个行业的默认风险敞口限制在18%,每种风格的风险敞口限制在36%。这些约束低于20%和40%的各自限制,因为我们使用历史风险敞口来约束我们第二天的投资组合。明天的曝光量可能与过去不同,所以缓冲会给你留下一点空间,让你在竞争限制下保持平衡。
  • 有些风险敞口比其他风险敞口更稳定。例如,随着时间的推移,每项资产的风险敞口往往不会像某些风格因素那样变化那么大。短期反转风险因素往往变化最大,因为它是在14天的跟踪窗口计算的。如果您在控制该因素的风险敞口方面遇到困难,您可以尝试覆盖36%历史风险敞口的默认约束。为此,您可以修改传递给order_optimal_portfolio的约束,使其如下所示:
constrain_sector_style_risk = opt.experimental.RiskModelExposure(  
    risk_model_loadings=context.risk_loading_pipeline,  
    version=0,  
    min_momentum=-0.1,  
    max_momentum=0.1,  
)
  • 最后,您可以将RiskModelExposure的版本设置为一个特定的版本(上面的版本=0),或者您可以将它设置为version=opt。使您的算法始终使用最新版本的默认值。对于比赛,您应该选择一个特定的版本来使用,因为您不知道您的算法将如何受到更改默认值的影响。

lesson 10 Positive Returns

为什么

  • 你的算法必须有正的回报。从你提交比赛的那一天开始,每天都要检查你的成绩。回报是在你提交比赛前两年开始计算的,直到最近的一个交易日。为了让算法在竞争中保持活跃,算法的返回值必须大于0。

你怎样才能满足这个要求呢?

写一个赚钱的策略的最好的方法是有一个样本外的阿尔法因子。如果你很难找到这样一个因素,你应该尝试通过社区论坛或系列讲座来寻找想法,或者研究一些其他可以在quant上找到的数据。之后,按照入门教程中介绍的方法,将你的想法转化为使用Alphalens和Pyfolio的算法。

lesson 11 Testing If Your Algorithm Meets the Criteria

  • 在提交你的算法到比赛之前,你可以测试它是否符合标准。要做到这一点,运行一个完整的backtest从2年前直到最近的交易日。当您的backtest完成后,从URL中复制backtest ID。URL的结构如下:
    https://www.quantopian.com/algorithms/ALGORITHM_ID/BACKTEST_ID
    然后,克隆这个笔记本并将您的backtest ID复制到第一个单元格中的get_backtest函数中。最后,运行笔记本中的所有单元并在底部查找报告。它应该是这样的:
    Quantopian教程系列四_第1张图片

你可能感兴趣的:(学习笔记)