Overall Statistics
Total Trades
444
Average Win
0.99%
Average Loss
-1.27%
Compounding Annual Return
24.237%
Drawdown
11.400%
Expectancy
0.166
Net Profit
60.904%
Sharpe Ratio
0.884
Loss Rate
34%
Win Rate
66%
Profit-Loss Ratio
0.78
Alpha
0.529
Beta
-19.822
Annual Standard Deviation
0.229
Annual Variance
0.053
Information Ratio
0.812
Tracking Error
0.229
Treynor Ratio
-0.01
Total Fees
$603.04
namespace QuantConnect.Algorithm.CSharp
{

    public class MeowChickyIronmanFramework : QCAlgorithmFramework
    {

        public override void Initialize()
        {
            SetStartDate(2017, 1, 1);  //Set Start Date
            SetEndDate(DateTime.Now.AddDays(-1));    //Set End Date
            SetCash(2000);             //Set Strategy Cash
            
            /// Available Indicators: { "ema","rsi" }
            string[] indicators = { "rsi" };
            
            UniverseSettings.Resolution = Resolution.Minute;
			SetWarmup(TimeSpan.FromDays(50));
            SetUniverseSelection(new MeowChickyUniverseSelectionModel());
            
            SetAlpha(new MeowChickyAlphaModel(indicators, resolution: UniverseSettings.Resolution));
            //SetAlpha(new EmaCrossAlphaModel(10,50,resolution: UniverseSettings.Resolution));
            //SetAlpha(new CompositeAlphaModel(
            	//new MeowChickyAlphaModel(indicators,10,50, resolution: UniverseSettings.Resolution),
            	//new EmaCrossAlphaModel(10,50,resolution: UniverseSettings.Resolution)
            	//));
            SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
            
            SetExecution(new StandardDeviationExecutionModel(60, 2, UniverseSettings.Resolution));
            //SetExecution(new ImmediateExecutionModel());
            
            SetRiskManagement(new CompositeRiskManagementModel(
            	//new MaximumSectorExposureRiskManagementModel(.45m),
            	//new MaximumUnrealizedProfitPercentPerSecurity(.15m),
                new MaximumDrawdownPercentPerSecurity(.01m),
                new TrailingStopRiskManagementModel(.02m)
            ));
            
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            if (orderEvent.Status.IsFill())
            {
                // Debug($"Purchased Stock: {orderEvent.Symbol}");
            }
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Securities;

namespace QuantConnect.Algorithm.Framework.Selection
{
    /// <summary>
    /// MeowChicky Universe Selection Model
    /// </summary>
    public class MeowChickyUniverseSelectionModel : FundamentalUniverseSelectionModel
    {
        private const int NumberOfSymbolsCoarse = 500;
        private const int NumberOfSymbolsFine = 100;

        // rebalances at the start of each month
        private int _lastMonth = -1;
        private readonly Dictionary<Symbol, decimal> _dollarVolumeBySymbol = new Dictionary<Symbol, decimal>();

        /// <summary>
        /// Initializes a new default instance of the <see cref="MeowChickyUniverseSelectionModel"/>
        /// </summary>
        public MeowChickyUniverseSelectionModel()
            : base(true)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MeowChickyUniverseSelectionModel"/>
        /// </summary>
        /// <param name="universeSettings">Universe settings defines what subscription properties will be applied to selected securities</param>
        /// <param name="securityInitializer">Security initializer initializes newly selected securities</param>
        public MeowChickyUniverseSelectionModel(UniverseSettings universeSettings, ISecurityInitializer securityInitializer)
            : base(true, universeSettings, securityInitializer)
        {
        }

        /// <summary>
        /// The stocks must have fundamental data
        /// The stock must have positive previous-day close price
        /// The stock must have positive volume on the previous trading day
        /// </summary>
        public override IEnumerable<Symbol> SelectCoarse(QCAlgorithmFramework algorithm, IEnumerable<CoarseFundamental> coarse)
        {
        
            // materialize to collection if not already materialized
            coarse = coarse as ICollection<CoarseFundamental> ?? coarse.ToList();
            if (!coarse.Any())
            {
                return Universe.Unchanged;
            }

            var month = coarse.First().EndTime.Month;
            if (month == _lastMonth)
            {
                return Universe.Unchanged;
            }
            _lastMonth = month;

            // The stocks must have fundamental data
            // The stock must have positive previous-day close price
            // The stock must have positive volume on the previous trading day
            var sortedByDollarVolume = from x in coarse
                                       where x.HasFundamentalData && x.Volume > 0 && x.Price > 1m && x.Price < 20m
                                       
                                       // Leave these nasdaq test symbols commented out for the time being.
                                       //where x.Symbol != "ZWZZT SJURTIR7CJFP" ||
                                       //x.Symbol != "ZXZZT SJTSDFE19S9X" || x.Symbol != "ZVZZT SJTSDFE19S9X" || x.Symbol != "ZWZZT" ||
                                       //x.Symbol != "ZXZZT" || x.Symbol != "ZVZZT" || x.Symbol != "ECOM"
                                       
                                       where x.Symbol != "ECOM"
                                       orderby x.DollarVolume descending
                                       select x;

            var top = sortedByDollarVolume.Take(NumberOfSymbolsCoarse).ToList();
            foreach (var i in top)
            {
                _dollarVolumeBySymbol[i.Symbol] = i.DollarVolume;
            }

            return top.Select(x => x.Symbol);
        }

        /// <summary>
        /// The company's headquarter must in the U.S.
        /// The stock must be traded on either the NYSE or NASDAQ
        /// At least half a year since its initial public offering
        /// The stock's market cap must be greater than 500 million
        /// </summary>
        public override IEnumerable<Symbol> SelectFine(QCAlgorithmFramework algorithm, IEnumerable<FineFundamental> fine)
        {
            // The company's headquarter must in the U.S.
            // The stock must be traded on either the NYSE or NASDAQ
            // At least half a year since its initial public offering
            // The stock's market cap must be greater than 500 million
            var filteredFine = (from x in fine
                                where 
                                	x.CompanyReference.CountryId == "USA" &&
                                    (x.CompanyReference.PrimaryExchangeID == "NYS" || x.CompanyReference.PrimaryExchangeID == "NAS") &&
                                    (algorithm.Time - x.SecurityReference.IPODate).Days > 180 &&
                                    x.EarningReports.BasicAverageShares.ThreeMonths *
                                    x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 500000000m &&
                                    x.ValuationRatios.PSRatio < 1m &&
                                    x.ValuationRatios.PricetoCashRatio < 15 &&
                                    x.ValuationRatios.EVToEBITDA < 10 &&
                                    x.ValuationRatios.PEGRatio < 1
                                select x).ToList();

            // select stocks with top dollar volume in every single sector
            //var myDict = new[] { "B", "I", "M", "N", "T", "U" }.ToDictionary(x => x, y => new List<FineFundamental>());
            //var percent = (float)NumberOfSymbolsFine / filteredFine.Count;
            //foreach (var key in myDict.Keys.ToList())
            //{
                var value = (from x in filteredFine
                             //where x.CompanyReference.IndustryTemplateCode == key
                             orderby _dollarVolumeBySymbol[x.Symbol] descending
                             select x).ToList();
                //myDict[key] = value.Take((int)Math.Ceiling(value.Count * percent)).ToList();
            //}

            //var topFine = myDict.Values.ToList().SelectMany(x => x).Take(NumberOfSymbolsFine).ToList();

            return value.Select(x => x.Symbol).Take(NumberOfSymbolsFine);
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;

namespace QuantConnect.Algorithm.Framework.Alphas
{
    /// <summary>
    /// Defines a custom alpha model that uses MACD crossovers. The MACD signal line is
    /// used to generate up/down insights if it's stronger than the bounce threshold.
    /// If the MACD signal is within the bounce threshold then a flat price insight is returned.
    /// </summary>
    public class MeowChickyAdxAlphaModel3 : AlphaModel
    {
        
        private readonly int _period;
        private readonly Resolution _resolution;
        //private const decimal BounceThresholdPercent = 0.01m;
        private readonly Dictionary<Symbol, SymbolData> _symbolData;

        /// <summary>
        /// Initializes a new instance of the <see cref="MacdAlphaModel"/> class
        /// </summary>
        /// <param name="period">The ADX period</param>
        /// <param name="resolution">The resolution of data sent into the MACD indicator</param>
        public MeowChickyAdxAlphaModel3(
            int period = 14,
            Resolution resolution = Resolution.Daily
            )
        {
            _period = period;
            _resolution = resolution;
            _symbolData = new Dictionary<Symbol, SymbolData>();
            Name = $"{nameof(MeowChickyAdxAlphaModel3)}({period},{resolution})";
        }

        /// <summary>
        /// Determines an insight for each security based on it's current Adx signal
        /// </summary>
        /// <param name="algorithm">The algorithm instance</param>
        /// <param name="data">The new data available</param>
        /// <returns>The new insights generated</returns>
        public override IEnumerable<Insight> Update(QCAlgorithmFramework algorithm, Slice data)
        {
            foreach (var sd in _symbolData.Values)
            {
                if (sd.Security.Price == 0) continue;

                
                var direction = InsightDirection.Flat;
                decimal magnitude = 0;

                if (sd.ADX > 25 && sd.ADX != 0)
                {
                    if (sd.ADX.PositiveDirectionalIndex > sd.ADX && sd.ADX.NegativeDirectionalIndex < sd.ADX)
                    {
                        direction = InsightDirection.Up;
                    }
                }
                else if (sd.ADX > 25 && sd.ADX != 0)
                {
                    if (sd.ADX.NegativeDirectionalIndex > sd.ADX && sd.ADX.PositiveDirectionalIndex < sd.ADX)
                    {
                       direction = InsightDirection.Down;
                    }
                }
                
                // ignore signal for same direction as previous signal
                if (direction == sd.PreviousDirection)
                {
                    continue;
                }

                if (sd.ADX >25 && direction == InsightDirection.Up)
                {
                    magnitude = ((sd.ADX.PositiveDirectionalIndex - sd.ADX.NegativeDirectionalIndex)/100)*(sd.ADX.NegativeDirectionalIndex);
                }
                else if (sd.ADX > 25 && direction == InsightDirection.Down)
                {
                    magnitude = ((sd.ADX.NegativeDirectionalIndex - sd.ADX.PositiveDirectionalIndex)/100)*(sd.ADX.PositiveDirectionalIndex);
                }
                
                if (sd.ADX != 0)
                {
                    var insightPeriod = _resolution.ToTimeSpan().Multiply(_period);
                    var insight = Insight.Price(sd.Security.Symbol, insightPeriod, direction, magnitude: Convert.ToDouble(magnitude));                    
                    sd.PreviousDirection = insight.Direction;
                    yield return insight;
                }

            }
        }

        /// <summary>
        /// Event fired each time the we add/remove securities from the data feed.
        /// This initializes the MACD for each added security and cleans up the indicator for each removed security.
        /// </summary>
        /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
        /// <param name="changes">The security additions and removals from the algorithm</param>
        public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes)
        {
            foreach (var added in changes.AddedSecurities)
            {
                if (_symbolData.ContainsKey(added.Symbol))
                {
                    continue;
                }
                _symbolData.Add(added.Symbol, new SymbolData(algorithm, added, _period, _resolution));
            }

            foreach (var removed in changes.RemovedSecurities)
            {
                SymbolData data;
                if (_symbolData.TryGetValue(removed.Symbol, out data))
                {
                    // clean up our consolidator
                    algorithm.SubscriptionManager.RemoveConsolidator(data.Security.Symbol, data.Consolidator);
                    _symbolData.Remove(removed.Symbol);
                }
            }
        }

        class SymbolData
        {
            public InsightDirection? PreviousDirection { get; set; }

            public readonly Security Security;
            public readonly IDataConsolidator Consolidator;
            public readonly AverageDirectionalIndex ADX;

            public SymbolData(QCAlgorithmFramework algorithm, Security security, int period, Resolution resolution)
            {
                Security = security;
                Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution);
                algorithm.SubscriptionManager.AddConsolidator(security.Symbol, Consolidator);

                ADX = new AverageDirectionalIndex("ADX", period);
                
                TimeSpan timePeriod = TimeSpan.FromDays(period);
                if (resolution == Resolution.Hour)
                {
                    timePeriod = TimeSpan.FromHours(period);
                }
                else if (resolution == Resolution.Minute)
                {
                    timePeriod = TimeSpan.FromMinutes(period);
                }
                else if (resolution == Resolution.Second)
                {
                    timePeriod = TimeSpan.FromSeconds(period);
                }

                var history = algorithm.History(security.Symbol, timePeriod);

                foreach (var bar in history)
                {
                    ADX.Update(bar);
                }

                algorithm.RegisterIndicator(security.Symbol, ADX, Consolidator);
            }
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;


namespace QuantConnect.Algorithm.Framework.Alphas
{
    /// <summary>
    /// Alpha model that uses an EMA cross to create insights
    /// </summary>
    public class MeowChickyAlphaModel : AlphaModel
    {
        // Alpha Model - Ema Properties
        private readonly int _emaFastPeriod;
        private readonly int _emaSlowPeriod;
        private readonly int _emaPredictionInterval;

        // Alpha Model - Roc Properties
        private readonly int _rocPeriod;

        // Alpha Model - Rsi Properties
        private readonly int _rsiPeriod;

        // Alpha Model Properties
        private readonly string[] _indicators;
        private readonly Resolution _resolution;
        private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
        private QCAlgorithm _algorithm;

        /// <summary>
        /// Initializes a new instance of the <see cref="MeowChickyAlphaModel"/> class
        /// </summary>
        /// <param name="indicators">The list of indicators to be used in this alpha model</param>
        /// <param name="emaFastPeriod">The fast EMA period</param>
        /// <param name="emaSlowPeriod">The slow EMA period</param>
        /// <param name="rocPeriod">The Roc period</param>
        /// <param name="rsiPeriod">The Rsi period</param>
        /// <param name="resolution">The resolution of data sent into the EMA indicators</param>
        public MeowChickyAlphaModel(
            string[] indicators,
            int emaFastPeriod = 10,
            int emaSlowPeriod = 50,
            int rocPeriod = 10,
            int rsiPeriod = 14,
            Resolution resolution = Resolution.Minute
            )
        {
            _indicators = indicators;
            _emaFastPeriod = emaFastPeriod;
            _emaSlowPeriod = emaSlowPeriod;
            _emaPredictionInterval = emaFastPeriod;
            _rocPeriod = rocPeriod;
            _rsiPeriod = rsiPeriod;
            _resolution = resolution;
            _symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
            Name = $"{nameof(MeowChickyAlphaModel)}({indicators},{emaFastPeriod},{emaSlowPeriod},{rocPeriod},{rsiPeriod},{resolution})";
        }

        /// <summary>
        /// Updates this alpha model with the latest data from the algorithm.
        /// This is called each time the algorithm receives data for subscribed securities
        /// </summary>
        /// <param name="algorithm">The algorithm instance</param>
        /// <param name="data">The new data available</param>
        /// <returns>The new insights generated</returns>
        public override IEnumerable<Insight> Update(QCAlgorithmFramework algorithm, Slice data)
        {
            _algorithm = algorithm;

            var insights = new List<Insight>();
            foreach (var symbolData in _symbolDataBySymbol.Values)
            {
                foreach (var indicator in _indicators)
                {
                    switch (indicator.ToLower())
                    {
                        case "ema":
                            {
                                insights = EmaAlphaModel(symbolData, insights);
                                break;
                            }
                        case "rsi":
                            {
                                insights = RsiAlphaModel(symbolData, insights);
                                break;
                            }
                    }
                }
            }
            return insights;
        }

        private List<Insight> EmaAlphaModel(SymbolData symbolData, List<Insight> insights)
        {
            if (symbolData.EmaFast.IsReady && symbolData.EmaSlow.IsReady)
            {
                var insightPeriod = _resolution.ToTimeSpan().Multiply(_emaPredictionInterval);
                if (symbolData.FastIsOverSlow)
                {
                    if (symbolData.EmaSlow > symbolData.EmaFast)
                    {
                        insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Down));
                    }
                }
                else if (symbolData.SlowIsOverFast)
                {
                    if (symbolData.EmaFast > symbolData.EmaSlow)
                    {
                        insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Up));
                    }
                }
            }

            symbolData.FastIsOverSlow = symbolData.EmaFast > symbolData.EmaSlow;

            return insights;
        }

        private List<Insight> RsiAlphaModel(SymbolData symbolData, List<Insight> insights)
        {
            if (symbolData.Rsi.IsReady && symbolData.Roc.IsReady)
            {
                InsightDirection insightDirection = symbolData.RsiPreviousInsightDirection;

                var insightPeriod = _resolution.ToTimeSpan().Multiply(_rsiPeriod);

                if (_algorithm.Portfolio[symbolData.Symbol].Invested == false)
                {
                    if (symbolData.Rsi < symbolData.RsiBuyThreshold)
                    {
                        if (symbolData.RsiPreviousInsightDirection == InsightDirection.Down || symbolData.RsiPreviousInsightDirection == InsightDirection.Flat)
                        {
                            insights.Add(Insight.Price(symbolData.Symbol, _resolution, _rsiPeriod, InsightDirection.Up, magnitude: Convert.ToDouble(symbolData.Roc)));
                            symbolData.RsiPreviousInsightDirection = InsightDirection.Up;
                        }
                    }
                }

                if (_algorithm.Portfolio[symbolData.Symbol].Invested == true)
                {
                    if (symbolData.Rsi > symbolData.RsiSellThreshold)
                    {
                        if (symbolData.RsiPreviousInsightDirection == InsightDirection.Up || symbolData.RsiPreviousInsightDirection == InsightDirection.Flat)
                        {
                            insights.Add(Insight.Price(symbolData.Symbol, _resolution, _rsiPeriod, InsightDirection.Down, magnitude: Convert.ToDouble(symbolData.Roc)));
                            symbolData.RsiPreviousInsightDirection = InsightDirection.Down;
                        }
                    }
                }
            }
            return insights;
        }

        /// <summary>
        /// Event fired each time the we add/remove securities from the data feed
        /// </summary>
        /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
        /// <param name="changes">The security additions and removals from the algorithm</param>
        public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes)
        {
            foreach (var added in changes.AddedSecurities)
            {
                SymbolData symbolData;
                if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData))
                {
                    // create fast/slow EMAs
                    var emaFast = algorithm.EMA(added.Symbol, _emaFastPeriod, _resolution);
                    var emaSlow = algorithm.EMA(added.Symbol, _emaSlowPeriod, _resolution);

                    // Create Roc indicator
                    var roc = algorithm.ROC(added.Symbol, _rocPeriod, _resolution);

                    // Create RSIs
                    var rsi = algorithm.RSI(added.Symbol, _rsiPeriod, resolution: _resolution);

                    _symbolDataBySymbol[added.Symbol] = new SymbolData
                    {

                        EmaFast = emaFast,
                        EmaSlow = emaSlow,
                        Roc = roc,
                        Rsi = rsi,
                        Security = added

                    };
                }
                else
                {
                    // a security that was already initialized was re-added, reset the indicators
                    symbolData.EmaFast.Reset();
                    symbolData.EmaSlow.Reset();
                    symbolData.Roc.Reset();
                    symbolData.Rsi.Reset();
                }
            }
        }

