Overall Statistics
Total Trades
187
Average Win
13.74%
Average Loss
-0.66%
Compounding Annual Return
18.651%
Drawdown
30.200%
Expectancy
3.950
Net Profit
341.596%
Sharpe Ratio
0.661
Loss Rate
77%
Win Rate
23%
Profit-Loss Ratio
20.97
Alpha
0.152
Beta
-0.111
Annual Standard Deviation
0.214
Annual Variance
0.046
Information Ratio
0.21
Tracking Error
0.252
Treynor Ratio
-1.275
Total Fees
$4255.00
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using System.Linq;
using QuantConnect.Interfaces;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Orders;
using QuantConnect.Data.Consolidators;

namespace QuantConnect.Algorithm.CSharp
{
    public class TestAlgo : QCAlgorithm, IRegressionAlgorithmDefinition
    {
    	
    	public RollingWindow<decimal> BidPrice = new RollingWindow<decimal>(4);
        public RollingWindow<decimal> AskPrice = new RollingWindow<decimal>(4);
        public RollingWindow<decimal> Volume = new RollingWindow<decimal>(4);
        
        private readonly List<OrderTicket> _openStopMarketOrders = new List<OrderTicket>();
        
        public override void Initialize() 
        {
            SetStartDate(2011, 01, 01);
            SetEndDate(DateTime.Now);
            SetCash(1000000);
            
            var futureSP500 = AddFuture(Futures.Indices.SP500EMini);
            futureSP500.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
			
			var benchmark = AddEquity("SPY");
            SetBenchmark(benchmark.Symbol);
		
		}
		
        public override void OnData(Slice slice)
        {
        	if (!Portfolio.Invested)
            {
                foreach(var chain in slice.FutureChains)
                {
                    // find the front contract expiring no earlier than in 90 days
                    var contract = (from futuresContract in chain.Value.OrderBy(x => x.Expiry) where futuresContract.Expiry > Time.Date.AddDays(90) select futuresContract).FirstOrDefault();

                    // if found, perform logic
                    if (contract != null)
                    {
        				BidPrice.Add(contract.BidPrice);
						AskPrice.Add(contract.AskPrice);
						Volume.Add(contract.Volume);

						if (!BidPrice.IsReady || !AskPrice.IsReady || !Volume.IsReady)
							continue;

                			// a long stop is triggered when the price rises above the value
                			// so we'll set a long stop 0.00001% above the current bar's close
                			var Long = (BidPrice[0] > AskPrice[1]);
   							var closeLong = BidPrice[0];
       						var stopPriceLong = closeLong * 1.0000001m;
       						var newTicketLong = StopMarketOrder(contract.Symbol, 10, stopPriceLong);
      						_openStopMarketOrders.Add(newTicketLong);

                			// a long stop is triggered when the price rises above the value
                			// so we'll set a long stop 0.00001% above the current bar's close
                			var Short = (AskPrice[0] < BidPrice[1]);
   							var closeShort = BidPrice[0];
       						var stopPriceShort = closeShort * 1.0000001m;
       						var newTicketShort = StopMarketOrder(contract.Symbol, 10, stopPriceShort);
      						_openStopMarketOrders.Add(newTicketShort);
      						
      						if (Long)
      								Log("Submitting StopMarketOrder for LongTrade");
       								StopMarketOrder(contract.Symbol, 10, stopPriceLong);
      							
       								// a short stop is triggered when the price falls below the value
       								// so we'll set a short stop 1% below the current bar's close
		
       								stopPriceLong = closeLong * .99m;
       								newTicketLong = StopMarketOrder(contract.Symbol, -10, stopPriceLong);
       								_openStopMarketOrders.Add(newTicketLong);

            						// when we submitted new stop market orders we placed them into this list,
            						// so while there's two entries they're still open and need processing
            						if (_openStopMarketOrders.Count == 2)
            						{
                						// check if either is filled and cancel the other
                						var longOrder = _openStopMarketOrders[0];
                						var shortOrder = _openStopMarketOrders[1];
                						if (CheckPairOrdersForFills(longOrder, shortOrder))
                						{
                							_openStopMarketOrders.Clear();
                    						return;
                						}

                						// if niether order has filled, bring in the stops by a penny

                						var newLongStop = longOrder.Get(OrderField.StopPrice) - 0.01m;
                						var newShortStop = shortOrder.Get(OrderField.StopPrice) + 0.01m;
                						Log("Updating stops - Long: " + newLongStop.ToString("0.00") + " Short: " + newShortStop.ToString("0.00"));
           								longOrder.Update(new UpdateOrderFields{StopPrice = newLongStop, Tag = "Update #" + (longOrder.UpdateRequests.Count + 1)});
               							shortOrder.Update(new UpdateOrderFields{StopPrice = newShortStop,Tag = "Update #" + (shortOrder.UpdateRequests.Count + 1)});
            						}

      						if (Short)
      								Log("Submitting StopMarketOrder for ShortTrade");
      								StopMarketOrder(contract.Symbol, 10, stopPriceShort);
      								
									// a short stop is triggered when the price falls below the value
       								// so we'll set a short stop 1% below the current bar's close
		
    		   						stopPriceShort = closeShort * .99m;
       								newTicketShort = StopMarketOrder(contract.Symbol, -10, stopPriceShort);
       								_openStopMarketOrders.Add(newTicketShort);
       					
            						// when we submitted new stop market orders we placed them into this list,
            						// so while there's two entries they're still open and need processing
            						if (_openStopMarketOrders.Count == 2)
            						{
               							// check if either is filled and cancel the other
               							var longOrder = _openStopMarketOrders[0];
               							var shortOrder = _openStopMarketOrders[1];
               							if (CheckPairOrdersForFills(longOrder, shortOrder))
               						{
                   						_openStopMarketOrders.Clear();
                   						return;
               						}
               							// if niether order has filled, bring in the stops by a penny

               							var newLongStop = longOrder.Get(OrderField.StopPrice) - 0.01m;
               							var newShortStop = shortOrder.Get(OrderField.StopPrice) + 0.01m;
               							Log("Updating stops - Long: " + newLongStop.ToString("0.00") + " Short: " + newShortStop.ToString("0.00"));
               							longOrder.Update(new UpdateOrderFields{StopPrice = newLongStop,Tag = "Update #" + (longOrder.UpdateRequests.Count + 1)});
               							shortOrder.Update(new UpdateOrderFields{StopPrice = newShortStop,Tag = "Update #" + (shortOrder.UpdateRequests.Count + 1)});
            				}
        				}
        			}
           		}
			}
		
        
       	public override void OnOrderEvent(OrderEvent orderEvent)
       	{
       		var order = Transactions.GetOrderById(orderEvent.OrderId);
        		Console.WriteLine("{0}: {1}: {2}", Time, order.Type, orderEvent);
       	}

