Overall Statistics
using System;
using System.Collections;
using System.Collections.Generic;
using MathNet.Numerics.Statistics;
using MathNet.Numerics;
using System.Linq;

namespace QuantConnect {
	//Returns the channel end values based on previous Trade bar
	public class PolynomialRegression 
    {
    	private int _period;
    	public int period	{get{return _period;}}
    	
		private double _deviation;
		private int _power;
		private int _samples;
    	
    	private decimal _oneStdDev;
    	public decimal oneStdDev	{get{return _oneStdDev;}}
		
		private decimal _lastPredictedValue;
    	public decimal lastPredictedValue	{get{return _lastPredictedValue;}}
    	
    	private decimal _slope;
    	public decimal slope	{get{return _slope;}}
    	
		private double[] _slopeCoefficients;
    	public double[] slopeCoefficients	{get{return _slopeCoefficients;}}
		
		private decimal _upBand;
    	public decimal upBand {get{return _upBand;}}
		
		private decimal _lowBand;
    	public decimal lowBand	{get{return _lowBand;}}
		
		//Will check if the value from the indicator should be used or not
		private bool _isReady;
		public bool	isReady	{get{return _isReady;}}
		
		private List<double> _yBuffer;
		public  List<double> yBuffer {get{return _yBuffer;}}
		
		private List<double> _xBuffer;
		public  List<double> xBuffer {get{return _xBuffer;}}
		
		public PolynomialRegression (int period, double deviation, int power)
		{
			this._period = period;
			this._deviation = deviation;
			this._power = power;
			this._samples = 0;
			this._yBuffer = new List<double>();
			this._xBuffer = new List<double>();
			//_xBuffer.Add(1);
		}
		
		public void AddSample(decimal price)
		{
			if (_samples<_period)
			{
				_slope = 1m;
				_upBand = price;
				_lowBand =price;
				_isReady = false;
				_samples++;
				_yBuffer.Add((double)price);
				_xBuffer.Add(_samples);
				return;
			}
			else
			{
				_slopeCoefficients = Fit.Polynomial(_xBuffer.ToArray(), _yBuffer.ToArray(), _power);       
				_isReady =  true;
				
				double[] _errors = new double[_xBuffer.Count()];
            	double[] _modelledValues = new double[_yBuffer.Count()];
            	for (int _curCount = 0;_curCount<_xBuffer.Count();_curCount++)
        		 {
            	   //_modelledValues[_curCount] = Evaluate.Polynomial(_xBuffer[_curCount], _slopeCoefficients);
            	  _modelledValues [_curCount] = _slopeCoefficients[0] + _slopeCoefficients[1]*_xBuffer[_curCount];
            	  _errors[_curCount] = _modelledValues[_curCount] - _yBuffer[_curCount];
                }
                
            	_oneStdDev = (decimal)ArrayStatistics.PopulationStandardDeviation(_errors);         				  //Standard Devation of errors  - Population uses N
            	_lastPredictedValue = (decimal)(_slopeCoefficients[0] + _slopeCoefficients[1]*_xBuffer.Last());        //Getting the last calculated value
            	_slope = (decimal)_slopeCoefficients[1];
            	_upBand = _lastPredictedValue + _oneStdDev*(decimal)_deviation;
            	_lowBand = _lastPredictedValue - _oneStdDev*(decimal)_deviation;
            	
            	_yBuffer.Add((double)price);		//Preparing for next band value
            	_yBuffer.RemoveAt(0);
            }
		}
	
    }

    //public class Indicator 
    //{
    //  ...or you can define whole new classes independent of the QuantConnect Context
    //}

}
namespace QuantConnect {

    //
    //	Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all
    //	files use "public partial class" if you want to split up your algorithm namespace into multiple files.
    //

    //public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm
    //{
    //  Extension functions can go here...(ones that need access to QCAlgorithm functions e.g. Debug, Log etc.)
    //}

    //public class Indicator 
    //{
    //  ...or you can define whole new classes independent of the QuantConnect Context
    //}
    
