1CROPS = [ZW=F ZC=F ZS=F]
2EQUITIES = [DE AGCO ANDE MOS NTR CF GNC.AX ELD.AX
3 COROMANDEL.NS CHAMBLFERT.NS M&M.NS ESCORTS.NS]
4LOOKBACK = 3 months
6function positions(bar):
7 crop_run = sum(mean(returns(CROPS, LOOKBACK, ending bar)))
9 # rising crop prices lift farm income, and farm income reaches
10 # the equipment and fertiliser makers later
11 return sign(crop_run) * equal_risk(EQUITIES, bar)
13# ── execution ────────────────────────────────────────────────────────
15COST_PER_TRADE = 15 bps of the notional that changes hands
17function on_bar(bar, book):
18 if not bar.is_month_end:
19 return # decisions are made monthly only
21 target = positions(bar) # the rule above
22 target = scale_to_gross(target, 1.0)
24 rebalance(book, target, bar)
26function scale_to_gross(w, limit):
27 gross = sum(abs(w)) # total capital at work
29 if gross == 0:
30 return w # flat is a valid target
32 return w * limit / gross # leverage fixed, never implicit
34function rebalance(book, target, bar):
35 for symbol in union(book.symbols, target.symbols):
36 delta = target[symbol] - book.weight(symbol)
38 if delta > 0:
39 buy(symbol, delta, fill = next_bar.close)
40 else if delta < 0:
41 sell(symbol, -delta, fill = next_bar.close)
43 book.charge(COST_PER_TRADE * abs(delta))
45# Orders are filled at the next month's close, never the one the decision
46# was made on. There is no stop_loss(), take_profit(), limit order or
47# position cap: a holding changes only when positions() returns a
48# different target at the next month end.