Overall Statistics
using MathNet.Numerics;
using QuantConnect.Indicators;
using System;
using System.Linq;

//Copied from this forum:
//href https://www.quantconnect.com/forum/discussion/695/adjusted-slope--exponential-slope----annualized-slope--r-squuared--adjusted-slope/p1

namespace QuantConnect.Algorithm.CSharp.Helpers
{
    public class AnnualizedExponentialSlopeIndicator : WindowIndicator<IndicatorDataPoint>
    {
        public AnnualizedExponentialSlopeIndicator(int period)
            : base("AESI(" + period + ")", period)
        {
        }

        public AnnualizedExponentialSlopeIndicator(string name, int period)
            : base(name, period)
        {
        }

        protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input)
        {
            if (window.Count < 3) return 0m;

            var xVals = new double[window.Count];
            var yVals = new double[window.Count];

            // load input data for regression
            for (int i = 0; i < window.Count; i++)
            {
                xVals[i] = i;
                // we want the log of our y values
                yVals[i] = Math.Log((double)window[window.Count - i - 1].Value);
            }

            //http://numerics.mathdotnet.com/Regression.html

            // solves y=a + b*x via linear regression
            var fit = Fit.Line(xVals, yVals);
            var intercept = fit.Item1;
            var slope = fit.Item2;

            // compute rsquared
            var rsquared = GoodnessOfFit.RSquared(xVals.Select(x => intercept + slope * x), yVals);

            // anything this small can be viewed as flat
            if (double.IsNaN(slope) || Math.Abs(slope) < 1e-25) return 0m;

            // trading days per year for us equities
            const int dayCount = 252;

            // annualize dy/dt
            var annualSlope = ((Math.Pow(Math.Exp(slope), dayCount)) - 1) * 100;

            // scale with rsquared
            //annualSlope = annualSlope * Math.Pow(rsquared, 2);
            annualSlope = annualSlope * rsquared;

            if (annualSlope >= (double)decimal.MaxValue || annualSlope <= (double)decimal.MinValue)
            {
                annualSlope = -1000;
                //Debug("Negative slope due to arithmic overflow");
            }

            return Convert.ToDecimal(annualSlope);

        }
    }
}
using MathNet.Numerics;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Concurrent;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect;
using QuantConnect.Data.Fundamental;
using QuantConnect.Brokerages;
using QuantConnect.Algorithm.CSharp.Helpers;
using QuantConnect.Data.Consolidators;

namespace QuantConnect.Algorithm.CSharp
{
    /*
    Momentum strategy according to
    
    ** Objective of the algorithm: **
    
    
    
    ** Trade rules: **
    
    The rules are:
    - Rule 00: ES futures
	
	** Change history: **
    20180102_01: Cannot get _spyMovingAverage to work.
	*/
    /// <summary>
    /// </summary>
    public class MomentumStrategyFuturesAlgorithm : QCAlgorithm
    {
        private const Resolution ResolutionAlgorithm = Resolution.Minute;
        // S&P 500 EMini futures
        private string[] roots = new[]
        {
            Futures.Indices.SP500EMini,
            //Futures.Metals.Gold,
            //^$TODO: do not add because current / previous contract goes wrong, futurechain to be added
        };
        private HashSet<Symbol> _futureContracts = new HashSet<Symbol>();
        private Dictionary<Symbol, AnnualizedExponentialSlopeIndicator> _annualizedExponentialSlope;
        private Dictionary<Symbol, SimpleMovingAverage> _simpelMovingAverage;
        private FuturesContract _currentContract = null;
        private FuturesContract _previousContract = null;

        // S&P 500 EMini futures
        private const string RootSP500 = Futures.Indices.SP500EMini;
        public Symbol SP500 = QuantConnect.Symbol.Create(RootSP500, SecurityType.Future, Market.USA);

        // Gold futures
        private const string RootGold = Futures.Metals.Gold;
        public Symbol Gold = QuantConnect.Symbol.Create(RootGold, SecurityType.Future, Market.USA);

        private const string SP500IndexSymbol = "SPY";

        /// Rule 10: Momentum is calculated based on 90 past days annualized exponential regression slope;
        private int _momentumWindow = 5;
        // Rule 05: If the stock is below its 100 days moving average, sell it;
        private int _furtureMovingAverageWindow = 5; 
        // ATR
        private const int ATRWindowSize = 14;