    class Utility{
    	
    	
    	/// <summary>
        /// Returns the business date (EventDate  + post days) after accouning for weekends;  will not take into other exchange holidays 
        /// </summary>
        /// <param name="EventDate"></param>
        /// <param name="postDays"></param>
        /// <returns></returns>
        public static DateTime getPostBusinessDate(DateTime EventDate, int postDays)
        {
            DateTime applicableDate = EventDate;
            //Checking if the event itself occurs on a weekend 
            if (postDays == 0)
                while (applicableDate.DayOfWeek == DayOfWeek.Saturday || applicableDate.DayOfWeek == DayOfWeek.Sunday)
                    applicableDate = applicableDate.AddDays(1);

            for (int tempCount = 0; tempCount < Math.Abs(postDays); tempCount++)
            {
                applicableDate = applicableDate.AddDays(Math.Sign(postDays));
                while (applicableDate.DayOfWeek == DayOfWeek.Saturday || applicableDate.DayOfWeek == DayOfWeek.Sunday)
                    applicableDate = applicableDate.AddDays(Math.Sign(postDays));
            }
            return applicableDate;
        }
    	
    	
    	public static List<DateTime> getDaysAroundEvent(List<DateTime> eventDates, int NbPreDays, int NbPostDays)
    	{
    		List<DateTime> _finalDates = new List<DateTime>();
    		foreach(DateTime eventDate in eventDates)
    		{
    			int count = -NbPreDays;
    			while(count<=NbPostDays)
    			{
    				_finalDates.Add(getPostBusinessDate(eventDate,count));
    				count++;
    			}
    		}
    		return _finalDates;
    	}

	}
	
}
using System;

namespace QuantConnect 
{   
    // Create 2 channels, operate only during Europe time, Mean Reversion only
    
    public partial class PolynomialRegressionDemo : QCAlgorithm
    {

		//string symbol = "EURUSD";
    	//	string symbol = "USDJPY";
		//	string symbol = "AUDUSD";
		//	string symbol = "USDCAD";
			string symbol = "EURCHF";
		//	string symbol = "EURSEK";
		//int europeStartHours = 3;	//NY Time
		//int usStartHours =  6;
		//int usEndHours = 15;
		bool isTradeTime;
		
		DateTime[] ECBDays = new DateTime[] { new DateTime(2015,1,22),new DateTime(2015,3,5),new DateTime(2015,4,15),new DateTime(2015,6,3),new DateTime(2015,7,16),new DateTime(2015,9,3),new DateTime(2015,10,22),new DateTime(2015,12,3),new DateTime(2016,1,21),new DateTime(2016,3,10),new DateTime(2016,4,21)};
		DateTime[] FedDays = new DateTime[]{ new DateTime(2015,1,28),new DateTime(2015,3,18),new DateTime(2015,4,29),new DateTime(2015,6,17),new DateTime(2015,7,29),new DateTime(2015,9,17),new DateTime(2015,10,28),new DateTime(2015,12,16),new DateTime(2016,1,27),new DateTime(2016,3,16),new DateTime(2016,4,27)};
		DateTime[] NFPDays = new DateTime[]{ new DateTime(2015,1,9),new DateTime(2015,2,6),new DateTime(2015,3,6),new DateTime(2015,4,3),new DateTime(2015,5,8),new DateTime(2015,6,5),new DateTime(2015,7,2),new DateTime(2015,8,7),new DateTime(2015,9,4),new DateTime(2015,10,2),new DateTime(2015,11,6),new DateTime(2015,12,4),new DateTime(2016,1,8),new DateTime(2016,2,5),new DateTime(2016,3,4),new DateTime(2016,4,1),new DateTime(2016,5,6),new DateTime(2016,6,3)};
        
        bool _excludeNFP = true;
        int _NbNFPPreDays = 4;
        int _NbNFPPostDays = 1;
        
        bool _excludeECB = true;
        int _NbECBPreDays =2;
        int _NbECBPostDays =1;
        
        bool _excludeFed = true;
		int _NbFEDPreDays = 0;
		int _NbFEDPostDays = 1;
	
        bool isTradDate;
        
        List <DateTime> _excludeDates;
        DateTime _latestEventDate;
        	
		
		int _fastPeriod = 300;			//Period in minutes 
		int _slowPeriod = 1200;			//Period in minutes 
		double _fastNbDevBands = 2.0;	//Number of deviations (bands)
		double _slowNbDevBands = 2;		//Number of deviations (band
		
		int _notional = 100000;
		double _leverage = 1;
		
		private OrderTicket _orderCurrentOrder;
    	private OrderTicket _orderStopLoss;
    	private OrderTicket _orderProfitTarget;
    	
    	decimal _fastHiBandPrev1, _fastLowBandPrev1;
		decimal _prevClose, _entryPrice, _exitPrice;
		decimal _stopPrice,_tpPrice;
		decimal _NAV;
		
		DateTime  _entryTime, _exitTime;		//Assumes only 1 trade at a time
		char _buyorsell;
		
		//int NbData;
		//int _NbOpenOrders = 0;
    	
    
    	PolynomialRegression prSlow;
    	PolynomialRegression prFast;
    	
