Notebook

May 14th Quantopian Hackathon 2016

Agenda

  1. Contest Rules
  2. Submission Guidelines
  3. Judging Criteria
  4. Dataset Introductions w/ Sample Algorithm Templates
  5. Submission Template

Schedule

Hackathon 2016 Agenda

10AM – 11AM: Introduction to Quantopian, dataset showcases, and explanation of competition rules.

11AM – 12PM: Hackathon Start. Competitors will be free to ask Quantopian panelist questions.

12:00PM – 12:30PM: Lunch

12:30PM – 5:30PM: Hackathon Afternoon Session. Competitors will be free to ask Quantopian panelists questions.

5:30PM – 5:45PM: Final announcement of 6:00 submission deadline.

6:00PM – 6:30PM: Submission deadline, wrap-up.

Additionally, we reserve the right to disqualify any entry at our sole discretion. For instance, if we believe that an entry is made in bad faith with the intent to "game" the contest, or if we conclude that the algorithm is not following the rules presented in our contest rules and judging criteria.

Rules & Submission Guidelines

  1. At 6:00PM (or before then if you're ready), all contestants will be able to run their out-of-sample backtests.
  2. Your algorithm MUST use one of the PsychSignal datasets:
    • data.psychsignal.twitter_withretweets_hackathon
    • data.psychsignal.aggregated_twitter_withretweets_stocktwits_hackathon
    • data.psychsignal.stocktwits_hackathon
    • While you can use any of the three, you'll only be able to research factors with stocktwits_hackathon
    • You will be able to run the full backtest over this time period by removing the `_hackathon` from your dataset import. This will only be possible once we begin allowing submissions.
  3. Contestants will be required to run a full backtest from January 1, 2011 up till May 12, 2016.
  4. Use the submission template found in this notebook to create your backtest tearsheet
  5. Download this notebook as an html file (by clicking Notebook at the top right -> Download as)
  6. Send the notebook along with your Name and Occupation to Hackathon@Quantopian.com using the email format below:
SUBJECT:
QuantCon Hackathon - [CONTESTANT NAME HERE]

BODY: 
Here is my submission for QuantCon Hackathon 2016. 
Name: [NAME]
Occupation: [OCCUPATION]
ATTACHED HTML NOTEBOOK AT BOTTOM
  1. If you are a team, please only send one submission. Include the name and emails of each of your team members.

Judging Criteria

  1. Each algorithm will be graded from it's backtest score during January 1, 2011 up till May 12, 2016
  2. Each algorithm will receive a score based on two risk metrics:
    • Sharpe: Higher sharpe the better
    • Drawdown: Lower drawdown the better
  3. Each algorithm MUST have:
    • Default Slippage & Commisions
    • A beta between .3 and -.3
    • Run in minutely mode
    • Capital base of 1,000,000
    • Average leverage 2.0 with maximum leverage under 2.5

Dataset Introductions w/ Template Algorithms

You do not have to use these templates but they are here for you to get started with.

In [14]:
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.research import run_pipeline
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import AverageDollarVolume

Hackathon Dataset: PsychSignal

PsychSignal: https://psychsignal.com/

Dataset Versions:

Please use these namespaces for your development

In [32]:
from quantopian.pipeline.data.psychsignal import (
    stocktwits_hackathon,
#     twitter_withretweets_hackathon,
#     aggregated_twitter_withretweets_stocktwits_hackathon
)

Take a look at what the data looks like through here

In [23]:
# PsychSignal
# This is the StockTwits (All Fields) dataset
from quantopian.pipeline.data.psychsignal import stocktwits_hackathon as psychsignal

pipe = Pipeline()
pipe.add(psychsignal.bull_scored_messages.latest, 'bull_messages')
pipe.add(psychsignal.bear_scored_messages.latest, 'bear_messages')
pipe.add(psychsignal.bullish_intensity.latest, "bullish_intensity")
pipe.add(psychsignal.bearish_intensity.latest, "bearish_intensity")
pipe.add(psychsignal.total_scanned_messages.latest, "total_messages")

output = run_pipeline(pipe, start_date='2014-01-04', end_date='2014-01-04')
output = output[output['total_messages'] > 10]
output.iloc[:5]
Out[23]:
bear_messages bearish_intensity bull_messages bullish_intensity total_messages
2014-01-06 00:00:00+00:00 Equity(2 [AA]) 0 0.00 3 1.87 11
Equity(24 [AAPL]) 55 1.77 74 1.67 432
Equity(351 [AMD]) 12 1.73 15 1.49 74
Equity(700 [BAC]) 7 1.73 10 1.79 50
Equity(2174 [DIA]) 2 2.44 5 1.23 27

Suggested Workflow

Factor Research

See Factor Output

In [33]:
# Sample Factor
from quantopian.pipeline.data.psychsignal import stocktwits_hackathon as psychsignal

class Factor(CustomFactor):
    """
    Baseline PsychSignal Factor
    """
    inputs = [psychsignal.bull_minus_bear]
    window_length = 1
    
    def compute(self, today, assets, out, bull_minus_bear):
        out[:] = bull_minus_bear
In [34]:
pipe = Pipeline()
factor = Factor()

# Screen out penny stocks and low liquidity securities.
dollar_volume = AverageDollarVolume(window_length=20)
is_liquid = dollar_volume.rank(ascending=False) < 1000

# Create the mask that we will use for our percentile methods.
base_universe = (is_liquid)

# Filter down to stocks in the top/bottom 10% by sentiment rank
longs = factor.rank().percentile_between(90, 100, mask=base_universe)
shorts = factor.rank().percentile_between(0, 10, mask=base_universe)

# Add Accern to the Pipeline
pipe.add(factor, "factor")
pipe.add(longs, "longs")
pipe.add(shorts, "shorts")

# Set our pipeline screens
pipe.set_screen((longs | shorts) & (factor != 0))

# Get the output of the pipeline
pipe_output = run_pipeline(pipe, start_date='2015-03-30', end_date='2015-03-30')
In [35]:
pipe.show_graph(format='png')
Out[35]:
In [36]:
pipe_output.iloc[0]
Out[36]:
factor     2.14
longs      True
shorts    False
Name: (2015-03-30 00:00:00+00:00, Equity(337 [AMAT])), dtype: object

Run Factor Tearsheet

Go here: https://www.quantopian.com/posts/factor-tear-sheet

Plug into template Long-Short Algorithm

This algorithm makes it very easy for you to plug Factors into. There's even code to combine multiple factors into an equally weighted scale.

In [37]:
import pandas as pd
import numpy as np

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.factors import CustomFactor, AverageDollarVolume
from quantopian.pipeline.data.psychsignal import (
    stocktwits_hackathon,
#     twitter_withretweets_hackathon,
#     aggregated_twitter_withretweets_stocktwits_hackathon
)

# Factor belongs here
    
def make_pipeline():
    # Create our pipeline
    pipe = Pipeline()
    
    # Screen out penny stocks and low liquidity securities.
    dollar_volume = AverageDollarVolume(window_length=20)
    is_liquid = dollar_volume.rank(ascending=False) < 1000
    
    # Create the mask that we will use for our percentile methods.
    base_universe = (is_liquid)

    # Filter down to stocks in the top/bottom 10% by sentiment rank
    factor = Factor()
    longs = factor.rank().percentile_between(90, 100, mask=base_universe)
    shorts = factor.rank().percentile_between(0, 10, mask=base_universe)
    
    # Multiple Factors
#     factor = Factor()
#     factor_2 = Factor_2()
#     combined_factor = (
#         factor.rank(mask=base_universe) +
#         factor_2.rank(mask=base_universe)
#     )
#     longs = combined_factor.rank().percentile_between(90, 100)
#     shorts = combined_factor.rank().percentile_between(0, 10)

    # Add Accern to the Pipeline
    pipe.add(longs, "longs")
    pipe.add(shorts, "shorts")

    # Set our pipeline screens
    pipe.set_screen((longs | shorts) & factor.notnan())
    return pipe

# Put any initialization logic here. The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
    attach_pipeline(make_pipeline(), name='factors')
    
    context.shorts = None
    context.longs = None
    # Create our scheduled functions
    # This is a monthly rebalance, please change according to your 
    # frequency
    schedule_function(rebalance, date_rules.month_start())
    schedule_function(record_positions, date_rules.every_day(),
                      time_rules.market_close())

def before_trading_start(context, data):
    # Assign long and short baskets
    results = pipeline_output('factors')
    if len(results.index) == 0:
        log.info("Not Enough Data Yet!")
        return
    assets_in_universe = results.index
    context.longs = assets_in_universe[results.longs]
    context.shorts = assets_in_universe[results.shorts]
    
def record_positions(context, data):
    # Record our leverage, exposure, positions, and number of open
    # orders
    record(lever=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions))
    
