Part III · Models · Chapter 3C
Fitting a model
Closed-form solutions and gradient descent
Chapter 3B wrote down the AR(1) model and its two parameters. This chapter finds their values from data, either exactly with a formula or step by step with gradient descent, the method under every modern machine learning (ML) library. It ends with regularization, which builds Chapter 3A's preference for simple models into the fit itself.
- The AR(1) model, its weight and its bias (Chapter 3B).
- Covariance and correlation as computed from a sample (Chapter 1F).
- The bias-variance tradeoff and overfitting (Chapter 3A).
Fitting a model means choosing its parameters so that its predictions miss the data by as little as possible. For a straight-line model a formula gives the answer at once. For large models no formula is practical, so the computer starts somewhere, measures which way the error falls most steeply, takes a small step that way and repeats. The size of that step is the setting that most often goes wrong.
1 · The loss: what fitting minimizes
Once a model is specified, you need to fit its parameters: find the weight and bias, in the AR(1) case, that minimize the prediction error on training data. The error is measured by a loss function, most often the mean squared error of Chapter 3A:
Each term is the squared gap between a return and its prediction, averaged over pairs of previous return and return.
Step 1: the data. Take five hypothetical daily returns, in percent, of 0.6, −1.2, 0.4, 0.2 and 0.6, which make four pairs of previous return and return: (0.6, −1.2), (−1.2, 0.4), (0.4, 0.2) and (0.2, 0.6).
Step 2: the loss at . With as well, every prediction is zero, so the loss is the mean of the squared returns: .
Step 3: the loss at . The gaps are −0.9, −0.2, 0.4 and 0.7, whose squares average , so the weight of −0.5 fits better.
With , expanding the squares for these four pairs gives the whole loss curve at once:
2 · The slope of the loss
To find the best weight you need the slope of the loss curve. The derivative of with respect to , written , is the slope of the curve at a point: how fast changes per unit change in , for a very small change. Three rules cover everything in this chapter: has derivative , has derivative and a constant has derivative zero. Applied to (3C.2), they give
To check it with numbers, note that at the formula gives a slope of 0.5. Moving from to raises the loss from 0.5 to 0.50505, a rise of 0.00505 for a step of 0.01, which is 0.505 per unit.
At the bottom of the curve the slope is zero, so the best weight solves , which gives . With two parameters, the partial derivative is the slope in the direction with held fixed, while is the slope in the direction. Together they form the gradient, which points in the direction in which the loss rises most steeply.
3 · The closed form: ordinary least squares
For linear regression with squared-error loss there is a one-line analytical solution, ordinary least squares (OLS). Stack the data in a design matrix , whose rows are observations and whose columns are features, with a column of ones for the bias. The targets go in a vector . The OLS estimator of the vector of weights is
Here is the transpose of , its rows turned into columns, while is the matrix inverse, the matrix version of dividing. The result is exact and fast for small datasets, which is why it is used inside scikit-learn's LinearRegression, R's lm() and basically every statistical package's linear regression function.
For the AR(1) case with one feature, (3C.4) collapses to a particularly clean form, with bars for sample means:
That is two numbers, with no iteration and no learning rate: compute the sample covariance and the sample variance, and divide.
Where the AR(1) formulas come from
Step 1: the slope in . Write and . The derivative of a square is times the derivative of . Since the derivative of with respect to is −1, the slope in is
Step 2: set it to zero. Dividing the sum by turns it into means, so , which gives , the second line of (3C.5).
Step 3: the slope in . The derivative of with respect to is , so
Step 4: substitute and solve. Put in , so each gap becomes . Setting the slope to zero leaves , where the leading has become because deviations from a mean sum to zero. Dividing both sides by turns them into the sample covariance and variance. So is their ratio, the first line of (3C.5).
Applied to the five returns, the means of the previous returns and of the returns are both zero. The covariance is and the variance of the previous returns is . So and , the minimum found from the slope.
Where the closed form breaks
The flaw of OLS is that it requires inverting a matrix of size features × features. While for a model with 5 features and 1,000 observations this is trivial, for a model with 50,000 features and 100 million observations, typical of large-scale machine learning, the matrix inversion becomes infeasible. You cannot load all of the data into memory at once: 100 million rows of 50,000 numbers is numbers, 40 terabytes at 8 bytes each. And inversion is in the feature count, where here counts features: its work grows with the cube of their number. Five features cost on the order of 125 operations, while 50,000 cost on the order of .
4 · Gradient descent
Gradient descent is iterative, repeating four actions at each step:
- Compute the current loss on the training data, or on a mini-batch of it.
- Compute the gradient of the loss with respect to each parameter.
- Take a small step in the direction opposite to the gradient, downhill on the loss surface.
- Repeat until the loss stops falling.
The update rule for a parameter at step is
where (eta) is the learning rate, the step size. Too large a learning rate and the optimizer overshoots, oscillates and may diverge entirely, while too small a rate makes convergence painfully slow. Tuning is part of the art of optimization: getting it right is most of the challenge in training modern machine learning models.
On the five returns, starting at with , the slope is 0.5, so the first step moves to . At the new slope of 0.25 the next step reaches −0.375, halving the remaining distance to −0.5 as every step does.
That halving is no accident, and the figure below shows why. It runs gradient descent on the loss , whose minimum is at and whose slope is . Subtract 0.5 from both sides of (3C.8) to see what one step does to the distance from the minimum:
Every step multiplies the distance by , so starting from , a distance of 1.5 from the minimum, the distance after steps is . Five cases follow from the size of :
- Below 0.5, the factor lies between 0 and 1, so the steps shrink and stay on one side.
- At exactly 0.5, the factor is zero and the first step lands on the minimum.
- Between 0.5 and 1, the factor lies between −1 and 0, so each step overshoots and the path zigzags inward.
- At exactly 1, the factor is −1, so the path bounces between −1 and 2 forever.
- Above 1, the factor is below −1, so each overshoot is bigger than the last and the path diverges.
On the five returns the slope, , is the distance from −0.5 itself rather than twice it. There each step multiplies the distance by , which at is the halving you saw.
The figure has two sliders, the learning rate from 0.01 to 1.2 (starting at 0.05) and the number of steps from 1 to 30 (starting at 15). The readouts give the start, where the last step lands and its distance to the optimum. Try learning rates of 0.01, 0.5, 0.9, 1.0 and 1.1 in turn.
At the starting settings the last step lands at , a distance of 0.3088, which is . At 0.01 the path crawls to −0.608 in 15 steps. At 0.9 it zigzags to 0.553, the same 0.0528 from the optimum that 0.1 reaches from the other side, because both multiply the distance by 0.8 in size. At 1.0 it ends at 2.000, while at 1.1 it is at 23.6, off the chart.
Mini-batches: stochastic gradient descent
The crucial property of gradient descent is that it does not require loading all the data at once. You can compute the gradient on a mini-batch, a small random subset of the training data, and take a step. The mini-batch gradient is a noisy but unbiased estimate of the full one, so the steps wander but head downhill on average. This is stochastic gradient descent (SGD), which scales to arbitrarily large datasets. Modern variants such as Adam (Kingma and Ba, 2014), RMSProp (Tieleman and Hinton, 2012) and SGD with momentum (Polyak, 1964) all build on this idea. Instead of inverting a giant matrix, they take many small steps with smart adaptations.
5 · The shape of the loss
A loss surface is convex when it is bowl-shaped, so that the straight line between any two points on it lies on or above it, as squared error on a linear model does. For convex loss functions, gradient descent converges to the global optimum from any starting point, provided the learning rate is appropriate. Convex problems are easy.
Non-convex loss functions include everything in deep learning, plus most realistic trading objectives. On them, gradient descent converges to some local minimum that depends on the starting point. Real-world loss surfaces have four hazards:
- Local minima: points where every nearby direction increases the loss, but the global optimum lies elsewhere.
- Saddle points: points where some directions go up and others go down. These are vastly more common than local minima in high-dimensional spaces.
- Plateaus: large regions where the gradient is nearly zero, slowing progress dramatically.
- Cliffs: regions where the gradient is enormous, causing standard SGD to take huge destabilizing steps.
6 · Modern optimizers
The plain SGD update is rarely used in practice, because modern variants address its specific failure modes.
SGD with momentum (Polyak, 1964) accumulates a running average of past gradients and uses it to dampen oscillation and escape saddle points. With the velocity and (gamma) a number between 0 and 1:
The velocity keeps you moving in directions that have consistently pointed downhill, even when the current local gradient is noisy. Under a steady gradient , the velocity settles where , that is at . With , that is : steps ten times the plain ones along a consistent slope.
AdaGrad (Duchi et al., 2011) adapts the learning rate per parameter, dividing it by the square root of the running sum of squared past gradients. Parameters that have already seen big updates get smaller updates from then on.
RMSProp (Tieleman and Hinton, 2012) is like AdaGrad but uses an exponential moving average instead of a cumulative sum, which prevents the learning rate from shrinking to zero.
Adam (Kingma and Ba, 2014) combines momentum with RMSProp. It is the default choice in most modern machine learning codebases: robust, fast and in need of minimal tuning.
You do not need to know the internals of these. You need to know that the optimizer is doing something smarter than vanilla gradient descent and that the choice of optimizer can dramatically affect training speed and final performance. For most trading applications with linear or simple nonlinear models, vanilla SGD or Adam with default hyperparameters works fine.
7 · Why optimization matters for trading
The optimization step is where most of the computational expense in modern quant research lives. Backtesting a strategy means fitting models, generating predictions, simulating execution, computing performance and iterating. Fitting a model on millions of (feature, target) pairs is the slow step. Modern quant firms run massive distributed-training infrastructure precisely because they are optimizing thousands of model variants in parallel.
For retail-scale work, fitting a model on a few thousand observations, optimization is essentially free. The bottleneck is data acquisition, feature engineering and avoiding overfitting, not the optimization step itself.
8 · Regularization
Regularization is a core technique that addresses overfitting at the optimization stage. It adds a penalty term to the loss function that discourages large parameter values. The two most common forms penalize the squared weights (L2 regularization, or ridge regression) or their absolute values (L1 regularization, or the lasso):
Here is the loss of (3C.1) and the are the model's weights. The hyperparameter (lambda) controls the strength of regularization. Higher means smaller fitted weights, which means a smoother model with less overfitting risk.
L2 keeps all features but shrinks their weights toward zero. L1 has the additional property that it zeros out many weights entirely, performing feature selection automatically. For trading models with many candidate features, L1 is often the right choice, because it produces sparse, interpretable models.
Step 1: the formulas. For a single weight on data with zero means, write for the covariance and for the variance of the feature. Setting the slope of each penalized loss to zero gives
with the lasso weight taking the sign of .
Step 2: the five returns. Here and , so the unpenalized weight is −0.5, while with ridge gives and the lasso .
Step 3: a stronger penalty. With , ridge gives , half the unpenalized weight, while the lasso gives and drops the feature entirely.
Ridge is the shrinkage toward zero that Chapter 3A's zero-forecast example argued for, a little bias bought with a large cut in variance. Choose by walk-forward testing, never by the in-sample fit, which always prefers .
For AR(1), with a single feature, regularization is unnecessary, whereas for multivariate models with dozens of features it is essential.
Regularization is the shrinkage you already demand of a clinical prediction model. A score built from many candidate predictors and few events overfits its development cohort: its coefficients come out too extreme and its predictions too confident in new patients. Penalized regression, ridge or lasso, shrinks the coefficients to correct that optimism, with the lasso also choosing among candidate biomarkers. The penalty is doing the same job in a trading model with dozens of candidate features.
- For one to a handful of features, use the closed form. OLS, which is what
LinearRegressionandlm()compute, is exact and instant at retail scale. - Standardize features before regularizing, dividing each by its standard deviation, so that the penalty treats them alike rather than punishing whichever happens to be measured in larger units.
- Tune and the learning rate out of sample, inside the walk-forward folds of Chapter 3A, counting each value tried as a trial.
- Watch the loss as you fit: a loss that rises or oscillates means the learning rate is too high, while one that barely moves means it is too low.
An optimizer finds the parameters that minimize the loss you gave it, on the data you gave it. If the loss is not what you care about, such as squared error when you trade only the sign, or the data contain lookahead, it optimizes the wrong thing perfectly. On non-convex problems it may also stop at a local minimum, so two runs from different starts can disagree.
- Use OLS when the features are few, turning to gradient descent or a modern optimizer only when the data or the feature count is too large for the closed form.
- Regularize any model with more than a few features, with chosen by walk-forward testing.
- Prefer the lasso when you have many candidate features and suspect most are noise.
Every added feature lowers the in-sample loss, as does every reduction in . The optimizer is doing its job, which is the problem: it is fitting noise as eagerly as signal. The only fair judge of a fitted model is its loss out of sample.
- Fitting means minimizing a loss, usually the mean squared error of the predictions.
- For linear models OLS gives the exact answer, , which for AR(1) is the covariance over the variance. It breaks only at a scale retail work never reaches.
- Gradient descent steps downhill by times the slope. Too small a learning rate crawls, while too large a rate overshoots, zigzags or diverges.
- Ridge shrinks weights and the lasso zeros them, with the penalty chosen out of sample.
9 · Check yourself
Question 1
A sample of daily returns has and , in squared percent, with means and . What are the OLS weight and bias?
Answer
By (3C.5), and .
Question 2
Run gradient descent on the figure's loss, , from with . Where is after three steps?
Answer
By (3C.9) each step multiplies the distance from 0.5 by . After three steps the distance is , so .
Question 3
Why does a learning rate of 1.1 fail on that loss while 0.9 succeeds?
Answer
The factor is −0.8 at 0.9, so each step overshoots but by less, and the path zigzags inward. At 1.1 it is −1.2, so each overshoot is 20% larger than the last and the path diverges.
Question 4
With a covariance of −0.1 and a variance of 1, what do ridge and the lasso give for the weight at ?
Answer
Ridge gives , while the lasso gives and so drops the feature.