Overall Statistics
Total Trades
53
Average Win
1.03%
Average Loss
-1.19%
Compounding Annual Return
33.867%
Drawdown
9.400%
Expectancy
0.271
Net Profit
19.885%
Sharpe Ratio
1.868
Loss Rate
32%
Win Rate
68%
Profit-Loss Ratio
0.87
Alpha
0.244
Beta
-0.036
Annual Standard Deviation
0.128
Annual Variance
0.016
Information Ratio
0.707
Tracking Error
0.143
Treynor Ratio
-6.695
Total Fees
$373.70
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Securities;

namespace QuantConnect.Algorithm.CSharp
{
   
    public class FuturesAlgo: QCAlgorithm
    {
    	int frequency = 90; // in minutes, resets every day
        int barCounter = 0; //used to count bars and consolidate
        
        FuturesContract _contract = null;
        BollingerBands _bb = null;
        
		bool _newDay = true;
		
		decimal prevPrice = 0;
		decimal prevUp = 0;
		decimal prevDown = 0;
		
        bool reset = true;
        
        public override void Initialize()
        {
            SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);
            //SetStartDate(year: 2011, month: 8, day: 15);
            SetStartDate(year: 2017, month: 1, day: 1);
            SetEndDate(year: 2017, month: 8, day: 15);
            SetCash(100000);
            //SetWarmUp(TimeSpan.FromDays(5));
            var future = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute);
            future.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(360));
        }

        
        public override void OnData(Slice slice)
        {
        	if (!InitContract(slice))
            {
                return;
            }
            if(reset)
            {
            	//need to roll/close contract in position if any
            	reset = false;
            	Log("RESET closing all positions");
            	foreach(var s in Portfolio.Securities)
            	{
            		SetHoldings(s.Key, 0);
            	}
            }
            if (_contract != null && barCounter % frequency == 0 && slice.Bars.ContainsKey(_contract.Symbol))
            {
            	OnCustomBarUpdate(null, slice.Bars[_contract.Symbol]);
            }
            barCounter++;
        	return;
        }

        private bool InitContract(Slice slice)
        {
        	if (!_newDay)//reset daily everyday we chekc whther futures need to be rolled
        	{
        		return true;
        	}
        	
            // if (_contract != null)
            // 	Log(_contract.Expiry.ToString());
            if (_contract != null && (_contract.Expiry -Time.Date).TotalDays >=3) //rolling 3 days before expiry
            {
                return true;
            }
            
            if (slice.FutureChains.Count() == 0)
            {
            	return false;
            }
            //On Expiry we will reset contracts
            foreach (var chain in slice.FutureChains)
            {
                //when selecting contract if on expiry date, then skip first as it woudl be the same one!
                int skip = 0;
                if (_contract != null)
                    Log("Expiry days away " + (_contract.Expiry - Time.Date).TotalDays + " - " + _contract.Expiry + " - " + Time.Date);
                
                _newDay = false;
                
                Log("future count " + chain.Value.Count() + ":" + string.Join(",", chain.Value));
                foreach (var newContract in chain.Value.OrderBy(x => x.Expiry))
				{
					Log("evaluating " + newContract.ToString());
					if ((newContract.Expiry - Time.Date).TotalDays > 3 && (_contract==null ||_contract.ToString() != newContract.ToString()))
					{
						_contract = newContract;
	                    
	                    //warming up the indicators
	                    _bb = new BollingerBands(_contract.Symbol, 20, 2, MovingAverageType.Exponential);
	                    var history = History(_contract.Symbol, 50 * frequency, Resolution.Minute);
	                    if (history.Count() == 0)
	                    {
	                    	//should never happen but it does for ESZ16... so as a workaround
	                    	Log("no historical data for " + newContract.ToString());
	                    	_bb = null;
	                    	_contract = null;
	                    	continue;
	                    }
	                    
	                    int counter = 0;
	                    DateTime dt = history.First().EndTime;
	                    foreach (var bar in history)
	                    {
	                    	if (bar.EndTime.DayOfWeek != dt.DayOfWeek)//every day we reset and start counting again!
	                    	{
	                    		counter = 0;
	                    		dt = bar.EndTime;
	                    	}
	                        if (counter % frequency == 0) // every frequency minutes
	                        {
	                            _bb.Update(new IndicatorDataPoint(_contract.Symbol, bar.EndTime, bar.Close));
	                            if (_bb.IsReady)
	                            {
	                            	var std = 0.5m * (_bb.MiddleBand-_bb.LowerBand);
	                            	Log("BB:"+ bar.EndTime + ","+ bar.Close + "," +_bb.MiddleBand.ToString() + "," + std.ToString());
	                            }
	                        }
	                        counter++;
	                    }
	                    
	                    //setting the consolidator
	                    //can't seem to get it to work properly, so dealing with it in OnData
	                    
	                    // Log("Before SubscriptionManager.Count " + SubscriptionManager.Count.ToString());
	                    // var customFrequency = new TradeBarConsolidator(TimeSpan.FromMinutes(frequency));
	                    // customFrequency.DataConsolidated += OnCustomBarUpdate;
	                    // SubscriptionManager.AddConsolidator(_contract.Symbol, customFrequency);
	                    // Log("After SubscriptionManager.Count " + SubscriptionManager.Count);
	                    
	                    
	                    //resetting comparisons prices as they wont work on the new one
	                    prevPrice = 0;
						prevUp = 0;
						prevDown = 0;
						Log("INIT DONE " + _contract.ToString() + " - BB READY " + _bb.IsReady.ToString());
						return true;
	                }	
				}
            }
            return false;
        }

		public void OnCustomBarUpdate(object sender, TradeBar bar)
		{
			if (_contract == null || bar.Symbol!=_contract.Symbol) // can happend during roll period
			{
				return;
			}
			Log("OnCustomBarUpdate");
			if (_contract != null)
			{
				//Log(bar.Close + " - " + _bb.LowerBand + " - " + _bb.UpperBand + " - " +prevPrice + " - " + prevDown + " - " + prevUp);
			}
			if (_bb.Current.EndTime < bar.EndTime)
			{
				//Log("P," + bar.Close + "," + _bb.Current.EndTime.ToString() + ",PPrice," + _bb.Current.Price);
				_bb.Update(new IndicatorDataPoint(_contract.Symbol, bar.EndTime, bar.Close));
			}
			
			if (prevPrice>0)
			{
				if (bar.Close >_bb.LowerBand && prevPrice < prevDown)
				{
					Log("BUY SIGNAL");
					if (Portfolio.ContainsKey(_contract.Symbol))
					{
						var existing = Portfolio[_contract.Symbol].Quantity;
						if (existing < 0)
						{
							Log("reversing LONG");
							MarketOrder(_contract.Symbol, -1 * existing * 2);		
						}
						else if (existing == 0)
						{
							Log("Going LONG");
							MarketOrder(_contract.Symbol, 2);		
						}
						//else if already long nothign to do
					}
					
				}
				else if (bar.Close <_bb.UpperBand && prevPrice > prevUp)
				{
					Log("SELL SIGNAL");
					var existing = Portfolio[_contract.Symbol].Quantity;
					if (existing > 0)
					{
						Log("reversing SHORT");
						MarketOrder(_contract.Symbol, -1 * existing * 2);		
					}
					else if (existing == 0)
					{
						Log("Going SHORT");
						MarketOrder(_contract.Symbol, -2);		
					}
					//else if already shorstring nothign to do
				}
			}
			prevPrice = bar.Close;
			prevUp = _bb.UpperBand;
			prevDown = _bb.LowerBand;
		}	
		
		public override void OnEndOfDay()
        {
            _newDay = true;
            barCounter = 0;
        }
        
        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            var order = Transactions.GetOrderById(orderEvent.OrderId);
            string msg = "ORDER " + order.Status.ToString() + ": " + order.Direction.ToString() + " " + order.Quantity.ToString("#.0") + " " + order.Symbol;
            if (order.Type == OrderType.StopMarket)
            {
                var o = ((QuantConnect.Orders.StopMarketOrder)order);
                msg += " - STOP @ " + o.StopPrice.ToString("#.00000");
            }
            else if (order.Type == OrderType.Market)
            {
                var o = order;
            }
            else if (order.Type == OrderType.Limit)
            {
                var o = ((QuantConnect.Orders.LimitOrder)order);
                msg += " - LIMIT @ " + o.LimitPrice.ToString("#.00000");
            }
            if (order.Status == OrderStatus.Filled)
            {
                msg += " - filled @ " + order.Price.ToString("#.00000");
                Log(msg);
            }
        }
    }
}