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.
Buy stocks where news sentiment barely impacts their price, sell stocks where news sentiment greatly impacts their price.
|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)