Quantopian

介绍(Lesson1)

欢迎来到Quantopian!入门教程将指导你通过Quantopian来研究和开发定量交易策略,它涵盖了Quantopian API的许多基础知识,并且是为平台新手设计的。要开始学习本教程,您需要具备一些基本的Python编程技能。

什么是交易算法?

交易算法是一种计算机程序,它定义了一组买卖资产的规则。大多数交易算法都是基于对历史数据研究得出的数学或统计模型来做出决策。

如何开始?

编写交易算法的第一步是找到可以建立策略基础的经济或统计关系。为此,我们可以使用Quantopian的研究环境访问和分析平台中可用的历史数据集。这个研究是Jupyter Notebook环境,它允许我们以称为“cell”的单元运行Python代码。例如,以下代码绘制了苹果公司(AAPL)的每日收盘价,以及其20天和50天移动平均线:

# Research environment functions
from quantopian.research import prices, symbols

# Pandas library: https://pandas.pydata.org/
import pandas as pd

# Query historical pricing data for AAPL
aapl_close = prices(
    assets=symbols('AAPL'),
    start='2013-01-01',
    end='2016-01-01',
)

# Compute 20 and 50 day moving averages on
# AAPL's pricing data
aapl_sma20 = aapl_close.rolling(20).mean()
aapl_sma50 = aapl_close.rolling(50).mean()

# Combine results into a pandas DataFrame and plot
pd.DataFrame({   
    'AAPL': aapl_close,
    'SMA20': aapl_sma20,
    'SMA50': aapl_sma50
}).plot(
    title='AAPL Close Price / SMA Crossover'
);

要使用上面的代码副本并将其粘贴到Research中的新笔记本中,或单击本课程右上角的“Get Notebook”按钮。进入研究模式后,按Shift + Enter键即可运行单元格。 输出应如下所示:

在下一节中,我们将使用Research探索Quantopian的数据集。然后,我们将定义我们的交易策略并根据历史数据测试它是否可以有效地预测回报。最后,我们将使用我们的发现在IDE(集成开发环境)中开发和测试交易算法。

数据探索(Lesson2)

第2-4课将在研究环境中进行。要在“研究”中进行设置,请点击下面的“Get Notebook”,以创建一个新笔记本或克隆本课程的笔记本版本。

数据探索

从2002年到最近完成的交易日,研究提供实用程序功能来查询8000多种美国股票的价格,数量和回报数据。这些函数获取资产(或资产列表)以及开始和结束日期,并返回按日期索引的pandas Series (或DataFrame)。让我们定义我们要探索的时间段,并使用returns函数来查询AAPL的数据:

# Research environment functions
from quantopian.research import returns, symbols

# Select a time range to inspect
period_start = '2014-01-01'
period_end = '2014-12-31'

# Query returns data for AAPL
# over the selected time range
aapl_returns = returns(
    assets=symbols('AAPL'),
    start=period_start,
    end=period_end,
)

# Display first 10 rows
aapl_returns.head(10)

替代数据

除了定价和数量数据外,Quantopian还集成了许多其他数据集,包括公司基本面,股票情绪分析和共识估计等。您可以在Quantopian的数据参考中找到完整的数据集列表。

在本教程中,我们的目标是建立一种基于情感数据选择和交易资产的算法,因此让我们看一下PsychSignal的StockTwits Trader Mood数据集。PsychSignal的数据集根据金融通讯平台Stocktwits上发布的消息的总体情绪,每天为股票分配牛市和熊市得分。

我们可以从检查stocktwits数据集中的消息量和情绪得分(牛市减去熊市)列开始。我们将使用Quantopian的Pipeline API查询数据,这是一个功能强大的工具,您将反复使用它来访问和分析Research中的数据。在下一课和后续教程中,您将学到更多关于Pipeline API的知识。现在,您只需要知道以下代码使用数据管道查询stocktwits并返回数据,并为AAPL绘制结果:

# Pipeline imports
from quantopian.research import run_pipeline
from quantopian.pipeline import Pipeline
from quantopian.pipeline.factors import Returns
from quantopian.pipeline.data.psychsignal import stocktwits

# Pipeline definition
def make_pipeline():

    returns = Returns(window_length=2)
    sentiment = stocktwits.bull_minus_bear.latest
    msg_volume = stocktwits.total_scanned_messages.latest

    return Pipeline(
        columns={
            'daily_returns': returns,
            'sentiment': sentiment,
            'msg_volume': msg_volume,
        },
    )

