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
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) )
{
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;
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