Introduction
The first article in this series introduced a project to code mechanical trading system robots for the .NET platform using the C# language. This article introduces how to code a trading system that will watch price action and make buying or selling decisions. It is the aim of this project to write a program that does not depend on any underlying platform to execute, but rather receives price data directly from a broker and places orders via an API.
The code provided here is part of a larger project to create a backtesting platform and an automated FOREX trading robot. Source code for this project is available here.
Background
This article implements the 4 percent model, developed by Ned Davis and popularized by Martin Zweig in his book Winning on Wall Street. This is a very simple trend following model that will put you on the right side of a sustained trend. This is not to say that this system does not have weaknesses. If too small of a percentage is chosen, the system can whipsaw, or execute many small losing trades.
This system makes an initial buying or selling decision depending on whether the prices rise or fall more than a certain percentage from the first price seen. Once the initial direction is set, the system reverses its position when the prices retrace a certain percentage from a local maximum or minimum value. For example, if the system is buying, and the price rises to a maximum of 104, then retraces back to 100, the system will then close the long position and sell to establish a short position.
This is a reversal system and it is continuously in the market. To fully utilize its potential, it must be implemented on a market that allows traders to go long or short with equal ease. The futures, options, and Forex markets all possess this property.
This project implements the random walk algorithm to generate simulated price data. The algorithm is shown in the boxes below. A virtual coin is flipped each time the function is called. If heads, the price increases by 1c, if tails, the price decreases by 1c. This random data is then sent to the account manager and to the trading system. The trading system makes a decision and notifies the account manager if it wants to buy or sell. The account manager then outputs the trade log to the screen.
Simulated Trading Example
The screenshot at the beginning of this article shows a run of the algorithm through random walk data. The price starts at 100 and starts randomly moving up and down by 1c. Since 100 is going to be the fist price, the first decision will be to buy if prices rise by 4% to 104, or sell if prices fall by 4% to 96. In this example, the 96 price target was hit first and the system places a sell order. The system is now looking for new lows, if prices retrace from this new low by 4%, then the system closes the sell order and places a buy order. In this example, the system reverses position at 98.01 as shown, since the prices must have come down to 94.08 (4% below 98.01). In the hypothetical example shown, after adding the transactions shown in the screen, the system shows a profit of 4.92. This very simple system will put you on the right side of a sustained trend, but is susceptible to whipsaws if the percentage is not appropriate for the width of the oscillations between maximums and minimums. Perhaps use of the ATR or the ADX indicators could reduce the whipsaws.
Using the Code
This project has been arranged so that an unmodified trading system taken from the 4xlab.net project executes successfully. The supporting class framework has been implemented in a minimalistic way to allow this system to output trading decisions. Features such as parameter optimization and end of trading reports containing gains, loses and drawdown figures are not available in this project.
The FourPercentModel.cs file contains a complete implementation for a trading system. The fPercentageChange
class inherits from the ForexObject
. This allows the framework to receive and execute trading systems by treating them as their base class (ForexObject
).
The base class ForexObject
defines the following methods:
-
public override void Init(string pParameters)
This method initializes the object. This was chosen instead of the constructor to allow an existing object to be re-initialized and allow the object to remember multiple runs with different parameters for optimization purposes.
The system is initialized by sending it a parameter string
in which parameter:value pairs are separated by semicolons. If no parameters are sent, the object is responsible for selecting default values.
-
public override void ReceiveTick(sTick pTick)
The following two methods are used by the object to receive real time quote data. If the object wants to receive tick data, it will register itself with the framework as a tick listener. The private
method DecisionFunction
must be called either here, or in the ReceiveCandle
method.
The DecisionFunction
method is responsible for analyzing quote data and making buying or selling decisions executed through the Account
object. In this example, it can be seen that the decision function involves looking for new minimums or new maximums depending on the current trading direction. Once prices retrace by a specified percentage, the system reverses direction. Trades are entered by calling Framework.Account.EnterTrade(int pDirection)
. For buy orders, use +1 for direction, use -1 for sell orders. The Account
object returns its trading status via the Framework.Account.InTrade()
method. A positive value means a buy order is open; a negative value means a sell order is open. Zero is returned if there are no trades open.
-
public override void ReceiveCandle(sCandle pCandle, int pPeriod, string pCBTitle)
This method is used by the object to receive candle data. To accomplish this, the object must register itself with the framework as a candle listener.
-
public override bool Finished()
This method allows the object to be called several times by the framework. The object can choose to change quote data after the end of each run and compare runs internally. If so, the first time the object is finished receiving quote data and this method is called, the object switches quote data and returns false
. The second time around, this method will return true
.
-
public override string Title()
This method allows individual objects in a collection to be identified by a friendly name.
File: FourPercentModel.cs
using System;
namespace FourPercentShell
{
public class fPercentageChange : ForexObject
{
double iPercentage;
double iMin;
double iMax;
bool FirstTick;
sTick Tick;
double Spread;
public fPercentageChange()
{
}
public override void Init(string pParameters)
{
this.InitializeParameters(pParameters,"PERCENT:0.001;");
iPercentage = PParser.GetDouble("PERCENT",0);
Framework.TickServer.RegisterTickListener("System","*",this);
Framework.WriteGraphLine("InTrade,Margin,Tick,Min,MinTh,Max,MaxTh");
FirstTick = true;
}
public override void ReceiveTick(sTick pTick)
{
Spread = pTick.Ask - pTick.Bid;
Tick = pTick;
DecisionFunction();
}
public override void ReceiveCandle(sCandle pCandle, int pPeriod, string pCBTitle)
{
}
private void DecisionFunction()
{
if (FirstTick)
{
FirstTick = false;
iMin = Tick.Bid;
iMax = Tick.Bid;
}
else
{
if (Framework.Account.InTrade()==1)
{
if (Tick.Bid > iMax)
{
iMax = Tick.Bid;
}
if ((iMax-Tick.Bid) > iPercentage*iMax)
{
Framework.Account.ExitTrade();
Framework.Account.EnterTrade(-1);
iMin = Tick.Bid;
iMax = 0;
}
}
if (Framework.Account.InTrade()==-1)
{
if (Tick.Bid < iMin)
{
iMin = Tick.Bid;
}
if ((Tick.Bid-iMin) > iPercentage*iMin)
{
Framework.Account.ExitTrade();
Framework.Account.EnterTrade(1);
iMax = Tick.Bid;
iMin = 0;
}
}
if (Framework.Account.InTrade()==0)
{
if ((Tick.Bid-iMin) > iPercentage*iMin)
{
Framework.Account.EnterTrade(1);
iMax = Tick.Bid;
iMin = 0;
}
if ((iMax-Tick.Bid) > iPercentage*iMax)
{
Framework.Account.EnterTrade(-1);
iMin = Tick.Bid;
iMax = 0;
}
}
}
double logInTrade = Framework.Account.InTrade();
double logMargin = Framework.Account.GetAccount().C;
double MinTh = iMin + iMin*iPercentage;
double MaxTh = iMax - iMax*iPercentage;
Framework.WriteGraphLine(logInTrade+","+logMargin+","+Tick.Bid+","+
iMin+","+MinTh+","+iMax+","+MaxTh);
}
public override bool Finished()
{
bool returnv = true;
return returnv;
}
public override string Title()
{
return "% Trend Change";
}
}
}
The following file shows how the Tick Server generates simulated price data based on the random walk model. First, the price is incremented or decremented depending on a random number. Then a Tick
object is created with Bid
and Ask
prices. Afterwards, the tick is sent first to the account simulator and to the registered tick listener later. The code implemented here only allows for one registered tick listener in addition to the account simulator.
File: Framework.cs
public class oTickServer
{
...
public void GenerateTick()
{
int randomint = (int)(RNG.NextDouble()*1000);
if (randomint>500)
{
price++;
}
else
{
price--;
}
Tick = new sTick();
Tick.Bid = price;
Tick.Ask = Tick.Bid + 0.01;
Framework.Account.ReceiveTick(Tick);
tl.ReceiveTick(Tick);
}
...
}
Read More About It
History
- 17th August, 2006: Initial post