Skip to main content Skip to footer

How to Create Custom Indicators and Overlays

A technical indicator is a series of data points on a chart, generated by applying a formula to a security’s price data. Technical indicators are used in forecasting market directions as they allow for an alternative interpretation of the strength and direction of the underlying price action.

The ComponentOne FinancialChart provides several built-in technical indicators and overlays. Although as a developer, you may prefer to create custom indicators and overlays for your FinancialChart.

Check out our new StockAnalysis demo where we use built-in indicators and overlays. To use the complete functionality of this demo, download ComponentOne Studio.

Creating a custom indicator and overlay

The custom indicator and overlay will integrate with a FinancialChart control.

ADX (Average Directional Index) Indicator

The ADX indicator is used primarily in determining momentum and the strength of a trend (regardless of direction) over time. The strength of a trend is usually categorized as follows:

  • Rising ADX means that the trend is gaining strength.
  • Falling ADX shows that the trend is losing momentum or reversing.
  • Flat ADX shows a sideways range.

It is important to know is that the ADX is non-directional -- it does not give any information about the direction of the trend. When the ADX goes up, it means the trend is gaining strength, this can signal either a bullish or a bearish trend.

An ADX indicator relies on two DI (Directional Index) lines to determine the momentum and strength of the trend. These lines are by default rendered in green and red and compare with a candle's highs and lows.

To calculate the ADX, we'll need to find the highs and lows of the specific time period. Afterwards, we can use below code to calculate the two DI lines and then ADX value is calculated:

// Calculate two DI lines and ADX.
            int dataLen = quoteData.Length;

            double pfactor = (double)(period - 1) / period;

            double tr;
            double dmp;
            double dmn;
            double dx = 0.0;
            double dmpA = 0.0;
            double dmnA = 0.0;
            double trA = 0.0;
            double adxfirst = 0.0;

            adxDataPts = new AdxDataPoint[dataLen];
            adxDataPts[0] = new AdxDataPoint(quoteData[0].LocalDate);

            for (int i = 1; i < dataLen; i++)
            {
                adxDataPts[i] = new AdxDataPoint(quoteData[i].LocalDate);

                double h = quoteData[i].High, l = quoteData[i].Low;
                double ph = quoteData[i - 1].High, pl = quoteData[i - 1].Low, pc = quoteData[i - 1].Close;

                tr = Math.Max(h - l, Math.Max(Math.Abs(h - pc), Math.Abs(l - pc)));

                if ((h - ph) >= (pl - l))
                {
                    dmp = ((h - ph) > 0.0) ? (h - ph) : 0.0;
                    dmn = 0.0;
                }
                else
                {
                    dmp = 0.0;
                    dmn = ((pl - l) > 0.0) ? (pl - l) : 0.0;
                }

                if (i <= period)
                {
                    trA += tr;
                    dmpA += dmp;
                    dmnA += dmn;
                }
                else
                {
                    trA = trA * pfactor + tr;
                    dmpA = dmpA * pfactor + dmp;
                    dmnA = dmnA * pfactor + dmn;
                }

                if (i >= period)
                {
                    double dipa = dmpA / trA * 100;
                    double dina = dmnA / trA * 100;

                    dx = Math.Abs(dipa - dina) / (dipa + dina) * 100;

                    adxDataPts[i].DIPA = dipa;
                    adxDataPts[i].DINA = dina;

                    if (i <= period + period - 1)
                    {
                        adxfirst += dx / period;
                        if (i == period + period - 1) 
                            adxDataPts[period + period - 1].ADX = adxfirst;
                    }
                }

                if (i > period + period - 1)
                {
                    adxDataPts[i].ADX = (adxDataPts[i-1].ADX * (period - 1) + dx) / period;
                }
            }

The below chart was created using the ComponentOne FinancialChart, rendering the data of Dell Technologies.

Dashboard layout for ASP.NET MVC

As we can see, the green and red lines are the two DI lines, and the black line is for ADX. Using this chart, we can make the following interpretations:

  • The rising ADX line (starting from 15-08-2017) signals a strong momentum or trend. Since ADX is non-directional, we must find out whether this strong momentum is for a bullish or a bearish trend. We can easily find this by looking at cross-overs of green and red lines.
  • In case of rising ADX line, if the green line crosses the red line upwards, it signals a strong bullish trend.
  • Conversely, in case of rising ADX line, if the green line crosses red line downwards, it signals a strong bearish trend.

