Overall Statistics
Total Trades
814
Average Win
0.73%
Average Loss
-0.74%
Compounding Annual Return
1.563%
Drawdown
11.500%
Expectancy
0.102
Net Profit
32.501%
Sharpe Ratio
0.327
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
0.99
Alpha
0.017
Beta
-0.007
Annual Standard Deviation
0.051
Annual Variance
0.003
Information Ratio
-0.276
Tracking Error
0.205
Treynor Ratio
-2.369
Total Fees
$4597.53
namespace QuantConnect 
{   
    /*
    *   SPYSellAfter3DownDays
    *	By:Ray Bohac
    *
    *   Playing with purchasing SPY after 3 days of consecutive close < open
    *	Inspiration from article at http://tradingwithpython.blogspot.com/2016/02/a-simple-statistical-edge-in-spy.html
    */
    public class SPYSellAfter3DownDays : QCAlgorithm
    {
        string symbol = "SPY";
        const int NUM_DAYS = 3;
        private OpenClose[] priceArray = new OpenClose[NUM_DAYS];
        private decimal _last = 0;
        
        
        public override void Initialize() 
        {
			
			
            //Start and End Date range for the backtest:
            SetStartDate(1998, 1, 1);         
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            
            //Cash allocation
            SetCash(100000);

            AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
            
            for (int i = 0; i < NUM_DAYS; i++) { priceArray[i] = new OpenClose();}
            
            
            // TimeRules https://www.quantconnect.com/terminal/docs/topic4253.html
            
            Schedule.On(DateRules.EveryDay(symbol), TimeRules.At(7,0,0), () =>
            {
                RotatePriceArray();
            });
            
            
            Schedule.On(DateRules.EveryDay(symbol), TimeRules.AfterMarketOpen(symbol, 0.30), () =>
            {
                priceArray[0].open = _last;
            });
            
            
            Schedule.On(DateRules.EveryDay(symbol), TimeRules.AfterMarketOpen(symbol, 30), () =>
            {
            	// 30 Minutes after market open
                SellCheck();
            });

            //Schedule.On(DateRules.EveryDay(symbol), TimeRules.BeforeMarketClose(symbol, 1), () =>
            //{
            //    priceArray[0].close = _last;
            //});
            
            
            Schedule.On(DateRules.EveryDay(symbol), TimeRules.At(15,30,0), () =>
            {
                BuyCheck();
            });
            
            SetWarmup(new TimeSpan(10, 0, 0, 0, 0));  // 10 Days
        }
        
        private void RotatePriceArray()
        {
        	for (int i = NUM_DAYS -1; i > 0; i--)
        	{
        		priceArray[i].close = priceArray[i-1].close;
        		priceArray[i].open  = priceArray[i-1].open;
        	}
        	priceArray[0].reset();
        	
        }
        
        private void BuyCheck()
        {
        	priceArray[0].close = _last;
        	
        	String LogStr = "BuyCheck: Fired at: " + Time;
        	for (int i = 0; i < NUM_DAYS; i++)
        		LogStr += " "+i.ToString()+"="+priceArray[i].ToString();
        	Log(LogStr);
        	
        	if (allClosedLower() && (!Portfolio.HoldStock))
        	{
        		Log("Buy On "+ Time);
        		int quantity = (int)Math.Floor(Portfolio.Cash / _last);
                Order(symbol,  quantity);
        	}
        }
        
        private void SellCheck()
        {
        	
        	if (Securities[symbol].Holdings.Quantity > 0)
        		Order(symbol, -Securities[symbol].Holdings.Quantity);
        }
        
        private bool allClosedLower()
        {
        	for (int i = 0; i < NUM_DAYS; i++)
        		if (!priceArray[i].closedLower())
        			return false;
        			
        	return true;
        }


        public void OnData(TradeBars data) 
        {   
        	
        	if (data.ContainsKey(symbol))
        	{
        		_last = data[symbol].Close;
        		priceArray[0].close = _last;
        	}
        }
    }
    
    public class OpenClose
    {
    	public decimal open = 0;
    	public decimal close = 0;
    	public bool closedLower()
    	{
    		return close < open;
    	}
    	
    	public void reset()
    	{
    		open = 0;
	    	close = 0;
    	}
    	
    	public override string ToString()
    	{
    		
    		return "("+ closedLower().ToString()[0]+")O:"+open.ToString("N4")+"/C:"+close.ToString("N4");
    	}
    }
}