        /// <summary>
        /// Contains data specific to a symbol required by this model
        /// </summary>
        private class SymbolData
        {
            public Security Security { get; set; }
            public Symbol Symbol => Security.Symbol;

            public ExponentialMovingAverage EmaFast { get; set; }
            public ExponentialMovingAverage EmaSlow { get; set; }

            public RateOfChange Roc { get; set; }

            public RelativeStrengthIndex Rsi { get; set; }
            public InsightDirection RsiPreviousInsightDirection { get; set; } = InsightDirection.Flat;
            public int RsiBuyThreshold { get; set; } = 25;
            public int RsiSellThreshold { get; set; } = 70;



            /// <summary>
            /// True if the fast is above the slow, otherwise false.
            /// This is used to prevent emitting the same signal repeatedly
            /// </summary>
            public bool FastIsOverSlow { get; set; }
            public bool SlowIsOverFast => !FastIsOverSlow;
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Util;

namespace QuantConnect.Algorithm.Framework.Alphas
{
    /// <summary>
    /// Uses Roc Percentage to create insights. 
    /// </summary>
    public class MeowChickyRocpAlphaModel : AlphaModel
    {
        private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();

        private readonly int _period;
        private readonly Resolution _resolution;

        /// <summary>
        /// Initializes a new instance of the <see cref="MeowChickyRocpAlphaModel"/> class
        /// </summary>
        /// <param name="period">The Rocp indicator period</param>
        /// <param name="resolution">The resolution of data sent into the RSI indicator</param>
        public MeowChickyRocpAlphaModel(
            int period = 14,
            Resolution resolution = Resolution.Daily
            )
        {
            _period = period;
            _resolution = resolution;
            Name = $"{nameof(MeowChickyRocpAlphaModel)}({_period},{_resolution})";
        }