# Pipeline execution
data_output = run_pipeline(
    make_pipeline(),
    start_date=period_start,
    end_date=period_end
)

# Filter results for AAPL
aapl_output = data_output.xs(
    symbols('AAPL'),
    level=1
)

# Plot results for AAPL
aapl_output.plot(subplots=True);

探索数据集时,请尝试查找可能用作交易策略基础的模式。例如,上图显示了每日收益与股票交易消息量之间的一些匹配峰值,并且在某些情况下,收益的峰值方向与AAPL的情绪得分方向一致。这看起来很有趣,我们应该进行更严格的统计检验以确认我们的假设。

在下一课中,我们将更深入地介绍Pipeline API。

管道API(Lesson3)

管道API是对资产进行剖面分析的一种强有力的工具。它允许我们在多个数据输入上定义一组计算,并一次分析大量资产。管道API的一些常见用法包括:

  1. 根据筛选规则选择资产
  2. 根据评分功能对资产进行排序
  3. 计算资产分配情况

在开始时,先引入管道类,然后创建一个返回空管道的函数。将管道定义放在函数里面,这可以帮助我们在管道变得越来越复杂的时候进行有效组织。这些在研究和IDE中传输数据管道时特别有用。

# Pipeline class
from quantopian.pipeline import Pipeline

def make_pipeline():
    # Create and return an empty Pipeline
    return Pipeline()

为了将输出添加到管道中,我们需要包含对数据集的引用,并且指定对该数据所执行的计算。举个例子,我们将在USEquityPricing数据集的close队列中添加一个引用。接着,我们就能将输出定义为本队列的最新值如下所示:

# Import Pipeline class and USEquityPricing dataset
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import USEquityPricing

def make_pipeline():
    # Get latest closing price
    close_price = USEquityPricing.close.latest

    # Return Pipeline containing latest closing price
    return Pipeline(
        columns={
            'close_price': close_price,
        }
    )

管道API还提供了许多内置的计算,其中一些计算是通过数据的尾随窗口进行的。举个例子,下面的代码导入了Psychsignal的stocktwits数据集,并且将输出定义为bull_minus_bear队列的三天移动的平均值:

# Import Pipeline class and datasets
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import USEquityPricing
from quantopian.pipeline.data.psychsignal import stocktwits

# Import built-in moving average calculation
from quantopian.pipeline.factors import SimpleMovingAverage


def make_pipeline():
    # Get latest closing price
    close_price = USEquityPricing.close.latest

    # Calculate 3 day average of bull_minus_bear scores
    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    # Return Pipeline containing close_price
    # and sentiment_score
    return Pipeline(
        columns={
            'close_price': close_price,
            'sentiment_score': sentiment_score,
        }
    )

普遍的选择

制定策略的一个重要部分是定义我们想要在我们的投资组合中考虑交易的资产集。我们通常把这组资产称为我们的交易空间。交易的范围应该尽可能的大,同时也要排除那些不适合我们投资组合的资产。例如,我们可能希望排除流动性差或交易困难的股票。

环球公司的QTradableStocksUS就提供了这一特点。我们可以使用管道构造函数的屏幕参数将QTradableStocksUS设置为我们的交易空间:

# Import Pipeline class and datasets
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import USEquityPricing
from quantopian.pipeline.data.psychsignal import stocktwits

# Import built-in moving average calculation
from quantopian.pipeline.factors import SimpleMovingAverage

# Import built-in trading universe
from quantopian.pipeline.experimental import QTradableStocksUS


def make_pipeline():
    # Create a reference to our trading universe
    base_universe = QTradableStocksUS()

    # Get latest closing price
    close_price = USEquityPricing.close.latest

    # Calculate 3 day average of bull_minus_bear scores
    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    # Return Pipeline containing close_price and
    # sentiment_score that has our trading universe as screen
    return Pipeline(
        columns={
            'close_price': close_price,
            'sentiment_score': sentiment_score,
        },
        screen=base_universe,
    )

现在管道定义已经完成,我们可以使用run_pipeline在一段特定的时间内执行它。输出将是根据日期和资产建立索引的panda DataFrame,其中的队列对应于我们添加到管道定义中的输出:

# Import run_pipeline method
from quantopian.research import run_pipeline

# Execute pipeline created by make_pipeline
# between start_date and end_date
pipeline_output = run_pipeline(
    make_pipeline(),
    start_date='2013-01-01',
    end_date='2013-12-31'
)

# Display last 10 rows
pipeline_output.tail(10)

在下一课中,我们将形式化我们的算法用于选择资产进行交易的策略。然后,我们将使用因子分析工具通过对历史数据的分析来评估我们的策略预测能力。

策略定义(Lesson4)

既然我们已经学会了如何访问和操作Quantopian内的数据,那么让我们为我们的多空股票策略构建一个数据管道。一般而言,多空股票策略包括建立资产相对价值的模型,并对那些我们确信会增加(多)和减少(空)最多的资产进行押注。

当高价值和低价值资产之间的收益差增加时,多空股票策略获利。多空股票策略的质量完全取决于其下属排名模型的质量。在本教程中,我们将使用一个简单的排名模式,我们的战略:

我们认为3天平均情绪得分高的资产价值高,3天平均情绪得分低的资产价值低。

策略分析

我们可以使用SimpleMovingAveragestocktwitsbull_minus_bear数据定义上面的策略,类似于我们在前一课中创建的管道:

# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.experimental import QTradableStocksUS


# Pipeline definition
def  make_pipeline():

    base_universe = QTradableStocksUS()

    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    return Pipeline(
        columns={
            'sentiment_score': sentiment_score,
        },
        screen=base_universe
    )

为了简单起见,我们将只分析根据sentiment_score排名的前350和后350只股票。我们可以使用我们的sentiment_score输出的topbottom方法为这些集合创建管道过滤器,并使用|操作符将它们组合起来以获得它们的并集。然后,我们将删除我们的可交易的领域之外的任何东西,使用&运算符来得到我们的过滤器和我们的领域之间的交集:

# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.experimental import QTradableStocksUS

# Pipeline definition
def  make_pipeline():

    base_universe = QTradableStocksUS()

    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    # Create filter for top 350 and bottom 350
    # assets based on their sentiment scores
    top_bottom_scores = (
        sentiment_score.top(350) | sentiment_score.bottom(350)
    )

    return Pipeline(
        columns={
            'sentiment_score': sentiment_score,
        },
        # Set screen as the intersection between our filter
        # and trading universe
        screen=(
            base_universe
            & top_bottom_scores
        )
    )

接下来,让我们在需要分析的时间段内执行管道。这大约需要1分钟。

# Import run_pipeline method
from quantopian.research import run_pipeline

# Specify a time range to evaluate
period_start = '2013-01-01'
period_end = '2016-01-01'

# Execute pipeline over evaluation period
pipeline_output = run_pipeline(
    make_pipeline(),
    start_date=period_start,
    end_date=period_end
)

除了我们的管线数据外,我们还需要这段时间内所有资产的定价数据。我们可以很容易地从管道输出的索引中获得这些资产的列表,并将该列表传递给prices,以获得我们需要的定价数据:

# Import prices function
from quantopian.research import prices

# Get list of unique assets from the pipeline output
asset_list = pipeline_output.index.levels[1].unique()

# Query pricing data for all assets present during
# evaluation period
asset_prices = prices(
    asset_list,
    start=period_start,
    end=period_end
)

现在我们可以使用Quantopian的开源因素分析工具Alphalens来测试我们选择策略的质量。首先,让我们使用get_clean_factor_and_forward_returns组合因子和定价数据。此函数将因子数据分类为分位数,并计算多个持有期内每个证券的远期回报。我们将把我们的因素数据分成2个分位数(上半部分和下半部分),并使用1天、5天和10天的持有期:

# Import Alphalens
import alphalens as al

# Get asset forward returns and quantile classification
# based on sentiment scores
factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=pipeline_output['sentiment_score'],
    prices=asset_prices,
    quantiles=2,
    periods=(1,5,10),
)

# Display first 5 rows
factor_data.head(5)

有了这种格式的数据,我们就可以使用Alphalens的一些分析和绘图工具。我们先来看整个时期内分位数的平均回报。因为我们的目标是建立一个多空策略,我们希望看到较低的分位数(1)有负回报,而较高的分位数(2)有正回报:

# Calculate mean return by factor quantile
mean_return_by_q, std_err_by_q = al.performance.mean_return_by_quantile(factor_data)

# Plot mean returns by quantile and holding period
# over evaluation time range
al.plotting.plot_quantile_returns_bar(
    mean_return_by_q.apply(
        al.utils.rate_of_return,
        axis=0,
        args=('1D',)
    )
);

我们还可以使用以下代码来绘制一个5天持有期的因素加权多空投资组合的累积回报率:

import pandas as pd
# Calculate factor-weighted long-short portfolio returns
ls_factor_returns = al.performance.factor_returns(factor_data)

# Plot cumulative returns for 5 day holding period
al.plotting.plot_cumulative_returns(ls_factor_returns['5D'], '5D', freq=pd.tseries.offsets.BDay());

上面的图表显示了一个很大的提款周期,这个分析还没有考虑到交易成本或市场影响。这不是一个很有前途的策略。在这一点上,我们真的应该使用Alphalens进行更深入的分析,然后对我们的战略思想进行迭代。但是在本教程中,让我们继续我们的策略。

定义并测试了一个策略之后,让我们使用它来构建和测试一个多空股票算法。本教程的其余部分将介绍算法API,并将在交互式开发环境(IDE)中进行。

算法API(Lesson5)

在上一课中,我们创建了一个数据管道,用于选择要为投资组合考虑的资产,并计算这些资产的alpha分数。剩下的课程将在Quantopian的交互式开发环境(IDE)中进行,在IDE中我们将构建一个交易算法,将我们的数据管道附加到它,并使用alpha分数来构建投资组合。然后,我们将通过对历史数据的模拟来分析我们的算法在更真实的条件下的性能。这种历史模拟通常被称为“回溯测试”。

算法API与核心函数

下一步将使用Quantopian的算法API为我们的交易算法构建一个基本结构。算法API提供了方便订单调度和执行的功能,并允许我们初始化和管理算法中的参数。

让我们来看看我们将在算法中使用的一些核心功能:

initialize(context)

当我们的算法开始运行并且需要上下文作为输入时,只调用一次initialize。任何参数初始化和一次性启动逻辑都应该放在这里。

context是一个扩展的Python字典,用于在整个仿真过程中维护状态,并且可以在我们算法的不同部分中引用。我们希望在函数调用之间持久化的任何变量都应该存储在上下文中,而不是使用全局变量。可以使用点表示法(Context.some_attribute)访问和初始化上下文变量。

before_trading_start(context, data)

在市场开盘前每天调用一次before_trading_start,需要上下文和数据作为输入。context是来自initialize的对同一个字典的引用,data是一个对象,它存储多个API函数,允许我们查找任何资产的当前或历史定价和卷数据。

在交易开始之前,也是我们获取管道输出的地方,在将其用于投资组合构建之前,对生成的数据进行任何预处理。我们将在下一课中讨论这个问题。

schedule_function(func, day_rule, time_rule)

在Quantopian上,算法可以在东部时间上午9:30-下午4:00之间的正常交易日交易股票,遵循纽约证券交易所的交易日历。schedule_函数允许我们在指定的日期和时间执行自定义函数。例如,我们可以安排一个函数,在每周第一天的开市交易中重新平衡我们的投资组合,如下所示:

schedule_function(
    rebalance,
    date_rule=date_rules.week_start(),
    time_rule=time_rules.market_open()
)      

调度函数应该在initialize中完成,使用此方法调度的自定义函数需要将上下文和数据作为参数。有关可用日期规则和时间规则的完整列表,请查看文档。

接下来,让我们为我们的交易算法构建一个框架。现在,我们将让我们的算法跟踪在模拟中经过的天数,并根据日期和时间记录不同的消息。在接下来的几节课中,我们将整合我们的数据管道并添加交易逻辑。

要运行此示例算法,请单击“克隆”按钮创建副本。进入IDE后,单击“构建算法”(左上角)或“运行完全反向测试”(右上角)运行反向测试。

# Import Algorithm API
import quantopian.algorithm as algo


def initialize(context):
    # Initialize algorithm parameters
    context.day_count = 0
    context.daily_message = "Day {}."
    context.weekly_message = "Time to place some trades!"

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        date_rule=algo.date_rules.week_start(),
        time_rule=algo.time_rules.market_open()
    )


