Overall Statistics
Total Trades
1271
Average Win
0.56%
Average Loss
-0.32%
Compounding Annual Return
134.851%
Drawdown
11.000%
Expectancy
0.435
Net Profit
135.952%
Sharpe Ratio
2.367
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.73
Alpha
0.485
Beta
21.027
Annual Standard Deviation
0.375
Annual Variance
0.141
Information Ratio
2.316
Tracking Error
0.375
Treynor Ratio
0.042
Total Fees
$1347.66
using System;
using System.Collections.Concurrent;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Indicators.CandlestickPatterns;

namespace QuantConnect.Algorithm.CSharp
{

    public class ShortTechnicalUniverseSelectionAlgorithm : QCAlgorithm
    {
        // tolerance to prevent bouncing
        const decimal Tolerance = 0.01m;
        private const int Count = 10;
        // use Buffer+Count to leave a little in cash
        private const decimal TargetPercent = -0.1m;
        private SecurityChanges _changes = SecurityChanges.None;
        // holds our coarse fundamental indicators by symbol
        private readonly ConcurrentDictionary<Symbol, SelectionData> _averages = new ConcurrentDictionary<Symbol, SelectionData>();
        
        public BollingerBands _eqBB;
        public BollingerBands _irBB;
        

        // class used to improve readability of the coarse selection function
        private class SelectionData
        {
            public ExponentialMovingAverage Fast;
            public ExponentialMovingAverage Slow;
            public RelativeStrengthIndex _shortRSI;
            public CandlestickPatterns _eveDoji;
            
            
            

            public SelectionData()
            {

                _shortRSI = new RelativeStrengthIndex(14);
                //_eveDoji = new CandlestickPatterns.EveningDojiStar(0.3m);
                
            }

            // updates the RSI and Technical indicators, returning true when they're ready
            public bool Update(DateTime time, decimal value)
            {
                //return Fast.Update(time, value) && Slow.Update(time, value);
                return _shortRSI.Update(time, value);
                //return _eveDoji.Updaate(time, value);
            }
        }


        public override void Initialize()
        {
            UniverseSettings.Leverage = 2.0m;
            UniverseSettings.Resolution = Resolution.Daily;

            SetStartDate(2018, 01, 01);
            SetEndDate(2019, 01, 01);
            //SetEndDate(DateTime.Now.Date.AddDays(-1));
            SetCash(10*1000);
            
            SetWarmup(200);
            
            
            AddEquity("SPY", Resolution.Daily);
            AddEquity("TLT", Resolution.Daily);
            
            _eqBB = BB("SPY", 200, 1, MovingAverageType.Simple, Resolution.Daily);
            _irBB = BB("TLT", 200, 1, MovingAverageType.Simple, Resolution.Daily);
            
            
            //rebalance to simple long portfolio (75/25, 50/50, or 25/75) at the beginning of the week based on broad market technical info
            Schedule.On(DateRules.WeekStart("SPY"), TimeRules.AfterMarketOpen("SPY", 10), () =>
			{
				RebalanceLong();
			});

            
            
            
            //trades a short portfolio on margin with an RSI screen and various CandlestickPatterns
            AddUniverse(coarse =>
            {
                return (from cf in coarse
                        // grab th SelectionData instance for this symbol
                        let avg = _averages.GetOrAdd(cf.Symbol, sym => new SelectionData())
                        
                        // Update returns true when the indicators are ready, so don't accept until they are
                        where avg.Update(cf.EndTime, cf.AdjustedPrice)
                        
                        where cf.Symbol != "SPY"
                        where cf.Symbol != "TLT"
                        

                        //filter by RSI
                        where avg._shortRSI > 80
                        
                        where cf.Price > 5.0m
                        where cf.DollarVolume > 1 * 1000000
                        
                        //where cf._eveDoji == True
                        
                        // sort symbols with a larger delta by percentage between the two averages
                        orderby avg._shortRSI descending
                       
                        // we only need to return the symbol and return 'Count' symbols
                        select cf.Symbol).Take(Count);
            });
        }


        public void OnData(TradeBars data)
        {
            if (_changes == SecurityChanges.None) return;

            // liquidate securities removed from our universe
            foreach (var security in _changes.RemovedSecurities)
            {
                if (security.Invested && (security.Symbol != "SPY" || security.Symbol != "TLT"))
                {
                    Liquidate(security.Symbol);
                }
            }

            // we'll simply go short each security we added to the universe
            foreach (var security in _changes.AddedSecurities)
            {
                SetHoldings(security.Symbol, TargetPercent);
            }
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            _changes = changes;
        }
        
        public void RebalanceLong()
        {
        	if (Securities["SPY"].Price > _eqBB.MiddleBand && Securities["TLT"].Price < _irBB.MiddleBand)
        	{
        		SetHoldings("SPY", 0.75);
        		SetHoldings("TLT", 0.25);
        	}
        	
        	else if (Securities["SPY"].Price < _eqBB.MiddleBand && Securities["TLT"].Price > _irBB.MiddleBand)
        	{
        		SetHoldings("SPY", 0.25);
        		SetHoldings("TLT", 0.75);
        	}
        	
        	else {
        		SetHoldings("SPY", 0.50);
        		SetHoldings("TLT", 0.50);
        	}
        	
        }
    }
}