Overall Statistics
Total Trades
537
Average Win
0.37%
Average Loss
-0.27%
Compounding Annual Return
4.288%
Drawdown
8.500%
Expectancy
0.064
Net Profit
4.324%
Sharpe Ratio
0.353
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
1.34
Alpha
-0.196
Beta
14.718
Annual Standard Deviation
0.114
Annual Variance
0.013
Information Ratio
0.212
Tracking Error
0.114
Treynor Ratio
0.003
Total Fees
$537.00
using System;
using System.Linq;
using QuantConnect.Indicators;
using QuantConnect.Data.Market;
using System.Collections.Concurrent;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators.CandlestickPatterns;
using System.Collections.Generic;

namespace QuantConnect.Algorithm.CSharp
{
    public class BasicTemplateAlgorithm : 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 EveningDojiStar _eveDoji;




            public SelectionData(QCAlgorithm algorithm, Symbol symbol)
            {

                _shortRSI = new RelativeStrengthIndex(14);
                _eveDoji = new EveningDojiStar(symbol, 0.3m);
                
            }

            // updates the RSI and Technical indicators, returning true when they're ready
            public bool RSIWarmUp(QCAlgorithm algorithm, Symbol symbol, int periods)
            {
                var bars = algorithm.History<TradeBar>(symbol, periods);
                if (_shortRSI.Samples > 1)
                {
                    return false;
                }
                foreach (var bar in bars)
                {
                    _shortRSI.Update(bar.EndTime, bar.Close);
                }
                return true;
            }

            public bool DojiStarWarmUp(QCAlgorithm algorithm, Symbol symbol, int periods)
            {
                var bars = algorithm.History<TradeBar>(symbol, periods);
                if (_eveDoji.Samples > 1)
                {
                    return false;
                }
                foreach (var bar in bars)
                {
                    _eveDoji.Update(bar);
                }
                return true;
            }
        }


        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(this, cf.Symbol))


                        // Previous code wasn't returning True from Update method, so it was an endless loop
                        // This will use a historical data call to warm up the indicator instead

                        where avg.RSIWarmUp(this, cf.Symbol, 14)
                        where avg.DojiStarWarmUp(this, cf.Symbol, 14)

                        where cf.Symbol.Value != "SPY"
                        where cf.Symbol.Value != "TLT"


                        //filter by RSI
                        where avg._shortRSI > 80

                        where cf.Price > 5.0m
                        where cf.DollarVolume > 1 * 1000000

                        //where avg._eveDoji.Current.Value < 0

                        // 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 override void OnSecuritiesChanged(SecurityChanges changes)
        {
            _changes = changes;
            
            if (_changes == SecurityChanges.None) return;

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

            // we'll simply go short each security we added to the universe
            foreach (var security in _changes.AddedSecurities)
            {
            	Log(security.Symbol.Value + " Added");
                if ((security.Symbol.Value != "SPY" || security.Symbol.Value != "TLT"))
                {
                    SetHoldings(security.Symbol, TargetPercent);
                }
            }
        }

        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);
            }

        }
    }
}