def before_trading_start(context, data):
    # Execute any daily actions that need to happen
    # before the start of a trading session
    context.day_count += 1
    log.info(context.daily_message, context.day_count)


def rebalance(context, data):
    # Execute rebalance logic
    log.info(context.weekly_message)

现在我们已经有了一个交易算法的基本结构,让我们将上一课中创建的数据管道添加到我们的算法中。

算法中的数据处理(Lesson6)

下一步将是将我们在Research中内置的数据管道集成到我们的算法中。与Research的一个重要区别是,在回测期间,随着模拟的进行,我们的管道每天都会执行,因此我们不需要include start_dateend_date参数。

为了在算法中使用我们的数据管道,第一步是在算法的initialize函数中添加对其的引用 。这是使用attach_pipeline方法完成的 ,该方法需要两个输入:对Pipeline对象的引用 (我们使用make_pipeline构造 ),以及用于标识它的String名称。

# Import Algorithm API
import quantopian.algorithm as algo


def initialize(context):
    # Attach pipeline to algorithm
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        date_rule=algo.date_rules.week_start(),
        time_rule=algo.time_rules.market_open()
    )


def before_trading_start(context, data):
    pass


def rebalance(context, data):
    pass

如上所述,我们的管道将在每天开放市场之前处理数据流并生成输出。我们可以使用pipeline_output函数在before_trading_start中获得管道的输出,该函数采用在initialize中指定的管道命名,并返回由管道生成的pandas DataFrame。现在,我们可以使用重新平衡功能记录管道输出中的前10行。

# Import Algorithm API
import quantopian.algorithm as algo


def initialize(context):
    # Attach pipeline to algorithm
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        date_rule=algo.date_rules.week_start(),
        time_rule=algo.time_rules.market_open()
    )


def before_trading_start(context, data):
    # Get pipeline output and
    # store it in context
    context.pipeline_data = algo.pipeline_output(
        'data_pipe'
    )


def rebalance(context, data):
    # Display first 10 rows
    # of pipeline output
    log.info(context.pipeline_data.head(10))

现在,让我们将在Research中内置的make_pipeline函数添加到算法中。与其像我们分析时那样限制资产的数量,我们的算法应该考虑交易气氛中具有情感得分的所有资产。为此,我们可以使用sentiment_score输出的notnull方法 创建一个过滤器,并使用&运算符获取其与可交易Universe的交集。

# Import Algorithm API
import quantopian.algorithm as algo

# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.filters import QTradableStocksUS


def initialize(context):
    # Attach pipeline to algorithm
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        date_rule=algo.date_rules.week_start(),
        time_rule=algo.time_rules.market_open()
    )


def before_trading_start(context, data):
    # Get pipeline output and
    # store it in context
    context.pipeline_data = algo.pipeline_output('data_pipe')


def rebalance(context, data):
    # Display first 10 rows
    # of pipeline output
    log.info(context.pipeline_data.head(10))


# Pipeline definition
def make_pipeline():

    base_universe = QTradableStocksUS()

    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    return Pipeline(
        columns={
            'sentiment_score': sentiment_score,
        },
        screen=(
            base_universe
            & sentiment_score.notnull()
        )
    )

我们的算法每天都会选择一种可交易的资产范围,并产生可用于确定投资组合中资产分配的alpha分数。在下一课中,我们将学习如何根据数据管道生成的alpha分数来构建最佳投资组合。

投资组合管理(Lesson7)

在之前的课程中,我们将数据管线合并到了我们的交易算法,现在是时候去定义我们的算法将会如何基于管线产生的alpha分数去重新调整他的投资组合。我们的目标是找一个目标投资组合,在保持一组被一系列规则或约束特定的结构的同事,根据alpha分数最大化返回。这是通常被提到的投资组合最优化问题。

Quantopian的Optimize API使我们可以轻松地将管道的输出转化为目标和一组约束。然后,我们可以使用order_optimal_portfolio将当前投资组合转换为满足我们规格的目标投资组合。

第一步是去定义一个目标,我们将会使用 maximizealpha 函数,它根据alpha分数尝试给对象分配相应的资源。

# Import Optimize API module
import quantopian.optimize as opt