    	//Initialize the data and resolution you require for your strategy:
        public override void Initialize() 
        {
        	SetTimeZone("America/New_York");	
			SetStartDate(2016,1, 1);
            SetEndDate(2016,5, 31);
            
           
            _excludeDates = new List<DateTime>();
           if(_excludeFed==true)
           		_excludeDates.AddRange(Utility.getDaysAroundEvent(FedDays.ToList(),_NbFEDPreDays, _NbFEDPostDays));
           if(_excludeNFP==true)
            	_excludeDates.AddRange(Utility.getDaysAroundEvent(NFPDays.ToList(),_NbNFPPreDays, _NbNFPPostDays));
            if(_excludeECB==true)
            	_excludeDates.AddRange(Utility.getDaysAroundEvent(ECBDays.ToList(),_NbECBPreDays, _NbECBPostDays));
            
            if(_excludeDates.Count()==0)
            	_excludeDates.Add(DateTime.Now.AddDays(1));
            
            _excludeDates = _excludeDates.Distinct().ToList();
            _excludeDates.Sort();				//Contains list of all sorted events which are to be avoided
            
            _latestEventDate = _excludeDates.ElementAt(0);
            
            AddSecurity(SecurityType.Forex,symbol, Resolution.Minute);
 			
 			//prUpper time should be greater than prFast by at least 1 period	
 			prSlow = new PolynomialRegression(_slowPeriod,_slowNbDevBands,1);
            prFast = new PolynomialRegression(_fastPeriod,_fastNbDevBands,1);
            //previous value of Fast channel
            _fastHiBandPrev1=0;
            _fastLowBandPrev1=0;
            _prevClose=0;
            //Cash allocation
            SetCash(_notional/_leverage);					//_leverage = 1 =>No Leverage;
            //NbData=0;
            
            var history = History(symbol, _slowPeriod + 10);	//Buffer of 10 for the slow channel
            foreach (var tradeBar in history)
            {
            	prFast.AddSample( tradeBar.Close);
        		prSlow.AddSample(tradeBar.Close);
            	
            }
        }

        //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
        public void OnData(TradeBars data) 
        {   
           decimal price = data[symbol].Close;
           var holdings  = Portfolio[symbol].Quantity;
          
          if(prSlow.isReady==false )			//Wait for upper channel to be ready 
        	{	
        		prFast.AddSample(price);
        		prSlow.AddSample(price);
        		return;
        	}
        	
        	//if (!Portfolio.HoldStock) 
            //Time Filters
            /*if(Time.Hour>=europeStartHours && Time.Hour<usStartHours)
            	isTradeTime = true;
            else 
            	isTradeTime = false;*/
           	isTradeTime = true;
           	
           	
           	if(Time.Date> _latestEventDate && _latestEventDate == _excludeDates.Last())
           		isTradDate=true;
           	else 
           	{	
           		if(Time.Date> _latestEventDate)
           		{	_latestEventDate = _excludeDates.ElementAt(_excludeDates.IndexOf(_latestEventDate)+1);
           			if(Time.Date == _latestEventDate)				//event dates move in days while data comes in minutes
           				isTradDate = false;
           			else isTradDate= true;
           		}
           		else if(Time.Date == _latestEventDate)
           			isTradDate = false;
           		else if(Time.Date < _latestEventDate)
           			isTradDate = true;
           	}		
           	
           	if(Time.DayOfWeek == DayOfWeek.Sunday)
           		isTradDate = false;
           	
           	if(isTradDate&& isTradeTime)
           		isTradeTime = true;
           	else 
           		isTradeTime = false;
           	
           	if(holdings==0)								//No position
            {  
            //	if(price<prFast.lowBand  & _prevClose>_fastLowBandPrev1 & prFast.slope>0  & prSlow.slope>0 & isTradeTime==true)						//Fast channel line of Fast band is greater than price - buy
            		if(price<prFast.lowBand  & _prevClose>_fastLowBandPrev1 & prFast.slope>0   & isTradeTime==true)	
            	{
            			_stopPrice = price - prFast.oneStdDev * 2.0m; 
            			_tpPrice = price + prFast.oneStdDev *3.0m; 
            			_buyorsell = 'B'; _entryTime = Time;_entryPrice = price;			//Recording Trade data
            			//	Debug("Placing Buy Mkt Order now..");
            			_orderCurrentOrder = Order(symbol, _notional);
            			//Debug("Purchased " +  symbol + " on " + Time.ToString() + " at Price: " + price.ToString("0.0000") + " SL: " + _stopPrice.ToString("0.0000") + " TP: " + _tpPrice.ToString("0.0000") );
            			_orderStopLoss = StopMarketOrder(symbol, -_notional, _stopPrice);
            			_orderProfitTarget = LimitOrder(symbol,-_notional, _tpPrice);
            	}
            //	else if(price>prFast.upBand & _prevClose<_fastHiBandPrev1 & prFast.slope<0  & prSlow.slope<0 & isTradeTime==true)							//higher channel of Fast band is less than price - sell
            		else if(price>prFast.upBand & _prevClose<_fastHiBandPrev1 & prFast.slope<0   & isTradeTime==true)								//higher channel of Fast band is less than price - sell
				{
						_stopPrice = price + prFast.oneStdDev*2.0m; 
            			_tpPrice = price - prFast.oneStdDev*3.0m; 
            			_buyorsell = 'S'; _entryTime = Time; _entryPrice = price;			//Recording Trade data
                		//	Debug("Placing Sell Mkt Order now..");
                		_orderCurrentOrder = Order(symbol, -_notional);
						//Debug("Sold " +  symbol + " on " + Time.ToString() + " at Price: " + price.ToString("0.0000") + " SL: " + _stopPrice.ToString("0.0000") + " TP: " + _tpPrice.ToString("0.0000"));
                		_orderStopLoss = StopMarketOrder(symbol, +_notional, _stopPrice);
                		_orderProfitTarget = LimitOrder(symbol,+_notional, _tpPrice);
            	}
            }
            	
            _fastLowBandPrev1 = prFast.lowBand;
            _fastHiBandPrev1 = prFast.upBand;
            _prevClose = price;
            
            prFast.AddSample(price);
            prSlow.AddSample(price);
           	
           	//	Debug(i.ToString() + " Time " + Time.ToString() + "Price = " + price +  " loBand = " + prFast.lowBand + " upBand = " + prFast.upBand);
           // Debug ("Last =" + PolynomialRegression._yBuffer.Last().ToString());
           //Debug("Time = " + Time.ToString() + "Price = " + price.ToString("0.0000"));
            
           /*	Plot("Custom","prUpper_upBand", prSlow.upBand);
            Plot("Custom","prFast_upBand", prFast.upBand);
            Plot("Custom","prFast_lowBand", prFast.lowBand);
            Plot("Custom","prUpper_lowBand", prSlow.lowBand);
           	Plot("Custom",symbol, data[symbol].Close);
            */   
            
            
        }
        
        
       
        
    
