I have a binary classification model that predicts BUY (1) and SELL (-1) with an out of sample F1 score of 71% (precision is 65% and recall is 80%). The model's output is a probability of a BUY label occurring, which is then used in a bet sizing formula to bet cash (similar to the kelly criterion). The model was also trained taking commission and conservative slippage into account.

Now that I have the trained model, I am backtesting on out of sample data. However, it seems that the execution is losing money in the long term. The model is performing as expected - even on the backtest data, it still performs with an F1 score of 71%, but it seems commission and slippage are eroding gains.

Are there any tips / rules / literature one should follow when backtesting and simulating execution? I find it strange that the model performs so well on out of sample data yet still loses money - again, the model was trained with conservative estimates on slippage, higher than would ever occur in actual trading.

EDIT: As suggested in the comments, I will expand a bit more on what the model is doing. The data is simple OHLCV time-series with some feature engineering applied (e.g. CDF values for the distribution of returns, making the prices stationary through the backshift operator, normalizing data between 0 and 1). The method for labelling data is taken from Lopez's Advances in Financial Machine Learing, specifically the Triple Barrier Labelling method; first you calculate percentage returns from close price, then calculate a EWMA of standard deviation (std) of these returns - this is like an implied volatility. The upper barrier is a multiple of the EWMA of std of returns and similarly with the lower barrier, the 3rd vertical barrier is a fixed window of time later (say 60 minutes, or 5 days). At each time i, calculate the returns between i and i + j. If this return hits (is greater than or equal to) the upper barrier (upper EWMA of std of returns at i), it is labelled BUY (1) at time i. If the return hits the lower barrier (lower EWMA of std of returns at i), it is labelled SELL (-1) at time i. If the return has not hit either upper or lower barrier by the time the fixed window time has elapsed, it is labelled a SELL (-1) at time i.

The backtest data is distributed the same as the training data, as shown by a chi-square test and the fact that the model achieves similar F1 scores between test data and backtest data (both out of sample).

  • 2
    $\begingroup$ Could you expand a little on what the model is doing ? Generally a buy/sell signal isn’t enough since your profit depends not only on being right on the direction of the next move, but also on the magnitude of it (unless you trade binary options for example). Perhaps in out of sample data the model generally correctly calls buy/sell decisions but the wrong calls offset the correct ones due to the distribution of gains/losses. Are you taking this into account in the in-sample fitting phase and how confident are you that the out of sample data has a distribution similar to the in-sample one ? $\endgroup$ – Ivan Apr 20 at 20:39
  • 1
    $\begingroup$ Starting with simple potential issues, what is the loss function you used during training and validation? Technically speaking, you should train it using a criterion that is congruent with what you want to do. Formally, if you would use a mean-square optimal model as an input in a trading strategy, what you are doing is applying a nonlinear transformation and evaluating it using a different loss function. If you change the prediction, the target and the loss function, why would you expect it to work? I mean, everyone does it, but it's not internally consistent. $\endgroup$ – Stéphane Apr 20 at 20:40
  • $\begingroup$ Thank you for your comments - I have edited and expanded the question to try and explain the labels and model better. $\endgroup$ – PyRsquared Apr 21 at 11:26

Can I ask what type of backetest you are using? Is it an event-driven backtest or a simple for-loop backtest. Depending on whether you wrote your own or are using a library for it, try and analyse a sample of trades individually.

If you are only predicting a buy or sell, then you aren't really left with any wriggle room such as a hold option. So therefore each trade you are making means you are paying transaction fees even if the price movements don't warrant any significance. I am building a system too which has any profits being whittled away by fees. You have to find a way to somehow make the concept of fees become something endogenous to your ML model, because granted whilst 71% is impressive, trading fees are something exogenous to ML models.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.