Newsletter
Article Library
Videos
What's New
About Us
Site Map
Search

 

 

The Breakout Bulletin

The following article was originally published in the December 2003 issue of The Breakout Bulletin.
 

A Neural Network-Inspired Trading System

Trading systems range in complexity from the simple to the inscrutable. Joe Krutsinger (ref. 1) wrote about his "Buy Monday" system: Buy the S&P at the open on Monday; exit on the close. You can't get much simpler than that. Neural networks are closer to the other end of the spectrum. Most traders probably assume that the design of a neural network-based trading systems is best left to those with specialized expertise and expensive software. While that may be true, I decided to see what I could do with EasyLanguage and a few hours of effort. 

 

What are Neural Networks?

Neural networks are nonlinear models loosely based on the way the brain is structured as a network of interconnected neurons. Mathematically, they're a way to fit a nonlinear model to a set of data. The process of building a neural network is similar to -- but more complex than -- fitting a line through a set of points using linear regression. A neural network is often described graphically as a set of nodes connecting an input layer through a "hidden" layer of nodes to an output. The inputs are summed together using a set of weights that connect the nodes to produce the output. A simple, two-input neural network with a three-node hidden layer is shown below in Fig. 1.

Simple neural network

Figure 1. A simple neural network with two inputs and a single output.
 

The output, O, is produced from the following equations (also see ref. 2):

 

    H1 = tanh(w11 * I1 + w21 * I2)

    H2 = tanh(w12 * I1 + w22 * I2)

    H3 = tanh(w13 * I1 + w23 * I2)

    O = tanh(c1 * H1 + c2 * H2 + c3 * H3)

 

I1 and I2 are the two inputs. These could be anything that might have some predictive value for trading, such as momentum, stochastics, ADX, moving averages, etc. A complex network might have dozens of inputs. The weights are w12, w12, w13, w21, w22, w23, c1, c2, and c3. These will be determined by fitting the model ("training the network") to the data. The hyperbolic tangent function, tanh, returns a value in the range [-1, 1], so the output, O, will lie in this range. The inputs I1 and I2 are typically scaled so that they also lie in the range [-1, 1].

 

The process of establishing the neural network is called training. It involves iterating on the weights using known input-output data. For example, the output O might be interpreted as a bullish/bearish signal, with values near +1 bullish and values near -1 bearish. Bullish and bearish patterns on a price chart would be identified and the corresponding inputs I1 and I2 recorded. This would give us sets of training data: (I1-1, I2-1, O-1), (I1-2, I2-2, O-2), (I1-3, I2-3, O-3), etc. The model, as given by the equations, would be applied to these examples, and the weights adjusted until the network correctly identified the bullish and bearish patterns. The technique traditionally used to adjust the weights in an iterative manner is called back-propagation.

 

Once the network is trained, it can be tested out-of-sample to make sure it is not over-fit to the training data. Out-of-sample testing simply means the network is tested on data that was not used during the training. If it performs well on the out-of-sample data, it can be deemed a successful model.

 

As you might guess, we are not going to try to replicate all these steps precisely in our EasyLanguage trading system. For one thing, TradeStation doesn't provide a back-propagation algorithm, so we will have to rely on its built-in optimization feature by making the weights for the network inputs to our system. That way, we can optimize on the weights using the system parameter optimization feature of TradeStation. Secondly, there's no easy way in TradeStation to provide training data sets to the model. Instead, we'll train the network directly on the price data by incorporating the network into a trading system and optimizing the weights of the network as part of the trading system. This approach is not ideal from an optimization standpoint, but is more direct and is consistent with the limitations of TradeStation.

 

For our trading system, we'll take the inputs to the neural network as follows:

 

   I1 = (C - C[2])/33

   I2 = (C - C[10])/64

 

These are the two and 10-day momentum, normalized to keep them in the range [-1, 1]. The output will be interpreted as a bullish/bearish signal, such that

    O >= 0.5 --> bullish

    O <= -0.5 --> bearish

 

On a bullish signal, we'll place an order to buy at the prior day's high on a stop. On a bearish signal, we'll place an order to sell at the prior day's low on a stop. For simplicity, all trades will be exited after two days, and no protective stop will be used. The complete system code is shown below in Fig. 2.

 

