Back to Community
Sentdex Dataset

I decided have another look at the Sentdex dataset.

I was wondering why it only contains the sentiment rating field and not the "Volume of Mentions" field. The latter could be very useful either on its own or in combination. Anybody know why this is not included in the Quantopian dataset? They have it on their website.

Anyhow, I tried reproducing this example strategy:
http://sentdex.com/blog/back-testing-sentdex-sentiment-analysis-signals-for-stocks

It's a basic wisdom-of-the-crowds concept ("wisdom of the press?" haha yeah right). I made some minor changes, but I'm not sure how they got their backtest to out-perform, except by luck. Even with slippage disabled mine only underperforms, which is what I would expect actually. Business/financial press generally seems to be reactionary rather than insightful.

I'm curious, has anybody found anything interesting in this dataset?

Clone Algorithm
11
Loading...
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
import numpy as np
import quantopian.algorithm as algo
import quantopian.optimize as opt
from quantopian.pipeline                  import Pipeline, CustomFactor
from quantopian.pipeline.filters          import QTradableStocksUS
from quantopian.pipeline.data.builtin     import USEquityPricing
from quantopian.pipeline.data             import Fundamentals
from quantopian.pipeline.factors          import SimpleMovingAverage, AverageDollarVolume, AnnualizedVolatility
    
from quantopian.pipeline.experimental     import risk_loading_pipeline

from quantopian.pipeline.data.sentdex     import sentiment

def initialize(context):
    set_commission(commission.PerTrade(cost=0))
    set_slippage(slippage.VolumeShareSlippage(volume_limit=1, price_impact=0))
        
    algo.schedule_function(rebalance,
                           algo.date_rules.every_day(),
                           algo.time_rules.market_close(minutes=45))
    
    algo.schedule_function(record_vars,
                           algo.date_rules.every_day(),
                           algo.time_rules.market_close())
    
    algo.attach_pipeline(make_pipeline(), 'pipeline')
    algo.attach_pipeline(risk_loading_pipeline(), 'risk')
    
    context.longs = {}
    
    
def make_pipeline():
    universe = QTradableStocksUS() 
    m = universe

    sent = sentiment.sentiment_signal.latest
    
    m &= (sent >= 6) | (sent <= -1)

    return Pipeline(
        columns={
            'buy': sent >= 6,
            'sell': sent <= -1,
            'sent': sent,
        },
        screen=m,
    )
    
def rebalance(context, data):
    output = algo.pipeline_output('pipeline')
    
    for s in output.index:
        if output.buy[s]:
            context.longs[s] = 1.0
        elif output.sell[s]:
            context.longs[s] = 0
        elif s in context.longs:
            context.longs[s] *= 0.99
    
    weights = {}
    for s, w in context.longs.items():
        weights[s] = w / sum(context.longs.values())
    
  
    #record(plen = len(output.index))
    #weights = output.weight / output.weight.abs().sum() * 1.05

    order_optimal_portfolio(
        objective=opt.TargetWeights( weights),
        constraints=[
            opt.MaxGrossExposure(1.005), # Gross exposure: 100.5%
            #opt.LongOnly(output.index),
            #opt.DollarNeutral(),         # Net exposure: 0
            opt.PositionConcentration.with_equal_bounds(-0.045, 0.045),    
            #opt.MaxTurnover(0.3),
            #opt.experimental.RiskModelExposure(
            #    risk_model_loadings=algo.pipeline_output('risk').dropna(),
            #    version=opt.Newest,
            #    min_momentum = -0.0,
                #max_momentum = 0.0,
                #min_short_term_reversal = -0.05,
                #max_short_term_reversal = 0.05,
                #min_value = -0.0,
                #max_value = 0.0,
                #min_size = -0.20,
                #max_size = 0.0,
            #    min_volatility = -0.10,
                #max_volatility = 0.0,
                #min_basic_materials=-0.0,
                #max_basic_materials=0.0,
                #min_consumer_cyclical=-0.0, 
                #max_consumer_cyclical=0.0, 
                #min_financial_services=-0.0, 
                #max_financial_services=0.0, 
                #min_real_estate=-0.0, 
                #max_real_estate=0.0, 
                #min_consumer_defensive=-0.0, 
                #max_consumer_defensive=0.0, 
                #min_health_care=-0.0, 
                #max_health_care=0.0, 
                #min_utilities=-0.0, 
                #max_utilities=0.0, 
                #min_communication_services=-0.0, 
                #max_communication_services=0.0, 
                #min_energy=-0.0, 
                #max_energy=0.0, 
                #min_industrials=-0.0,
                #max_industrials=0.0, 
            #    min_technology=-0.0, 
                #max_technology=0.0,
            #),
        ],
    )    


    
def record_vars(context, data):
    record(l = context.account.leverage)
    longs = shorts = 0
    for stock in context.portfolio.positions:
        if   context.portfolio.positions[stock].amount > 0: longs  += 1;
        elif context.portfolio.positions[stock].amount < 0: shorts += 1;
    record(lngs = longs, shrts = shorts)
There was a runtime error.