Back to Community
Accern Alphaone Long Short

Note: Accern's Alphaone dataset is no longer available in the platform. For a similar example, check out Sentdex's News Sentiment Analysis sample algorithm.

Since we released Accern data into Pipeline and the backtester I've been working on something to post in the forums kind of like the VIX algo. While the aforementioned algo wouldn't be suitable for the contest or fund, this algo is a taste of the type we are looking for in the fund, and a candidate for doing well in the contest.

Accern Alphaone provides sentiment data for securities consisting of a sentiment score ranging from -1 to 1 and an impact score ranging from 0 to 100. The impact score measures how likely the stock price will change as a result of the sentiment. I found their impact score to be especially interesting and decided to see if I could find a signal in that. In the below algo I hypothesize that securities with a low average impact score would outperform securities with a high average impact score. Consequently I bought the low impact stocks and sold the high impact stocks. The results seem to be somewhat predictive but very sensitive to the look back period. Unfortunately, the free dataset is only available until mid December 2013 so there isn't a lot of time to backtest, but the premium dataset extends two more years to the present.

For more information on the integration see Josh's post.

TL;DR

Buy stocks where news sentiment barely impacts their price, sell stocks where news sentiment greatly impacts their price.

Clone Algorithm
295
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import CustomFactor
from quantopian.pipeline.data.accern import alphaone_free as alphaone

import pandas as pd
import numpy as np


# Calculates the average impact of the sentiment over the window length
class AvgImpact(CustomFactor):
    
    def compute(self, today, assets, out, impact):
        np.mean(impact, axis=0, out=out)

        
class AvgDailyDollarVolumeTraded(CustomFactor):
    
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)

        
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
    
    pipe = Pipeline()
    pipe = attach_pipeline(pipe, name='sentiment_metrics')
    
    # Add our AvgImpact factor to the pipeline
    pipe.add(AvgImpact(inputs=[alphaone.impact_score], window_length=20), "avg_impact")    
    
    dollar_volume = AvgDailyDollarVolumeTraded()
    
    # Screen out low liquidity securities.
    pipe.set_screen(dollar_volume > 10**7)
    context.shorts = None
    context.longs = None
    # context.spy = sid(8554)
    
    schedule_function(rebalance, date_rules.month_start(), time_rules.market_open(hours=1))
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))
    
    
def before_trading_start(context, data):
    results = pipeline_output('sentiment_metrics').dropna()         
    ranks = results["avg_impact"].rank().order()
    context.shorts = ranks.tail(50)
    context.longs = ranks.head(50)
    
    # The pipe character "|" is the pandas union operator
    update_universe(context.longs.index | context.shorts.index)
    

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    record(lever=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           oo=len(get_open_orders()))
        
    
def rebalance(context, data):
    
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, -1.0 / len(context.shorts))
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, 1.0 / len(context.longs))
            
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if security in data:
            if security not in (context.longs.index | context.shorts.index):
                order_target_percent(security, 0)
We have migrated this algorithm to work with a new version of the Quantopian API. The code is different than the original version, but the investment rationale of the algorithm has not changed. We've put everything you need to know here on one page.
There was a runtime error.
Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

20 responses

Error: Runtime exception: UsageNotAllowed: You do not have access to the following dataset(s): accern.alphaone_free (quantopian.com/data/accern/alphaone_free)

class AvgImpact(CustomFactor):  
    def compute(self, today, assets, out, impact):  
        np.mean(impact, axis=0, out=out)  

Shouldn't that store to out[:] = ...?

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Hi Gary,
To gain access to this (or any free sample set) from our partners, you need to go to the page for the data set and enable access. So in this case, go to quantopian.com/data/accern/alphaone and hit the "Get free sample" button.

On our to-do list is to fix up this error message to be more clear.

Thanks,
Josh

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

@ Thomas

Check out http://stackoverflow.com/questions/27293830/utility-of-parameter-out-in-numpy-functions for a good explanation of why I used the out parameter instead of equaling the result to out[:].

Ah, I missed that you passed in the out kwarg.

For those interested in this algo, James Christopher, Kumesh Aroomoogan (CEO of Accern) and I will be holding a webinar next Wednesday to discuss this data and how James Christopher built this algorithm.

Register today.