        /// <summary>
        /// Updates this alpha model with the latest data from the algorithm.
        /// This is called each time the algorithm receives data for subscribed securities
        /// </summary>
        /// <param name="algorithm">The algorithm instance</param>
        /// <param name="data">The new data available</param>
        /// <returns>The new insights generated</returns>
        public override IEnumerable<Insight> Update(QCAlgorithmFramework algorithm, Slice data)
        {
            var insights = new List<Insight>();
            foreach (var kvp in _symbolDataBySymbol)
            {
                var symbol = kvp.Key;
                var rocp = kvp.Value.ROCP;
                var previousDirection = kvp.Value.PreviousDirection;
                

                if (rocp.IsReady)
                {
                    var insightPeriod = _resolution.ToTimeSpan().Multiply(_period);
                    var direction = InsightDirection.Flat;
                    if (rocp > 0)
                    {
                    	
                        direction = InsightDirection.Up;
                    }
                    else if(rocp < 0)
                    {
                    	direction = InsightDirection.Down;
                    }

                    // ignore signal for same direction as previous signal
                    if (direction == previousDirection)
                    {
                        continue;
                    }
                    var insight = Insight.Price(kvp.Value.Symbol, _resolution, _period, direction, magnitude: Convert.ToDouble(rocp));                    
                    kvp.Value.PreviousDirection = insight.Direction;
                    yield return insight;
                }
            }           
        }