        private Security _spy;// = QuantConnect.Symbol.Create(SP500IndexSymbol, SecurityType.Equity, Market.USA);
        private SimpleMovingAverage _spyMovingAverage;
        private decimal _spyPriceClose = 0;
        private decimal _esPriceClose = 0;

        private SecurityChanges _securityChanges = SecurityChanges.None;
       
        // Rule 08: If the SP500 is above the 200 days moving average we buy stocks, otherwise not;
        private int _trendfilter = 10;

        // Rule 04: If the stock is not in the top 100/ 20% ranking, sell it;
        private int _topNStockOfSp500 = 100;
        // Rule 06: If the stock gapped > 15%, sell it;
        private decimal _stockMaximumgap = 0.15m;
        // Look back period of stock gap
        private int _stockMaximumGapWindow = 60;
        // Rule 13: Trade maximum 30 stocks;
        private int _maxStockInPortfolio = 30;
        // Rule x: leverage increase if risk managable;
        private int LeverageFactor = 1;

        private bool _isDebugging = true;
        private bool _isPlotting = true;
        private bool _isPlotSpyMovingAverage = true;
        private int _isLogSpyMovingAveragePivot = 0;

        /// <summary>
        /// Helper to create AnnualizedExponentialSlopeIndicator
        /// </summary>
        /// <param name="symbol">symbol</param>
        /// <param name="period">period</param>
        /// <param name="resolution">resolution of data</param>
        /// <returns></returns>
        public AnnualizedExponentialSlopeIndicator AESI(string symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
        {
            var name = CreateIndicatorName(symbol, string.Format("AESI({0})", period), resolution);
            var aesi = new AnnualizedExponentialSlopeIndicator(name, period);
            RegisterIndicator(symbol, aesi, resolution, selector);
            return aesi;
        }
        /// <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()
        {
            //speed up execution
            if (IsDebugging)
            {
                _isPlotSpyMovingAverage = true;
                _trendfilter = 100;
                _topNStockOfSp500 = 20;
                _stockMaximumGapWindow = 14;
                _maxStockInPortfolio = 5;
                _furtureMovingAverageWindow = 100;
                _momentumWindow = 90;
            }

            //Set trading window
            SetStartDate(year: 2017, month: 1, day: 1);
            SetEndDate(year: 2017, month: 4, day: 1);
            //SetEndDate(DateTime.Now);

            foreach (var root in roots)
            {
                // set our expiry filter for this futures chain
                AddFuture(root, ResolutionAlgorithm).SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
            }
            _annualizedExponentialSlope = new Dictionary<Symbol, AnnualizedExponentialSlopeIndicator>();
            _simpelMovingAverage = new Dictionary<Symbol, SimpleMovingAverage>();

            var benchmark = AddEquity(SP500IndexSymbol);
            SetBenchmark(benchmark.Symbol);
            SetBenchmark(d => 1m);

            //Set brokermodel
            SetCash(100000);
            SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);

            //Set moving average on SPY and benchmark
            _spy = AddEquity(SP500IndexSymbol, Resolution.Minute);
            //_spyMovingAverage = SMA(SP500IndexSymbol, _trendfilter, Resolution.Daily);
            
            //var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(1));
            //consolidator.DataConsolidated += OnTradeBarDataConsolidated;
            //SubscriptionManager.AddConsolidator(SP500IndexSymbol, consolidator);

            //_spyMovingAverage = new SimpleMovingAverage(_trendfilter);

            //RegisterIndicator(SP500IndexSymbol, _spyMovingAverage, consolidator);

            //Log("Added new consolidator for " + _spy.Symbol.Value);

            //set warm up algorithm to avoid premature trading
            SetWarmUp(_trendfilter + 1);

            if (IsDebugging)
            {
                Log("*** DEBUGGING: TAKE CARE OF PARAMETERS ***");
            }


        }


        /// Is debugging set, speed up processing
        public bool IsDebugging { get { return _isDebugging; } }
        /// Is plotting set
        public bool IsPlotting { get { return _isPlotting; } }

