Derived by the Research Lead from Mason et al., 'Enhanced Momentum with Momentum Transformers': a learned LSTM-plus-causal-attention daily position allocator, trained with a differentiable Sharpe loss, on a fixed panel of nine US Select Sector SPDR ETFs. This is the Research Lead's operationalization, not the authors' strategy and not a reproduction of their CRSP/Compustat stock experiment. Every rule below is a choice made here; the developer needs no other document. 1. UNIVERSE (fixed, all listed since Dec 1998, so there is no survivorship issue): XLK.USEQ (primary), XLB, XLE, XLF, XLI, XLP, XLU, XLV, XLY (.USEQ). Daily bars only (1-DAY), OHLCV. XLC and XLRE are excluded because they started in 2018/2015. 2. FEATURES (8 per ETF, computed at the close of session t from closes up to t only): sigma_t = exponentially weighted std of daily close-to-close returns, span 60 sessions (floor at 1e-4). (a)-(e) normalized returns for k in {1, 21, 63, 126, 252}: (C_t / C_{t-k} - 1) / (sigma_t * sqrt(k)), clipped to [-5, 5]. (f)-(h) MACD signals for (S,L) in {(8,24),(16,48),(32,96)}: m = EWMA_S(C) - EWMA_L(C) (EWMA with halflife ln(0.5)/ln(1-1/n), i.e. alpha=1/n); q = m / rolling std of C over 63 sessions; y = q / rolling std of q over 252 sessions; clip to [-5, 5]. A session is usable only when all 8 features are finite (about 350 sessions of warm-up). 3. LABEL (resolves the timing question): the decision is made at the close of session t and fills at the OPEN of session t+1 (platform next_open_fill, supported on USEQ). The position is then held until the next decision fills at the open of t+2. So the label is the NEXT-OPEN-TO-NEXT-OPEN return R_{i,t} = O_{i,t+2} / O_{i,t+1} - 1. A training sample at t is usable only when O_{t+2} is known, i.e. t <= training-cutoff session - 2. Labels are never next-open-to-close. 4. ARCHITECTURE (one network shared by all nine ETFs; ETF identity is NOT an input): d_model = hidden_size (initial 16). - Variable selection network: each of the 8 scalar features goes through its own gated residual network (GRN) to a d_model vector; a separate GRN on the concatenated 8 raw features plus softmax produces 8 selection weights; the output is the weighted sum (d_model). - GRN definition: eta2 = ELU(W2 a + b2); eta1 = W1 eta2 + b1; out = LayerNorm(skip(a) + GLU(eta1)), GLU(g) = (W4 g + b4) * sigmoid(W5 g + b5), skip = linear projection when dims differ, identity otherwise. - LSTM, one layer, hidden_size units, run over the sequence of selected vectors; then gated skip: LayerNorm(VSN_out + GLU(LSTM_out)). - Causal multi-head self-attention, attention_heads = 4 (head dim = hidden_size/4), additive mask so step s sees only steps <= s; output projection, then LayerNorm(prev + GLU(attn_out)); then a position-wise GRN; then LayerNorm(LSTM-block output + GLU(GRN_out)). - Output: linear to 1 unit, tanh -> x_{i,t} in (-1, 1). No dropout. No changepoint-detection module. All computation in NumPy with hand-written backpropagation (BPTT through the LSTM, gradients through attention, LayerNorm, GLU, ELU, softmax). No PyTorch/TensorFlow/JAX, no external weight files, no pickled models. Do not substitute nearest-neighbour retrieval, a fixed kernel, frozen random features or an indicator vote for trained attention. 5. TRAINING SAMPLES: for each ETF separately, cut its usable feature history (up to the training cutoff) into NON-OVERLAPPING sequences of sequence_length sessions (initial 252), aligned so the last sequence ends at the cutoff; drop a leading partial sequence. Sequences from all nine ETFs are pooled into one dataset (pooled-per-ETF training, not a joint-portfolio loss). The chronologically last 10% of sequences (by end date, across ETFs) is the validation set; the rest is training. 6. LOSS (resolves the loss question): for every sequence b and step s the model outputs x_{b,s}. Volatility-scaled position p_{b,s} = x_{b,s} * min(sigma_target / sigma_{b,s}, 3.0) with sigma_target = 0.15 / sqrt(252) (daily). Captured return c_{b,s} = p_{b,s} * R_{b,s} - (turnover_penalty_bps / 10000) * |p_{b,s} - p_{b,s-1}|. The turnover term pairs each step with the PREVIOUS STEP OF THE SAME SEQUENCE, using the model's own output there; the first step of every sequence has no turnover term (no pairing across sequence or batch boundaries). Loss for a minibatch = -sqrt(252) * mean(c) / (std(c) + 1e-9), with mean and std taken over ALL (sequence, step) values in the minibatch (every step contributes, not only the last). Add L2 weight decay 1e-5 to all weight matrices. This is the differentiable loss; the platform's net_sharpe objective is only the outer optimizer's score and is not the training loss. 7. OPTIMIZER: Adam, learning rate 1e-3 (beta1 0.9, beta2 0.999), minibatch 64 sequences (reshuffled every epoch with a seeded RNG), gradient global-norm clip 1.0, Xavier-uniform init, LSTM forget-gate bias 1.0, max 60 epochs, early stopping when the validation loss has not improved for 8 epochs, restore the best-validation weights. Random seed 42 (numpy.random.default_rng(42) per retrain, reseeded identically each retrain so results are deterministic). 8. RETRAIN SCHEDULE (causal expanding window): the first training happens at the first session with at least 1260 usable feature sessions (about 5 years after the features become finite, i.e. around 2005). The model is then retrained every 252 sessions on ALL usable history up to that session (expanding window, cutoff rule from item 3). Between retrains the weights are frozen. No position is taken before the first training completes. Training uses only data available at the retrain session. 9. INFERENCE AND TRADING: at each daily close t, for each ETF, feed its last sequence_length feature vectors (fewer if history is shorter, minimum 63) and take the output at the final step: x_{i,t}. Target weight (fraction of account equity, signed) w_{i,t} = x_{i,t} * min(sigma_target_annual 0.15 / (sigma_{i,t} * sqrt(252)), 3.0) / 9, then clip each |w| to 0.25. If the gross sum of |w| exceeds 1.5, scale all weights down proportionally. Shorts are allowed (USEQ margin account). Rebalance an ETF only when |w_target - w_current| > rebalance_band (0.02 of equity) to avoid tiny orders; otherwise leave it. Orders are market orders decided on the close and filled at the next session open (next_open_fill). Shares are whole shares (round toward zero). 10. RISK CONTROL route (b): signal-based exit (daily re-evaluation; a position is reduced/closed or flipped when the model's target changes) with capped sizing: no single ETF above 25% of equity, gross at most 150% (well under the venue's 2x). No stop-loss. Intended portfolio volatility about 8-12% annualised. 11. COSTS: platform USEQ costs (zero commission, modelled spread + impact) apply in the backtest; the loss's turnover_penalty_bps (initial 2) is a training regulariser only. Dividends are not in PnL (split-adjusted prices) and borrow cost is not modelled; sector SPDRs are easy to borrow. 12. RUNTIME: training at the 2025 cutoff has about 9 x 20 years x 252 / 252 = ~180 sequences of length 252 (or ~720 of length 63); about 20 retrains in total. If the developer measures that the full architecture cannot fit within the sandbox runtime, report that measured limitation instead of shrinking the model silently.