Cross-Sectional Ranking Strategies
Runtime contract: LIVE/PAPER, candle evaluation (for example 1h), with
the strategy's current balances and positions supplied. These fixed-notional
basket examples use portfolio_value(), which requires that live state.
Historical backtests should express a target gross weight directly through
rebalance_to(...); they do not provide live balances to this calculation.
Momentum Top-Bottom Basket
Tags: cross_sectional, ranking, momentum, top_n, bottom_n, basket, long_short, rebalance, cross_mode
Functions: get_data, drop_nan, top_n, bottom_n, portfolio_value, long_short_equal_weight, cap_weights, rebalance_to
Description: Ranks a fixed tradable universe by trailing momentum, allocates a fixed basket budget, goes long the strongest assets and short the weakest assets, then rebalances in cross mode.
Code:
scores = {}
for ticker in context['tickers']:
data = get_data(ticker)
ret = data.close / data.close.shift(20) - 1
last_ret = ret[-1]
if last_ret is None:
continue
scores[ticker] = last_ret
scores = drop_nan(scores)
longs = top_n(scores, 2)
shorts = bottom_n(scores, 2)
target_basket_notional = 1000.0
equity = portfolio_value()
target_gross = min(target_basket_notional / equity, 1.0) if equity else 0.0
weights = long_short_equal_weight(longs, shorts, gross=target_gross)
weights = cap_weights(weights, 0.25)
rebalance_to(weights, min_change=0.0)
RSI Mean-Reversion Basket
Tags: cross_sectional, ranking, rsi, mean_reversion, basket, cross_mode
Functions: get_data, rsi, drop_nan, bottom_n, portfolio_value, equal_weight, rebalance_to
Description: Ranks a fixed universe by latest RSI and rotates a fixed basket budget into the most oversold assets.
Code:
scores = {}
for ticker in context['tickers']:
data = get_data(ticker)
rsi_value = rsi(data.close, 14)[-1]
if rsi_value is None:
continue
scores[ticker] = rsi_value
scores = drop_nan(scores)
longs = bottom_n(scores, 2)
target_basket_notional = 1000.0
equity = portfolio_value()
target_gross = min(target_basket_notional / equity, 1.0) if equity else 0.0
weights = equal_weight(longs, gross=target_gross)
rebalance_to(weights, min_change=0.0)