def rebalance(context, data):
    if context.shorts is None or context.longs is None:
        return
    short_weight = -1.0/len(context.shorts)
    long_weight = 1.0/len(context.longs)
    assets_in_universe = (context.longs  | context.shorts)

    # Order our shorts
    for security in context.shorts:
        if data.can_trade(security):
            order_target_percent(security, short_weight)
            
    # Order our longs
    for security in context.longs:
        if data.can_trade(security):
            order_target_percent(security, long_weight)
            
    # Order securities not in the portfolio
    for security in context.portfolio.positions:
        if data.can_trade(security):
            if security not in assets_in_universe:
                order_target_percent(security, 0)
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-37-295d112b4994> in <module>()
      2 import numpy as np
      3 
----> 4 from quantopian.algorithm import attach_pipeline, pipeline_output
      5 from quantopian.pipeline import Pipeline
      6 from quantopian.pipeline.factors import CustomFactor, AverageDollarVolume

ImportError: No module named algorithm

Submission Template

1 January 2011 - 12 May 2016 BACKTEST

In [1]:
bt = get_backtest('573785ad82cd270f926abb5e')
bt.create_full_tear_sheet()

# Send to SLEE@QUANTOPIAN.COM
100% Time: 0:00:14|###########################################################|
Entire data start date: 2011-01-04
Entire data end date: 2016-05-13


