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); } } } } }