Overall Statistics
Total Trades
1
Average Win
0.62%
Average Loss
0%
Compounding Annual Return
69.263%
Drawdown
0.500%
Expectancy
0
Net Profit
0.618%
Sharpe Ratio
6.047
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
-0.22
Beta
0.921
Annual Standard Deviation
0.052
Annual Variance
0.003
Information Ratio
-13.116
Tracking Error
0.02
Treynor Ratio
0.338
using System;
using System.Collections;
using System.Collections.Generic; 
using QuantConnect.Securities;  
using QuantConnect.Models;   

namespace QuantConnect 
{   
    // Name your algorithm class anything, as long as it inherits QCAlgorithm
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
        AverageDirectionalIndex adx = new AverageDirectionalIndex(3);
        //Initialize the data and resolution you require for your strategy:
        public override void Initialize()
        {
            SetStartDate(2014, 12, 01);         
            SetEndDate(DateTime.Now.Date.AddDays(-1)); 
            SetCash(25000);
            AddSecurity(SecurityType.Equity, "SPY", Resolution.Minute);
        }

        //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
        public void OnData(TradeBars data) 
        {   
            TradeBar SPY = data["SPY"];
            if (!Portfolio.Invested) Order("SPY", 100);
            
            //Build indicator:
            adx.AddSample(SPY);
            Log("READY? " + adx.Ready + " VALUE: " + Math.Round(adx.ADX,2).ToString());
            
            Plot("ADX", "adx", Math.Round(adx.ADX,2));
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using QuantConnect.Securities;
using QuantConnect.Models;
using System.Linq;

namespace QuantConnect {

    /* ADX Indicator - Average Directional Index is a complicated but powerful indicator.
    *  
    *      1. Calculate the Directional Movements: +DM_t, -DM_t.
    *      2. Find the Average Directional Movement: ADM_t
    *      3. Calculate the Average True Range: ATR_t
    *      4. Calculate the Directional Indexes: DI+_t, DI-_t, 
    *         Directional Movement Index: DX_t,
    *         then Average Directional Movement Index! ADX_t
    *      
    *  Requires day to be divided into segments, periods and a running record kept of the previous value so the averages can be made.
    */
    public class AverageDirectionalIndex {
        
        //Public Result Access: Primary ADX Indicator
        public decimal ADX {
            get; private set;
        }
        
        //Public Result Access: DMI Positive:
        public decimal DMI_Pos {
            get; private set;
        }
        
        //Public Result Access: DMI Negative:
        public decimal DMI_Neg {
            get; private set;
        }
        
        //Public Result Access: Direction of the ADX Indicator:
        public decimal Decision {
            get; private set;
        }
        
        //Public Result Access: When indicator has sufficient data flags as true.
        public bool Ready {
            get; private set;
        }
        
        //Initialize
        private ADXCacheItem indicatorMemory = new ADXCacheItem();
        private decimal _expConst = 0;
        private int _samplePeriods = 0;
        private Candle _superCandle = new Candle();
        private FixedLengthQueue<TradeBar> _rollingQueue = new FixedLengthQueue<TradeBar>(0);
        
        // Constructor: Set the sample period:
        public AverageDirectionalIndex(int samplePeriods) {
            _expConst = (2m / (decimal)(samplePeriods + 1));
            _samplePeriods = samplePeriods;
            _rollingQueue = new FixedLengthQueue<TradeBar>(samplePeriods);
            Ready = false;
        }
        
    
        /// <summary>
        /// Calculate the ADX figure, return an indicator result.
        /// </summary>
        public decimal AddSample(TradeBar bar) {
            
            //0. Save these samples in running OHLC candle until requested samplePeriod reached:
            _rollingQueue.Enqueue(bar);
            if (_rollingQueue.Count < _samplePeriods) return Decision;
            
            //Create the bar on this rolling window:
            var bars = _rollingQueue.ToList();
            foreach (var queueBar in bars)
            {
                _superCandle.Update(bar);
            }
            
            //0. Define a result storage for this session.
            ADXCacheItem current = new ADXCacheItem();
            current.OHLC = _superCandle;
            
            //0. If this is the first candle skip it and come back for second: to calc directional index can't be relative to 0.
            if (!indicatorMemory.Set) {
                current.Set = true; 
                indicatorMemory = current;
                _superCandle = new Candle();
                return Decision;
            }
            
            //1. Calculate the Directional Movements: store results back into current-variable class cache
            GetDirectionalMovements(ref current);

            //2. Find the Average Directional Movement.
            GetAverageDirectionalMovements(ref current);

            //3. Get the Average True Range:
            GetAverageTrueRange(ref current);

            //4. Get the Average Directional Movement Index ADX-t, and DI+, DI-
            GetADX(ref current);

            //Strong Trend is Present, and have at least X-min data
            Decision = 0;
            if (current.Adx > 40) {
                //NOW! We have an ADX result, interpret it..
                if (current.DmiPos > 40) {
                    Decision = 1;
                } else if (current.DmiNeg > 40) {
                    Decision = -1;
                }
            }

            //Save the results to publicly accessible properties.
            ADX = current.Adx;
            DMI_Neg = current.DmiNeg;
            DMI_Pos = current.DmiPos;

            //Update the indicator cache - store previous result between calls.
            current.Set = true; Ready = true;
            indicatorMemory = current;
            _superCandle = new Candle();

            return Decision;
        }
        
        
        /// <summary>
        /// 1. Get the pure directional movements, in DM+, DM- Form.
        /// </summary>
        /// <param name="current">ADX Cache class for easy storing for next analysis session.</param>
        private void GetDirectionalMovements(ref ADXCacheItem current) {
            //Change from the previous period to now.
            decimal deltaHigh = current.OHLC.High - indicatorMemory.OHLC.High;
            decimal deltaLow = indicatorMemory.OHLC.Low - current.OHLC.Low;

            //Allocate the Delta Movement.
            if ((deltaHigh < 0 && deltaLow < 0) || (deltaHigh == deltaLow)) {
                current.Dm_plus = 0;
                current.Dm_neg = 0;

            } else if (deltaHigh > deltaLow) {
                current.Dm_plus = deltaHigh;
                current.Dm_neg = 0;

            } else if (deltaHigh < deltaLow) {
                current.Dm_plus = 0;
                current.Dm_neg = deltaLow;
            }
        }
        
        
        
        /// <summary>
        /// 2. Get the Exp Average of the directional movement indexs
        /// </summary>
        private void GetAverageDirectionalMovements(ref ADXCacheItem current) {
            if (!Ready) {
                //If this is the first run,
                current.Adm_plus = current.Dm_plus;
                current.Adm_neg = current.Dm_neg;
            } else {
                //This is not our first sample
                current.Adm_plus = (current.Dm_plus * _expConst) + (indicatorMemory.Adm_plus * (1 - _expConst));
                current.Adm_neg = (current.Dm_neg * _expConst) + (indicatorMemory.Adm_neg * (1 - _expConst)); ;
            }
        }

        

        /// <summary>
        /// 3. Get the true range of the price.
        /// </summary>
        private void GetAverageTrueRange(ref ADXCacheItem current) {
            decimal yesterdayClose = indicatorMemory.OHLC.Close;

            decimal trueRange = System.Math.Max(Math.Abs(current.OHLC.High - current.OHLC.Low),
                                System.Math.Max(Math.Abs(current.OHLC.High - yesterdayClose),
                                                Math.Abs(yesterdayClose - current.OHLC.Low)));

            //Get the current true range:
            if (indicatorMemory.Atr == 0) {
                current.Atr = trueRange;
            } else {
                current.Atr = (trueRange * _expConst) + ((1 - _expConst) * indicatorMemory.Atr);
            }
        }
        


        /// <summary>
        /// 4. Get the Directional Movement Index
        /// </summary>
        private void GetADX(ref ADXCacheItem current) {
            decimal dmi_plus = 0;  
            decimal dmi_neg = 0;  

            if (current.Atr > 0) { 
                dmi_plus = (current.Adm_plus / current.Atr) * 100;
                dmi_neg = (current.Adm_neg / current.Atr) * 100;
            }

            if ((dmi_plus + dmi_neg) != 0) {
                current.Dx = (Math.Abs(dmi_plus - dmi_neg) / (dmi_plus + dmi_neg)) * 100;
            } else {
                current.Dx = indicatorMemory.Dx;
            }

            //Save the results.
            current.DmiPos = dmi_plus;
            current.DmiNeg = dmi_neg;
            current.Adx = current.Dx * _expConst + (1 - _expConst) * indicatorMemory.Adx;
        }

        
        /// <summary>
        /// Provide a structure for caching the previous values of the ADX
        /// </summary>
        public class ADXCacheItem {
            public Candle OHLC = new Candle();
            public bool Set = false;
            public decimal Atr = 0;
            public decimal Dm_plus = 0;
            public decimal Dm_neg = 0;
            public decimal Adm_plus = 0;
            public decimal Adm_neg = 0;
            public decimal Dx = 0;
            public decimal DmiPos = 0;
            public decimal DmiNeg = 0;
            public decimal Adx = 0;
        }
        
        
        /// <summary>
        /// Simple online "super-tradebar" generator for making an OHLC from multiple bars.
        /// </summary>
        public class Candle {
            public Candle() { }
            public decimal Open = 0;
            public decimal High = Decimal.MinValue;
            public decimal Low = Decimal.MaxValue;
            public decimal Close = 0;
            public int Samples = 0;
            
            public void Update(TradeBar bar) {
                if (Open == 0) Open = bar.Open;
                if (High < bar.High) High = bar.High;
                if (Low > bar.Low) Low = bar.Low;
                Close = bar.Close;
                Samples++;
            }
        }
        
        /// <summary>
        /// Cap the queue length
        /// </summary>
        public class FixedLengthQueue<T> : ConcurrentQueue<T>
        {
            private readonly object syncObject = new object();
        
            public int Size { get; private set; }
        
            public FixedLengthQueue(int size)
            {
                Size = size;
            }
        
            public new void Enqueue(T obj)
            {
                base.Enqueue(obj);
                lock (syncObject)
                {
                    while (base.Count > Size)
                    {
                        T outObj;
                        base.TryDequeue(out outObj);
                    }
                }
            }
        }
        
    } // End ADX Indicator Class
    
} // End Namespace