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
Probabilistic 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
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders;

namespace QuantConnect.Algorithm.CSharp
{
    public class TopGainersWIthIndicatorsAlgorithm : QCAlgorithm
    {
        private readonly Dictionary<DateTime, List<string>> _backtestSymbolsPerDay = new Dictionary<DateTime, List<string>>();
        private const string fileUrl = @"https://www.dropbox.com/s/rc7xay8voo7elol/stock-picker-backtest-2020-10-16.csv?dl=1";
        private Dictionary<string, SecurityInfo> _securityDetails;
        private decimal _stopLossPercent = 0.98m;  //2% trailing loss
        private decimal _maxProfit = 1.011m;  //1.10% Profit
        decimal minimumPurchase = 500m;
        private int _momentumPeriod = 60;
        private int _priceIncreaseFrequency = 3;
        private int _priceIncreaseFrequencyOverrideMomentumPeriod = 12;
        private int _startHour = 9;
        private int _startMin = 30;
        private bool _tradeDataAvailable = false;
        private decimal _percentBelowDailyHigh = 0.02m;

        public override void Initialize()
        {
            UniverseSettings.Resolution = Resolution.Second;
            SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);

            SetStartDate(2020, 10, 23);
            SetEndDate(2020, 10, 23);
            SetCash(100000);
            SetTimeZone("America/New_York");

            //Transactions.MarketOrderFillTimeout = TimeSpan.FromSeconds(30);
            _securityDetails = new Dictionary<string, SecurityInfo>();
            SetUniverseSelection(
                new ScheduledUniverseSelectionModel(
                    DateRules.EveryDay(),
                    TimeRules.Every(TimeSpan.FromMinutes(200)),
                    SelectSymbols
                )
            );

            SetWarmUp(_momentumPeriod, Resolution.Second);
            Schedule.On(
                DateRules.EveryDay(),
                // 15 minutes before market close,
                TimeRules.At(15, 45),
                () =>
                {
                    // before market close we Liquidate ALL
                    Liquidate();

                }
            );
            Schedule.On(
                DateRules.EveryDay(),

                TimeRules.At(18, 45),
                () =>
                {

                    _securityDetails = new Dictionary<string, SecurityInfo>();
                    _backtestSymbolsPerDay.Clear();
                    UniverseManager.Clear();
                }
            );
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            Debug($"OnSecuritiesChanged {Time}: {changes}");
            Debug($" added {string.Join(",", changes.AddedSecurities.Select(x => x.Symbol.Value))}");
            Debug($" removed {string.Join(",", changes.RemovedSecurities.Select(x => x.Symbol.Value))}");
        }


