1UNIVERSE = all 59 instruments
3function positions(bar):
4 signal = features.oni_3m_aligned
6 for symbol in UNIVERSE:
7 # sign learned only from history available at t
8 beta = slope(returns(symbol) against signal, up to bar.prev)
9 w[symbol] = sign(beta) / vol_36m(symbol, bar.prev)
11 size = clip(zscore(signal, expanding) / 2, -1, 1)
12 return w * size
14# ── execution ────────────────────────────────────────────────────────
16COST_PER_TRADE = 15 bps of the notional that changes hands
18function on_bar(bar, book):
19 if not bar.is_month_end:
20 return # decisions are made monthly only
22 target = positions(bar) # the rule above
23 target = scale_to_gross(target, 1.0)
25 rebalance(book, target, bar)
27function scale_to_gross(w, limit):
28 gross = sum(abs(w)) # total capital at work
30 if gross == 0:
31 return w # flat is a valid target
33 return w * limit / gross # leverage fixed, never implicit
35function rebalance(book, target, bar):
36 for symbol in union(book.symbols, target.symbols):
37 delta = target[symbol] - book.weight(symbol)
39 if delta > 0:
40 buy(symbol, delta, fill = next_bar.close)
41 else if delta < 0:
42 sell(symbol, -delta, fill = next_bar.close)
44 book.charge(COST_PER_TRADE * abs(delta))
46# Orders are filled at the next month's close, never the one the decision
47# was made on. There is no stop_loss(), take_profit(), limit order or
48# position cap: a holding changes only when positions() returns a
49# different target at the next month end.