Overall Statistics
using QuantConnect.Data.Consolidators;

namespace QuantConnect 
{   
    /*
    *   John Ehlers' Empirical Mode Decomposition
    *	(programmed by Jean-Paul van Brakel)
    */
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
    	public string _ticker = "SPY"; 					// which stock ticker
		public static double DC_delta = 0.5;			// band sensitivity
		public static int DC_period = 20; 				// lags to consider
		public static decimal DC_frac = 0.10M; 			// fraction sensitivity
		public static int MESA_length = 9;
		private TradeBarConsolidator consolidator;
		public static int _consolidated_days = 5;		// number of days
        private readonly RollingWindow<TradeBar> Closes = new RollingWindow<TradeBar>(MESA_length);
        private readonly RollingWindow<double> BPHist = new RollingWindow<double>((int)DC_period);
 		private readonly RollingWindow<double> PeakHist = new RollingWindow<double>(55);
		private readonly RollingWindow<double> ValleyHist = new RollingWindow<double>(55);
        private readonly SimpleMovingAverage MA_BP = new SimpleMovingAverage(2*DC_period);
        private readonly SimpleMovingAverage MA_Peak = new SimpleMovingAverage(50);
        private readonly SimpleMovingAverage MA_Valley = new SimpleMovingAverage(50);
		private Chart plotter;
		decimal _oldprice = 100000;
		decimal _price;
		int _old_dir = 0;
		int _mama_dir = 0;
		int _trend_dir = 0;
    	
        public override void Initialize() 
        {
            //Start and End Date range for the backtest:
            SetStartDate(2000, 1, 1);         
            SetEndDate(2014, 1, 1);
            SetCash(25000);
            AddSecurity(SecurityType.Equity, _ticker, Resolution.Daily);
            consolidator = new TradeBarConsolidator(TimeSpan.FromDays(_consolidated_days));
            consolidator.DataConsolidated += ConsolidatedHandler;
            SubscriptionManager.AddConsolidator(_ticker, consolidator);
            
			plotter = new Chart("Decomp", 				ChartType.Overlay);
	        plotter.AddSeries(new Series("Mean", 		SeriesType.Line));
			plotter.AddSeries(new Series("Upper band", 	SeriesType.Line));
			plotter.AddSeries(new Series("Lower band", 	SeriesType.Line));
			AddChart(plotter);
			
			PeakHist.Add(0.0);	 // add one empty Peak entry
            ValleyHist.Add(0.0); // add one empty Valley entry
        }

        public void OnData(TradeBars data) 
        {   
        	// ignore this for now
        }
        
        public void ConsolidatedHandler(object sender, TradeBar data) {
        	Closes.Add(data);
        	_price = data.Close;
        	if (!Closes.IsReady) return;
        	
        	// Empirical Mode Decomposition
			// *********************************************************************************************************
			double beta = Math.Cos(2*Math.PI/DC_period);
			double gamma = (1 / Math.Cos(4*Math.PI*DC_delta / DC_period));
			double alpha = gamma - Math.Sqrt(Math.Pow(gamma, 2) - 1);
			double p0 = (double)((decimal)Closes[0].High+(decimal)Closes[0].Low)/2;
			double p2 = (double)((decimal)Closes[2].High+(decimal)Closes[2].Low)/2;
			double BP = 0;
			if (BPHist.IsReady) {
				BP = 0.5*(1-alpha)*(p0-p2)+beta*(1+alpha)*BPHist[0]-alpha*BPHist[1];
			} else {
				BP = 0.5*(1-alpha)*(p0-p2);
			}
			// update data
			BPHist.Add(BP); // so current BP is now [0]
			MA_BP.Update(new IndicatorDataPoint(data.Time, (decimal)BP));
			decimal Mean = MA_BP;
			
			if (!BPHist.IsReady) return;
			
			// calculate peak and valley
			double Peak = PeakHist[0];
			double Valley = ValleyHist[0];
			if (BPHist[1] > BPHist[0] && BPHist[1] > BPHist[2]) {
				Peak = BPHist[1];
			}
			if (BPHist[1] < BPHist[0] && BPHist[1] < BPHist[2]) {
				Valley = BPHist[1];
			}
			// update data
			PeakHist.Add(Peak);		// so current Peak is now [0]
			ValleyHist.Add(Valley);	// so current Valley is now [0]
			MA_Peak.Update(new IndicatorDataPoint(data.Time, (decimal)Peak));
			MA_Valley.Update(new IndicatorDataPoint(data.Time, (decimal)Valley));
			
			decimal AvgPeak = MA_Peak;
			decimal AvgValley = MA_Valley;

			// calculate final indicators
			decimal upperBand = DC_frac*AvgPeak;
			decimal lowerBand = DC_frac*AvgValley;
			
			// Update chart
			Plot("Decomp", "Mean", Mean);
            Plot("Decomp", "Upper band", upperBand);
            Plot("Decomp", "Lower band", lowerBand);
			// *********************************************************************************************************
            
            // Update chart
			Plot("Decomp", "Mean", Mean);
            Plot("Decomp", "Upper band", upperBand);
            Plot("Decomp", "Lower band", lowerBand);
            
            // No logic (this algorithm is to demonstrate the decomposition)
            if (!Portfolio.HoldStock) {
            	Order(_ticker,  100);
            }
        }
    }
}