Overall Statistics
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
namespace QuantConnect 
{   
    /*
    *   QuantConnect University: Full Basic Template:
    *
    *   The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect.
    *   We have explained some of these here, but the full algorithm can be found at:
    *   https://github.com/QuantConnect/Lean/tree/master/Algorithm
    */
    public class BollingerAlgo : QCAlgorithm
    {
    	private List<Symbol> toTradeLong  = new List<Symbol>();
    	private List<Symbol> toTradeShort = new List<Symbol>();
    	
        public override void Initialize() 
        {
			
            //Start and End Date range for the backtest:
            SetStartDate(2014, 1, 1);         
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            
            //Cash
            SetCash(25000);
            
            UniverseSettings.Resolution = Resolution.Hour;
            UniverseSettings.Leverage = 0;
            
            //screen universe based on if the price is above/below bollinger bands
            AddUniverse(coarse => {
            	return (from c in coarse
            		let bb = BB(c.Symbol, 20, 2, MovingAverageType.Exponential, Resolution.Hour)
	    			where (c.Price > bb.UpperBand || c.Price < bb.LowerBand)
	    			orderby c.DollarVolume descending 
            			select c.Symbol).Take(500);
			});
            
            
        }

        //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)
        {   
        	//list to put stocks to trade
        	toTradeLong.Clear();
        	toTradeShort.Clear();
        	
        	//check which type of order to make (short or long)
            foreach(Symbol Key in data.Keys)
				{	
    				int check = checkBollinger(Key, data[Key]);
    				if(check == 1){
    					toTradeLong.Add(Key);
    				}else if(check == -1){
    					toTradeShort.Add(Key);
    				}
				}
				
				makeTrades();
        }
        
        //check whether a stock is above/below upper/lower bands. 
        public int checkBollinger(Symbol sym, TradeBar data){
        	var bb = BB(sym, 20, 2, MovingAverageType.Exponential, Resolution.Hour);
        	
        	if (bb.UpperBand > data.Close){
        		//above
        		return 1;
        	}else if(bb.UpperBand < data.Close){
        		//below
        		return -1;
        	}else{
        		//within both
        		return 0;
        	}
        }
        
        public void makeTrades(){
        	if(Portfolio.HoldStock){
        		Liquidate();
        	}
        	//wait until all positions are closed
        	do
			{
   			// nothing
			} while (Portfolio.HoldStock);
        	
        	int lengthLong  = toTradeLong.Count;
        	int lengthShort = toTradeShort.Count;
        	
        	//set each list to contain no more than 3 items
        	if(lengthLong > 3){
        		lengthLong = 3;
        	}
        	if(lengthShort > 3){
        		lengthShort = 3;
        	}
        	//divide the cash to long and short allocations
        	decimal cash = Portfolio.Cash;
        	if(lengthLong != 0){
        		//half to long, dive the half up
        		decimal cashLong = (cash / 2 ) / lengthLong;
        		
        		//iterate through and place orders
        		for(int i = 0; i < lengthLong; i ++){
        			Symbol sym = toTradeLong[i];
        			double weight = 0.5 / lengthLong;
        			SetHoldings(sym.Value, weight);
        		}
        	}
        	if(lengthShort != 0){
        		//half to short, dive the half up
        		decimal cashShort = (cash / 2 ) / lengthShort;
        		
        		//iterate through and place orders
        		for(int i = 0; i < lengthShort; i ++){
        			Symbol sym = toTradeShort[i];
        			double weight = 0.5 / lengthShort;
        			SetHoldings(sym.Value, weight * -1);
        		}
        	}
        	
        }
        
    }
}