Backtest Months: 64
                   Backtest
annual_return          0.05
annual_volatility      0.19
sharpe_ratio           0.37
calmar_ratio           0.17
stability              0.48
max_drawdown          -0.31
omega_ratio            1.07
sortino_ratio          0.55
skewness               0.37
kurtosis               4.16
information_ratio     -0.01
alpha                  0.04
beta                   0.29

Worst Drawdown Periods
   net drawdown in %  peak date valley date recovery date duration
0              30.96 2013-11-22  2016-02-11           NaT      NaN
1              17.60 2013-06-27  2013-09-03    2013-11-18      103
2              14.28 2011-07-07  2011-10-03    2011-10-21       77
3               9.13 2011-12-20  2012-04-10    2012-05-08      101
4               6.79 2011-10-27  2011-11-03    2011-11-30       25


2-sigma returns daily    -0.024
2-sigma returns weekly   -0.046
dtype: float64
Stress Events
                                    mean    min    max
US downgrade/European Debt Crisis -0.002 -0.023  0.014
Fukushima                          0.001 -0.014  0.008
EZB IR Event                       0.001 -0.017  0.028
Apr14                              0.002 -0.033  0.035
Oct14                              0.001 -0.014  0.021
Fall2015                          -0.001 -0.023  0.026
Recovery                           0.001 -0.045  0.063
New Normal                         0.000 -0.058  0.063

Top 10 long positions of all time (and max%)
[u'SDS-32382' u'FAZ-37048' u'GILD-3212' u'HLF-26892' u'TZA-37133'
 u'FAS-37049' u'VALE-23536' u'DAL-33729' u'TNA-37515' u'GDX-32133']