    	// If the StopLoss or ProfitTarget is filled, cancel the other
        // If you don't do this, then  the ProfitTarget or StopLoss order will remain outstanding
        // indefinitely, which will cause very bad behaviors in your algorithm
        public override void OnOrderEvent(OrderEvent orderEvent)
		{
			// Ignore OrderEvents that are not closed
			if (!orderEvent.Status.IsClosed())	{ return; }
			
			// Defensive check
			if (_orderProfitTarget == null || _orderStopLoss == null) {	return;}
			
			//This is getting called recursively if an order is canceled
			if(orderEvent.Status == OrderStatus.Canceled )	
			{	
				//	Debug("Canceled outstanding order"); 
				return;
			}
			
			var filledOrderId = orderEvent.OrderId;
			
			//	Debug("current order ID " +_orderCurrentOrder.OrderId + "Filled Order ID  = " + filledOrderId );
			if(_orderCurrentOrder.OrderId +3 == filledOrderId)		
			{
				//Debug("Market Order checked");
				return;
			}
			

			// If the ProfitTarget order was filled, close the StopLoss order
			if (_orderProfitTarget.OrderId == filledOrderId)
			{
				//	Debug("TP Order hit");
				if(_orderStopLoss.Status != OrderStatus.Filled)
					_orderStopLoss.Cancel();
				else Liquidate();
			}

			// If the StopLoss order was filled, close the ProfitTarget
			if (_orderStopLoss.OrderId == filledOrderId)
			{
				//	Debug("SL Order hit");
				if(_orderProfitTarget.Status != OrderStatus.Filled)
					_orderProfitTarget.Cancel();
				else Liquidate();	
			}
			
				_exitPrice = orderEvent.FillPrice; _exitTime = Time;
				_NAV = Portfolio.TotalPortfolioValue;
				double _thisTradePnL = (double)(_exitPrice-_entryPrice)*_notional;
				if(char.ToUpper(_buyorsell).CompareTo('S')==0 )
					_thisTradePnL*= -1;
				Debug( ",Entry Time," + _entryTime + "," + _entryTime.DayOfWeek + ","+ _entryPrice.ToString("0.0000") + "," + _buyorsell + "," + _exitPrice.ToString("0.0000") + "," + _exitTime + "," + _thisTradePnL.ToString("0") + "," + _NAV.ToString("0") );
		}
	}
}