Overall Statistics
Total Trades
490
Average Win
1.28%
Average Loss
-0.70%
Compounding Annual Return
8.220%
Drawdown
19.600%
Expectancy
0.196
Net Profit
48.466%
Sharpe Ratio
0.51
Probabilistic Sharpe Ratio
8.768%
Loss Rate
58%
Win Rate
42%
Profit-Loss Ratio
1.83
Alpha
-0.007
Beta
0.389
Annual Standard Deviation
0.127
Annual Variance
0.016
Information Ratio
-0.809
Tracking Error
0.149
Treynor Ratio
0.166
Total Fees
$1901.84
Estimated Strategy Capacity
$7700000.00
Lowest Capacity Asset
FISV R735QTJ8XC9X
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;   
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion
namespace QuantConnect.Algorithm.CSharp
{
    public class LongTrendVolatility : QCAlgorithm
    {
        /********** Const ************/
        const string BENCHMARK = "QQQ";
        
        /// Used to Enable Ticker List For Specialized Runs
        const bool ENABLE_TICKER_LIST = false;

        const int ROLLING_WINDOW_COUNT = 21;

        const int NUM_POSITIONS = 8;

        decimal POSITION_SIZE;

        /********** Vars ************/
        int _LastYear = -1;

        // Start Times
        /// START BACK 1 MONTH FOR WARMUP
        DateTime startDate = new DateTime(2009, 1, 1);
        DateTime endDate = new DateTime(2014, 1, 1);

        /********** Structures ************/
        string[] _TickerList = {"NFLX", "MED", "AMZN", "NUS", "TPX", "TUP", "SHOO", "CROX", 
            "F", "FDS", "RJF", "GNW", "MIDD", "LULU", "CAR", "MELI", "DDS", "ODP", "RPM", 
            "NEU", "DECK", "SKX", "PVH", "HBI", "BC", "DAN", "SWK", "CHKP", "SWKS", "MRVL"};

        // Map Symbols to their Rolling Window of Tradebar Data
        Dictionary<Symbol, RollingWindow<TradeBar>> _WindowDict = new Dictionary<Symbol, RollingWindow<TradeBar>>();

        // Map Symbols to their Indicator Data
        Dictionary<Symbol, SymbolData> _SymbolDict = new Dictionary<Symbol, SymbolData>();

        // Industry Group Mapping
        Dictionary<int, string> _Industries = new Dictionary<int, string>();

        // Mapping Stocks To Their Industry Group
        Dictionary<int, List<Security>> _IndustryStocks = new Dictionary <int, List<Security>>();

        Dictionary<Symbol, TradeStruct> _TradeInfo = new Dictionary<Symbol, TradeStruct>();
        /********** Methods ************/

        public override void Initialize()
        {
            POSITION_SIZE = 1m / NUM_POSITIONS;

            SetStartDate(startDate);
            SetEndDate(endDate);
            SetCash(100000);

            UniverseSettings.Resolution = Resolution.Daily;
            UniverseSettings.DataNormalizationMode = DataNormalizationMode.SplitAdjusted;
            EnableAutomaticIndicatorWarmUp = true;

            //AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectFine));
            ///AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectRussell500));
            ///AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectRussell));
            AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectNdx100));
            //AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectNdx200));
            var security = AddEquity(BENCHMARK, Resolution.Daily);

            SetBenchmark(BENCHMARK);

            /// Setup Industry Mapping
            Type type = typeof(MorningstarIndustryCode); // MyClass is static class with static properties
            foreach (var p in type.GetFields( System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public
                                              ))
            {
                object v = p.GetValue(null); // static classes cannot be instanced, so use null...=

                var industryCode = v.ToString().ToInt32();
                _Industries[industryCode] = p.Name;
                _IndustryStocks[industryCode] = new List<Security>();
            }

            Schedule.On(Schedule.DateRules.EveryDay(),
                Schedule.TimeRules.AfterMarketOpen(security.Symbol, 1), LowVolTrend);

