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

 

 

 

The Breakout Bulletin

The following article was originally published in the September 2007 issue of The Breakout Bulletin.
 

Automated System Development

In the July 2006 issue of Futures magazine (ref. 1), I read an interesting article by Mike Barna. He described a computer program he developed that automatically generates trading systems using a genetic programming algorithm. Very few details about how the algorithm works were provided, and the article was laced with technical jargon. However, the basic idea was clear. He was using a computer algorithm to construct trading rules and combine them in different ways in order to find the set of trading rules that worked best. It was optimization of the trading system development process, rather than optimization of trading systems per se. He followed that article with one the next month that provided an example of a trading system produced by this process (ref. 2).

When I accessed Mr. Barna’s web site, I was interested to find that he was getting ready to sell a commercial version of his software. My interest quickly faded when I learned he was planning to sell the program for $60,000 per copy. My first thought was “I wonder if I could do something like that myself”. So, this month, I’m presenting my own simplified version of automated system generation.

On his web site, it says that his product is the result of years of hard work. My version took about three days, so you can probably guess it’s not as complicated or sophisticated as Mr. Barna’s program. On the other hand, I’m not only disclosing how I did it, I’m giving you the code for free. As I suspect you’ll agree, it’s surprising how much one can actually accomplish with some fairly simple algorithms.

Price Pattern Rules

In principle, any type of indicator or trading logic could be included in the trading system generator I’ve developed. However, to keep things fairly simple for the purposes of this newsletter, I decided to restrict the rules of the generated trading systems to price patterns. Each entry rule of a generated trading system will have the following form:

            P1[N1]  Ineq P2[N2]

where P1 and P2 are prices (open, high, low, or close), N1 and N2 are the number of bars to look back (e.g., Close[2] is the close two bars ago), and Ineq is an inequality, either <= or >=. Examples of rules include the following:

            Close <= Close[2]

            Low[2] <= High[10]

            High[3] >= Close[4]

and so on. P1, P2, N1, N2, and Ineq are all variables to be determined by the system generation process.

N1 and N2 will be restricted to the range 0 – 20. Also, the number of rules, NRules, will be a variable with values ranging from one to 10. A trade entry will be triggered if all the rules are true. In that case, the entry will be taken at the open of the next bar. The trade direction will be set beforehand, so that the system will be generating systems that are either all long or all short trades. This is done because some possible sets of rules will have no obvious logical inverse, so it wouldn’t be possible to simply reverse the logic for long trades to get a short entry condition, or vice-versa. To obtain trading logic for both long and short trades, the system can be run twice, once for long trades and the second time for short trades.

Trades will be exited at the market after a fixed number of bars, NX, which will range from one and 20.

Finding the Rules

The key to this process is finding candidate trading systems. A system can consist of between one and 10 rules of the form shown above. We enter at market if all the rules are true, and we exit a certain number of bars later. If this were coded as a traditional TradeStation system, we’d have no practical way to optimize it because TradeStation uses a direct optimization method in which all possible combinations are considered. In this case, with a maximum of 10 rules, there are more than a trillion combinations, not even considering the parameter values.

A different method, such as the genetic algorithm that Mr. Barna used, is needed. However, rather than program a genetic algorithm for this article, I decided to use a “poor man’s” genetic algorithm. At each step of the optimization, the values for each variable (P1, P2, N1, N2, Ineq, NRules, and NX) will be chosen randomly. There will be multiple values of P1, P2, N1, N2, and Ineq depending on the number of rules, NRules.

Each step of the optimization generates a different trading system as the variables are randomly selected. If the performance results of the system meet the requirements entered by the user, the generated system will be written to a file in EasyLanguage code.

Putting it All Together

The code for the AutoSystemGen system is shown below.

