Overall Statistics
Total Trades
2354
Average Win
0.09%
Average Loss
-0.01%
Compounding Annual Return
45.513%
Drawdown
5.400%
Expectancy
1.116
Net Profit
13.240%
Sharpe Ratio
2.654
Probabilistic Sharpe Ratio
81.757%
Loss Rate
87%
Win Rate
13%
Profit-Loss Ratio
15.38
Alpha
0.038
Beta
0.821
Annual Standard Deviation
0.115
Annual Variance
0.013
Information Ratio
-0.195
Tracking Error
0.102
Treynor Ratio
0.37
Total Fees
$2725.29
using QuantConnect.Data.Custom.Tiingo;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;

namespace QuantConnect
{
	public partial class BootCampTask : QCAlgorithm
    {
    	private RollingWindow<TradeBar> Window;
    	
        public override void Initialize()
        {
	        SetStartDate(2016, 11, 1);
	        SetEndDate(2017, 3, 1);  
			var symbols = new[] {QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA), 
        	QuantConnect.Symbol.Create("NKE", SecurityType.Equity, Market.USA)};
			SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
        	AddAlpha(new NewsSentimentAlphaModel());
        	SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); 
    		SetExecution(new ImmediateExecutionModel()); 
        	SetRiskManagement(new NullRiskManagementModel());
        }
    }
    
    public class NewsData
    {
    	public Symbol Symbol { get; }
    	public RollingWindow<double> Window { get; }
    	
    	public NewsData(Symbol symbol)
    	{
	    	Symbol = symbol;
	    	Window = new RollingWindow<double>(100);
    	}
    }
	
	public partial class NewsSentimentAlphaModel : AlphaModel        
	{	
        private double _score;

        public Dictionary <Symbol, NewsData> _newsData = new Dictionary<Symbol, NewsData>();
		
		public Dictionary<string, double> wordScores = new Dictionary<string, double>()
        {
	    	{"attractive",0.5}, {"bad",-0.5}, {"beat",0.5}, {"beneficial",0.5},
	    	{"down",-0.5}, {"excellent",0.5}, {"fail",-0.5}, {"failed",-0.5}, {"good",0.5},
	    	{"great",0.5}, {"growth",0.5}, {"large",0.5}, {"lose",-0.5}, {"lucrative",0.5},
	    	{"mishandled",-0.5}, {"missed",-0.5}, {"missing",-0.5}, {"nailed",0.5},
	    	{"negative",-0.5}, {"poor",-0.5}, {"positive",0.5}, {"profitable",0.5},
	    	{"right",0.5}, {"solid",0.5}, {"sound",0.5}, {"success",0.5}, {"un_lucrative",-0.5},
	    	{"unproductive",-0.5}, {"up",0.5}, {"worthwhile",0.5}, {"wrong",-0.5},
{"abandoned",-1},
{"abandonment",-1},
{"abandon",-1},
{"abase",-2},
{"abasement",-2},
{"abash",-2},
{"abate",-1},
{"abdicate",-1},
{"aberration",-2},
{"abhor",-2},
{"abhorred",-2},
{"abhorrence",-2},
{"abhorrent",-2},
{"abhorrently",-2},
{"abhors",-2},
{"abidance",2},
{"abide",2},
{"abject",-2},
{"abjectly",-2},
{"abjure",-1},
{"abilities",1},
{"ability",1},
{"able",1},
{"abnormal",-1},
{"abolish",-1},
{"abominable",-2},
{"abominably",-2},
{"abominate",-2}
 //and so on
	    };
    	
    	public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data) 
        {
	        var insights = new List<Insight>();
	        
	        var news = data.Get<TiingoNews>();
	
	        foreach (var article in news.Values)
	        {
	            var words = article.Description.ToLower().Split(' ');
	            _score = words
	            	.Where(x => wordScores.ContainsKey(x))
	            	.Sum(x => wordScores[x]);
	            
	            // 1.  Get the underlying symbol and save to the variable symbol
	        	var symbol = article.Symbol.Underlying;
	        	
	        	// 2. Add scores to the rolling window associated with its _newsData symbol 
	        	_newsData[symbol].Window.Add(_score);
	            
            	// 3. Sum the rolling window scores, save to sentiment
            	// If _sentiment aggregate score for the time period is greater than 5, emit an up insight
            	var sentiment = _newsData[symbol].Window.Sum();                 
            	if (sentiment > 5)
            	{
                	insights.Add(Insight.Price(symbol, TimeSpan.FromDays(1), InsightDirection.Up));
            	}
	        }
	        return insights;
        }
        
        public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
	    {
        	
	        foreach (var security in changes.AddedSecurities)
	        {
	            var symbol = security.Symbol;
	            var newsAsset = algorithm.AddData<TiingoNews>(symbol);
	            _newsData[symbol] = new NewsData(newsAsset.Symbol);
	        }
        
        	foreach (var security in changes.RemovedSecurities)
        	{	
        		NewsData newsData;
	            if (_newsData.Remove(security.Symbol, out newsData))
	            {
	                algorithm.RemoveSecurity(newsData.Symbol);
	            }
        	}
	    }
	}
	
}