{
  NN Inspired
  This system uses a neural network-like function to trigger entry. The "weights" of
  the network are determined by optimization within TradeStation.

 

  Mike Bryant
  Breakout Futures
  www.BreakoutFutures.com

  mrb@BreakoutFutures.com

  Copyright 2003 Breakout Futures

 }
 Inputs: w11     (0),    { weights }
         w12     (0),
         w13     (0),
         w21     (0),
         w22     (0),
         w23     (0),
         c1      (0),
         c2      (0),
         c3      (0);

 

 Var:    I1      (0),    { input 1 }
         I2      (0),    { input 2 }
         H1      (0),    { hidden node 1 }
         H2      (0),    { hidden node 2 }
         H3      (0),    { hidden node 3 }
         NNOut   (0);    { function output }

 

 { Define inputs: 2 and 10-day momentum, scaled }
 I1 = (C - C[2])/33;
 I2 = (C - C[10])/64;

 

 { Define "neural net" function }
 H1 = tanh(w11*I1 + w21*I2, 50);
 H2 = tanh(w12*I1 + w22*I2, 50);
 H3 = tanh(w13*I1 + w23*I2, 50);

 NNOut = tanh(c1*H1 + c2*H2 + c3*H3, 50);


 {Print("date: ", date:8:0, " NN Output: ", NNOut:6:3);}

 

 { Place trades based on function output }
 If NNOut >= 0.5 then
    Buy next bar at High stop;

 If NNOut <= -0.5 then
    Sell short next bar at low stop;

 If BarsSinceEntry = 2 then Begin
    Sell this bar on close;
    Buy to cover this bar on close;
 End;

 

Fig. 2. EasyLanguage code for neural network-inspired system, "NN Inspired".

 

Our "training" period will be on daily data for the E-mini S&P, from 9/1997 to 12/31/1999. $75 will be deducted from each trade for slippage and commissions. We'll optimize the nine network weights over this data, then test the system out-of-sample for one year, from 1/1/2000 to 12/31/2000. Because of the large number of inputs, we'll limit the parameter values to -1, 0, +1. Every combination of weights with the values -1, 0, +1 will be tested by the optimization process. This gives us 3 to the 9th power or 19683 optimization trials. On my 2.2 GHz computer, this took approximately 1.5 hours in TradeStation 7.1. 

 

The resulting optimal weights were:

 

   w11 = -1

   w12 = 0

   w13 = 1

   w21 = -1

   w22 = 1

   w23 = -1

   c1 = 1

   c2 = -1

   c3 = 1

 

Here are the optimized results:

 

   Net Profit: $17,700

   Profit Factor: 1.47

   No. Trades: 99

   % Profitable: 52%

   Ave. Trade: $179

   Max DD: -$6,813

 

I then tested the system out-of-sample over the year following the optimization period. Over this period (1/1/00 to 12/31/00), the system produced the following results:

 

   Net Profit: $12,863

   Profit Factor: 1.56

   No. Trades: 51

   % Profitable: 55%

   Ave. Trade: $252

   Max DD: -$10,325

 

The fact that the system traded profitably on data not used in the optimization is a good sign. However, using other optimization periods, the walk-forward (out-of-sample) results did not always hold up. In particular, the last two years or so seem to be fundamentally different than the prior five or six years. While it's possible to optimize successfully up through, say, June 2003, the best results are achieved with relatively fewer trades than in prior years. That doesn't leave enough data from June forward to test the system out-of-sample.

 

Finding a good balance between the optimization and evaluation periods is always a challenge. There needs to be enough data in the optimization period to avoid over-fitting the system, but you have to leave enough data to properly evaluate the system. If the optimization period ends too far back, the market dynamics in the evaluation period may be markedly different from the optimization period, rendering the optimized results useless going forward. One way to address this problem is to shorten the time scale. Instead of developing a system for daily bars, focus on intraday data. That makes it possible to have more data over a shorter time period, where the market dynamics may be more stable. It would be interesting here to apply our system to hourly bars. The system could be modified slightly to buy/sell in the morning and exit on the close. The resulting increase in the number of trades may make it possible to include both optimization and evaluation periods within a shorter time frame, so that the optimized results would be more valid going forward.

 

Despite the inherent complexity of neural networks, hopefully I've demonstrated that some of the basic features of neural networks can be incorporated into even a simple trading system. By using the tanh function and the basic structure of a neural network, we've essentially added a nonlinear indicator to a simple trading system. One of the primary limitations was that the number of inputs (i.e., the network weights) was so large that we had to restrict our optimization to the values -1, 0, 1. However, this process could be viewed as a screening step for the weights. There's nothing preventing us from refining the optimization during a second pass. For example, if the optimal weight from the first pass was +1, we could go back and try values between 0.5 and 1.5. Similarly, for optimal values of -1, we could try values between -0.5 and -1.5 on a second pass. We might also try reducing the number of nodes in the hidden layer. This would reduce the number of weights. Different or additional inputs could also be tried.

 

The primary benefit of a neural network approach is the nonlinear structure of the functions composing the network. Nonlinear functions are better suited to the complexity of market data than linear functions. The biggest problem is probably the tendency to over-fit the network to the training data. If you decide to pursue this approach further, don't forget to thoroughly test any system out-of-sample, if not in real-time tracking, before committing real money.

 

That's all for now. Good luck with your trading.

 

References:

  1. Joe Krutsinger, The Trading Systems Toolkit, Probus Publishing Co., Chicago, 1994.

  2. Guido J. Deboeck, Trading on the Edge, John Wiley & Sons, Inc., New York, 1994.

 

Mike Bryant

Breakout Futures