Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
NaN
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
NaN
Tracking Error
NaN
Treynor Ratio
NaN
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;

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();
        
        // Constructor: Set the sample period:
        public AverageDirectionalIndex(int samplePeriods) {
            _expConst = (2m / (decimal)(samplePeriods + 1));
            _samplePeriods = 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:
            _superCandle.Update(bar);
            if (_superCandle.Samples < _samplePeriods) return Decision;
            
            //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++;
            }
        }
        
    } // End ADX Indicator Class
    
} // End Namespace                        
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"];
            adx.AddSample(SPY);
            Log("READY? " + adx.Ready + " VALUE: " + Math.Round(adx.ADX,2).ToString());
        }
    }
}