Overall Statistics
using System;
using System.Collections.Concurrent;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;

namespace QuantConnect.Algorithm.CSharp
{
    public class AlertBlackViper : QCAlgorithm
    {
    	private ConcurrentDictionary<Symbol, SelectionData> costats = new ConcurrentDictionary<Symbol, SelectionData>();
    	
    	
    	
    	private class SelectionData
        {
        	public RelativeStrengthIndex rsi;
        	public SimpleMovingAverage sRSI; 
        	public ExponentialMovingAverage fast;
        	public ExponentialMovingAverage slow;
        	public IchimokuKinkoHyo ichi;
        	public long marketCap;
        	public decimal value;
        	public Int16 buy;
        	//Days since purchase
			
            public SelectionData(QCAlgorithm algy, Symbol sym)
            {
                rsi = new RelativeStrengthIndex(14, MovingAverageType.Wilders);
                sRSI = new SimpleMovingAverage(10);
                fast = new ExponentialMovingAverage(50);
                slow = new ExponentialMovingAverage(200);
                ichi = new IchimokuKinkoHyo(9,26,52);
                IEnumerable<TradeBar> bars = algy.History<TradeBar>(sym, 200);
                foreach(TradeBar bar in bars)
                {
                	Update(bar);
                }
                marketCap = 0;
                value = 0;
                buy = 0;
            }
            public bool Update(TradeBar tb)
            {
            	int success = 0;
            	DateTime time = tb.EndTime;
            	value = tb.Close;
            	
            	if(rsi.Update(time, value))
            	{
            		if(sRSI.Update(time, rsi))
            		{
            			success++;
            		}
            	}
//        		roll.Add(value);
        		fast.Update(time, value);
        		if(slow.Update(time, value))
        		{
        			success++;
        		}
            	if(ichi.Update(tb))
            	{
            		success++;
            	}
            	if(success == 3)
            	{
            	if
            	(
	           		((sRSI.Current < 30m  && ScaledDelta < 0) || 
					(ichi.Tenkan > ichi.Kijun && ichi.Chikou > tb.Close
					&& ichi.Kijun > ichi.SenkouA && ichi.Tenkan > ichi.SenkouB))
//					&& (marketCap == 0 || (marketCap > 1000000000L && marketCap < 5000000000L))

					 
				)
				{
					buy = 1;
				}
				else if
				(
					((sRSI.Current > 70m && ScaledDelta > 0) ||
           			(ichi.Tenkan < ichi.Kijun && ichi.Chikou < ichi.Kijun)
					|| (ichi.Kijun < ichi.SenkouA && ichi.Tenkan < ichi.SenkouB))
				)
				{
					buy = -1;
				}
				else buy = 0;
				return true;
            	}
					 
            	return false;;
            }
            public bool setMarketCap(long amt)
            {
				if(amt <= 0)
            	{
            		marketCap = 0;
            	}
            	else marketCap = amt;
            	return true;
            }
            
          
            public decimal ScaledDelta
            {
                get { return (fast - slow)/((fast + slow)/2m); }
            }
            public bool aboveOne
            {
            	get { return value > fast || value > slow; }
            }
        }

        public override void Initialize()
        { 
            SetCash(1000);
            UniverseSettings.Resolution = Resolution.Daily;
        	SetStartDate(2007, 1, 1);
			SetEndDate(2010, 1, 1);
			SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash);
			Portfolio.MarginCallModel = MarginCallModel.Null;
//			AddUniverse(SelectCoarse, SelectFine);
			AddSecurity(SecurityType.Equity, "SPY", Resolution.Daily);
			SetBenchmark("SPY");
			AddUniverse(SelectCoarse, SelectFine);

        }

        /// OnData event is the primary entry point for your algorithm. 
        //  Each new data point will be pumped in here.
        /// Slice object keyed by symbol containing the stock data
        public void OnData(TradeBars tbs)
        {
        	int amtStocks = 10;
        	if(IsWarmingUp)
        		return; 
			List<Symbol> data = (from s in tbs.Keys
        			let disun = costats.GetOrAdd(s, sym => new SelectionData(this, s))
        			let tb = tbs[s]
					where disun.Update(tb) && disun.buy == 1

					orderby disun.ScaledDelta ascending
				select tb.Symbol).Take(amtStocks+10).ToList();
			
			if(costats.ContainsKey("SPY"))
        	if(costats["SPY"].slow.IsReady)
        	if(costats["SPY"].aboveOne)
        	{
        		if(data.Count > 0)
            	{
            		
            		decimal PPS = Portfolio.TotalPortfolioValue / amtStocks;
            		int total = (int)Math.Min(data.Count, Math.Floor(Portfolio.Cash / PPS));
            		int i = 0;
            		long count = 0;
            		Symbol sym = data[i];
            		decimal num = 0m;
            		if(total > 0)
            		while(count < total && i < total)
            		{
						sym = data[i];
						num = Math.Floor(PPS / tbs[sym].Close);
						
						if(!Portfolio[sym].Invested && num > 0m)
						{
            				MarketOrder(sym, num);
						}
						i++;
            			count++;
            			
            		}
            	}
        	}
            if (Portfolio.Invested)
            {
            	foreach(Symbol item in Portfolio.Keys)
            	{
            		if(costats.ContainsKey(item))
            		{
            			SelectionData disun = costats[item];
            			if(Portfolio[item].Invested)
            			if(disun.buy == -1)
            			{
							Liquidate(item);
            			}
            			
            		}
        			
            	}
            }
            
        }
        



        public IEnumerable<Symbol> SelectCoarse(IEnumerable<CoarseFundamental> tbs)
        {
        	return (from tb in tbs
				select tb.Symbol);
        }
        public IEnumerable<Symbol> SelectFine(IEnumerable<FineFundamental> fine)
        {
            return (from f in fine
            	let disun = costats.GetOrAdd(f.Symbol, sym => new SelectionData(this, f.Symbol))
            	where disun.setMarketCap(f.MarketCap)
            	select f.Symbol);
        }
    }
}