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