       	private bool CheckPairOrdersForFills(OrderTicket longOrder, OrderTicket shortOrder)
       	{
       		if (longOrder.Status == OrderStatus.Filled)
       		{
           		Log(shortOrder.OrderType + ": Cancelling short order, long order is filled.");
      			shortOrder.Cancel("Long filled.");
       			return true;
       		}
       			
       			if (shortOrder.Status == OrderStatus.Filled)
           		{
               		Log(longOrder.OrderType + ": Cancelling long order, short order is filled.");
               		longOrder.Cancel("Short filled");
               		return true;
           		}
           			return false;
    			}
		
       	private bool TimeIs(int day, int hour, int minute)
       	{
       		return Time.Day == day && Time.Hour == hour && Time.Minute == minute;
  		}
    	
        /// <summary>
       	/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
       	/// </summary>
       	public bool CanRunLocally { get; } = true;

       	/// <summary>
       	/// This is used by the regression test system to indicate which languages this algorithm is written in.
       	/// </summary>
       	public Language[] Languages { get; } = { Language.CSharp };

       	/// <summary>
       	/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
       	/// </summary>
       	public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
       	{
           	{"Total Trades", "0"},
           	{"Average Win", "0%"},
           	{"Average Loss", "0%"},
           	{"Compounding Annual Return", "0%"},
           	{"Drawdown", "0%"},
           	{"Expectancy", "0"},
           	{"Net Profit", "0%"},
           	{"Sharpe Ratio", "0"},
           	{"Loss Rate", "0%"},
           	{"Win Rate", "0%"},
           	{"Profit-Loss Ratio", "0"},
           	{"Alpha", "0"},
           	{"Beta", "0"},
       		{"Annual Standard Deviation", "0"},
           	{"Annual Variance", "0"},
           	{"Information Ratio", "0"},
           	{"Tracking Error", "0"},
           	{"Treynor Ratio", "0"},
           	{"Total Fees", "$0.00"}
       	};
    }
}