Momentum + Value — a Strategy That Survives Out of Sample¶
Most of the classic single factors look great in a backtest and then evaporate out of sample (see the other examples). This one is different: short-horizon momentum (last month's winners keep winning, briefly) blended with value (cheap beats expensive) is one of the most durable combinations in equities. We hold a wide dollar-neutral book and let weekly rebalancing keep turnover in check — and we check that the edge survives out of sample across many markets, not just one lucky draw.
try:
import convexpi.lab # noqa
except ImportError:
import subprocess, sys
subprocess.run([sys.executable, "-m", "pip", "install", "-q", "convexpi-lab"])
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
print("ready")
The strategy¶
Combine two real edges into one score and trade the spread. We weight short-horizon momentum
(mom_1m) a bit more than value (val_bm), and go long the top half / short the bottom half — a wide
book diversifies away single-name noise, and weekly rebalancing (the grader's default) keeps the
high-turnover momentum leg from being eaten by costs.
import numpy as np
from convexpi.lab import Strategy
class MyStrategy(Strategy):
"""Short-horizon momentum + value, dollar-neutral, wide book (top/bottom half)."""
weights = {"mom_1m": 1.0, "val_bm": 0.5}
frac = 0.5
def on_day(self, day, features, prices, portfolio):
n = len(prices)
score = np.zeros(n)
for name, wt in self.weights.items():
score += wt * np.nan_to_num(features.get(name, np.zeros(n)))
k = max(1, int(n * self.frac))
order = np.argsort(score)
w = np.zeros(n)
w[order[-k:]] = 1.0 / k # long the strongest
w[order[:k]] = -1.0 / k # short the weakest
return w
Does it survive? Check across many markets¶
A single backtest can be lucky. The honest test is robustness: evaluate out of sample on many independent synthetic markets and look at the distribution of OOS Sharpe — not one number.
from convexpi.lab import SyntheticMarket, Grader
oos = []
for seed in range(1, 21):
r = Grader(SyntheticMarket(n_stocks=200, n_days=1260, seed=seed)).evaluate(MyStrategy())
oos.append(r.oos_sharpe)
oos = np.array(oos)
print(f"out-of-sample Sharpe across 20 markets:")
print(f" mean : {oos.mean():+.2f}")
print(f" win rate : {np.mean(oos > 0):.0%} (fraction of markets with positive OOS)")
print(f" range : [{oos.min():+.2f}, {oos.max():+.2f}]")
fig, ax = plt.subplots(figsize=(8, 3))
ax.hist(oos, bins=10, color="steelblue"); ax.axvline(0, color="grey", lw=1)
ax.axvline(oos.mean(), color="darkorange", lw=2, label=f"mean {oos.mean():+.2f}")
ax.set_title("OOS Sharpe distribution (20 markets)"); ax.set_xlabel("OOS Sharpe"); ax.legend()
plt.tight_layout(); plt.show()
The honest part¶
Positive on average and most of the time — but look at the left tail: some markets still hand it a losing draw. That's the truth about even good strategies: an edge is a tilt in the distribution, not a guarantee. The permanent leaderboard grades this on one hidden market, so the badge you see is one draw from that histogram.
What I'd try next¶
- Add a third lightly-weighted factor and see if it tightens the distribution (lifts the left tail).
- Vary the book width (
frac) and rebalance horizon to trade off noise vs. turnover cost. - Compare against the single-factor examples — diversification is what turns a coin-flip into an edge.

