← All Articles

I created an algorithm that improves any investment strategy. Here’s how it works.

A guide on how to use AI to create and optimize any trading strategy

5 min read

When I was a graduate student at Carnegie Mellon, I learned about a rare and powerful algorithm – genetic optimization.

The genetic algorithm is unlike any AI algorithm. When I saw how we used it to transform a chaotic jumble of random strings into the exact target phrase ‘To be or not to be.’ — all by simulating natural selection — I was blown away. I thought about how I can apply this to real-world problems.

As an avid investor, my mind immediately went to how we can apply this same algorithm to optimize investing strategies.

I coded the algorithm with resounding success, creating a tool capable of theoretically improving any investment strategy. Here’s how it works.

What is a Genetic Algorithm?

A genetic algorithm is a biologically-inspired AI algorithm that operates differently than ordinary Machine Learning (ML) algorithms.

Traditional optimization algorithms require gradients. These gradients basically tell us how we ought to move the parameters of the thing we’re trying to improve in order to get closer to our final goal.

For example, with large language models, these gradients tell us how to adjust the weights and biases in order to better predict the next token in a sequence.

Genetic algorithms, however, do not use gradients.

They work by using a combination of operators that mimic real-world biological phenomenon. For optimizing a trading strategy, they are used to continuously find the best set of trading strategies without calculating gradients, which are impossible for most set of complex problems.

In the context of trading strategy optimization, these operators are:

  • Initialization: Creates the initial population of random investment strategies, starting from a specific strategy, and making random changes to it.
  • Selection: Picks the best performing strategies from the population, similar to “survival of the fittest” in nature. Better performing strategies have a higher chance of being selected.
  • Crossover or recombination: Takes two successful strategies and combines their features to create new “offspring” strategies. Like genetic recombination in biology, this creates new variations that might perform even better than their “parents.”
  • Mutation: Randomly modifies small parts of our strategies to maintain diversity and explore new possibilities. This prevents the algorithm from getting stuck in local optima.
  • Evaluation: Tests each strategy against historical data or simulated scenarios to measure its performance. Better performing strategies get higher “fitness scores.”
  • Replacement: Removes poorly performing strategies and replaces them with new offspring, maintaining a constant population size while improving overall quality over generations.

Knowing that these rare algorithms can optimize any function, I sought to implement it into my trading platform.

And now everybody in the world has access to a trading strategy optimization algorithm. Here’s how it works.

Optimizing a trading strategy

I created a platform that is capable of optimizing any investment strategy using genetic algorithms. I’m going to show how I’m using the OpenAI o1 model and genetic algorithms to create the best simple moving average crossover strategy.

1. Creating an initial trading strategy with AI

First, we’ll go to nexustrade.io/chat, and switch the model to OpenAI’s o1 model. We’ll then type the following into the AI chat.

Create the best Simple Moving Average Crossover strategy for META stock

We need at least 1 buy strategy and at least 2 sell strategies, including stop losses and/or take profits

Unlike other large language model, the O1 model “thinks” about the question. In theory, this thinking helps the model create the best trading strategy that it possibly can.

After around 3 minutes, the model comes up with the following strategy.

The results of the O1 model

If you want to see the full conversation for yourself, check out this link.

We can see that the model created a profitable investing strategy. Let’s zoom in on it and see the exact trading rules.

The SMA trading strategy for META

While this strategy is already good, we’re gonna make it better with genetic optimization. Let’s create a new portfolio and move on to step 2.

2. Define our optimization parameters

Our new META Portfolio

After creating a portfolio, we’ll be automatically navigated to the portfolio's dashboard. On the dashboard, we can see a big OPTIMIZE button.

We’ll click that button, and once we do, a modal will pop-up.

The optimization configuration for this portfolio

The platform has many different fields we can use to optimize our portfolio. We can click the “?” next to the field, and it’ll briefly explain its purpose.

For an in-depth guide on what these parameters do, check out the following article.

For now, we’ll leave most of the parameters to their default value, but change the following:

  • Increase the population size from 25 to 30
  • Increase the number of generations from 5 to 50
  • Increase the number of windows from 3 to 6
  • Increase the mutation from 0.1 to 0.3
  • Modify the first “fitness function” to percentChange.
  • Change the start date to 01/04/2017
The updated optimization configuration

We’ll then click submit. This starts the optimization process.

3. Optimize the portfolio and understand what’s happening

The optimization process in action

The optimization process is an iterative algorithm that slowly improves the performance of the portfolio across time. In this example, the two things that will be improved, called the “fitness functions", are the final percent change and the average drawdown.

The percent change is simply the ratio between the final portfolio value and the initial portfolio value. Higher values are preferred.

In contrast, the average drawdown is the average distance from the highest point in the graph to the subsequent lowest point. Lower values are better because it means the portfolio didn’t experience many large drops while being deploying

