1UNIVERSE = 35 agribusiness equities, measured against their home index
2LOOKBACK = months bar-12 .. bar-2 # skips the most recent month
3MIN_NAMES = 12
5function positions(bar):
6 for symbol in UNIVERSE:
7 score[symbol] = sum(returns(symbol, LOOKBACK))
9 if count(score) < MIN_NAMES:
10 return {}
12 return long_short(score, count(score) / 3, bar)
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.