        /// <summary>
        /// Raises the data event.
        /// </summary>
        /// <param name="data">Data.</param>
        public void OnData(TradeBars data)
        {
            foreach (var bar in data.Values)
            {
                if (data.ContainsKey(SP500IndexSymbol))
                {
                    _spyPriceClose = data[SP500IndexSymbol].Close;
                }
                if(data.ContainsKey(SP500))
                {
                    Log("sp500 price");
                }
            }
        }
        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="slice">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice slice)
        {
            #region SecurityChanges
            // if we have no changes, do nothing
            if (_securityChanges != SecurityChanges.None)
            {
                // Liquidate removed securities that do not rank anymore
                // Rule 07: If the stock left the index, sell it;
                foreach (var security in _securityChanges.RemovedSecurities)
                {
                    if (security.Invested)
                    {
                        Liquidate(security.Symbol);
                    }
                    //clean up dictionairies
                    if (security.Type == SecurityType.Future)
                    {
                        if (_annualizedExponentialSlope.ContainsKey(security.Symbol))
                        {
                            _annualizedExponentialSlope.Remove(security.Symbol);
                            Log(string.Format("_annualizedExponentialSlope removed {0}", security.Symbol));
                        }
                        if (_simpelMovingAverage.ContainsKey(security.Symbol))
                        {
                            _simpelMovingAverage.Remove(security.Symbol);
                            Log(string.Format("_simpelMovingAverage removed {0}", security.Symbol));
                        }
                    }
                }
                if (_spyMovingAverage == null)
                {
                    var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(1));
                    consolidator.DataConsolidated += OnTradeBarDataConsolidated;
                    SubscriptionManager.AddConsolidator(SP500IndexSymbol, consolidator);

                    _spyMovingAverage = new SimpleMovingAverage(_trendfilter);

                    RegisterIndicator(SP500IndexSymbol, _spyMovingAverage, consolidator);

                    Log("Added new consolidator for " + _spy.Symbol.Value);
                }
                //indicate that_changes are processed
                _securityChanges = SecurityChanges.None;
            }
            #endregion SecurityChanges

            #region consolidator of future data into days
            foreach (var chain in slice.FutureChains)
            {
                //Log(string.Format("slice.FutureChain: {0}", chain.ToString()));
                // find the front contract expiring no earlier than in 15 days
                var firstContract = (
                    from futuresContract in chain.Value.OrderBy(x => x.Expiry)
                    where futuresContract.Expiry > Time.Date.AddDays(15)
                    select futuresContract
                    ).FirstOrDefault();

                if (firstContract == null)
                    return;

                //Log(string.Format("firstContract: {0}", firstContract.Symbol));

                if(_currentContract == null || (_currentContract.Symbol != firstContract.Symbol))
                {
                    _previousContract = _currentContract;
                    _currentContract = firstContract;
                    Log(string.Format("CurrentContract: {0}, PreviousContract: {1}", _currentContract.Symbol, _previousContract == null ? "-" : _previousContract.Symbol.ToString()));
                }

                foreach (var contract in chain.Value)
                {
                    if (!_futureContracts.Contains(contract.Symbol))
                    {
                        _futureContracts.Add(contract.Symbol);

                        var consolidator = new QuoteBarConsolidator(TimeSpan.FromHours(1));
                        consolidator.DataConsolidated += OnQuoteBarDataConsolidated;
                        SubscriptionManager.AddConsolidator(contract.Symbol, consolidator);

                        _annualizedExponentialSlope[contract.Symbol] = new AnnualizedExponentialSlopeIndicator(_momentumWindow);
                        _simpelMovingAverage[contract.Symbol] = new SimpleMovingAverage(_furtureMovingAverageWindow);

                        RegisterIndicator(contract.Symbol, _annualizedExponentialSlope[contract.Symbol], consolidator);
                        RegisterIndicator(contract.Symbol, _simpelMovingAverage[contract.Symbol], consolidator);

                        Log("Added new consolidator(s) for " + contract.Symbol.Value);

                    }
                }
            }
            #endregion consolidator of future data into days

            if (IsWarmingUp) return;

            if (!Securities.ContainsKey(_spy.Symbol))
                return;

