Overall Statistics |
Total Trades 4468 Average Win 0.23% Average Loss -0.20% Compounding Annual Return -7.314% Drawdown 24.600% Expectancy -0.027 Net Profit -18.312% Sharpe Ratio -0.367 Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.15 Alpha -0.076 Beta 0.312 Annual Standard Deviation 0.142 Annual Variance 0.02 Information Ratio -0.805 Tracking Error 0.161 Treynor Ratio -0.166 Total Fees $4509.46 |
using MathNet.Numerics.Distributions; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Orders; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace QuantConnect.Algorithm.CSharp { public class BasicTemplateAlgorithm : QCAlgorithm { //Count the number of days that pass, so that the algo only executes every 2 weeks int countDay = 0; //Create a Dictionary to store each security and a rolling window of their closing price for the past 20 trading days Dictionary<Symbol, RollingWindow<decimal>> _storage = new Dictionary<Symbol, RollingWindow<decimal>>(); //Create a list to capture the stocks that are entered into the universe List<Symbol> top10Gainers = new List<Symbol>(); List<Symbol> top10Losers = new List<Symbol>(); //Create list to record the positive and negative price movers each iteration of the algo List<Symbol> recordPositiveChanges = new List<Symbol>(); List<Symbol> recordNegativeChanges = new List<Symbol>(); public override void Initialize() { SetStartDate(2013, 9, 01); SetEndDate(2016, 5, 01); SetCash(50000); UniverseSettings.Resolution = Resolution.Daily; AddUniverse(CoarseSelectionFunction); } public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { ///Add each security in the coarse library to the dictionary, along with the price for that day to its rolling window ///if the security already exists in the Dictionary, just add that day's price to that security's ///Rolling window. foreach (var coarseItem in coarse) { if (!_storage.ContainsKey(coarseItem.Symbol)) { _storage.Add(coarseItem.Symbol, new RollingWindow<decimal>(20)); } _storage[coarseItem.Symbol].Add(coarseItem.Price); } //Create a list of the top 100 stocks by dollar volume and store by their symbol var findTop100 = (from coarseItem in coarse where _storage[coarseItem.Symbol].Count == 20 orderby coarseItem.DollarVolume descending select coarseItem.Symbol).Take(100); //Count how many days have passed countDay++; //Return empty / nothing until 20 days pass //Then, only return the universe if 1 week has passed yet if (!(countDay >= 20) || countDay % 5 != 0) { return new List<Symbol>(); } //If 1 week has passed, then return a new universe //Clear out the universe list so it can be updated top10Gainers.Clear(); top10Losers.Clear(); //Create a list to contain the top 10 stocks with the highest positive price change top10Gainers = (from symbol in findTop100 let start = _storage[symbol][19] let end = _storage[symbol][0] let delta = (end - start) / start orderby delta descending select symbol).Take(10).ToList(); //Create a list to contain the top 10 stocks with the highest negative price change top10Losers = (from symbol in findTop100 let start = _storage[symbol][19] let end = _storage[symbol][0] let delta = (end - start) / start orderby delta ascending select symbol).Take(10).ToList(); //Create a universe which will be returned to include all stocks that need to be analyzed var universe = new List<Symbol>(); universe.AddRange(top10Gainers); universe.AddRange(top10Losers); return universe; } public void OnData(TradeBars data) { //Only execute if 5 trading days have gone by if (countDay % 5 == 0) { Liquidate(); //Short stocks that are doing well, and long stocks that have not done well in the past 2 weeks //Then add the respective stocks to a list to be used the next iteration of the algo foreach (var security in top10Gainers) { //Order(security, -10); SetHoldings(security, -.07m); } foreach (var security in top10Losers) { //Order(security, 10); SetHoldings(security, .07m); } } } } }