Overall Statistics
Total Trades
2797
Average Win
0.53%
Average Loss
-0.99%
Compounding Annual Return
15.437%
Drawdown
44.600%
Expectancy
0.079
Net Profit
120.627%
Sharpe Ratio
0.626
Probabilistic Sharpe Ratio
14.652%
Loss Rate
30%
Win Rate
70%
Profit-Loss Ratio
0.53
Alpha
0.269
Beta
-0.183
Annual Standard Deviation
0.391
Annual Variance
0.153
Information Ratio
0.25
Tracking Error
0.447
Treynor Ratio
-1.335
Total Fees
$4265.35
namespace QuantConnect.Algorithm.CSharp
{
    using QuantConnect.Algorithm;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Data;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Orders;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;


    // public class EmaCrossAlphaModelX : EmaCrossAlphaModel
    // {
    //     public EmaCrossAlphaModelX(int fastPeriod = 12, int slowPeriod = 26, Resolution resolution = Resolution.Daily) : base(fastPeriod, slowPeriod, resolution) { }
    //     public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
    //     {
    //         var updates = base.Update(algorithm, data);
    //         //return updates;
    //         double? equal = 10.0 / (((SeparatedConcernEMAWeighted)algorithm).tickers.Count * 1.0);
    //         List<Insight> weighted = new List<Insight>();
    //         foreach (var update in updates)
    //         {
    //             Insight temp = null;
    //             if (update.Weight.HasValue == false || update.Weight.Value == 0.0)
    //             {
    //                 temp = new Insight(
    //                     update.Symbol,
    //                     update.Period,
    //                     update.Type,
    //                     update.Direction,
    //                     update.Magnitude,
    //                     update.Confidence,
    //                     update.SourceModel,
    //                     equal);
    //             }
    //             else
    //             {
    //                 temp = update;
    //             }
    //             weighted.Add(temp);
    //         }
    //         return weighted;
    //     }
    //     public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
    //     {
    //         base.OnSecuritiesChanged(algorithm, changes);
    //     }
    // }

    public class StandardDeviationExecutionModelX : StandardDeviationExecutionModel
    {
        public StandardDeviationExecutionModelX(int period = 60, decimal deviations = 2, Resolution resolution = Resolution.Hour) : base(period, deviations, resolution) { }
        public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets)
        {
            base.Execute(algorithm, targets);
        }

        public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
        {
            base.OnSecuritiesChanged(algorithm, changes);
        }
    }

    public class InsightWeightingPortfolioConstructionModelX : InsightWeightingPortfolioConstructionModel
    {
        public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
        {
            return base.CreateTargets(algorithm, insights);
        }
        public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
        {
            base.OnSecuritiesChanged(algorithm, changes);
        }
        protected override Dictionary<Insight, double> DetermineTargetPercent(List<Insight> activeInsights)
        {
            return base.DetermineTargetPercent(activeInsights);
        }
        protected override double GetValue(Insight insight)
        {
            return base.GetValue(insight);
            //return insight.Score.Direction;
        }
    }

    public class MaximumUnrealizedProfitPercentPerSecurityX : MaximumUnrealizedProfitPercentPerSecurity
    {
        public MaximumUnrealizedProfitPercentPerSecurityX(decimal maximumUnrealizedProfitPercent = 0.05M) : base(maximumUnrealizedProfitPercent) { }
        public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
        {
            return base.ManageRisk(algorithm, targets);
        }
        public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
        {
            base.OnSecuritiesChanged(algorithm, changes);
        }
    }

    public class SeparatedConcernEMAWeighted : QCAlgorithm
    {
        public Dictionary<int, Insight> insights = new Dictionary<int, Insight>();
        int i = 0;
        //random stock picks. replace these with your own picks
        public List<string> tickers = new List<string> { "GILD", "ABMD", "UNH", "ALXN", "BLK", "HFC", "KSU" };
        public override void Initialize()
        {
            SetStartDate(2015, 4, 5);  //Set Start Date
            SetCash(100000);             //Set Strategy Cash


            //         // AddEquity("SPY", Resolution.Hour);

            AddAlpha(new WeightedEmaCrossAlphaModel(50, 200, Resolution.Hour));

            SetExecution(new StandardDeviationExecutionModelX(60, 0.75m, Resolution.Hour));

            //SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());

            SetPortfolioConstruction(new InsightWeightingPortfolioConstructionModelX());

            //SetRiskManagement(new MaximumUnrealizedProfitPercentPerSecurityX(0.03m));
            SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.09m));


            UniverseSettings.Resolution = Resolution.Hour;

            var symbols = tickers.Select(t => QuantConnect.Symbol.Create(t, SecurityType.Equity, Market.USA)).ToArray();
            SetUniverseSelection(new LiquidETFUniverse());

            //SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
            //InsightsGenerated += SeparatedConcernEMAWeighted_InsightsGenerated;

        }

        private void SeparatedConcernEMAWeighted_InsightsGenerated(Interfaces.IAlgorithm algorithm, GeneratedInsightsCollection eventData)
        {
            //Insight.CloseTimeUtc
            //Insight.Confidence
            //Insight.Direction
            //Insight.EstimatedValue
            //Insight.GeneratedTimeUtc
            //Insight.GroupId
            //Insight.Id
            //Insight.Magnitude
            //Insight.Period
            //Insight.ReferenceValue
            //Insight.ReferenceValueFinal
            //Insight.Score
            //Insight.SourceModel
            //Insight.Symbol
            //Insight.Type
            //Insight.Weight
            //this.EmitInsights

            foreach (var insight in eventData.Insights)
            {
                insights.Add(i++, insight);
            }
            //delete old insights
            var keys = new List<int>();
            foreach (var kvp in insights)
            {
                if (kvp.Value.IsActive(Time) == false)
                {
                    keys.Add(kvp.Key);
                }
            }
            keys.ForEach(k => insights.Remove(k));
        }

        public static OrderDirection ItoODir(InsightDirection direction)
        {
            switch (direction)
            {
                case InsightDirection.Down:
                    return OrderDirection.Sell;
                case InsightDirection.Up:
                    return OrderDirection.Buy;
                default:
                    return OrderDirection.Hold;
            }
        }

        // OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        // Slice object keyed by symbol containing the stock data
        public override void OnData(Slice data)
        {
            // //foreach (var target in PortfolioConstruction.CreateTargets(this, insights.Values.ToArray()))
            // foreach(var insight in insights)
            // { 
            // 	if(data.ContainsKey(insight.Value.Symbol) == false) continue;
            //     var cash = Portfolio.Cash;
            //     var holding = Portfolio[insight.Value.Symbol];
            //     //holding.SetHoldings(holding.Price, Portfolio.GetMarginRemaining(insight.Value.Symbol, ItoODir(insight.Value.Direction)));
            //     if(insight.Value.Direction == InsightDirection.Up)
            //     {
            //     	SetHoldings(insight.Value.Symbol, 1.0m/tickers.Count);
            //     	//Debug(insight.Value.Symbol.Value + ": before; " + cash + ", after; " +  Portfolio.Cash);
            //     }
            //     if(insight.Value.Direction == InsightDirection.Down)
            //     {
            //     	SetHoldings(insight.Value.Symbol, -1.0m/tickers.Count);
            //     	//Debug(insight.Value.Symbol.Value + ": before; " + cash + ", after; " +  Portfolio.Cash);
            //     }
            // }
        }

        public override void OnWarmupFinished()
        {
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
        }
    }
}
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 WeightedEmaCrossAlphaModel : AlphaModel
    {
        private readonly int _fastPeriod;
        private readonly int _slowPeriod;
        private readonly Resolution _resolution;
        private readonly int _predictionInterval;
        private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;

        /// <summary>
        /// Initializes a new instance of the <see cref="EmaCrossAlphaModel"/> class
        /// </summary>
        /// <param name="fastPeriod">The fast EMA period</param>
        /// <param name="slowPeriod">The slow EMA period</param>
        /// <param name="resolution">The resolution of data sent into the EMA indicators</param>
        public WeightedEmaCrossAlphaModel(
            int fastPeriod = 12,
            int slowPeriod = 26,
            Resolution resolution = Resolution.Daily
            )
        {
            _fastPeriod = fastPeriod;
            _slowPeriod = slowPeriod;
            _resolution = resolution;
            _predictionInterval = fastPeriod;
            _symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
            Name = $"{nameof(EmaCrossAlphaModel)}({fastPeriod},{slowPeriod},{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(QCAlgorithm algorithm, Slice data)
        {
            var insights = new List<Insight>();
            foreach (var symbolData in _symbolDataBySymbol.Values)
            {
                if (symbolData.Fast.IsReady && symbolData.Slow.IsReady)
                {
                    var ratio1 = (double)symbolData.Slow.Current.Value/ (double)symbolData.Fast.Current.Value;
                    var ratio2 = (double)symbolData.Fast.Current.Value / (double)symbolData.Slow.Current.Value;
                    var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval);
                    if (symbolData.FastIsOverSlow)
                    {
                        if (ratio1 > 1.0005)
                        {
                            insights.Add(Insight.Price(
                                symbolData.Symbol,
                                _resolution, 
                                _predictionInterval, 
                                InsightDirection.Down, 
                                null, null, null,  
                                ratio1*ratio1*ratio1
                            ));
                        }
                    }
                    else if (symbolData.SlowIsOverFast)
                    {
                        if (ratio2 > 1.0005)
                        {
                            insights.Add(Insight.Price(
                                symbolData.Symbol,
                                _resolution,
                                _predictionInterval,
                                InsightDirection.Up,
                                null, null, null,
                                ratio2*ratio2*ratio2
                            ));
                        }
                    }
                }

                symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow;
            }

            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(QCAlgorithm algorithm, SecurityChanges changes)
        {
            foreach (var added in changes.AddedSecurities)
            {
                SymbolData symbolData;
                if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData))
                {
                    // create fast/slow EMAs
                    var fast = algorithm.EMA(added.Symbol, _fastPeriod, _resolution);
                    var slow = algorithm.EMA(added.Symbol, _slowPeriod, _resolution);
                    _symbolDataBySymbol[added.Symbol] = new SymbolData
                    {
                        Security = added,
                        Fast = fast,
                        Slow = slow
                    };
                }
                else
                {
                    // a security that was already initialized was re-added, reset the indicators
                    symbolData.Fast.Reset();
                    symbolData.Slow.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 Fast { get; set; }
            public ExponentialMovingAverage Slow { get; set; }

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