By optimizing these two objectives, we’ll create an entire population of portfolios. Some will have a high percent change but a relatively higher drawdown. Others will have a low percent change, but near-0 drawdown.

By generating an entire population, we can look through all of the different options, and pick the best portfolio with a trade-off between the two “fitness functions”.

Larger windows take longer to optimize than shorter windows. Because we're optimizing across 7 years, the process will take longer than if we were to optimize over 1 to 2. So, we must wait.

Twenty minutes later, we receive an email notification that the optimization process is complete. Let’s see our results.

4. Explore our final population of optimized portfolios

The final optimization results

After a short amount of time, we’ve successfully generated a population of trading strategies, each better than the initial portfolio.

On average, here’s how our portfolio changed from generation 1 to generation 50 in the training set.

  • Percent Change: 11.65% => 29.49%
  • Sharpe Ratio : -0.17 => 0.33
  • Sortino Ratio: -0.18 => 0.24
  • Max Drawdown: 9.41% => 13.49%
  • Average Drawdown: 2.32% => 2.15%

As we can see, the average performance increased for nearly every metric. the percent change, risk-adjusted returns, and average drawdown were also significantly better towards the end.

This boost in performance isn’t just limited to the training set. The validation set, or the set of data that is used to evaluate the model's performance on unseen data during training, also improved significantly.

The validation set performance

From generation 1 to generation 50, the validation set performance had the following improvements:

  • Percent Change: 44.44% => 72.41%
  • Sharpe Ratio : -0.35 => 0.39
  • Sortino Ratio: -0.06 => 0.29
  • Max Drawdown: 21.84% => 24.88%
  • Average Drawdown: 5.19% => 2.75%

Just like in the training set, the validation set performance improved significantly for every metric except the maximum drawdown. Objectively, we’ve created a population of portfolios that outperform the original portfolio, even when tested on unseen data.

We can now browse the different portfolios that we created. Some of them have a drawdown of 0, because they didn’t make a single trade. This is the “best” portfolio if we consider max drawdown as the metric that we want to improve (because we can’t have a better drawdown than 0).

An example of a portfolio with a drawdown of 0

Other portfolios have an insanely high percent return, with a higher drawdown. Here is one such example:

A portfolio with a high percent return

With these amazing returns, you would think that we successfully cracked the stock market, right?

Unfortunately, it’s not THAT easy.

A deeper look on our generated portfolios

With these above results, we would naturally think that we cracked the code for algorithmic trading.

Unfortunately, it’s not that easy. If we zoom in on our above strategy, here’s what we see.

The backtest performance of our strategy

Within the past year, our portfolio didn’t make a single trade at all! The S&P500 increased more than 20% in the year, and our portfolio was completely flat!

This is true for all of our optimized portfolios. This happens because stock market returns are nonstationary, meaning the distribution of returns change over time.

In other words, returns for stock returns for one year might change for the next.

And, even though the performance of our strategy is satisfactory when we zoom out an additional year, the reality is that this simply isn’t good enough for real-world trading.

The backtest performance of our strategy for the past two years

Fortunately, not all hope is lost. There are a number of things we can do to solve our problem.

Solving this problems

We just learned that optimizing our trading strategy is more complex than clicking a single button. However, there are still a number of things we can do.

For one, we can tune our hyperparameters. It might be the case that optimizing for the past year is better than optimizing for the past few years.

Changing our optimization range

Additionally, we can make modifications to our indicators themselves.

For example, we can update the range of possible values for the optimization. By updating the left SMA to be between 20 and 40 and the right SMA to be between 200 to 400, we’ll force the left indicator to always be less than the right indicator.

Updating the min/max value for the left SMA indicator

This may allow the optimization process to trade more frequently.

So, while the optimization process isn’t perfect, there are ways to improve it, all within the NexusTrade app. The curious investor can dive deeper into it, and see if they can discover the secrets to automated trading strategy optimization.

Conclusion

Genetic algorithms are a unique and powerful optimization algorithm, capable of optimizing nearly anything. Unlike traditional optimization algorithms, they don’t require gradients, and can be used to optimize complex things such as trading strategies.

And thus, inspired by my CMU class project, I applied genetic optimization to the stock market. While the results initially looked promising, both on the training set and validation set, we can see that the portfolios didn’t make a single trade for the year of 2024.

While genetic algorithms show immense promise for optimizing trading strategies, their application requires careful fine-tuning and real-world adjustments. With NexusTrade, retail investors have unprecedented access to these advanced tools, empowering them to bridge the gap between theory and practice and unlock new possibilities in algorithmic trading.

Don’t believe me? Try it for yourself. Getting started is free.

Discussion

Sign in or create a free account to join the discussion.

No comments yet.