Quant500 Academy

1. Optimization, the heart of machine learning

Level 10: Machine Learning Applied to Trading

Machine learning has been attracting interest since the nineteen-sixties, but plenty of people are afraid to get started, mostly because it looks as though it demands a deep command of linear algebra and calculus. The aim of this level is to take that fear away and show you that, with relatively little effort, you can build practical models that solve real problems. That said, let us be clear from the outset rather than sell smoke: building genuinely accurate models is still a complex and demanding job.

Machine learning rests on three pillars:

Of the three, one deserves a sentence of its own: optimization is at the heart of almost every machine learning algorithm. When we say that a model learns, what is actually happening is that a numerical procedure is searching for the parameter values that minimize an error function. In regression we minimize the sum of squared errors; in classification, the cross-entropy; in Markowitz-style portfolio optimization, we minimize variance subject to a target return. The model and the objective function change, but the conceptual machinery is identical: define an error, work out which direction makes it decrease, and move that way.

That moving is gradient descent: you compute the derivative of the error function with respect to each parameter and take a small step in the direction opposite to the gradient. We are going to write it out by hand, with no ML libraries at all, on a minimal financial problem: predicting tomorrow's return from today's return.

import numpy as np

rng = np.random.default_rng(42)

# Synthetic series of daily returns with a pinch of autocorrelation
r_today = rng.normal(0, 0.01, 2000)
r_tomorrow = 0.15 * r_today + rng.normal(0, 0.01, 2000)

# We rescale the input variable: optimization is VERY sensitive to scale
x = (r_today - r_today.mean()) / r_today.std()
y = r_tomorrow

w, b = 0.0, 0.0      # parameters to be learned
lr = 0.1             # learning rate

for epoch in range(500):
    pred = w * x + b
    error = pred - y
    grad_w = 2 * np.mean(error * x)
    grad_b = 2 * np.mean(error)
    w -= lr * grad_w
    b -= lr * grad_b
    if epoch % 100 == 0:
        print(epoch, 'MSE =', float(np.mean(error ** 2)))

print('learned w:', round(w, 6), '| learned b:', round(b, 8))

Pay attention to the scaling detail. If you train directly on returns whose standard deviation is 0.01, the curvature of the error function with respect to w is minuscule and the algorithm takes an eternity to move, while b converges almost immediately. That is not a failure of the model: it is a failure of the optimization. Problems of that kind, invisible if all you ever do is call a library function, are precisely why it is worth understanding what happens underneath.

The rest of Quant500

What you are learning, applied to the index every day:

The model portfolio, weekly in your inbox

Every Saturday, its week in one minute: how it went, the best and the worst, and which insiders bought with their own money. Plus, the day the model is rebuilt, which stocks come in and which go out. A simulation, not advice. At most one email a week, no ads, no account; one-click unsubscribe. Made by one person: Pol Gracia.

A model portfolio with simulated results, not a personalized recommendation. Your email is used for this only: privacy.

Behind the Academy and the rest of Quant500 there is one person: Pol Gracia Serrahima.