Overall Statistics
Total Trades
150
Average Win
0.03%
Average Loss
-0.02%
Compounding Annual Return
0.080%
Drawdown
0.400%
Expectancy
0.276
Net Profit
0.400%
Sharpe Ratio
0.369
Probabilistic Sharpe Ratio
4.567%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.78
Alpha
-0
Beta
0.006
Annual Standard Deviation
0.001
Annual Variance
0
Information Ratio
-0.878
Tracking Error
0.156
Treynor Ratio
0.095
Total Fees
$150.00
Estimated Strategy Capacity
$300000000.00
Lowest Capacity Asset
GSM UEP8E0RQCFOL
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using System.Collections.Concurrent;

namespace QuantConnect 
{   

	
   /// <summary>
    /// Example structure for structuring an algorithm with indicator and consolidator data for many tickers.
    /// </summary>
    /// <meta name="tag" content="consolidating data" />
    /// <meta name="tag" content="indicators" />
    /// <meta name="tag" content="using data" />
    /// <meta name="tag" content="strategy example" />
    public class TrendMovingAverageAlgorithm : QCAlgorithm
    {
    	private SecurityChanges _changes = SecurityChanges.None;
    	
        /// <summary>
        /// This is the period of bars we'll be creating
        /// </summary>
        public readonly TimeSpan BarPeriod = TimeSpan.FromHours(24);
        
        /// <summary>
        /// This is the period of our slow sma indicators
        /// </summary>
        //public readonly int SlowSimpleMovingAveragePeriod = 200;
        
        /// <summary>
        /// This is the period of our fast sma indicators
        /// </summary>
        //public readonly int FastSimpleMovingAveragePeriod = 50;
        
        /// <summary>
        /// This is the number of consolidated bars we'll hold in symbol data for reference
        /// </summary>
        public readonly int RollingWindowSize = 100;
        
        /// <summary>
        /// Holds all of our data keyed by each symbol
        /// </summary>
        public readonly ConcurrentDictionary<string, SymbolData> Data = new ConcurrentDictionary<string, SymbolData>();
        
        /// <summary>
        /// Contains all of our equity symbols
        /// </summary>
        public readonly IReadOnlyList<string> EquitySymbols = new List<string>
        {
            "DNN",
            "IBM",
            "AAPL",
            "GSM",
            "OXY",
            "M"
        };
        
        /// <summary>
        /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
        /// </summary>
        /// <seealso cref="QCAlgorithm.SetStartDate(System.DateTime)"/>
        /// <seealso cref="QCAlgorithm.SetEndDate(System.DateTime)"/>
        /// <seealso cref="QCAlgorithm.SetCash(decimal)"/>
        public override void Initialize()
        {
            SetStartDate(2017, 01, 01);
            SetEndDate(2021, 12, 31);
			SetCash(100000);
			//UniverseSettings.Leverage = 2.0m;
			
            // initialize our equity data
            foreach (var symbol in EquitySymbols)
            {
                var equity = AddEquity(symbol);
                //Data.Add(symbol, new SymbolData(equity.Symbol, BarPeriod, RollingWindowSize));
                Data[symbol] = new SymbolData(equity.Symbol, BarPeriod, RollingWindowSize);
                
                AddSecurity(SecurityType.Equity, symbol, Resolution.Daily);
            }

            // loop through all our symbols and request data subscriptions and initialize indicatora
            foreach (var kvp in Data)
            {
                // this is required since we're using closures below, for more information
                // see: http://stackoverflow.com/questions/14907987/access-to-foreach-variable-in-closure-warning
                var symbolData = kvp.Value;

                // define a consolidator to consolidate data for this symbol on the requested period
                var consolidator = (IDataConsolidator)new TradeBarConsolidator(BarPeriod);
                    
                // define our indicator
                //symbolData.SlowSMA = new SimpleMovingAverage(CreateIndicatorName(symbolData.Symbol, "SlowSMA" + SlowSimpleMovingAveragePeriod, Resolution.Daily), SlowSimpleMovingAveragePeriod);
                //symbolData.FastSMA = new SimpleMovingAverage(CreateIndicatorName(symbolData.Symbol, "FastSMA" + FastSimpleMovingAveragePeriod, Resolution.Daily), FastSimpleMovingAveragePeriod);
                // wire up our consolidator to update the indicator
                consolidator.DataConsolidated += (sender, baseData) =>
                {
                    // 'bar' here is our newly consolidated data
                    var bar = (IBaseDataBar)baseData;
                    // update the indicator
                    //symbolData.SlowSMA.Update(bar.Time, bar.Close);
                    //symbolData.FastSMA.Update(bar.Time, bar.Close);
                    
                    // we're also going to add this bar to our rolling window so we have access to it later
                    symbolData.Bars.Add(bar);
                };

                // we need to add this consolidator so it gets auto updates
                SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator);
            }
            