        private IEnumerable<Symbol> SelectSymbols(DateTime dateTime)
        {
            var file = Download(fileUrl);
            _backtestSymbolsPerDay.Clear();
            UniverseManager.Clear();
            foreach (var line in file.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var csv = line.ToCsv();
                var date = DateTime.ParseExact(csv[0], "yyyyMMdd", null);
                var symbols = csv.Skip(1).ToList();
                if (_backtestSymbolsPerDay.ContainsKey(date))
                {
                    _backtestSymbolsPerDay[date].AddRange(symbols);
                }
                else
                {
                    _backtestSymbolsPerDay[date] = symbols;
                }

            }

            List<string> result;
            if (_backtestSymbolsPerDay.TryGetValue(dateTime.Date, out result))
            {
                var response = result.Distinct().
                    Select(x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA));
                Debug($"*******{dateTime} {string.Join(",", response)}");

                return response;
            }
            _tradeDataAvailable = false;
            return new List<Symbol>() { };
        }

        public override void OnData(Slice data)
        {
            foreach (var kvp in data.Bars)
            {
                if (!_securityDetails.ContainsKey(kvp.Key.Value))
                {
                    _securityDetails[kvp.Key.Value] = new SecurityInfo()
                    {
                        TradeBars = new List<TradeBar>(),
                        Symbol = kvp.Key,
                        MomentumPercent = MOMP(kvp.Key, _momentumPeriod, Resolution.Second),
                        RelativeStrengthIndex = RSI(kvp.Key, _momentumPeriod, resolution: Resolution.Second),
                    };
                }

                ;
                var security = _securityDetails[kvp.Key.Value];
                Debug($"{kvp.Key} security.MomentumPercent {security.MomentumPercent}  security.RelativeStrengthIndex {security.RelativeStrengthIndex}");
                var bar = kvp.Value;
                if (bar.High > security.HighestPrice)
                {
                    security.HighestPrice = bar.High;
                    if (Portfolio[kvp.Key].Invested)
                    {
                        UpdateStopTrailingLoss(security, bar.Symbol);
                    }
                }

                if (security.WarmupComplete && !Portfolio[kvp.Key].Invested)
                {

                    if ((security.RelativeStrengthIndex > 50
                         && security.BollingerBands < 0) ||
                        (security.MomentumPercent > 1
                        && security.MovingAverageConvergenceDivergence > 0)
                        )
                    {
                        SetHoldings(bar.Symbol, 0.8);
                    }
                }
            }
        }

        private void UpdateStopTrailingLoss(SecurityInfo securityDetail, Symbol sym)
        {
            var orderTicket = securityDetail.StopTrailingLossOrderTicket;
            if (orderTicket != null)
            {
                orderTicket.Update(new UpdateOrderFields()
                {
                    StopPrice = _stopLossPercent * securityDetail.HighestPrice
                });
                if (_stopLossPercent * securityDetail.HighestPrice >= securityDetail.FillPrice * _maxProfit)
                {
                    if (securityDetail.StoLimit != null && securityDetail.StoLimit.OrderId > 0)
                    {
                        securityDetail.StoLimit.Cancel();
                    }
                }
                Plot("Data Chart", "Stop Price", orderTicket.Get(OrderField.StopPrice));
            }

            else if (_securityDetails[sym.Value].StoLimit?
                .OrderId > 0)
            {
                _securityDetails[sym.Value].StopTrailingLossOrderTicket
                    = StopMarketOrder(sym,
                        -Portfolio[sym].Quantity,
                        _securityDetails[sym.Value].FillPrice * _stopLossPercent);

            }
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            if (orderEvent.Status == OrderStatus.Filled && orderEvent.Direction == OrderDirection.Buy)
            {

                _securityDetails[orderEvent.Symbol.Value].FillPrice = orderEvent.FillPrice;
                _securityDetails[orderEvent.Symbol.Value].HoldingQuantity = orderEvent.Quantity;
                //Only Take Profit if Stop trailing loss is Lower than profit


                _securityDetails[orderEvent.Symbol.Value].StoLimit = LimitOrder(
                    orderEvent.Symbol,
                    -Portfolio[orderEvent.Symbol].Quantity,
                    _securityDetails[orderEvent.Symbol.Value].FillPrice * _maxProfit);




                Debug($"{orderEvent.Symbol} filled@ { orderEvent.FillPrice} " +
                      $"qty  {orderEvent.Quantity} " +
                      $"sell@ {_securityDetails[orderEvent.Symbol.Value].FillPrice * _maxProfit} " +
                      $"stopLoss@ {_securityDetails[orderEvent.Symbol.Value].FillPrice * _stopLossPercent}");

            }
            else if (orderEvent.Status == OrderStatus.Filled && orderEvent.Direction == OrderDirection.Sell
            )
            {
                var order = Transactions.GetOrderById(orderEvent.OrderId);

                if (order.Type == OrderType.Limit || order.Type == OrderType.StopMarket)
                {
                    Transactions.CancelOpenOrders(order.Symbol);
                }
            }

        }

    }
    public class SecurityInfo
    {
        public Symbol Symbol { get; set; }
        public decimal HighestPriceForToday { get; set; }
        public decimal HighestPrice { get; set; }
        public decimal FillPrice { get; set; }
        public MomentumPercent MomentumPercent { get; set; }
        public RelativeStrengthIndex RelativeStrengthIndex { get; set; }
        public BollingerBands BollingerBands { get; set; }
        public MovingAverageConvergenceDivergence MovingAverageConvergenceDivergence { get; set; }

        public bool WarmupComplete =>
            this.MomentumPercent.IsReady && this.RelativeStrengthIndex.IsReady;
        public List<TradeBar> TradeBars { get; set; }
        public decimal HoldingQuantity { get; set; }
        public OrderTicket StopTrailingLossOrderTicket { get; set; }
        public OrderTicket StoLimit { get; set; }

        public void UpdateIndicators(DateTime time, decimal price)
        {
            this.MomentumPercent.Update(time, price);
            this.RelativeStrengthIndex.Update(time, price);
        }
    }
}