Edit: This algo resulted in a fix to my PvR code wrt shorting, apologies and thank you.
(Its risk is fairly close to the starting capital so the chart is pretty close to profit vs risk. Removed the original comment since it wouldn't add any value at this point).

The webinar mentioned above was recorded and can be found here: https://youtu.be/0aNpsZgSHTk

hi Josh, i know there is accern version 2 data set. For this report, are you using original or version 2?

Hi Sophie,

In this case, Josh is using the dataset found at Accern's Alpha One - although I'm not 100% sure which version 2 you're referring to. Would you mind clarifying/posting a link to version 2?

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Has anyone else encountered missing data in this data set? I have been getting a lot of NaNs and unchanging numbers out of Pipeline with it. I'm using the free set for now FYI.

Ben,

Could you provide a short example of where you're seeing the missing data? It'd be incredibly helpful as I troubleshoot the issue you're seeing.

Seong

Hi Seong,

I made a separate post about it with some more detail: https://www.quantopian.com/posts/missing-sentiment-data

Essentially, around the end of September 2012 in my backtest, I stop seeing new values come through the pipeline for the article_sentiment and impact_score variables, and get NaNs when trying to calculate the RSI of the sentiment. In the linked post, the reason I was getting key errors was because I was dropping NA's from my pipeline output. Regardless, I still don't seem to be getting all the data I would expect.

Thanks for your help,
Ben

Great work James. Just as an FYI, looks like Wisdom Tree just released two quant-driven long-short ETFs. Excerpted from seekingalpha.com:

" DYLS tracks the WisdomTree Dynamic Long/Short U.S. Equity Index, which consists of long positions in approximately 100 U.S. large- and mid-cap stocks that meet eligibility requirements and have the best combined score based on fundamental growth and value signals, and short positions in the largest 500 U.S. companies. The long positions are weighted according to their volatility characteristics, while the short positions are weighted by market cap and designed to hedge against market risk. The long-portfolio will be 100% invested at all times, while the short portfolio will vary between 0% and 100% exposure based on "a quantitative rules-based market indicator that scores growth and value market signals."

DYB tracks the WisdomTree Dynamic Bearish U.S. Equity Index, which switches between long positions in the same stocks as DYLS and U.S. Treasurys. DYB's short portfolio is the same as DYLS's. The long equity portfolio can range from 0% to 100% while employing a "variable monthly hedge ratio" from 75% to 100% in the short portfolio. During times when the market indicator shows unattractive readings on valuation and growth characteristics, DYB can move to 100% exposure to U.S. Treasurys."

Addendum:

QuantShares U.S. Market Neutral Momentum ( MOM ) was the best-performing alternative ETF in 2015, delivering a return of 23.5%. MOM tracks the Down Jones U.S. Thematic Market Neutral Momentum Index, which is a long-short index that tracks momentum and is dollar neutral.

Alphaone's data is no longer offered through Quantopian Data so the code below will not work.

Seong

Clone Algorithm
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import CustomFactor
from quantopian.pipeline.data.accern import alphaone_free as alphaone

from quantopian.pipeline.data.eventvestor.factors import BusinessDaysUntilNextEarnings, BusinessDaysSincePreviousEarnings

import pandas as pd
import numpy as np


# Calculates the average impact of the sentiment over the window length
class AvgImpact(CustomFactor):
    
    def compute(self, today, assets, out, impact):
        np.mean(impact, axis=0, out=out)

        
class AvgDailyDollarVolumeTraded(CustomFactor):
    
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)

def make_pipeline():
    """
    Create and return our pipeline.
    
    We break this piece of logic out into its own function to make it easier to
    test and modify in isolation.
    
    In particular, this function can be copy/pasted into research and run by itself.
    """
    pipe = Pipeline()
    
    # Add our AvgImpact factor to the pipeline
    pipe.add(AvgImpact(inputs=[alphaone.impact_score], window_length=7), "avg_impact")    
    avoid_earnings_days = 7
    
    """
    Risk Framework
    There are two options: Screen your securities out in initialize() or
    do it right before you order. Both have slightly different behaviors.
    If you choose to do it in initialize, the initial cohort of stocks that
    you filter through in `before_trading_start` will not have an earnings
    announcement soon. If you choose to do it before you order, you're keeping
    all securities that might've met your initial SMA & dollar volume filter
    and choosing to take them out afterwards. Both work, but it will depend 
    on your strategy
    """
    # Option 1 of the risk framework. We choose to filter out
    # securities in initialize.
    # EarningsCalendar.X is the actual date of the announcement
    # E.g. 9/12/2015
    # pipe.add(EarningsCalendar.next_announcement.latest, 'next')
    # pipe.add(EarningsCalendar.previous_announcement.latest, 'prev')
    # BusinessDaysX is the integer days until or after the closest
    # announcement. So if AAPL had an earnings announcement yesterday,
    # prev_earnings would be 1. If it's the day of, it will be 0.
    # For BusinessDaysUntilNextEarnings(), it is common that the value
    # is NaaN because we typically don't know the precise date of an
    # earnings announcement until about 15 days before
    ne = BusinessDaysUntilNextEarnings()
    pe = BusinessDaysSincePreviousEarnings()
    pipe.add(ne, 'next_earnings')
    pipe.add(pe, 'prev_earnings')
    # The number of days before/after an announcement that you want to
    # avoid an earnings for.
    dollar_volume = AvgDailyDollarVolumeTraded()
    pipe.set_screen((ne.isnan() | (ne > avoid_earnings_days) | (pe > avoid_earnings_days)) & (dollar_volume > 10**7))
    """
    End of Risk Framework
    """
    # Without the earnings screen
    # pipe.set_screen(dollar_volume > 10**7)

    return pipe
    
        
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
    context.shorts = None
    context.longs = None
    attach_pipeline(make_pipeline(), 'sentiment_metrics')
    
    schedule_function(rebalance, date_rules.week_start(), time_rules.market_open(hours=1))
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))
    
