Machine Learning Trading System Development

A recording of a webinar I presented in September 2015 describing the design, testing, and validation of trading systems using machine learning methods.

The video has been posted to YouTube.  Click the image to begin.

Comments are welcome and discussion is encouraged.


This Post Has 4 Comments

  1. Hello,

    I’d like initiate a discussion on trading system development using machine learning approach. After reading the latest QTA book from Howard I started learning process of ML methods and Python programming language.
    TSDP systems and ML systems are hard to compare but, I struggle to develop ML strategy which works better than any of my TSDP systems.
    What constitutes good ML strategy?


    1. Hi Richard —

      Changing from trading system development platform to machine learning might involve several changes in perspective.

      In machine learning:

      If you have not already switched from impulse signals to state signals, do it now. For machine learning, state signals are universal. Every bar / data point has a target — it is the position for one bar ahead.

      Before getting too deeply into model creation, decide how you will trade a successful model. When to compute signals, when to make trades, whether to go close to close, or use profit targets, etc. Set up your data gathering, transformations, and prediction from the point in time where you will be performing all those tasks.

      As you analyze the data, identify the data bars where you want to be taking trades and those where you do not. They will help define your target.

      All data points must be self-contained and independent. So, no overlapping trades, no references to earlier data values.

      Management and measurement are coincident. They should have been all along, but it becomes more important with machine learning / pattern recognition. No subjective decisions outside the rules of the model — such as exiting from trades before the rules signal an exit. Each data point is probably a daily bar. Each bar (no matter what its length) has a target, the target values computed by the model may change from day to day, implying the trader must be willing to change positions every day to stay in synch with the model.

      The developer / trader has some meta-choices to make. Whether to use a classification model to forecast direction, such as beLong or beFlat. Or use a regression model to forecast change, such as expect the price tomorrow to be 0.25% higher than the close today. If you use a regression model, what threshold will trigger an order? That is, when to go long, when to stay flat.

      There can be no change in signal without some change in some indicator. If the only rule is beLong = price > MA(price,200), there will be long sequences of either True or False. You need indicators that change as often as the signal change you desire.

      When the forecast is one day ahead (one bar ahead), there is very little difference between price-based indicators. Try each of the short term indicators based on price — RSI with a short lookback, detrended price oscillator, position-in-range such as stochastic, z-score. Pick whichever works best for your application, or your favorite. Using more than one is probably redundant.

      Try adding inter-market data series. If you are trading a common stock or stock-based ETF, add interest rates, currency rate, commodities.

      Try adding broad market diffusion indexes — number up / (number up + number down), up volume / (up volume + down volume), new highs / (new highs + new lows), etc. Be careful not to introduce membership bias.

      Normalize or standardize as necessary.

      Be aware that train / test split is used to guide the training of the model. An additional set of data may be required for out-of-sample testing / validation.

      Trading system development platform systems are decision trees. The splits are orthogonal to the axes — such as (pseudocode) Buy = RSI < 20 and average > 200. You should be able to develop a decision tree model that equals your TSDP model. When that works, relax the orthogonal requirement by trying support vector machine models. Or use ensemble methods with a large number of incomplete decision trees.


      1. Hello Howard,

        Thank you very much for your guidance. This is fantastic summary of the ML approach. You have filled out some “blanks” I had after reading QTA book.
        I expected ML to improve on the traditional TSDP. In the book you use RSI2 as an example which generates certain in-sample and out-of-sample results which indicate that RSI2 strategy has positive expectancy.
        I was trying to prove that ML can improve on TSDP results by feeding RSI2 feature dataset to ML classifier (using Python code examples from Chapter 8).

        In my experience RSI2 feature on it own is not sufficient for ML classifier to find the pattern which yields better results than TSDP approach. Maybe that is why you mention in the book that – “Within a few hours of copying it into your own Python environment, changing the primary data series, adding predictor variables, and modifying parameters, you will have different and probably much better results. ”

        Your statement, seems to suggest that, in some cases primary data series is too noisy or not big/long enough for ML classifier to detect the pattern.
        As you stated in the book, ML algorithm will not find the pattern or improve on TSDP strategy which does not have an “edge”.
        Is this the correct statement? Is this the experience of any other QTA book readers?

        Kind Regards

        1. Hi Richard —

          Recall that a traditional trading system based on a calculated indicator such as RSI2 is an implementation of a decision tree.

          In a pseudocode, the program might be:

          RSIValue = RSI ( C, 2);
          Buy = Cross (20, RSIValue);
          Sell = Cross ( RSIValue, 50);

          Buy and Sell are impulse signals, true on those few single bars where the RSI value crosses the parameter values, false on all other bars. Without loss of generality, we can convert from impulse signals to state signals.

          Again in pseudocode:
          beLong = flip (Buy, Sell);
          beFlat = flip (Sell, Buy);

          The “signal space” is now divided into two areas. beLong is set to True at the first cross of RSIValue down through the 20 level, and it remains True for the duration of the trade until the RSIValue rises up through the 50 level. The decision tree process examines each bar in sequence. If beLong is True, accumulate the gain from that bar’s close to the next bar’s close; if beLong is False, beFlat will be True (the signal is binary), so the gain for the bar ahead is zero — the position is flat.

          Whether the development platform is traditional (AmiBroker) or machine learning (Python / scikit-learn), the model is a decision tree. The space is divided along lines that are perpendicular to the axes. All of the following systems are equivalent, and you should obtain the same results from them all when they are run over the same data and same time periods.

          1. AmiBroker using impulse signals.
          2. AmiBroker using state signals.
          3. Python scikit-learn decision tree using state signals.

          To improve on the system results, independent of development platform, refine:
          1. The test period. The system must be stationary over the period of development and follow-on testing.
          2. The critical levels — RSI lookback of 2, decision partitions at RSIValues of 20 and 50.

          To your specific question about whether the primary data series might not be long enough, the criteria are related to stationarity rather than number of bars. It would be ideal if the system worked (generated enough profit to compensate for the risk) over all time periods, but that is unlikely. During those periods when it does not work, there will be drawdowns. Tests will give estimates of the length and duration of the drawdowns and the developer / trader must decide what level of drawdown is within that to be expected periodically from the system and compare that with the level that can be tolerated by the trader. Be willing to take the system offline when drawdown exceeds tolerance. Even better, adjust position size trade-by-trade to take advantage of periods of good performance and withhold funds during drawdowns.

          We are all searching for good indicators that produce good signals. Good, in this case, means there is a clear functional relationship between the value of the indicator and the value of the target. Good is when the signal divides the space neatly so that there are few losing bars for the section when beLong is True. The RSI indicator is noisy — the relationship is very fuzzy. Plot RSIValue on the horizontal axis versus gain for the bar ahead on the vertical axis. We would like a line, we see a cloud. Refining the system requires some way to further divide the space to remove losing days. Adding more data series — intermarket series — is a good way to do that. That adds a dimension to the plot, so it is no longer easily viewed on a screen or paper, and it increases the likelihood of over-fitting the model to the data, so follow good test / validation practices.


Leave a Reply