With the above three interpretations in mind, we can see that a strong bullish momentum start on 15-08-2017 and end on 03-Nov-2017. Similarly, we see a strong bearish momentum on 29-Jan-2018 and continued until Feb-2018.

Pivot Points

Pivot points are used to determine the overall trend of the market over different timeframes. These can be calculated for daily, weekly, bi-weekly, and monthly. They are used to calculate support and resistance. One of their main advantages (compared with other indicators/overlays) is their static nature -- they remain at the same level throughout that time-period. Price usually tends to deflect or pause when a pivot-point or resistance level is tested.

Different types of Pivot points

Pivot points can range from Standard (or floor pivot) to Camarilla, Fibonacci, etc. Pivot points and associated support and resistance levels are calculated by using the High, Low and Close values of any financial instrument.

  • Pivot Point (PP) = (High + Low + Close)/3
  • First Resistance (R1) = (2*PP) – Low
  • Second Resistance (R2) = PP + (High-Low)
  • Third Resistance (R3) = High + 2(PP-Low)
  • First Support (S1) = (2*PP) – High
  • Second Support (S2) = PP – (High-Low)
  • Third Support (S3) = Low -2(High-PP)

Above values can be calculated in code as follows:

C# code for calculating Pivot points will come here.

Once these values are calculated, individual values must be plotted as a Line series and then rendered as an overlay on top of the chart.

Generating Pivot Points

The below code can be used to generate Pivot points and then render on ComponentOne FinancialChart. For simplicity, we have used Monthly Pivot points; however, if you have essential data, then you can generate hourly, daily, weekly, monthly, and yearly pivots.

List<PivotPoint> pdatas = new List<PivotPoint>();

            DateTime dataDate = DateTime.MinValue;
            double high = double.MinValue, low = double.MaxValue, close = -1, pivot = -1;

            int p = 0;
            while (DateTime.Parse(qdata[p].LocalDate).Day > 7 && high == double.MinValue)
                p++; // skip to first complete month

            int month = DateTime.Parse(qdata[p].LocalDate).Month;
            high = qdata[p].High;
            low = qdata[p].Low;
            double delta = high - low;
            p++;

            while (p < qdata.Length)
            {
                DateTime qdate = DateTime.Parse(qdata[p].LocalDate);
                if (qdate.Month == month)
                {
                    if (qdata[p].High > high) high = qdata[p].High;
                    if (qdata[p].Low < low) low = qdata[p].Low;
                }
                else
                {
                    month = qdate.Month;
                    close = qdata[p - 1].Close;
                    pivot = (high + low + close) / 3;
                    delta = high - low;
                    pdatas.Add(new PivotPoint()
                    {
                        EffectiveDate = new DateTime(qdate.Year, qdate.Month, 1).ToShortDateString(),
                        StartingIndex = p,
                        Pivot = pivot,
                        S1 = isStandard ? pivot * 2 - high            : pivot - (0.382 * delta),
                        S2 = isStandard ? pivot - delta               : pivot - (0.618 * delta),
                        S3 = isStandard ? low - 2 * (high - pivot)    : pivot - (1.0 * delta),
                        R1 = isStandard ? pivot * 2 - low             : pivot + (0.382 * delta),
                        R2 = isStandard ? pivot + delta               : pivot + (0.618 * delta),
                        R3 = isStandard ? high + 2 * (pivot - low)    : pivot + (1.0 * delta),
                    });

                    high = qdata[p].High;
                    low = qdata[p].Low;
                }
                p++;
            }

            if (DateTime.Parse(qdata[--p].LocalDate).Month == month)
            {
                //create an extra PivotPoint element to match the last date
                PivotPoint pp = pdatas[pdatas.Count-1];
                pdatas.Add(new PivotPoint()
                {
                    EffectiveDate = qdata[p].LocalDate,
                    StartingIndex = p,
                    Pivot = pp.Pivot,
                    S1 = pp.S1,
                    S2 = pp.S2,
                    S3 = pp.S3,
                    R1 = pp.R1,
                    R2 = pp.R2,
                    R3 = pp.R3,
                });
            }

The below chart was created in ComponentOne FinancialChart, with actual data from Dell Technologies.

ComponentOne FinancialChart

As we can see, the stock price remains near Pivot. Whenever Support, or Resistance is broken, the price comes back again to Pivot.

If you have any questions about this tutorial, please leave us a comment. Additionally, if you have a request for a specific demo, be sure to leave a comment below!

Amit Pal

Product Analyst
comments powered by Disqus