Overall Statistics
namespace QuantConnect
{   
    /*
    *   Basic Template Algorithm
    *
    *   The underlying QCAlgorithm class has many methods which enable you to use QuantConnect.
    *   We have explained some of these here, but the full base class can be found at:
    *   https://github.com/QuantConnect/Lean/tree/master/Algorithm
    */
    public class BasicTemplateAlgorithm : QCAlgorithm
    {	
    	
    	public String StockTicker = "SPY";
    	
    	public Symbol OptionSymbol;
        private const decimal GoalRate = 0.25M;
        private const decimal GoalFactor = 1 + GoalRate;
    	
    	
		public RollingWindow<Decimal> PercentChangeH = new RollingWindow<Decimal>(1);
		public Decimal PercentChange;
		public RateOfChangePercent PercentChangeI;
        private string OrderTrackingDebugStr = "";
		
		public int OrderQuantity (decimal cash, decimal price) {
			return (int) Math.Floor(cash / price);
		}
		
		bool HasOrderOrHolding = false;

		
        public override void Initialize() 
        {
        	// backtest parameters
            SetStartDate(2016, 07, 1);         
            SetEndDate(DateTime.Now);
            
            // cash allocation
            SetCash(3000);
            
            // request specific equities
            // including forex. Options and futures in beta.
             var equity = AddEquity(StockTicker, Resolution.Daily);
            //AddForex("EURUSD", Resolution.Minute);
            
			// Must add option universe filter
            var option = AddOption(StockTicker, Resolution.Daily);
            OptionSymbol = option.Symbol;
            option.SetFilter(universe => from symbol in universe

                                        // default is monthly expirations only
                                        .Expiration(TimeSpan.FromDays(30), TimeSpan.FromDays(60))
                                         where symbol.ID.OptionRight == OptionRight.Call
                                         where Math.Abs(symbol.ID.StrikePrice - universe.Underlying.Price) < 10
                                         select symbol);

            // use the underlying equity as the benchmark
            SetBenchmark(equity.Symbol);
            
            PercentChangeI = ROCP(StockTicker, 1, Resolution.Daily);

        }

        /* 
        *	New data arrives here.
        *	The "Slice" data represents a slice of time, it has all the data you need for a moment.	
        */ 
        public override void OnData(Slice data) 
        {
			if (!PercentChangeI.IsReady) return;
			
        	PercentChangeH.Add(PercentChangeI);
        	PercentChange = PercentChangeH[0];
        	
        	Plot("Daily", PercentChangeI);

        	ExecuteShort(data);
	    	ExecuteLong(data);
		}
		
		
        public void ExecuteLong(Slice slice)
        {

        	if (HasOrderOrHolding) { return; } // We already have a position

            if ((PercentChange < -0.02m)
               && (PercentChange > -0.125m)  // -2.5 to -12.5%
               )
            {

                OptionChain chain;
                if (slice.OptionChains.TryGetValue(OptionSymbol, out chain))
                {
                    var contract = (
                        from optionContract in chain.OrderByDescending(x => x.Strike)
                        select optionContract
                        ).FirstOrDefault();

                    if (contract != null)
                    {
                    	HasOrderOrHolding = true;
                        MarketOrder(contract.Symbol, OrderQuantity(Portfolio.Cash, contract.AskPrice) );
                    }
                }
            }
        }

        public void ExecuteShort(Slice slice)
        {

        	foreach (var security_option in Securities)
            {
            	if ((security_option.Value.Symbol.SecurityType == SecurityType.Option) && (security_option.Value.Invested))
            	{
            		Decimal midPrice = MidPrice(security_option.Value.BidPrice, security_option.Value.AskPrice);
            		var currentGoal = ((security_option.Value.Holdings.AveragePrice * security_option.Value.Holdings.AbsoluteQuantity * 100) * GoalFactor) + security_option.Value.Holdings.TotalFees;
            		var currentValue = (midPrice * security_option.Value.Holdings.AbsoluteQuantity * 100);
            	
            		Plot("Plotter", "HoldingGoal", currentGoal);
                    Plot("Plotter", "HoldingValue", currentValue);
                    
            		OrderTrackingDebugStr = String.Format("{0} - POSITION IN {1} {2:0.00} {3} {4:MM/dd/yy} -- Cost {5:0.00} -- Will exit at {6:0.00} and current value={7:0.00}", 
            			Time.ToString(),
            			security_option.Value.Symbol.Underlying,
                        security_option.Value.Symbol.ID.StrikePrice, 
                        security_option.Value.Symbol.ID.OptionRight, 
                        security_option.Value.Symbol.ID.Date,
                        security_option.Value.Holdings.AbsoluteHoldingsCost,
                        currentGoal,
                        currentValue
                        );
                        
                        
            		if (currentValue >= currentGoal)
            		{
            			HasOrderOrHolding = false;
            			Liquidate();
            		}
            	}
            }
        }
        
        private void ShowOrderTracking()
        {
        	if (HasOrderOrHolding)
        	  Debug(OrderTrackingDebugStr);
        }
        
        private Decimal MidPrice(Decimal Low, Decimal High)
        {
            return Math.Round(((High - Low) / 2) + Low, 2);
        }

    }
    
    
}