[ 0.06   0.058  0.056  0.055  0.054  0.054  0.053  0.053  0.052  0.052]


Top 10 short positions of all time (and max%)
[u'UVXY-41969' u'UWTI-42471' u'TSLA-39840' u'VRX-10908' u'FB-42950'
 u'BABA-47740' u'VXX-38054' u'NFLX-23709' u'GLD-26807' u'ARNA-21724']
[-0.363 -0.359 -0.288 -0.27  -0.267 -0.262 -0.261 -0.253 -0.252 -0.248]


Top 10 positions of all time (and max%)
[u'UVXY-41969' u'UWTI-42471' u'TSLA-39840' u'VRX-10908' u'FB-42950'
 u'BABA-47740' u'VXX-38054' u'NFLX-23709' u'GLD-26807' u'ARNA-21724']
[ 0.363  0.359  0.288  0.27   0.267  0.262  0.261  0.253  0.252  0.248]


All positions ever held
[u'UVXY-41969' u'UWTI-42471' u'TSLA-39840' u'VRX-10908' u'FB-42950'
 u'BABA-47740' u'VXX-38054' u'NFLX-23709' u'GLD-26807' u'ARNA-21724'
 u'AAPL-24' u'NUGT-40553' u'USO-28320' u'AMZN-16841' u'TZA-37133'
 u'CMCS_A-1637' u'BAC-700' u'GILD-3212' u'SPY-8554' u'GOOG_L-26578'
 u'PLUG-20776' u'HLF-26892' u'QQQ-19920' u'VWO-27102' u'SINA-21448'
 u'IWM-21519' u'BIDU-27533' u'IVV-21513' u'LNKD-41451' u'SLV-28368'
 u'TWTR-45815' u'EFA-22972' u'BRK_B-11100' u'XOP-32279' u'GENZ-3166'
 u'XLI-19657' u'GPRO-47208' u'PEP-5885' u'PXP-24112' u'FXI-26703'
 u'MHS-25445' u'MDY-12915' u'SDS-32382' u'FAZ-37048' u'FAS-37049'
 u'VALE-23536' u'DAL-33729' u'TNA-37515' u'GDX-32133' u'JNJ-4151'
 u'PBR-21916' u'UNP-7800' u'XLV-19661' u'ABX-64' u'HAL-3443' u'GE-3149'
 u'CHK-8461' u'TWC-33133' u'HD-3496' u'MS-17080' u'CF-27558' u'WMB-8214'
 u'CSCO-1900' u'INTC-3951' u'WMT-8229' u'EBAY-24819' u'DELL-25317'
 u'XLU-19660' u'XLY-19662' u'FOXA-12213' u'EWZ-21757' u'YHOO-14848'
 u'XOM-8347' u'XLP-19659' u'XIV-40516' u'LOW-4521' u'JPM-25006'
 u'FCX-13197' u'SLB-6928' u'CVS-4799' u'HYG-33655' u'PM-35902' u'MCD-4707'
 u'KO-4283' u'QCOM-6295' u'EWJ-14520' u'MRK-5029' u'BBRY-19831'
 u'VNQ-26669' u'ORCL-5692' u'VZ-21839' u'DIS-2190' u'ESRX-2618'
 u'EEM-24705' u'IYR-21652' u'CRM-26401' u'DOW-2263' u'APC-455' u'PG-5938'
 u'EMC-2518' u'OXY-5729' u'AGN-8572' u'BIIB-3806' u'WYNN-24124'
 u'XLE-19655' u'COH-22099' u'BMY-980' u'JNK-35175' u'AMGN-368' u'WBA-8089'
 u'WFC-8151' u'QLD-32272' u'AIG-239' u'HPQ-3735' u'CBS-7962' u'SSO-32270'
 u'AVGO-38650' u'CAT-1267' u'CVX-23112' u'WFM-8158' u'SLXP-22269'
 u'MDLZ-22802' u'BA-698' u'OIH-22463' u'TGT-21090' u'MO-4954' u'CMI-1985'
 u'NEM-5261' u'VLO-7990' u'MDT-4758' u'CELG-1406' u'UTX-7883' u'UNH-7792'
 u'XLB-19654' u'XRT-32275' u'AXP-679' u'ISRG-25339' u'EOG-2564' u'PFE-5923'
 u'QID-32381' u'JD-46979' u'XLK-19658' u'POT-6109' u'MSFT-5061' u'IBM-3766'
 u'COF-12160' u'BP-19675' u'VTI-22739' u'TBT-36144' u'YUM-17787'
 u'STX-24518' u'BTU-22660' u'AMT-24760' u'COP-23998' u'TXN-7671'
 u'BRCM-18529' u'GM-40430' u'CLF-1595' u'LZ-4620' u'MCK-12350'
 u'ABBV-43694' u'MA-32146' u'HEDJ-39116' u'SNDK-13940' u'PXD-17436'
 u'VOO-40107' u'DTV-26111' u'HON-25090' u'SQQQ-39211' u'DUK-2351'
 u'UPS-20940' u'AA-2' u'TEVA-7407' u'DE-2127' u'ABT-62' u'APA-448'
 u'LQD-23881' u'KRFT-43405' u'LVS-26882' u'LO-36346' u'BHI-858'
 u'USB-25010' u'XLF-19656' u'MET-21418' u'ACN-25555' u'PCP-5822' u'DD-2119'
 u'PRGO-6161' u'CI-1539' u'DIA-2174' u'NOV-24809' u'LYB-39546' u'CSX-1937'
 u'SFSF-35114' u'MON-22140' u'TWX-357' u'AGNC-36243' u'PLL-6030'
 u'SYF-47415' u'CTL-1960' u'LIFE-19800' u'DXJ-34164' u'BAX-734'
 u'MOS-26721' u'LLY-4487' u'KMI-40852' u'NSM-5452' u'PPG-6116' u'COST-1787'
 u'CHTR-39095' u'ONXX-14986' u'SH-32268' u'DG-38936' u'GG-22226'
 u'NVDA-19725']