{

  AutoSystemGen

  This system is designed to automatically generate profitable

  trading systems based on price patterns. When the system is

  optimized, it randomly generates price patterns and writes

  Easylanguage trading system code for each system that meets

  specified performance criteria. After the optimization is

  complete, the code for each successful system can be found

  in the text file specified in the function WriteSystems.

 

  Mike Bryant

  Breakout Futures

  www.BreakoutFutures.com

  mrb@BreakoutFutures.com

 

  Copyright 2007 Breakout Futures

 

 }

 Inputs: OptStep   (0),    { Optimization step; optimize this var }

         TradeDir  (1),    { +1 -> long trades; -1 -> short trades }

         reqNetProf(0),    { minimum required net profit }

         reqMaxDD  (0),    { required max drawdown limit }

         reqNTrades(0),    { required minimum number of trades }

         reqPerWins(0),    { required minimum percentage of wins }

         reqProfFac(0);    { required minimum profit factor }               

        

 Var:    NRules   (0),    { Number of rules/patterns to use }

         NBarExit (0),    { Number of bars to hold trades }

         ii       (0),    { Loop counter }

         ProfFac  (0),    { profit factor }

         FuncRet  (false),{ function return variable }

         EntNext  (false);{ logical flag for entering next bar }

        

 Array:  PriceL[10](0),   { 0 - 3 for O, H, L, C for left-hand side }

         PriceR[10](0),   { 0 - 3 for O, H, L, C for right-hand side }

         InEq[10]  (0),   { 0 - 1 for >=, <= }

         DaysL[10] (0),   { days back for left-hand price }

         DaysR[10] (0);   { days back for right-hand price }

 

 { Randomly select values for the variables that define the rules }

 If BarNumber = 1 then

    FuncRet = GetPatVars(PriceL, PriceR, InEq, DaysL, DaysR, NRules, NBarExit);

 

 { Evaluate the price patterns/rules to determine if a trade should be placed }

 EntNext = true;

 For ii = 0 to NRules - 1 Begin

     EntNext = EntNext and EvalPattern(ii, PriceL, PriceR, InEq, DaysL, DaysR);

 End;

 

 { Place the trade, either long or short }

 If EntNext then Begin

      If TradeDir > 0 then

       Buy next bar at market

    else if TradeDir < 0 then

       Sell short next bar at market;

 End;

 

 { Exit the open trade NBarExit bars after entry }

 If BarsSinceEntry = NBarExit then Begin

    If MarketPosition > 0 then

       Sell next bar at market

    else if MarketPosition < 0 then

       Buy to cover next bar at market;

 End;

 

 { Write out the trading system code if the system is successful }

 If AbsValue(GrossLoss) > 0 then

    ProfFac = GrossProfit/AbsValue(GrossLoss)

 else

      ProfFac = 100;

 

 If LastBarOnChart and NetProfit >= reqNetProf and

    AbsValue(MaxIDDrawDown) <= AbsValue(reqMaxDD) and

    TotalTrades >= reqNTrades and

    PercentProfit >= reqPerWins and

    ProfFac >= reqProfFac then

       FuncRet = WriteSystem(OptStep, TradeDir, PriceL, PriceR, InEq, DaysL, DaysR,

                             NRules, NBarExit, "C:\AutoSysGen-Output1.txt");

If you look at the system inputs, the first input is called OptStep. To run this system, you optimize it in TradeStation by varying this input from 1 to some large number, such as 10,000, in steps of 1. This will cause the system to generate, for example, 10,000 different trading systems. The ones that meet the specified performance criteria are written to the file shown as an input to the WriteSystem function (C:\AutoSysGen-Output1.txt). The performance criteria are specified via the system inputs (reqNetProfit, reqMaxDD, etc.).

Most of the hard work is performed by the functions that the system calls. The function GetPatVars randomly selects the values for the variables that determine the trading rules. To determine whether or not a trade entry will occur on the next bar, the price pattern rules are evaluated by the function EvalPattern. Finally, if the system meets the performance criteria, the corresponding EasyLanguage code is generated and written out to a text file by the function WriteSystem. The code for the AutoSystemGen system and all the functions is available on my download page.

Example

As an example, consider the 30-year treasury bond futures market (symbol @US.P in TradeStation 8.2). I optimized the AutoSystemGen system over the past 20 years of t-bond prices with the OptStep input optimized from 1 to 10000. This means the system evaluated 10,000 different trading systems. I ran the optimization twice, once for long trades and once for short trades. For performance criteria, I chose the following requirements: net profit of at least $30,000, worst-case drawdown no more than $7500, at least 200 trades, percent profitable of at least 50%, and profit factor of at least 1.2. On my dual core process computer running Vista, it took approximately 10 minutes to run each optimization (10,000 systems per optimization).

The systems generated by this process are shown below. These are the systems written to the file AutoSysGen-Output1.txt by the WriteSystem function. The first ones are the long-only systems, followed by a short-only system (the only one that met the performance criteria).

System 2332, @US.P, 9/17/2007 12:23:00, Long Trades

 Net Profit = 53562.50, Max DD = -7381.25, Num Trades = 250, Percent Wins = 56.80, Prof factor = 1.631

{ System code starts here... }

Var: EntNext (false);

EntNext = Open[2] >= Low[16] and

    Low[9] >= Low[3] and

    Close[14] <= Low[6] and

    High[1] >= Low[3];

If EntNext then

   Buy next bar at market;

If BarsSinceEntry = 2 then

   Sell next bar at market;

{ End system code }

 

System 5771, @US.P, 9/17/2007 12:27:00, Long Trades

 Net Profit = 42145.00, Max DD = -5733.75, Num Trades = 207, Percent Wins = 57.00, Prof factor = 1.631

{ System code starts here... }

Var: EntNext (false);

EntNext = High[7] >= Low[19] and

    Close[20] >= Close[5] and

    High[18] >= Low[2] and

    High[2] <= Open[6];