        /// <summary>
        /// Cleans out old security data and initializes the Rocp for any newly added securities.
        /// This functional also seeds any new indicators using a history request.
        /// </summary>
        /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
        /// <param name="changes">The security additions and removals from the algorithm</param>
        public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes)
        {
            // clean up data for removed securities
            if (changes.RemovedSecurities.Count > 0)
            {
                var removed = changes.RemovedSecurities.ToHashSet(x => x.Symbol);
                foreach (var subscription in algorithm.SubscriptionManager.Subscriptions)
                {
                    if (removed.Contains(subscription.Symbol))
                    {
                        _symbolDataBySymbol.Remove(subscription.Symbol);
                        subscription.Consolidators.Clear();
                    }
                }
            }

            // initialize data for added securities
            var addedSymbols = new List<Symbol>();
            foreach (var added in changes.AddedSecurities)
            {
                if (!_symbolDataBySymbol.ContainsKey(added.Symbol))
                {
                    var rocp = algorithm.ROCP(added.Symbol, _period, _resolution);
                    var symbolData = new SymbolData(added.Symbol, rocp);
                    _symbolDataBySymbol[added.Symbol] = symbolData;
                    addedSymbols.Add(symbolData.Symbol);
                }
            }

            if (addedSymbols.Count > 0)
            {
                // warmup our indicators by pushing history through the consolidators
                algorithm.History(addedSymbols, _period, _resolution)
                    .PushThrough(data =>
                    {
                        SymbolData symbolData;
                        if (_symbolDataBySymbol.TryGetValue(data.Symbol, out symbolData))
                        {
                            symbolData.ROCP.Update(data.EndTime, data.Value);
                        }
                });
            }
        }
        

        /// <summary>
        /// Contains data specific to a symbol required by this model
        /// </summary>
        private class SymbolData
        {
            public Symbol Symbol { get; }
            public RateOfChangePercent ROCP { get; }
            public InsightDirection PreviousDirection { get; set; }

            public SymbolData(Symbol symbol, RateOfChangePercent rocp)
            {
                Symbol = symbol;
                ROCP = rocp;
            }
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Util;

namespace QuantConnect.Algorithm.Framework.Alphas
{
    /// <summary>
    /// Uses ROC to create insights. Crossing from pos to neg will create a direction insight and rate of change is magnitude
    /// </summary>
    public class MeowChickyRocAlphaModel : AlphaModel
    {
        private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();

        private readonly int _period;
        private readonly Resolution _resolution;

        /// <summary>
        /// Initializes a new instance of the <see cref="MeowChickyRocAlphaModel"/> class
        /// </summary>
        /// <param name="period">The Roc indicator period</param>
        /// <param name="resolution">The resolution of data sent into the Roc indicator</param>
        public MeowChickyRocAlphaModel(
            int period = 14,
            Resolution resolution = Resolution.Daily
            )
        {
            _period = period;
            _resolution = resolution;
            Name = $"{nameof(MeowChickyRocAlphaModel)}({_period},{_resolution})";
        }

        /// <summary>
        /// Updates this alpha model with the latest data from the algorithm.
        /// This is called each time the algorithm receives data for subscribed securities
        /// </summary>
        /// <param name="algorithm">The algorithm instance</param>
        /// <param name="data">The new data available</param>
        /// <returns>The new insights generated</returns>
        public override IEnumerable<Insight> Update(QCAlgorithmFramework algorithm, Slice data)
        {
            var insights = new List<Insight>();
            foreach (var kvp in _symbolDataBySymbol)
            {
                var symbol = kvp.Key;
                var roc = kvp.Value.ROC;
                var previousDirection = kvp.Value.PreviousDirection;
                

                if (roc.IsReady)
                {
                    var direction = InsightDirection.Flat;
                    if (roc > 0)
                    {
                    	direction = InsightDirection.Up;
                    }
                    else if(roc < 0)
                    {
                    	direction = InsightDirection.Down;
                    }

                    // ignore signal for same direction as previous signal
                    if (direction == previousDirection)
                    {
                        continue;
                    }
                    
                    double magnitude = 0;
                    if(roc < 1)
                    {
                    	magnitude = Convert.ToDouble(roc.Current.Value);
                    }
                    else
                    {
                    	magnitude = 1;
                    }
                    var insight = Insight.Price(kvp.Value.Symbol, _resolution, _period, direction, magnitude: magnitude);                    
                    kvp.Value.PreviousDirection = insight.Direction;
                    yield return insight;
                }
            }           
        }

        /// <summary>
        /// Cleans out old security data and initializes the Roc for any newly added securities.
        /// This functional also seeds any new indicators using a history request.
        /// </summary>
        /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
        /// <param name="changes">The security additions and removals from the algorithm</param>
        public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes)
        {
            // clean up data for removed securities
            if (changes.RemovedSecurities.Count > 0)
            {
                var removed = changes.RemovedSecurities.ToHashSet(x => x.Symbol);
                foreach (var subscription in algorithm.SubscriptionManager.Subscriptions)
                {
                    if (removed.Contains(subscription.Symbol))
                    {
                        _symbolDataBySymbol.Remove(subscription.Symbol);
                        subscription.Consolidators.Clear();
                    }
                }
            }

            // initialize data for added securities
            var addedSymbols = new List<Symbol>();
            foreach (var added in changes.AddedSecurities)
            {
                if (!_symbolDataBySymbol.ContainsKey(added.Symbol))
                {
                    var roc = algorithm.ROC(added.Symbol, _period, _resolution);
                    var symbolData = new SymbolData(added.Symbol, roc);
                    _symbolDataBySymbol[added.Symbol] = symbolData;
                    addedSymbols.Add(symbolData.Symbol);
                }
            }

            if (addedSymbols.Count > 0)
            {
                // warmup our indicators by pushing history through the consolidators
                algorithm.History(addedSymbols, _period, _resolution)
                    .PushThrough(data =>
                    {
                        SymbolData symbolData;
                        if (_symbolDataBySymbol.TryGetValue(data.Symbol, out symbolData))
                        {
                            symbolData.ROC.Update(data.EndTime, data.Value);
                        }
                    });
            }
        }

        

        /// <summary>
        /// Contains data specific to a symbol required by this model
        /// </summary>
        private class SymbolData
        {
            public Symbol Symbol { get; }
            
            public RateOfChange ROC { get; }
            public InsightDirection PreviousDirection { get; set; }

            public SymbolData(Symbol symbol, RateOfChange roc)
            {
                Symbol = symbol;
                ROC = roc;
                
            }
        }        
    }
}