def rebalance(context, data):
  # Retrieve alpha from pipeline output
  alpha = context.pipeline_data.sentiment_score

  if not alpha.empty:
      # Create MaximizeAlpha objective
      objective = opt.MaximizeAlpha(alpha)

接着,我们需要明确规定我们目标投资组合需要满足的约束条例 让我们在 initialize 定义一些阈值,然后开始存储阈值在我们的context 变量中。

# Constraint parameters
context.max_leverage = 1.0
context.max_pos_size = 0.015
context.max_turnover = 0.95

现在,我们能够通过使用我们在上面定义的阈值在rebalance函数明确我们的约束

# Import Optimize API module
import quantopian.optimize as opt


def rebalance(context, data):
  # Retrieve alpha from pipeline output
  alpha = context.pipeline_data.sentiment_score

  if not alpha.empty:
      # Create MaximizeAlpha objective
      objective = opt.MaximizeAlpha(alpha)

      # Create position size constraint
      constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
          -context.max_pos_size,
          context.max_pos_size
      )

      # Constrain target portfolio's leverage
      max_leverage = opt.MaxGrossExposure(context.max_leverage)

      # Ensure long and short books
      # are roughly the same size
      dollar_neutral = opt.DollarNeutral()

      # Constrain portfolio turnover
      max_turnover = opt.MaxTurnover(context.max_turnover)

最后,我们能够传递我们对象和约束规则给order_optimal_portfolio函数去计算出一个目标投资组合,发布转换我们当前的投资组合到最优状态投资组合的必要命令。

# Import Algorithm API
import quantopian.algorithm as algo

# Import Optimize API
import quantopian.optimize as opt


def rebalance(context, data):
  # Retrieve alpha from pipeline output
  alpha = context.pipeline_data.sentiment_score

  if not alpha.empty:
      # Create MaximizeAlpha objective
      objective = opt.MaximizeAlpha(alpha)

      # Create position size constraint
      constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
          -context.max_pos_size,
          context.max_pos_size
      )

      # Constrain target portfolio's leverage
      max_leverage = opt.MaxGrossExposure(context.max_leverage)

      # Ensure long and short books
      # are roughly the same size
      dollar_neutral = opt.DollarNeutral()

      # Constrain portfolio turnover
      max_turnover = opt.MaxTurnover(context.max_turnover)

      # Rebalance portfolio using objective
      # and list of constraints
      algo.order_optimal_portfolio(
          objective=objective,
          constraints=[
              constrain_pos_size,
              max_leverage,
              dollar_neutral,
              max_turnover,
          ]
      )

风险管理

除了对我们的目标投资组合加以约束,我们也希望限制他暴露于可能影响其性能的常见风险因素。例如,由于情绪数据stocktwits的瞬变性和我们利用情绪分数峰值的意图,我们的算法可能会面临短期反转风险。

我们打算使用 quantopian风险模型去管理我们投资组合暴露的常见的风险因素。风险模型计算暴露给16种不同风险因素的估值。(11种区域因素和5种风格因素,包括短期反转)我们可以在我们的算法中使用risk_loading_pipeline函数轻松访问这些数据,该函数返回一个数据管道,该数据管道为风险模型中的每个因素生成一列输出。

与我们的数据管道类似,我们需要将风险数据管道附加到我们的算法中,并提供一个名称来识别它。然后我们可以从before_trading_start 中获取其输出并将其存储在context中。

# Import Algorithm API
import quantopian.algorithm as algo

# Import Risk API method
from quantopian.pipeline.experimental import risk_loading_pipeline

def initialize(context):
    # Constraint parameters
    context.max_leverage = 1.0
    context.max_pos_size = 0.015
    context.max_turnover = 0.95

    # Attach data pipelines
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )
    algo.attach_pipeline(
        risk_loading_pipeline(),
        'risk_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        algo.date_rules.week_start(),
        algo.time_rules.market_open(),
    )


def before_trading_start(context, data):
    # Get pipeline outputs and
    # store them in context
    context.pipeline_data = algo.pipeline_output(
      'data_pipe'
    )

    context.risk_factor_betas = algo.pipeline_output(
      'risk_pipe'
    )

下一步是在我们的投资组合最优化逻辑中添加一个RiskModelExposure约束。这个约束接受风险模型生成的数据,并对我们的目标投资组合对模型中包含的每个因素的总体风险敞口设置限制。