If EntNext then

   Buy next bar at market;

If BarsSinceEntry = 2 then

   Sell next bar at market;

{ End system code }

 

System 7622, @US.P, 9/17/2007 12:29:00, Long Trades

 Net Profit = 59348.75, Max DD = -7222.50, Num Trades = 208, Percent Wins = 60.58, Prof factor = 1.924

{ System code starts here... }

Var: EntNext (false);

EntNext = Low[2] <= High[9] and

    Open[11] >= Open[18] and

    Close[17] <= Low[18];

If EntNext then

   Buy next bar at market;

If BarsSinceEntry = 3 then

   Sell next bar at market;

{ End system code }

 

System 7718, @US.P, 9/17/2007 12:29:00, Long Trades

 Net Profit = 35526.25, Max DD = -6936.25, Num Trades = 292, Percent Wins = 56.85, Prof factor = 1.418

{ System code starts here... }

Var: EntNext (false);

EntNext = Close[3] >= High[19] and

    High[8] >= Low[9] and

    High[6] <= Open[10] and

    Low[16] <= High[3];

If EntNext then

   Buy next bar at market;

If BarsSinceEntry = 1 then

   Sell next bar at market;

{ End system code }

 

System 6160, @US.P, 9/17/2007 12:42:00, Short Trades

 Net Profit = 31277.50, Max DD = -6846.25, Num Trades = 369, Percent Wins = 51.76, Prof factor = 1.297

{ System code starts here... }

Var: EntNext (false);

EntNext = High[9] >= Low[6] and

    Close[15] >= High[8] and

    High[7] <= Low[20] and

    High[6] >= High[7];

If EntNext then

   Sell short next bar at market;

If BarsSinceEntry = 1 then

   Buy to cover next bar at market;

{ End system code }

The listing for each system includes the system number (corresponding to the OptStep input), market symbol, current date, and whether the system is long-only or short-only. The next line contains a few summary performance statistics to help in evaluating each system. Finally, the system code is shown. To evaluate the systems in TradeStation, the code between the two comment lines ({ …}) can be copied and pasted into a strategy in TradeStation, then run in the chart window.

For example, I copied the first system shown above (#2332) to TradeStation and saved it as a strategy. When I ran this on the @US.P chart, I obtained the following equity curve:

Figure 1. Long-only system for t-bonds, last 20 years, with $15 per trade deducted for trading costs, generated by system AutoSystemGen.

The last system in the output file is a for a short-only system (#6160). When saved in TradeStation as a strategy and applied to the same t-bond chart, the following equity curve is produced:

Figure 2. Short-only system for t-bonds, last 20 years, with $15 per trade deducted for trading costs, generated by system AutoSystemGen.

With a small amount of additional effort, the two systems could be combined into a single system that generates the long and short trades in the same system.

Comments

Automatically generating trading systems is an attractive idea. The traditional process of developing a trading system is extremely time consuming and involves systematically eliminating many ideas that simply don’t work. Also, we all have biases about how the markets work, and these biases affect how we develop trading systems. Hopefully, our biases guide us in the right direction, but they can also limit the possible systems we might come up with. Rather than starting with a market bias and a limited set of rules, an automatic system generator starts with a wide array of possible rules and finds what works without bias while quickly eliminating what doesn’t.

The downsides of automatic system generation are (1) it’s not a trivial matter to develop a good system generator, and (2) it’s an optimization process, with all the caveats of any trading system optimization. The AutoSystemGen system described here is a very simple system generator limited to price patterns with a simple exit rule. However, the process could be expanded to include other types of indicators and system rules. To make it suitable for day trading, an exit-on-close rule could be added to each generated system. To find better systems faster, the random process of assigning values to variables could be replaced with a genetic algorithm.

It’s notable that the random selection of values for variables is as effective as it is. A genetic algorithm starts with a randomly drawn selection of values, but then modifies the values to “evolve” other sets of values. Randomness is introduced periodically in genetic algorithms to shake things up and make sure enough variation is introduced into the search process. For the AutoSystemGen system, I’ve effectively taken a genetic algorithm and eliminated everything but the randomness. And the algorithm is still fairly effective.

The AutoSystemGen system is optimizing both the selection of rules and the parameter values of the system simultaneously. As with any type of system optimization, it’s important to test out-of-sample, preferably in real time. Real-time tracking of the generated systems prior to committing real money is the best way to be sure the systems are not over-fit to the market. A system that works well in real time following optimization has the best chance of holding up well in actual trading.

References

1. Mike Barna, Building Trading Systems the Automatic Way, Futures, July 2006, pp. 44-46.

2. Mike Barna, Going for the Gold -- Automatically, Futures, August 2006, pp. 44-47.

 

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

 

Mike Bryant

Breakout Futures