def before_trading_start(context, data):
    results = pipeline_output('sentiment_metrics').dropna(subset=['avg_impact'])         
    ranks = results["avg_impact"].rank().order()
    context.shorts = ranks.tail(50)
    context.longs = ranks.head(50)
    
    stocks = context.longs.index + context.shorts.index
    context.results = results.ix[stocks]
    
    # The pipe character "|" is the pandas union operator
    update_universe(context.longs.index | context.shorts.index)
    

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    record(lever=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           oo=len(get_open_orders()))
    
def rebalance(context, data):
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, -1.0 / len(context.shorts))
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, 1.0 / len(context.longs))
        
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if security in data:
            if security not in (context.longs.index + context.shorts.index):
                order_target_percent(security, 0)        
    

There was a runtime error.

Alphaone's data is no longer offered through Quantopian Data so the code below will not work.

Seong

An experiment using the same rebalance dates but a new ranking methodology.

Here I'm using impact score * sentiment score and only long/shorting the top 1% in each category. The idea behind the ranking methodology is that we'll look at which securities have the highest sentiment in either direction and take into account whether or not this sentiment will affect the stock's price. This version does not contain earnings calendars.

Clone Algorithm
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import CustomFactor
from quantopian.pipeline.data.accern import alphaone_free as alphaone

import pandas as pd
import numpy as np


# Calculates the average impact of the sentiment over the window length
class AvgImpact(CustomFactor):
    
    def compute(self, today, assets, out, sentiment, impact):
        np.mean((sentiment*impact), axis=0, out=out)

        
class AvgDailyDollarVolumeTraded(CustomFactor):
    
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)

        
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
    
    pipe = Pipeline()
    pipe = attach_pipeline(pipe, name='sentiment_metrics')
    
    # Add our AvgImpact factor to the pipeline
    pipe.add(AvgImpact(inputs=[alphaone.article_sentiment, alphaone.impact_score], window_length=7), "avg_impact")    
    
    dollar_volume = AvgDailyDollarVolumeTraded()
    
    # Screen out low liquidity securities.
    pipe.set_screen(dollar_volume > 10**7)
    context.shorts = None
    context.longs = None
    # context.spy = sid(8554)
    
    schedule_function(rebalance, date_rules.week_start(), time_rules.market_open(hours=1))
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))
    
    
def before_trading_start(context, data):
    results = pipeline_output('sentiment_metrics').dropna()
    longs = results[results['avg_impact'] > 0]
    shorts = results[results['avg_impact'] < 0]
    long_ranks = longs["avg_impact"].rank().order()
    short_ranks = shorts['avg_impact'].rank().order()
    short_quartile = int(len(short_ranks.index)*.01)
    long_quartile = int(len(long_ranks.index)*.01)
    context.shorts = short_ranks.tail(short_quartile)
    context.longs = long_ranks.head(long_quartile)
    
    # The pipe character "|" is the pandas union operator
    update_universe(context.longs.index | context.shorts.index)
    

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    record(lever=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           oo=len(get_open_orders()))
        
    
def rebalance(context, data):
    
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, -1.0 / len(context.shorts))
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, 1.0 / len(context.longs))
            
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if security in data:
            if security not in (context.longs.index | context.shorts.index):
                order_target_percent(security, 0)
There was a runtime error.

"quantopian.com/data/accern/alphaone" link is not working.

Page not found?

Wondering the same ^

Same! ^

Thank you for the questions,

Sorry for the late notice, Alphaone's data is no longer offered through Quantopian Data. We'll be taking down this thread shortly.

Seong