[ 0.363  0.359  0.288  0.27   0.267  0.262  0.261  0.253  0.252  0.248
  0.246  0.244  0.242  0.238  0.235  0.233  0.231  0.229  0.227  0.226
  0.223  0.222  0.221  0.22   0.217  0.217  0.217  0.215  0.214  0.214
  0.214  0.214  0.211  0.208  0.208  0.206  0.204  0.203  0.2    0.199
  0.198  0.198  0.06   0.058  0.054  0.053  0.053  0.052  0.052  0.051
  0.051  0.051  0.051  0.05   0.05   0.05   0.05   0.05   0.05   0.05   0.05
  0.05   0.05   0.05   0.05   0.05   0.049  0.049  0.049  0.049  0.049
  0.049  0.049  0.049  0.049  0.049  0.049  0.048  0.048  0.048  0.048
  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048
  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048  0.048
  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047
  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047  0.047
  0.047  0.047  0.047  0.047  0.046  0.046  0.046  0.046  0.046  0.046
  0.046  0.046  0.046  0.046  0.046  0.046  0.046  0.046  0.046  0.046
  0.046  0.046  0.046  0.046  0.045  0.045  0.045  0.045  0.045  0.045
  0.045  0.045  0.045  0.045  0.045  0.045  0.045  0.045  0.045  0.045
  0.045  0.045  0.045  0.044  0.044  0.044  0.044  0.044  0.044  0.044
  0.044  0.044  0.044  0.044  0.044  0.044  0.044  0.044  0.044  0.044
  0.044  0.044  0.044  0.044  0.043  0.043  0.043  0.043  0.043  0.043
  0.043  0.043  0.043  0.043  0.043  0.043  0.042  0.042  0.042  0.042
  0.042  0.042  0.042  0.042  0.042  0.042  0.042  0.042  0.042  0.041
  0.041  0.041  0.04   0.04 ]


In [ ]: