Overall Statistics
Total Trades
1112
Average Win
0.94%
Average Loss
-1.09%
Compounding Annual Return
6912.402%
Drawdown
21.400%
Expectancy
0.195
Net Profit
191.776%
Sharpe Ratio
4.367
Loss Rate
36%
Win Rate
64%
Profit-Loss Ratio
0.87
Alpha
3.975
Beta
-1.021
Annual Standard Deviation
0.896
Annual Variance
0.802
Information Ratio
4.09
Tracking Error
0.941
Treynor Ratio
-3.831
Total Fees
$9511.61
//Copyright Warren Harding 2016.
//Granted to the public domain.
//Use entirely at your own risk.
//Custom algorithm development: warrencharding@yahoo.com.
//Do not remove this copyright notice.

using System;
using System.Collections.Generic;
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;
using QuantConnect.Securities;
namespace QuantConnect
{
    public class Algo4 : QCAlgorithm
    {
    	//You can adjust this first set to optimize.
    	int atrPeriod = 15;
    	decimal buyLowRatio = 0.97m;
    	decimal sellHighRatio = 1.03m;
    	decimal minimumAtrPercentage=0.01m;
    	
    	//Be careful adjusting this next one, too high of a setting will result in unrealistically large
    	//purchases being made with no regards for slippage.
    	decimal ratioOfLastMinuteForMaxTrade =0.05m;
    	
    	//Your broker is going to hate you if you set these too low as it will result in large amounts of unfilled
    	//order cancellations. It bogs down LEAN as well.
    	int minutesToHoldBuyOrdersFor=3;
    	int minutesToHoldSellOrdersFor=3;
        
        Dictionary<string,AverageTrueRange> atrs=new Dictionary<string,AverageTrueRange>();
        Dictionary<string,OrderTicket> buyOrders=new Dictionary<string,OrderTicket>();
        Dictionary<string,int> buyOrderCounts = new Dictionary<string,int>();
        Dictionary<string,decimal> buyOrderPrices = new Dictionary<string,decimal>();
        Dictionary<string,OrderTicket> sellOrders=new Dictionary<string,OrderTicket>();
        Dictionary<string,int> sellOrderCounts = new Dictionary<string,int>();
        public override void Initialize()
        {
            SetStartDate(2016, 1, 1);
			SetEndDate(2016, 4, 1);
            SetCash(25000);

			//volatile etf's
			//string tickersString="UVXY,XIV,NUGT,DUST,JNUG,JDUST,LABU,LABD,GUSH,DRIP,TVIX,GASL,GASX,DWTI,UWTI,DGAZ,UGAZ,UBIO,ZBIO,BRZU,RUSS,SCO,UCO,RUSL,ERY,ERX,BIOL,SVXY,VXX,SILJ,BIB,BIS,VIXY,SOXL,VIIX,SOXS,BZQ,USLV,SLVP,DSLV,GDXJ,GLDX";

			//volatile stocks
			string tickersString="LGCY,CDRB,RPRX,BCEI,SXE,UNXL,LEI,ARGS,ALIM,MCEP,AREX,CWEI,DRYS,GBSN,ORIG,SRPT,DNR,CBAY,DRWI,ECR,RLYP,NADL,EVEP,SKYS,VRNG,PTCT,ERN,CLF,RESN,WG,EPE,BAS,GLF,SDRL,PLG,VYGR,HCLP,ANFI,GST,LEU,GSL,RXII,MEP,FCSC,CHMA,DSX,EMES,TDW,GNCA,CCXI,VSLR,JONE,TTPH,CNXR,CRMD,CARA,SALT,GRAM,SN,CBMX,MEMP,FMSA,CPXX,TROV,ETE,CLVS,OVAS,ENPH,OMEX,NGL,TMST,CHK,CLMT,ORPN,WLL,SM,HBM,GOL,YRD,BBG,BPT,SGYP,UNT,CNAT,RXDX,CLD,VRX,ATW,RBPAA,GLBL,PES,CIE,TKAI,AMID,AVGR,HLX,SKY,SDLP,INAP,AEGR";
			
			//string tickersString=tickersString1+","+tickersString2;
			string[] tickers = tickersString.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string ticker in tickers)
			{
				AddSecurity(SecurityType.Equity,ticker,Resolution.Minute);
			}
            foreach (Security s in Securities.Values)
            {
            	s.FeeModel=new CustomFeeModel();
            	atrs.Add(s.Symbol,ATR(s.Symbol,atrPeriod,MovingAverageType.Simple,Resolution.Minute));
            }
        }
		
        public void OnData(TradeBars data)
        {
				Buy(data);
				Sell(data);
        }
        
        public void Buy(TradeBars data)
        {
        	CancelBuyOrders();
        	int quantity = 0;
        	decimal minimumPurchase = 500m;
        	decimal maxTrade;
            OrderTicket orderTicket;
            decimal buyPrice;
    	    foreach (TradeBar bar in data.Values)
            {
            	if (Portfolio.Cash - SumBuyOrders(buyOrders,buyOrderPrices) < minimumPurchase)
                {
                    break;
                }
                if (!Portfolio[bar.Symbol].HoldStock)
                {
                    maxTrade = bar.Close * bar.Volume / ratioOfLastMinuteForMaxTrade;
                    quantity =(int)Math.Floor(Math.Min(Portfolio.Cash-SumBuyOrders(buyOrders,buyOrderPrices), maxTrade) / bar.Close);
                    if (quantity * bar.Close > minimumPurchase & quantity > 0)
                    {
                        if (atrs[bar.Symbol] / bar.Close > minimumAtrPercentage)
                        {
                        	if (buyOrders.ContainsKey(bar.Symbol) == false)
                        	{
                            	buyPrice=bar.Low * buyLowRatio;
                                orderTicket = LimitOrder(bar.Symbol, quantity,buyPrice);
                                buyOrders.Add(bar.Symbol,orderTicket);
                                buyOrderCounts.Add(bar.Symbol,0);
       							buyOrderPrices.Add(bar.Symbol,buyPrice);
                        	}
                        }
                    }
                }
            }
            foreach (string key in buyOrderCounts.Keys.ToList())
            {
                buyOrderCounts[key] = buyOrderCounts[key] + 1;
            }
        }
        
        public void Sell(TradeBars data)
        {
        	CancelSellOrders();
        	decimal sellPrice;
    	    TradeBar bar;
    	    OrderTicket orderTicket;
            foreach (SecurityHolding stock in Portfolio.Values)
            {
                if (Portfolio[stock.Symbol].Quantity > 0 & data.ContainsKey(stock.Symbol))
                {
                    bar = data[stock.Symbol];
                    if (sellOrders.ContainsKey(stock.Symbol)==false)
                    {
                        sellPrice = bar.High * sellHighRatio;
                        orderTicket = LimitOrder(stock.Symbol, -Portfolio[stock.Symbol].Quantity, sellPrice);
                        sellOrders.Add(stock.Symbol,orderTicket);
                        sellOrderCounts.Add(stock.Symbol,0);
                    }
                }
            }
            foreach (string key in sellOrderCounts.Keys.ToList())
            {
                sellOrderCounts[key] = sellOrderCounts[key] + 1;
            }
        }
        
        public void CancelBuyOrders()
        {
        	string[] symbols=buyOrders.Keys.ToArray();
        	foreach (string symbol in symbols)
        	{
			    if (buyOrderCounts[symbol]>minutesToHoldBuyOrdersFor)
	        	{
	        		buyOrders[symbol].Cancel();
	        		buyOrders.Remove(symbol);
	        		buyOrderCounts.Remove(symbol);
	        		buyOrderPrices.Remove(symbol);
	        	}
        	}
        	symbols=buyOrders.Keys.ToArray();
        	foreach (string symbol in symbols)
        	{
    		    if (buyOrders[symbol].Status == OrderStatus.Filled)
	            {
            		buyOrders.Remove(symbol);
            		buyOrderCounts.Remove(symbol);
            		buyOrderPrices.Remove(symbol);
	            }
        	}
        }
        
        public void CancelSellOrders()
        {
        	string[] symbols=sellOrders.Keys.ToArray();
        	foreach (string symbol in symbols)
        	{
			    if (sellOrderCounts[symbol]>minutesToHoldSellOrdersFor)
	        	{
	        		sellOrders[symbol].Cancel();
	        		sellOrders.Remove(symbol);
	        		sellOrderCounts.Remove(symbol);
	        	}
        	}
        	symbols=sellOrders.Keys.ToArray();
        	foreach (string symbol in symbols)
        	{
    		    if (sellOrders[symbol].Status == OrderStatus.Filled)
	            {
            		sellOrders.Remove(symbol);
            		sellOrderCounts.Remove(symbol);
	            }
        	}
        }
        
        public static decimal SumBuyOrders(Dictionary<string,OrderTicket> buyOrders, Dictionary<string,decimal> buyOrderPrices)
        {
        	decimal sum=0;
            foreach (string key in buyOrders.Keys.ToList())
            {
                sum += buyOrders[key].Quantity * buyOrderPrices[key];
            }
            return sum;
        }
       
        
    }
    
    public class CustomFeeModel : IFeeModel
    {
        public decimal GetOrderFee(Security security, Order order)
        {
            var fee = order.AbsoluteQuantity*0.01m;
            if (fee<5)
            {
            	fee=5;
            }
            if (fee>10)
            {
            	fee=10;
            }
            return fee;
        }
    }
}