Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C#
Article

Creating a Mechanical Trading System Part 1: Technical Indicators

Rate me:
Please Sign up or sign in to vote.
4.06/5 (15 votes)
3 Aug 2006CPOL3 min read 122.4K   3.9K   84   13
How to program the building blocks of a mechanical trading system: creating technical indicators
Sample Image - Technical_Indicators.jpg

Introduction

This article explains how to code technical analysis indicators on the .NET platform using the C# language. This is the first step towards creating a fully automated trading robot that does not depend on any underlying platform to perform its tasks. The final product will receive quotes directly from a broker via an API, perform price analysis, and decide whether or not to place orders to buy or sell.

The code provided here is part of a larger project to create a backtesting platform and an automated FOREX trading robot. The source code for this project is available here.

This will cover the implementation details of the Exponential Moving Average, and the Moving Average Convergence Divergence (MACD) indicators. These two indicators have been chosen to exemplify how modular design and object oriented programming can help create complex indicators out of simple ones.

The MACD indicator has been chosen for this article since it produces a rather distinct entry signal based on its two lines crossing. This article does not advocate taking the crossovers both as entry and exit signals since this indicator is lagging and produces signals once the trend has changed. The entries provided by this indicator should be complemented with exit techniques based on other indicators. Of particular interest are exits described by Charles Le Beau using the Average True Range indicator such as the Chandelier and Yoyo Exits.

Background

The nature of the final product, a trading robot, demands that the indicators are coded with real time signals in mind. Each indicator has four important methods:

  • Constructor: Initializes the object and instantiates any other indicators needed.
  • ReceiveTick: Informs the indicator that a new value has been received. The indicator can now store it in an internal buffer, or perform computations with the new value
  • Value: Returns the value of the indicator. This method uses the internal buffer filled by ReceiveTick to compute its data.
  • IsPrimed: Returns true when the indicator has received enough values to start producing a meaningful output. For example, a 14 period simple moving average will not return output values until 14 input values are received.

The MACD indicator is constructed with three EMAs. A slow (longer period) EMA and a fast (shorter period) EMA both receive the current price. The difference from the fast and slow EMAs is called the MACD, and is sent to a third EMA called the Signal. The values plotted in the chart are the MACD and the Signal. By instantiating three EMA objects and defining the relationships between them, a more complex indicator such as the MACD can be easily created.

Indicators have to be instantiated first with the proper parameters. Then the ReceiveTick method needs to be called with a value. To obtain the result from the indicator, the Value method needs to be called. This method returns a value of 0 if not enough values have been received. The IsPrimed method can be called to determine if the indicator has received enough values to compute a value.

Note that the ReceiveTick method can either receive price data, or data from another indicator. This flexibility is what enables the MACD indicator to be built from three Exponential Moving Average objects.

Source Code

C#
//
// 4X Lab.NET © Copyright 2005-2006 ASCSE LLC
// http://www.4xlab.net
// email: 4xlab@4xlab.net
//

using System;

namespace _4XLab.NET
{
    public class iEMA
    {
        private int tickcount;
        private int periods;
        private double dampen;
        private double emav;

        public iEMA(int pPeriods)
        {
            periods = pPeriods;
            dampen  = 2/((double)1.0+periods);
        }

        public void ReceiveTick(double Val)
        {
            if (tickcount < periods)
                emav += Val;
            if (tickcount ==periods)
                emav /= periods;
            if (tickcount > periods)
                emav = (dampen*(Val-emav))+emav;

            if (tickcount <= (periods+1) )
            {            
                // avoid overflow by stopping use of tickcount
                // when indicator is fully primed
                tickcount++;
            }
        }

        public double Value()
        {
            double v;

            if (isPrimed())
                v = emav;
            else
                v = 0;

            return v;
        }

        public bool isPrimed()
        {    
            bool v = false;
            if (tickcount > periods)
            {
                v = true;
            }
            return v;
        }
    }

    public class iMACD
    {
        int pSlowEMA, pFastEMA, pSignalEMA;
        iEMA slowEMA, fastEMA, signalEMA;

        // restriction: pPFastEMA < pPSlowEMA
        public iMACD(int pPFastEMA, int pPSlowEMA, int pPSignalEMA)
        {
            pFastEMA = pPFastEMA;
            pSlowEMA = pPSlowEMA;
            pSignalEMA = pPSignalEMA;

            slowEMA = new iEMA(pSlowEMA);
            fastEMA = new iEMA(pFastEMA);
            signalEMA = new iEMA(pSignalEMA);
        }

        public void ReceiveTick(double Val)
        {
            slowEMA.ReceiveTick(Val);
            fastEMA.ReceiveTick(Val);

            if (slowEMA.isPrimed() && fastEMA.isPrimed())
            {
                signalEMA.ReceiveTick(fastEMA.Value()-slowEMA.Value());
            }
        }

        public void Value(out double MACD, out double signal, out double hist)
        {
            if (signalEMA.isPrimed())
            {
                MACD = fastEMA.Value() - slowEMA.Value();
                signal = signalEMA.Value();
                hist = MACD - signal;
            }
            else
            {
                MACD = 0;
                signal = 0;
                hist = 0;
            }
        }

        public bool isPrimed()
        {    
            bool v = false;
            if (signalEMA.isPrimed())
            {
                v = true;
            }
            return v;
        }
    }
}

Credits

The image in this article was obtained with a product that includes software developed as part of the NPlot library project available from here.

Read More About It

History

  • 3rd August, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionEMA is not calculated correctly Pin
Mario M.12-Oct-17 2:47
Mario M.12-Oct-17 2:47 
Generalwhy 4xlab.net is gone? Pin
Southmountain9-Jan-15 9:42
Southmountain9-Jan-15 9:42 
could you post more information about this site?
diligent hands rule....

GeneralPlease Pin
tapfuma5-Mar-11 5:47
tapfuma5-Mar-11 5:47 
QuestionError Pin
ahmedalhoseny13-Jan-10 0:38
ahmedalhoseny13-Jan-10 0:38 
QuestionCalculate Macd Value Pin
ibrahim19801-Jan-10 12:28
ibrahim19801-Jan-10 12:28 
GeneralImpressed Pin
mbaocha25-Aug-09 20:28
mbaocha25-Aug-09 20:28 
GeneralGreat Work! Pin
MTRIG4-Feb-09 6:43
MTRIG4-Feb-09 6:43 
GeneralCoding Pin
jingyeu6-Dec-07 20:20
jingyeu6-Dec-07 20:20 
Generalabout NPlot Pin
775852115-Aug-06 21:32
775852115-Aug-06 21:32 
GeneralRe: about NPlot Pin
Alejandro Simon25-Aug-06 12:42
Alejandro Simon25-Aug-06 12:42 
GeneralMessage Closed Pin
2-May-16 21:23
Liza Akter2-May-16 21:23 
General*Very* interesting, keep it up! Pin
Axel Rietschin4-Aug-06 7:12
professionalAxel Rietschin4-Aug-06 7:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.