            // Set requested data resolution
            UniverseSettings.Resolution = Resolution.Daily;
            //SetUniverseSelection(new ManualUniverseSelectionModel(EquitySymbols.Select(x=>new Symbol(SecurityIdentifier.GenerateBase(null, x, Market.USA), x)).ToList()));

            // Use ShareClassMeanReversionAlphaModel to establish insights
            //SetAlpha(new ShareClassMeanReversionAlphaModel(symbols));

            // Equally weigh securities in portfolio, based on insights
            SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());

            // Set Immediate Execution Model
            SetExecution(new ImmediateExecutionModel());

            // Set Null Risk Management Model
            SetRiskManagement(new NullRiskManagementModel());
        }
		
		
		/// <summary>
        /// Event fired each time the we add/remove securities from the data feed
        /// </summary>
        /// <param name="changes">Object containing AddedSecurities and RemovedSecurities</param>
        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            _changes = changes;
        }
		
        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">TradeBars IDictionary object with your stock data</param>
        public override void OnData(Slice data)
        {
        	if (_changes == SecurityChanges.None) return;
        	
            // loop through each symbol in our structure
            foreach (var symbolData in Data.Values)
            {
            	// this check proves that this symbol was JUST updated prior to this OnData function being called
            	if(symbolData.WasJustUpdated(Time))
            	{
	            	//symbolData.Update();
	                if (symbolData.IsReady)
	                {
	                	if(data.Bars.ContainsKey(symbolData.Symbol.Value))
	                	{
		                	//Debug($"{symbolData.Symbol.Value} - Close:{data.Bars[symbolData.Symbol.Value].Close}, SMA50:{symbolData.FastSMA}, SMA200:{symbolData.SlowSMA} - IsReady");
	                		if (!Portfolio[symbolData.Symbol].Invested)
		                    {
		                    	//Debug($"{symbolData.Symbol.Value} - Close:{data.Bars[symbolData.Symbol.Value].Close}, SMA50:{symbolData.FastSMA}, SMA200:{symbolData.SlowSMA} - MA Trigger");
			                	//if (symbolData.IsMATrigger()) //data.Bars[symbolData.Symbol.Value].Close))
			                	if (symbolData.IsTrigger())
			                	{
			                    	//Debug($"{symbolData.Symbol.Value} - Open Trade");
			                        MarketOrder(symbolData.Symbol, 10);
			                        symbolData.OpenTrade();
			                        Debug($"{symbolData.Symbol.Value} - Open:{data.Bars[symbolData.Symbol.Value].Close} | SL:{symbolData.CurrentTradeStopLoss} | TP:{symbolData.CurrentTradeMaxPrice}");
			                	}
		                    }
		                    else
		                    {
		                    	//Debug($"{symbolData.Symbol.Value} - MaxPrice:{symbolData.MaxPrice}");
		                    	//check for close
		                    	if (symbolData.CheckForClose()) //data.Bars[symbolData.Symbol.Value].Close))
			                	{
			                    	Debug($"{symbolData.Symbol.Value} - Close Trade {data.Bars[symbolData.Symbol.Value].Close}");
			                        Liquidate(symbolData.Symbol);
			                	}
		                    }
		                		
		                	//Debug($"{symbolData.Symbol.Value} - IndicatorsData:{symbolData.IndicatorsData}");
		                	
		                	//if (symbolData.LastStage != "init")
		                	//	Debug($"{symbolData.Symbol.Value} - LastStage:{symbolData.LastStage}");
	                	}
	                }
            	}
            }
        }

        /// <summary>
        /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
        /// </summary>
        /// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks>
        /*public override void OnEndOfDay(Symbol symbol)
        {
            int i = 0;
            foreach (var kvp in Data.OrderBy(x => x.Value.Symbol))
            {
                // we have too many symbols to plot them all, so plot ever other
                if (kvp.Value.IsReady && ++i%2 == 0)
                {
                    Plot(kvp.Value.Symbol.ToString(), kvp.Value.SlowSMA);
                    Plot(kvp.Value.Symbol.ToString(), kvp.Value.FastSMA);
                }
            }
        }*/

        /// <summary>
        /// Contains data pertaining to a symbol in our algorithm
        /// </summary>
        public class SymbolData
        {
            /// <summary>
            /// This symbol the other data in this class is associated with
            /// </summary>
            public readonly Symbol Symbol;
            /// <summary>
            /// A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and
            /// can be accessed like:
            ///  mySymbolData.Bars[0] - most first recent piece of data
            ///  mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing)
            /// </summary>
            public readonly RollingWindow<IBaseDataBar> Bars;
            
            /// <summary>
            /// The period used when populating the Bars rolling window.
            /// </summary>
            public readonly TimeSpan BarPeriod;
            
            /// <summary>
            /// The slow simple moving average indicator for our symbol
            /// </summary>
            //public SimpleMovingAverage SlowSMA;
            
            //public readonly RollingWindow<decimal> SlowSMAWindow;
            
            /// <summary>
            /// The fast simple moving average indicator for our symbol
            /// </summary>
            //public SimpleMovingAverage FastSMA;
            
            //public readonly RollingWindow<decimal> FastSMAWindow;
			
			public string LastStage;
			
			public decimal MaxPrice;
			
			public decimal CurrentTradeMaxPrice;
			public decimal CurrentTradeStopLoss;
			
			public string IndicatorsData;
			
            /// <summary>
            /// Initializes a new instance of SymbolData
            /// </summary>
            public SymbolData(Symbol symbol, TimeSpan barPeriod, int windowSize)
            {
                Symbol = symbol;
                BarPeriod = barPeriod;
                Bars = new RollingWindow<IBaseDataBar>(windowSize);
                //SlowSMAWindow = new RollingWindow<decimal>(windowSize);
                //FastSMAWindow = new RollingWindow<decimal>(windowSize);
            }
			
			public void Update()
			{
				//SlowSMAWindow.Add(SlowSMA);
				//FastSMAWindow.Add(FastSMA);
			}
			
			public void OpenTrade()
			{
				CurrentTradeMaxPrice = GetMaxPrice();
				CurrentTradeStopLoss = Bars.Skip(1).Take(4).Min(x=>x.Low)*(decimal)0.95;
			}
			
			public bool CheckForClose() //decimal close)
			{
				MaxPrice = CurrentTradeMaxPrice;
				var close = Bars[1].Close;
				var tp = close > MaxPrice || ((MaxPrice - close) <= close*(decimal)0.005);
				var sl = close < CurrentTradeStopLoss;
				return tp || sl;
			}
			
			private decimal GetMaxPrice() //int period)
			{
				return Bars.Skip(1).Max(x=>x.Close);
			}
			
			//public bool IsMATrigger() //decimal close)
			public bool IsTrigger() 
			{
				/*var ma1 = FastSMA;
				var ma1_30 = FastSMAWindow[30];
				var ma1_60 = FastSMAWindow[60];
				var ma1_90 = FastSMAWindow[90];
				
				var ma2 = SlowSMA;
				var ma2_30 = SlowSMAWindow[30];
				var ma2_60 = SlowSMAWindow[60];
				var ma2_90 = SlowSMAWindow[90];

            	var treshhold1 = Bars[1].Close * (decimal)0.001;
				var treshhold2 = Bars[1].Close * (decimal)0.01;
				IndicatorsData = $"ma1:{ma1}|ma1_30:{ma1_30}|ma1_60:{ma1_60}|ma1_90:{ma1_90}|ma2:{ma2}|ma2_30:{ma2_30}|ma2_60:{ma2_60}|ma2_90:{ma2_90}|treshhold1:{treshhold1}|treshhold2:{treshhold2}";
				
				var ma2UpTrend = (ma2 - ma2_30) > treshhold2;
				
			    LastStage = ma2UpTrend ? "stage1" : "init";
				ma2UpTrend = ma2UpTrend ? (ma2_30 - ma2_60) > treshhold2 : false;
				LastStage = ma2UpTrend ? "stage2" : LastStage;
				ma2UpTrend = ma2UpTrend ? (ma2_60 - ma2_90) > treshhold2 : false;
				LastStage = ma2UpTrend ? "stage3" : LastStage;
				ma2UpTrend = ma2UpTrend ? (ma1 - ma2) > treshhold2*2 : false;
				LastStage = ma2UpTrend ? "stage4" : LastStage;
				//ma2UpTrend = ma2UpTrend ? (ma2 - close) > treshhold2  : false;
				ma2UpTrend = ma2UpTrend ? (Bars.Skip(1).Take(3).Min(x=>x.Low) <= ma2) : false;
				LastStage = ma2UpTrend ? "stage5" : LastStage;
				ma2UpTrend = ma2UpTrend ? (Bars[1].Close > ma2 && ((Bars[1].Close - ma2) <= treshhold2)) : false;
				LastStage = ma2UpTrend ? "stage6" : LastStage;
				
				return ma2UpTrend;*/
				
				var treshhold = Bars[1].Close * (decimal)0.04;
				return (Bars[1].Close - Bars[2].Close) > treshhold;
			}
			
            /// <summary>
            /// Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
            /// </summary>
            public bool IsReady
            {
                //get { return Bars.IsReady && SlowSMA.IsReady && FastSMA.IsReady && SlowSMAWindow.IsReady && FastSMAWindow.IsReady; }
                get { return Bars.IsReady; }
            }

            /// <summary>
            /// Returns true if the most recent trade bar time matches the current time minus the bar's period; this
            /// indicates that Update() was just called on this instance.
            /// </summary>
            /// <param name="current">The current algorithm time</param>
            /// <returns>True if this instance was just updated with new data, false otherwise</returns>
            public bool WasJustUpdated(DateTime current)
            {
                return Bars.Count > 0 && Bars[0].Time == current - BarPeriod;
            }
        }
    }
}