            //- Rule 08: If the SP500 is above the 200 days moving average we buy stocks, otherwise not;
            if (Securities[_spy.Symbol].Price <= _spyMovingAverage.Current.Value)
            {
                //$TODO: buy T-note/ gold/ silver?
                if (_isLogSpyMovingAveragePivot >= 0)
                {
                    Log(string.Format("Spy in downtrend: {0} < {1}", Securities[_spy.Symbol].Price, _spyMovingAverage.Current.Value));
                    _isLogSpyMovingAveragePivot = -1;
                }
            }
            else
            {
                if (_isLogSpyMovingAveragePivot <= 0)
                {
                    Log(string.Format("Spy in uptrend: {0} > {1}", Securities[_spy.Symbol].Price, _spyMovingAverage.Current.Value));
                    _isLogSpyMovingAveragePivot = 1;
                }
                //decimal investedFuturesQuantity = 0;
                //foreach (var securityKeyValuePair in Portfolio.Securities)
                //{
                //    Security security = securityKeyValuePair.Value;
                //    if (security.Type == SecurityType.Future)
                //    {
                //        investedFuturesQuantity += security.Holdings.Quantity;
                //    }
                //}
                if (_currentContract != null)
                {
                    if(!_annualizedExponentialSlope.ContainsKey(_currentContract.Symbol))
                    {
                        return;
                    }
                    if (!_simpelMovingAverage.ContainsKey(_currentContract.Symbol))
                    {
                        return;
                    }
                    //Contract is most likely to (be) expire soon; liquidate contract
                    if (_previousContract != null && Portfolio.Securities.ContainsKey(_previousContract.Symbol))
                    {
                        Liquidate(_previousContract.Symbol);
                        //$TODO: buy immediately new current contract or decide based on new market entry.
                    }

                    if (!Portfolio.Securities.ContainsKey(_currentContract.Symbol))
                    {
                        if (_annualizedExponentialSlope[_currentContract.Symbol].Current.Value > 0)
                        {
                            // Do we have cash to trade?
                            if (Portfolio.Cash > 0)
                            {
                                decimal estimatedPortfolioCashBalance = Portfolio.Cash - _currentContract.LastPrice;
                                if(estimatedPortfolioCashBalance >= 0)
                                    LimitOrder(_currentContract.Symbol, 1, _currentContract.LastPrice);
                            }
                        }
                    }
                    else
                    {
                        if(_simpelMovingAverage[_currentContract.Symbol].Current.Value < _currentContract.LastPrice)
                        {
                            Liquidate(_currentContract.Symbol);
                            //$TODO: replace by SP500 moving average.
                        }
                    }
                }
            }
            ///Plotting
            if (IsPlotting)
            {
                //foreach (var chain in slice.FutureChains)
                //{
                //    foreach (var contract in chain.Value)
                //    {
                //        Log(String.Format("{0},Bid={1} Ask={2} Last={3} OI={4}",
                //             contract.Symbol.Value,
                //             contract.BidPrice,
                //             contract.AskPrice,
                //             contract.LastPrice,
                //             contract.OpenInterest));
                //    }
                //}
            }
        }
        private void OnQuoteBarDataConsolidated(object sender, QuoteBar quoteBar)
        {
            //Log(quoteBar.ToString());
            //if(_annualizedExponentialSlope.ContainsKey(quoteBar.Symbol))
            //{
            //    Log(_annualizedExponentialSlope[quoteBar.Symbol].ToDetailedString());
            //}
        }
        private void OnTradeBarDataConsolidated(object sender, TradeBar tradeBar)
        {
            Log(tradeBar.ToString());
        }

        /// <summary>
        /// Portfolio risk weight
        /// - Rule 09: Calculate the position sizes, based on 10 basis points using ATR formula;
        /// - Rule 12: Position Size = (portfolioSize * 0, 001 / ATR) = #Shares;
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="atr"></param>
        /// <returns></returns>
        public decimal GetPositionSize(Symbol symbol, decimal atr)
        {
            if (atr == 0)
                return 0;

            decimal risk = this.Portfolio.TotalPortfolioValue * 0.001m;

            return (decimal)((risk / atr) * Securities[symbol].Price) / Portfolio.TotalPortfolioValue * 100;

        }
        /// <summary>
        /// Get the Average True Range (ATR)
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="windowSize"></param>
        /// <returns></returns>
        public decimal GetATR(Symbol symbol, int windowSize)
        {
            //validate that the security is in the universe
            if (!Securities.ContainsKey(symbol))
                return 0;

            IEnumerable<Slice> slices = History(windowSize, Resolution.Daily);
            var window = slices.Get(symbol, Field.Close).ToList();

            if (window.Count < 3) return 0m;

            var atr = ATR(symbol, windowSize, MovingAverageType.Exponential, Resolution.Daily);

            return atr.Current.Value;

        }
        /// <summary> 
        /// Calculate Mean
        /// </summary>
        private decimal GetMean(Symbol symbol, int windowSize)
        {
            //validate that the security is in the universe
            if (!Securities.ContainsKey(symbol))
                return 0;

            IEnumerable<Slice> slices = History(windowSize, Resolution.Daily);
            IEnumerable<decimal> close = slices.Get(symbol, Field.Close);
            var closes = close.ToDoubleArray();

            return (decimal)(closes.Mean());
        }
        /// <summary> 
        /// Calculate Gap
        /// return np.max(np.abs(np.diff(close_data))/close_data[:-1])
        //  	out[n] = (a[n+1] - a[n]) / a[n]
        /// </summary>
        private decimal GetGap(Symbol symbol, int windowSize)
        {
            //validate that the security is in the universe
            if (!Securities.ContainsKey(symbol))
                return 0;

            IEnumerable<Slice> slices = History(windowSize, Resolution.Daily);
            var window = slices.Get(symbol, Field.Close).ToList();
            //var closes = close.ToDoubleArray();

            if (window.Count < 3) return 0m;

            var diff = new double[window.Count];

            // load input data for regression
            for (int i = 0; i < window.Count - 1; i++)
            {
                diff[i] = (double)((window[i + 1] - window[i]) / (window[i] == 0 ? 1 : window[i]));
            }

            return (decimal)diff.MaximumAbsolute();
        }
     
        // this event fires whenever we have changes to our universe
        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            _securityChanges = changes;

            if (changes.AddedSecurities.Count > 0)
            {
                Log("Securities added: " + string.Join(",", changes.AddedSecurities.Select(x => x.Symbol.Value)));
            }
            if (changes.RemovedSecurities.Count > 0)
            {
                Log("Securities removed: " + string.Join(",", changes.RemovedSecurities.Select(x => x.Symbol.Value)));
            }

            foreach (var change in changes.AddedSecurities)
            {           
                var history = History<TradeBar>(change.Symbol, 1, Resolution.Daily);

                foreach (var data in history.OrderByDescending(x => x.Time).Take(1))
                {
                    Log("History: " + data.Symbol.Value + ": " + data.Time + " > " + data.Close);
                }
            }
        }
        // Fire plotting events once per day:
        public override void OnEndOfDay()
        {
            if (!_spyMovingAverage.IsReady)
                Log("*** !_spyMovingAverage.IsReady ***");

            if (_spyMovingAverage.Current.Value == 0)
                Log("*** _spyMovingAverage.Current.Value == 0 ***");

            if (_currentContract != null)
            {
                if (!_annualizedExponentialSlope.ContainsKey(_currentContract.Symbol))
                    Log(string.Format("_annualizedExponentialSlope does not contain {0}", _currentContract.Symbol));

                if (!_simpelMovingAverage.ContainsKey(_currentContract.Symbol))
                    Log(string.Format("_simpelMovingAverage does not contain {0}", _currentContract.Symbol));
            }

            ///Plotting
            //Assuming daily mode,dont chart in a smaller res and kill quota
            if (IsPlotting)
            {
                Plot(SP500IndexSymbol, "Price", _spyPriceClose);
                if (_isPlotSpyMovingAverage && _spyMovingAverage.IsReady)
                {
                    Plot(SP500IndexSymbol, _spyMovingAverage.Current.Value);
                }
                if (_currentContract != null)
                {
                    Plot(SP500, "Price", _currentContract.LastPrice);
                    if (_annualizedExponentialSlope.ContainsKey(_currentContract.Symbol))
                    {
                        Plot(SP500, _annualizedExponentialSlope[_currentContract.Symbol].Current.Value);
                    }
                }

                if (Portfolio.TotalPortfolioValue > 0)
                {
                    var accountLeverage = Portfolio.TotalAbsoluteHoldingsCost / Portfolio.TotalPortfolioValue;
                    Plot("Leverage", "Leverage", accountLeverage);
                }
            }
        }
    }
}