Overall Statistics
using System;
using System.Collections.Generic;
using QuantConnect.Brokerages;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;

namespace QuantConnect.Algorithm.CSharp
{
    public class NabeelMacd: QCAlgorithm, IRegressionAlgorithmDefinition
    {
        private MovingAverageConvergenceDivergence _macd;
        private NormalizedAverageTrueRange _atr;
        private readonly string _symbol = "SPY";
        private TradeBar _last;

        /// <summary>
        /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
        /// </summary>
        public override void Initialize()
        {
            SetStartDate(2019, 01, 01);
            SetEndDate(2019, 01, 8);
            //SetEndDate(2020, 01, 01);
            SetCash(10000);

            SetBrokerageModel(BrokerageName.Alpaca);
            SetWarmUp(TimeSpan.FromMinutes(26 * 60));

            AddSecurity(SecurityType.Equity, _symbol, Resolution.Minute);

            var barConsolidator = new TradeBarConsolidator(TimeSpan.FromMinutes(60));
            // var barConsolidator = new TradeBarConsolidator(TimeSpan.FromHours(4));
            barConsolidator.DataConsolidated += ConslidatedBarHandler;
            SubscriptionManager.AddConsolidator(_symbol, barConsolidator);

            // define our daily macd(12,26) with a 9 day signal
            _macd = MACD(_symbol, 12, 26, 9, MovingAverageType.Exponential, Resolution.Hour);
            _atr = new NormalizedAverageTrueRange(10);
            
            RegisterIndicator(_symbol, _macd, TimeSpan.FromMinutes(30));
            RegisterIndicator(_symbol, _atr, TimeSpan.FromMinutes(30));
        }

        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">TradeBars IDictionary object with your stock data</param>
        public void OnData(TradeBars data)
        {
        }

        /// <summary>
        /// This is our event handler for our 30 minute trade bar defined above in Initialize(). So each time the consolidator
        /// produces a new 30 minute bar, this function will be called automatically. The 'sender' parameter will be the
        /// instance of the IDataConsolidator that invoked the event, but you'll almost never need that!
        /// </summary>
        private void ConslidatedBarHandler(object sender, TradeBar consolidated)
        {
            if (!_macd.IsReady || !_atr.IsReady) {
                return;
            }
            var holding = Portfolio[_symbol];
            
            var signalDeltaPercent = (_macd - _macd.Signal)/_macd.Fast;
            const decimal tolerance = 0.0025m;

            if (_atr < 4) {
                return;
            }

            // if our macd is greater than our signal, then let's go long
            if (holding.Quantity <= 0 && signalDeltaPercent > tolerance) { // 0.01%
                // longterm says buy as well
                SetHoldings(_symbol, 1.0);
            }
            // of our macd is less than our signal, then let's go short
            else if (holding.Quantity >= 0 && signalDeltaPercent < -tolerance) {
                Liquidate(_symbol);
            }

            // plot both lines
            Plot("MACD", _macd, _macd.Signal);
            Plot(_symbol, "Open", consolidated.Open);
            Plot(_symbol, _macd.Fast, _macd.Slow);

            _last = consolidated;
        }

        /// <summary>
        /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
        /// </summary>
        public bool CanRunLocally { get; } = true;

        /// <summary>
        /// This is used by the regression test system to indicate which languages this algorithm is written in.
        /// </summary>
        public Language[] Languages { get; } = { Language.CSharp, Language.Python };

        /// <summary>
        /// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
        /// </summary>
        public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
        {
            {"Total Trades", "84"},
            {"Average Win", "4.79%"},
            {"Average Loss", "-4.16%"},
            {"Compounding Annual Return", "2.963%"},
            {"Drawdown", "34.700%"},
            {"Expectancy", "0.228"},
            {"Net Profit", "37.907%"},
            {"Sharpe Ratio", "0.274"},
            {"Probabilistic Sharpe Ratio", "0.399%"},
            {"Loss Rate", "43%"},
            {"Win Rate", "57%"},
            {"Profit-Loss Ratio", "1.15"},
            {"Alpha", "0.034"},
            {"Beta", "-0.04"},
            {"Annual Standard Deviation", "0.113"},
            {"Annual Variance", "0.013"},
            {"Information Ratio", "-0.234"},
            {"Tracking Error", "0.214"},
            {"Treynor Ratio", "-0.775"},
            {"Total Fees", "$443.74"},
            {"Fitness Score", "0.013"},
            {"Kelly Criterion Estimate", "0"},
            {"Kelly Criterion Probability Value", "0"},
            {"Sortino Ratio", "0.216"},
            {"Return Over Maximum Drawdown", "0.085"},
            {"Portfolio Turnover", "0.024"},
            {"Total Insights Generated", "0"},
            {"Total Insights Closed", "0"},
            {"Total Insights Analysis Completed", "0"},
            {"Long Insight Count", "0"},
            {"Short Insight Count", "0"},
            {"Long/Short Ratio", "100%"},
            {"Estimated Monthly Alpha Value", "$0"},
            {"Total Accumulated Estimated Alpha Value", "$0"},
            {"Mean Population Estimated Insight Value", "$0"},
            {"Mean Population Direction", "0%"},
            {"Mean Population Magnitude", "0%"},
            {"Rolling Averaged Population Direction", "0%"},
            {"Rolling Averaged Population Magnitude", "0%"},
            {"OrderListHash", "-1703572248"}
        };
    }
}