# Constrain target portfolio's risk exposure
# By default, max sector exposure is set at
# 0.2, and max style exposure is set at 0.4
factor_risk_constraints = opt.experimental.RiskModelExposure(
    context.risk_factor_betas,
    version=opt.Newest
)

最后,下面的算法包含了我们的策略和投资组合约束逻辑并准备好进行回溯测试。克隆算法后,单击IDE右上角的“Runfullbacktest”运行完全回溯测试。

# Import Algorithm API
import quantopian.algorithm as algo

# Import Optimize API
import quantopian.optimize as opt

# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import SimpleMovingAverage

# Import built-in universe and Risk API method
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.experimental import risk_loading_pipeline


def initialize(context):
    # Constraint parameters
    context.max_leverage = 1.0
    context.max_pos_size = 0.015
    context.max_turnover = 0.95

    # Attach data pipelines
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )
    algo.attach_pipeline(
        risk_loading_pipeline(),
        'risk_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        algo.date_rules.week_start(),
        algo.time_rules.market_open(),
    )


def before_trading_start(context, data):
    # Get pipeline outputs and
    # store them in context
    context.pipeline_data = algo.pipeline_output('data_pipe')

    context.risk_factor_betas = algo.pipeline_output('risk_pipe')


# Pipeline definition
def make_pipeline():

    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
        mask=QTradableStocksUS()
    )

    return Pipeline(
        columns={
            'sentiment_score': sentiment_score,
        },
        screen=sentiment_score.notnull()
    )


def rebalance(context, data):
    # Retrieve alpha from pipeline output
    alpha = context.pipeline_data.sentiment_score

    if not alpha.empty:
        # Create MaximizeAlpha objective
        objective = opt.MaximizeAlpha(alpha)

        # Create position size constraint
        constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
            -context.max_pos_size,
            context.max_pos_size
        )

        # Constrain target portfolio's leverage
        max_leverage = opt.MaxGrossExposure(context.max_leverage)

        # Ensure long and short books
        # are roughly the same size
        dollar_neutral = opt.DollarNeutral()

        # Constrain portfolio turnover
        max_turnover = opt.MaxTurnover(context.max_turnover)

        # Constrain target portfolio's risk exposure
        # By default, max sector exposure is set at
        # 0.2, and max style exposure is set at 0.4
        factor_risk_constraints = opt.experimental.RiskModelExposure(
            context.risk_factor_betas,
            version=opt.Newest
        )

        # Rebalance portfolio using objective
        # and list of constraints
        algo.order_optimal_portfolio(
            objective=objective,
            constraints=[
                constrain_pos_size,
                max_leverage,
                dollar_neutral,
                max_turnover,
                factor_risk_constraints,
            ]
        )

在下一课中,你将学习如何更深入地分析回测结果。

回测分析(Lesson8)

当你的回测完成后,单击“Notebook”选项卡。

这将显示带有以下代码的研究笔记本:

bt = get_backtest('5a4e4faec73c4e44f218170a')
bt.create_full_tear_sheet()

注意:笔记本中的字母数字的字符串和上面显示的是不同的。这个字符串是你的回测在量子中的唯一标识符。你也可以在完整的回测结果页面中找到它。

执行此单元格(Shift + Enter)会将你回测生成的数据加载到研究笔记本中,并使用它来创建一个Pyfolio撕纸。Pyfolio是量子用于投资组合和风险分析的开源工具。 它提供了许多可视化工具,旨在帮助您更好地了解算法的行为以及随着时间的推移所面临的风险。

例如,下图显示了我们的投资组合随时间推移的市场滚动风险。我们之所以构造多头-空头股票交易算法的原因之一是要保持与市场的低相关性,因此我们希望该图在整个回测期间始终保持在0附近。

撕纸的另一个有趣的部分是性能归因部分。 下图使用量子的风险模型来说明可以将多少收益归因于您的策略,以及其中多少来自共同的风险因素。

从上图我们可以看到我们投资组合的大部分总收益来自特定收益。这表明算法的性能并非来自于常见风险因素,这是一件好事。恭喜你完成了关于量子的入门教程!现在您已经熟悉了平台的API,请尝试研究和开发您自己的策略,并将它们提交给竞赛。如果你需要一些想法,可以看看这个系列讲座来了解更多关于量化金融的知识,或者看看其他成员在社区中分享的想法。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×