            SetWarmUp(new TimeSpan(252, 0, 0, 0));
        }

        public override void OnEndOfAlgorithm()
        {
            Liquidate();
            base.OnEndOfAlgorithm();
        }

        public void LowVolTrend()
        {
            if(IsWarmingUp)
            {
                return;
            }

            Transactions.CancelOpenOrders();

            /// Update Stop Loss If Necessary
            /// Close Any Trades and Remove Them If Necessary
            int lNumberOfPositionsToOpen = NUM_POSITIONS - (_TradeInfo.Count);

            UpdateOpenPositions();

            if(ActiveSecurities[BENCHMARK].Close < (_SymbolDict[BENCHMARK].FiftySma))
            {
                Liquidate();
                _TradeInfo.Clear();
                return;
            }  
            
            if(ActiveSecurities[BENCHMARK].Close < (_SymbolDict[BENCHMARK].FiftySma + (_SymbolDict[BENCHMARK].Atr*2)))
            {
                return;
            }  

            if(lNumberOfPositionsToOpen == 0)
            {
                return;
            }

            var lStocksToTrade = (from pair in _SymbolDict
                where ActiveSecurities.ContainsKey(pair.Key)
                where _WindowDict.ContainsKey(pair.Key)
                where _WindowDict[pair.Key].Count == ROLLING_WINDOW_COUNT
                where pair.Key != BENCHMARK
                && _SymbolDict[pair.Key].AverageDollarVolume > 14000000
                && ActiveSecurities[pair.Key].Close > 1
                && ActiveSecurities[pair.Key].Close < 175
                && !ActiveSecurities[pair.Key].Invested
                && _SymbolDict[pair.Key].FiftyDayHigh.PeriodsSinceMaximum == 0
                && _SymbolDict[pair.Key].RSI > 50
                orderby (ActiveSecurities[pair.Key].Close / _SymbolDict[pair.Key].FiftyDayLow) descending
                select pair.Key).Take(lNumberOfPositionsToOpen).ToList();

            foreach(var lPotentialTrade in lStocksToTrade)
            {

                var lTarget = POSITION_SIZE * 0.98m;
                var lQuantity = CalculateOrderQuantity(lPotentialTrade, lTarget);
                bool lCanTrade = true;

                if(ActiveSecurities[lPotentialTrade].Close * lQuantity > Portfolio.MarginRemaining)
                {
                    lCanTrade = false;
                }

                if(lCanTrade)
                {
                    /// SetHoldings(lPotentialTrade, POSITION_SIZE * 0.98m);
                    var limitPrice = ActiveSecurities[lPotentialTrade].Close;
                    LimitOrder(lPotentialTrade, lQuantity, limitPrice, "BUY");

                    /// Add Stock and Initial Stop Loss
                    /// decimal lStopLoss = ActiveSecurities[lPotentialTrade].Close - ( (_SymbolDict[lPotentialTrade].Atr) * 5.0m);

                    /// Wider Stops Seemed to have Worked Better Russell Style Stocks
                    /// decimal lStopLoss = ActiveSecurities[lPotentialTrade].Close - ( (_SymbolDict[lPotentialTrade].Atr) * 3.5m);
                    decimal lStopLoss = limitPrice - ( (_SymbolDict[lPotentialTrade].Atr) * 2.0m);
                    decimal lTarg = limitPrice + ( (_SymbolDict[lPotentialTrade].Atr) * 5.0m);

                    _TradeInfo[lPotentialTrade] = new TradeStruct(lStopLoss, ActiveSecurities[lPotentialTrade].Close, lTarg);
                }
            }   
        }

        public void UpdateOpenPositions()
        {
            List<Symbol> lClosedPositions = new List<Symbol>();

            foreach(var openPositionPair in _TradeInfo)
            {
                if(!ActiveSecurities.ContainsKey(openPositionPair.Key) || !ActiveSecurities[openPositionPair.Key].Invested || !_SymbolDict.ContainsKey(openPositionPair.Key))
                {
                    lClosedPositions.Add(openPositionPair.Key);
                    continue;   
                }

                /*if(ActiveSecurities[openPositionPair.Key].Close < _SymbolDict[openPositionPair.Key].FifteenEma)
                {
                    lClosedPositions.Add(openPositionPair.Key);
                    continue; 
                }*/

                openPositionPair.Value.CurrentHigh = Math.Max(openPositionPair.Value.CurrentHigh, ActiveSecurities[openPositionPair.Key].High);

                /// var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.8m : 0.8;
                var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.82m : 0.775m;
                ///var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.82m : 0.725m;
                /*trailingMultiplier = ActiveSecurities[openPositionPair.Key].Close < (_SymbolDict[openPositionPair.Key].FiftySma - (_SymbolDict[openPositionPair.Key].Atr*2.5m))
                    ? 0.86m : trailingMultiplier;*/
                
                var lTrailValue = openPositionPair.Value.CurrentHigh * trailingMultiplier;
                ///var lAtrTrail = openPositionPair.Value.CurrentHigh - (_SymbolDict[openPositionPair.Key].Atr * 7.5m);

                ///openPositionPair.Value.StopLoss = Math.Max(openPositionPair.Value.StopLoss, lTrailValue);

                if(ActiveSecurities[openPositionPair.Key].Close < openPositionPair.Value.StopLoss ||
                    ActiveSecurities[openPositionPair.Key].Close > openPositionPair.Value.Target)
                {
                    lClosedPositions.Add(openPositionPair.Key);
                }

                /// 15 Ema Trailing Adjustment Stop
                /*if(ActiveSecurities[openPositionPair.Key].Close < _SymbolDict[openPositionPair.Key].FifteenEma)
                {
                    openPositionPair.Value.StopLoss = Math.Max(openPositionPair.Value.StopLoss, ActiveSecurities[openPositionPair.Key].Low * 0.99m);
                }*/
            }

            foreach(var lClosedTrade in lClosedPositions)
            {
                _TradeInfo.Remove(lClosedTrade);
                Liquidate(lClosedTrade);
            }
        }

        public void WindowBarHandler(object sender, TradeBar windowBar)
        {
            if(!_WindowDict.ContainsKey(windowBar.Symbol))
            {
                _WindowDict[windowBar.Symbol] = new RollingWindow<TradeBar>(ROLLING_WINDOW_COUNT); 
            }

            _WindowDict[windowBar.Symbol].Add(windowBar);
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            // if we have no changes, do nothing
            if (changes == SecurityChanges.None) return;

            foreach (var security in changes.RemovedSecurities)
            {
                if(_SymbolDict.ContainsKey(security.Symbol))
                {
                    _SymbolDict.Remove(security.Symbol);
                }

                if(security.Fundamentals != null)
                {
                    var lCode = security.Fundamentals.AssetClassification.MorningstarIndustryCode;
                    if(_IndustryStocks.ContainsKey(lCode))
                    {
                        _IndustryStocks[lCode].Remove(security);
                    }
                }
            }

            foreach (var security in changes.AddedSecurities)
            {
                if(!_SymbolDict.ContainsKey(security.Symbol) && security.IsTradable)
                {
                    security.SetLeverage(1);
                    _SymbolDict.Add(security.Symbol, new SymbolData(security.Symbol, this));

                    var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(1));
                    consolidator.DataConsolidated += WindowBarHandler;

                    SubscriptionManager.AddConsolidator(security.Symbol, consolidator);

                    if(security.Fundamentals != null)
                    {
                        var lCode = security.Fundamentals.AssetClassification.MorningstarIndustryCode;
                        if(_IndustryStocks.ContainsKey(lCode))
                        {
                            _IndustryStocks[lCode].Add(security);
                        }
                    }
                }
            }
        }

        IEnumerable<Symbol> SelectCoarse(IEnumerable<CoarseFundamental> coarse)
        {
            if (Time.Year == _LastYear)
            {
                return Universe.Unchanged;
            }

            var sortedByDollarVolume =
                (from x in coarse
                 where x.HasFundamentalData && x.DollarVolume > 0 && x.Price > 0
                 && DoesTickerExist(x.Symbol.Value)
                 orderby x.DollarVolume descending
                 select x.Symbol).ToList();

            return sortedByDollarVolume;
        }

        IEnumerable<Symbol> SelectFine(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
                 where x.MarketCap > 100000000 
                 where x.MarketCap < 15000000000
                 orderby x.MarketCap descending
                 select x.Symbol).Take(1000).ToList();

            _LastYear = Time.Year;

            return filteredFine;
        }

        IEnumerable<Symbol> SelectRussell(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
                 orderby x.MarketCap descending
                 select x.Symbol).Take(1000).ToList();

            _LastYear = Time.Year;

            return filteredFine;
        }

        IEnumerable<Symbol> SelectRussell500(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
                 orderby x.MarketCap descending
                 select x.Symbol).Take(500).ToList();

            _LastYear = Time.Year;

            return filteredFine;
        }

        IEnumerable<Symbol> SelectRussellModified(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
                 orderby x.MarketCap descending
                 select x).Take(1000);

            var russell = (from x in filteredFine
                where x.Price < 300
                select x.Symbol).ToList();

            _LastYear = Time.Year;

            return russell;
        }

        IEnumerable<Symbol> SelectNdx100(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS")
                 where x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices
                 orderby x.MarketCap descending
                 select x.Symbol).Take(100).ToList();

            _LastYear = Time.Year;

            return filteredFine;
        }

        IEnumerable<Symbol> SelectNdx200(IEnumerable<FineFundamental> fine) 
        {
            var filteredFine =
                (from x in fine
                 where (x.CompanyReference.PrimaryExchangeID == "NAS")
                 where x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices
                 orderby x.MarketCap descending
                 select x.Symbol).Take(200).ToList();

            _LastYear = Time.Year;

            return filteredFine;
        }

        public bool DoesTickerExist(string ticker)
        {
            if(!ENABLE_TICKER_LIST)
            {
                return true;
            }


        	bool tickerExists = false;
        	foreach(var symbol in _TickerList)
        	{
        		if(ticker == symbol)
                {
                    tickerExists = true;
                    break;
                }
        	}
            return tickerExists;
        }
    }

    public class TradeStruct
    {
        public decimal StopLoss;
        public decimal CurrentHigh;
        public decimal Target;

        public TradeStruct(decimal aStopLoss, decimal aHigh, decimal aTarg)
        {
            StopLoss = aStopLoss;
            CurrentHigh = aHigh;
            Target = aTarg;
        }
    }

    public class SymbolData
    {
        Symbol _Symbol;
        QCAlgorithm _Algorithm;

        public AverageTrueRange Atr;
        public SimpleMovingAverage AveragePrice;
        public SimpleMovingAverage FiftySma;
        public ExponentialMovingAverage TwoHundredEma;
        public ExponentialMovingAverage FifteenEma;

        public SimpleMovingAverage AverageDollarVolume;
        public RateOfChangePercent FiftyDayChange;
        public Maximum FiftyDayHigh;
        public Minimum FiftyDayLow;
        
        public RateOfChangePercent oneMonth;
        public RateOfChangePercent threeMonth;
        public RateOfChangePercent sixMonth;
        public RateOfChangePercent nineMonth;
        public RateOfChangePercent twelveMonth;
        public RelativeStrengthIndex RSI;

        public SymbolData(Symbol aSymbol, QCAlgorithm aAlgorithm)
        {
            _Symbol = aSymbol;
            _Algorithm = aAlgorithm;

            RSI = aAlgorithm.RSI(aSymbol, 30);

            /// Indicator Setup
            Atr = aAlgorithm.ATR(aSymbol, 63, MovingAverageType.Simple, Resolution.Daily);
            AveragePrice = aAlgorithm.SMA(aSymbol, 63, Resolution.Daily);
            FiftySma = aAlgorithm.SMA(aSymbol, 50, Resolution.Daily);

            TwoHundredEma = aAlgorithm.EMA(aSymbol, 200);
            FifteenEma = aAlgorithm.EMA(aSymbol, 15);

            AverageDollarVolume = aAlgorithm.SMA(aSymbol, 63, Resolution.Daily, x => ( ((TradeBar)x).Volume * ((TradeBar)x).Close ));

            FiftyDayChange = aAlgorithm.ROCP(aSymbol, 50);

            FiftyDayHigh = aAlgorithm.MAX(aSymbol, 50, Resolution.Daily, x => ( ((TradeBar)x).Close ));
            FiftyDayLow = aAlgorithm.MIN(aSymbol, 50, Resolution.Daily, x => ( ((TradeBar)x).Low ));

            /*oneMonth = aAlgorithm.ROCP(aSymbol, 21, Resolution.Daily);
            threeMonth = aAlgorithm.ROCP(aSymbol, 63, Resolution.Daily);
            sixMonth = aAlgorithm.ROCP(aSymbol, 126, Resolution.Daily);
            nineMonth = aAlgorithm.ROCP(aSymbol, 189, Resolution.Daily);
            twelveMonth = aAlgorithm.ROCP(aSymbol, 252, Resolution.Daily);*/
        }

        public decimal AdrPercent
        {
            get
            {
                return (Atr / AveragePrice) * 100;
            }
        }

        public decimal IbdRs
        {
            get
            {
                // return (twelveMonth*0.2m) + nineMonth + sixMonth + threeMonth;
                return (twelveMonth*2.0m) + nineMonth + sixMonth + threeMonth;
            }
        }
    }
}