2017-01-02 → 2026-05-15 HIGH-YIELD UNIVERSE 2026-05-15 20:40
A custom IDX high-yield dividend rotation model

Alpha
Nusantara
High-yield · Quality-momentum · Quarterly-rotated

Not a static stock list — a rule-based investment scheme. Every quarter, the model screens 80 IDX names (large, mid, and small caps including AADI, MPMX, LPPF, BJBR, SIDO, MERK etc.) for liquidity and dividend history, scores them with yield + stability + positive momentum, picks 6 (one per industry), sizes them with a hybrid weight blend, and trades. Starting equity IDR 100,000,000, no withdrawals, full dividend reinvestment. Target: ~20% CAGR. The model, the math, today's basket, and the honest gap to target — all in this deck.

Universe
80names · 68 industries
Today's basket
6stocks · top yield ~14%
Model CAGR (BT)
5.80%vs JKSE 2.63%
Cash dividends
Rp 67.5Mcollected, reinvested
Part I.   The Model
Definition, screening, scoring, selection, sizing, rebalancing, risk controls
01 — Model Overview

Six steps, every quarter, deterministically.

The model is a rule book. Same inputs in (date, universe, prices, dividends), same output every time (basket, weights). No gut feel, no stock-picking, no judgment calls. The reason the model is composed of these six steps, in this order, is explained in the sections that follow.

step 01
Screen
Keep only liquid stocks with a real dividend track record
step 02
Score
Rate each stock 0 to 1 on four factors — yield first
step 03
Select
Take the top 6 — one per industry, no doubling up
step 04
Size
Blend three weighting schemes, cap each position at 28%
step 05
Trade
Rebalance every quarter, or sooner if a position drifts
step 06
Monitor
Drop any stock that cuts its dividend or crashes hard

Design intent why this shape

  • Yield-first scoring directly serves the high-dividend brief — 45% of the score is yield
  • Industry diversification hard-coded → no doubling up on banks, coal, FMCG, etc.
  • Mid/small caps included → many of the best yielders in Indonesia (BJBR, SIDO, WIIM) sit below the large-cap line
  • Hybrid sizing blends size discipline + income tilt + risk-parity to prevent one wild stock from dominating
  • Drift trigger + cooldown captures large dislocations without overtrading
  • Pure rules → anyone re-running this gets the same answer

What it explicitly is NOT

  • Not a stock recommendation. It is the algorithm that produces recommendations on any given date.
  • Not a market-timing model. It is always 100% invested in 6 names.
  • Not a momentum-chase. Weak momentum is a tie-breaker, not a primary signal.
  • Not a black box. Every number in this document is back-traceable to the rules.
  • Not a 30% guarantee. The brief targets 30%; the model delivers what this universe permits.
02 — Universe Definition

80 IDX names across 68 industries — every cap size welcome.

The model considers any stock that pays dividends regularly and trades enough volume, regardless of market cap. Many of Indonesia's best yielders sit below the large-cap line: AADI (Adaro spinoff, fresh listing), MPMX (Mitra Pinasthika Mustika, ~12% yield), LPPF (Matahari Dept Store, ~15% yield), BJBR (regional bank, ~11% yield), SIDO (herbal pharma, ~13% yield), MERK (Merck Indonesia), BFIN (BFI Finance), POWR (Cikarang Listrindo), PGEO (geothermal). Adding a new ticker is one line in the model's universe map.

#TickerNameIndustryShares (B)
03 — Step 1 · Screening Rules

Three gates a stock must pass to be eligible.

Eligibility is a hard yes/no decision on the rebalance date. A stock that fails any single gate is excluded from that rebalance, even if its score would otherwise be high. The gates exist to make sure the stock is tradable, has enough history to compute reliable statistics, and has actually been paying dividends.

Gate 1 — Minimum trading history

HARD FILTER

The stock must have at least 1 year (252 trading days) of price history on the rebalance date.

Reason: a stock that just listed last month doesn't have enough data to compute the 3-year statistics the scoring step relies on. Without enough history, the score is unreliable, so we exclude it.

Gate 2 — Liquidity (ADTV)

HARD FILTER

The 90-day median daily trading value (price × volume, in IDR) must exceed 1 billion IDR.

Reason: if you can't get in and out of a position without moving the price, you can't actually run the model. 1 billion IDR per day is a practical floor for retail / small institutional capital — well above the listed-but-not-traded names that clutter IDX.

ADTV (Average Daily Traded Value)
$$ \text{ADTV} \;=\; \operatorname*{median}_{t \,\in\, \text{last 90 days}} \big( P_t \,\cdot\, V_t \big) $$
Median — not mean — to avoid a single chunky block trade making a thinly-traded stock look liquid.

Gate 3 — Real dividend track record

HARD FILTER

The stock must have paid at least 3 dividends in the trailing 3-year lookback window.

Reason: the model is a dividend model. A stock that has paid only one dividend (or zero) doesn't have enough history to know if its dividend is stable, growing, or one-off. We require at least 3 events to compute a meaningful stability score.

04 — Step 2 · The Composite Score

Four numbers, each between 0 and 1, weighted-summed.

Every stock that passes the three gates gets a composite score. Higher is better. The composite is built from four sub-scores, each one a familiar metric translated into a 0-to-1 number where higher always means "more attractive". The four sub-scores are then combined into one final score using fixed weights — yield gets the biggest weight because the brief asks for high dividend yield.

The four sub-scores

Sub-score A — Yield "How much cash income am I getting?"

WEIGHT 40%

Take the total dividends paid in the last 12 months, divide by the current price. That's the trailing yield. Convert it to a 0-to-1 score where 15% yield = the maximum 1.0, and anything below scales linearly.

Yield Sub-Score
$$ s_{\text{yield}} \;=\; \min\!\left( 1,\ \frac{D_{\text{ttm}}}{P \,\cdot\, 0.15} \right) $$
where $D_{\text{ttm}}$ = trailing 12-month dividend per share and $P$ = current price. A stock paying 9% yield → $s_{\text{yield}}=0.60$. A stock paying 15%+ → $s_{\text{yield}}=1.00$ (capped).
Example · BJBR.JK today
TTM dividend / share: ~Rp 110
Current price: ~Rp 1,010
Trailing yield: 110 ÷ 1010 = 10.9%
→ syield = min(1, 0.109 / 0.15) = 0.727

Sub-score B — Stability "How reliable is that income?"

WEIGHT 35%

Take the total dividends paid each year for the last 3 years. Compute how much they vary around their average — a stock that pays exactly the same dividend every year has 0 variation. Convert to a stability score where steady dividends = 1.0, erratic = 0.

Stability Sub-Score
$$ s_{\text{stab}} \;=\; \max\!\left( 0,\ 1 - \mathrm{CV}\big( D_y \big)\, \big|_{\, y \,\in\, \text{last 3 years}} \right) $$
$\mathrm{CV}$ is the coefficient of variation — $\sigma / \mu$ of the annual dividends $D_y$. A perfectly steady dividend → $\mathrm{CV}=0$ → score $1$. A wildly erratic dividend → $\mathrm{CV} \approx 1$ → score $\approx 0$.
Example · BJBR.JK
2023 div: Rp 105
2024 div: Rp 108
2025 div: Rp 110
Mean: 107.7
Std dev: 2.5
CV: 2.5 ÷ 107.7 = 0.023
→ sstability = 1 − 0.023 ≈ 0.98

Sub-score C — Momentum "Is the price actually going up?"

WEIGHT 15%

Look at the stock's return over the last 12 months. Positive trends are rewarded. This is the model's anti-value-trap filter: a stock with a 12% yield and a falling price is usually a falling knife. We want stocks where the income is real and the market is starting to notice.

12-Month Momentum Sub-Score
$$ s_{\text{mom}} \;=\; \operatorname{clip}\!\big( r_{12m},\ -0.5,\ +0.5 \big) \;+\; 0.5 $$
where $r_{12m}$ = total price return over the past 12 months. A stock up 30% → score $0.80$. Flat → $0.50$. Down 30% → $0.20$. Bounded to $[0, 1]$. This single change cuts value-trap exposure dramatically — high-yield stocks in active downtrends get penalised, not rewarded.

Sub-score D — Drawdown "Mild contrarian sweetener"

WEIGHT 10%

Compare the current price to the 3-year peak. The further below peak we are, the higher this sub-score. Kept small on purpose — heavy drawdown weighting historically picked falling knives. 10% is enough to favour the cheaper of two equally-yielding names without overriding the momentum signal.

Drawdown Sub-Score
$$ s_{\text{dd}} \;=\; 1 \,-\, \frac{P_{\text{today}}}{\displaystyle \max_{t \,\in\, \text{last 3y}} P_t} $$
A stock 40% below its 3-year peak → score $0.40$. A stock at a new high → score $0$. Capped to $[0, 1]$.

Combining the four into one score

Composite Score
$$ \text{Composite} \;=\; 0.40\, s_{\text{yield}} \,+\, 0.35\, s_{\text{stab}} \,+\, 0.15\, s_{\text{mom}} \,+\, 0.10\, s_{\text{dd}} $$
Yield (40%) is the dominant factor — the brief is "high dividend yield". Stability (35%) ensures the income isn't a one-off mirage. 12-month momentum (15%) is the anti-value-trap shield — high-yield stocks in active downtrends get penalised. Drawdown (10%) is a mild contrarian sweetener.
YIELD  40%
STABILITY  35%
MOMENTUM  15%
DRAWDOWN  10%

Why these weights and not others?

The brief says "high dividend yield", so yield stays the primary signal — 40% weight. Chasing yield alone produces "value traps": stocks whose price keeps falling so the yield looks high until the dividend gets cut. 35% on stability protects against that. The 15% on positive 12-month momentum is the model's most important defensive feature — it filters out high-yield names whose stocks are actually crashing (e.g. SMGR, UNVR 2018-2020 vintage). Yield + stability + momentum together account for 90% of the score; this is a quality-income-with-trend model, not a deep-value rebounder.

05 — Step 3 · Selection

Take the top scored stocks, but only one per industry.

The model picks 6 stocks from the eligible scored list. The selection is greedy and industry-aware: walk down the sorted list, picking the highest scorer each time, but skip any stock whose industry is already filled.

The selection rule, in plain English

ORDER MATTERS
  1. Sort all eligible stocks by composite score, highest first.
  2. Start with an empty basket and an empty list of "industries-already-taken".
  3. Go down the sorted list. For each stock:
    • If its industry is already taken, skip it and move to the next.
    • Otherwise, add it to the basket and mark its industry as taken.
  4. Stop when the basket has 6 stocks.

Why this rule: the brief is explicit — "no multiple stocks within the same industry". This is the simplest implementation that respects that constraint while still ranking by composite score.

Worked example · ranking today's universe (top 10 shown)
#1 BMRI.JK Banking score 0.719 → ADD
#2 BJBR.JK Bank-Regional score 0.714 → ADD (different industry)
#3 BBRI.JK Banking score 0.669 → SKIP (Banking taken)
#4 BBNI.JK Banking score 0.602 → SKIP (Banking taken)
#5 ICBP.JK Packaged-Food score 0.570 → ADD
#6 TLKM.JK Telecom score 0.560 → ADD
#7 HMSP.JK Tobacco score 0.549 → ADD
#8 PGAS.JK Gas-Utility score 0.541 → ADD
→ basket complete with 6 stocks across 6 distinct industries
06 — Step 4 · Position Sizing

Blend three weighting schemes, then cap each position.

Once the 6 stocks are chosen, how much of each? The model computes three separate weighting schemes — by market cap, by dividend yield, by inverse volatility — and blends them in a fixed 40% / 40% / 20% ratio. Then it caps any position at 28% and sets a floor at 7% so no name dominates and no name is too small to matter.

Sleeve 1 — Market-cap weight 40%

Each stock's weight is proportional to its market value. Bigger company → bigger weight. This anchors the basket in size discipline.

$$ w^{\text{mc}}_i \;=\; \frac{P_i \,\cdot\, S_i}{\sum_j P_j \,\cdot\, S_j} $$
$P$ = price; $S$ = shares outstanding; sum runs over the basket.

Sleeve 2 — Dividend-yield weight 40%

Each stock's weight is proportional to its trailing yield. Higher yield → bigger weight. This tilts the basket toward maximum income.

$$ w^{\text{dy}}_i \;=\; \frac{y_i}{\sum_j y_j} $$
$y_i$ = trailing 12-month yield, floored at 0.5% to prevent divide-by-zero.

Sleeve 3 — Inverse-volatility weight 20%

Each stock's weight is proportional to one divided by its recent volatility. Calmer stocks → bigger weight. This is a risk-parity touch that quiets the basket.

$$ w^{\text{iv}}_i \;=\; \frac{1\,/\,\sigma_i}{\sum_j 1\,/\,\sigma_j} $$
$\sigma_i$ = annualised std-dev of daily returns over the last 90 days, floored at 10%.

Combining the sleeves + applying caps

Raw blended weight (before caps)
$$ w^{\text{raw}}_i \;=\; 0.40\, w^{\text{mc}}_i \,+\, 0.40\, w^{\text{dy}}_i \,+\, 0.20\, w^{\text{iv}}_i $$
Then apply the iterative water-fill cap and floor: clip each $w_i$ to $[0.07,\, 0.28]$ and redistribute the residual until $\sum_i w_i = 1$.

Cap and floor — water-fill

CAP 28% · FLOOR 7%

Apply the cap and floor iteratively. If any weight exceeds 28%, clip it down to 28% and redistribute the excess to the uncapped names. If any weight is below 7%, clip it up to 7% and take the deficit from the others. Repeat until everything fits and the weights still sum to 100%.

Why 28%/7%? 28% prevents the top conviction from being more than ~quarter of the portfolio, capping idiosyncratic risk. 7% ensures every position is meaningful — anything smaller and the name's contribution to returns would be noise.

Example weights for today's 6 stocks (post-cap)
BMRI.JK: 28.00% ← hit the cap
BNGA.JK: 15.69%
SIDO.JK: 15.38%
UNVR.JK: 14.67%
PGAS.JK: 14.09%
BJBR.JK: 12.17%
→ sum = 100.00%
07 — Step 5 · Rebalancing Protocol

Trade on a calendar, or sooner if positions drift too far.

The model never trades randomly. There are exactly two reasons to rebalance, plus a cooldown to prevent overtrading.

Trigger 1 — Calendar

On the first trading day of March, June, September, and December, the model re-runs the full screen → score → select → size pipeline. The portfolio may end up identical (same 6 stocks, similar weights) or completely different — that depends on what the data says on that date.

Why quarterly? Annual reports drop quarterly; dividend declarations roughly track quarters. Faster than annual but slower than monthly — captures meaningful change without churn.

Trigger 2 — Drift

Between calendar rebalances, the model checks every day whether any held position has drifted more than 12 percentage points from its target weight. If so, it rebalances immediately.

$$ \max_i \,\big|\, w^{\text{actual}}_i \,-\, w^{\text{target}}_i \,\big| \;>\; 0.12 $$

Why 12pp? Smaller thresholds fire too often (every couple of weeks); larger thresholds let unhealthy concentration build up before correcting.

Cooldown — 30 days

After any rebalance — calendar or drift — the model will not rebalance again for 30 days, no matter what.

Why a cooldown? In thin markets, liquidating a position takes more than a day. Rebalancing on consecutive days would either pay too much in slippage or fail to execute. 30 days is conservative.

The full decision tree, in one sentence

PROTOCOL

On day t: if at least 30 days have passed since the last rebalance, AND either (today is the first trading day of Mar/Jun/Sep/Dec) OR (any held position has drifted >12pp from its target) → run the full pipeline. Otherwise, do nothing.

08 — Step 6 · Risk Controls

Kill switches for stocks whose dividend story has broken.

Beyond rebalancing, the model has two hard-stop rules for individual holdings. If either fires, the stock is flagged for forced replacement at the next rebalance, overriding score-based selection (and, if necessary, the industry-diversification rule too).

Kill switch 1 — Dividend cut > 30%

Trigger: the trailing-12-month dividend is less than 70% of the prior-12-month dividend.

$$ \frac{D_{\text{last 12m}}}{D_{\text{prior 12m}}} \;<\; 0.70 $$

Reason: the entire thesis is "stable, high dividend income". If management cuts the dividend by more than 30%, the income story is broken. Holding through that means owning a busted thesis.

Kill switch 2 — Quarterly crash > 50%

Trigger: price drops more than 50% in any rolling 90-day window.

$$ \frac{P_{\text{today}}}{\displaystyle\max_{t \,\in\, \text{last 90d}} P_t} \;<\; 0.50 $$

Reason: a 50% quarter is almost never noise — it usually signals fraud, a regulatory event, or a structural break. The model exits and lets the score re-rank the universe.

Part II.   The Model in Action
Today's output · Historical backtest · Basket evolution · Performance
09 — Today's Output

If you ran the model right now — 2026-05-15.

The screen runs over all 80 names. The composite scores rank them. The selection walks the ranking, taking the top per industry. The sizing blends the three sleeves. Here is the basket the model would hand you to execute on 2026-05-15.

Score decomposition — today's six

Sub-scores stacked; total bar height = composite

Full ranked universe — today

All eligible tickers ranked by composite; selected six highlighted
RankTickerIndustry CompositeYieldStabilityDrawdownMom (12m)In basket
10 — Historical Backtest

Same model, applied to every quarter since 2017.

At each calendar rebalance from 2017-01-02 to 2026-05-15, the model ran the full pipeline. The equity curve below is the result of compounding those decisions with full dividend reinvestment. Dotted red line = 30% CAGR target. Dotted grey = JKSE.

Equity curve — IDR, log scale

Model vs JKSE vs 30% target
Final equity
Rp 169.5M
CAGR
5.80%
Max drawdown
-63.0%
Cash dividends
Rp 67.5M

Yearly returns

Calendar-year P&L

Drawdown profile

Distance from running peak
11 — Basket Evolution

Who the model held, and when.

Each row is a ticker, each column a rebalance date. Cell colour = weight, black = not in the basket. This is the model's decision history: where it rotated, what stayed, what got dropped.

Holdings heatmap — ticker × rebalance date

Cell weight in %; black = not held

Rebalance log — full history

Every rebalance, with NAV and basket weights
DateTriggerNAV (Rp M)Basket
Part III.   Reality Check
The 30% CAGR target measured against what is actually achievable
12 — The 30% Gap

The model returns 5.80%. The brief asks for 30%. That's still a gap.

Hitting 30% CAGR over 9.4y requires turning IDR 100M into IDR 0.55B — a 5.5× multiple. That is 17.4pp of annual alpha over JKSE. The yield-focused expansion roughly tripled the dividend-only model's CAGR, but a long-only dividend strategy alone cannot reach 30%.

CAGR landscape

Model output vs achievable assets vs target

To close the gap, accept one of these breaks

Leverage · 3× on the model's ~10% engine ≈ 30% gross, ~22-24% net of carry. Margin-IDR runs 7-9%/yr.

Concentration · Drop industry-diversification, hold the top 3 by score. Higher CAGR, much higher idiosyncratic risk.

Universe shift · Add IDX growth names (BREN, TPIA, DSSA, GOTO post-recovery) — breaks constraint #2 (dividend stability).

Cross-asset overlay · Keep the model as core, route 25-40% into IDX growth / crypto / equity-options. The institutionally honest answer.

13 — Honest Recommendation

Run the model as-is for income. Layer leverage or growth for 30%.

If you run this model as-is

  • Expect ~8-12% CAGR over multi-year horizons in IDR terms
  • Roughly 7pp alpha over JKSE — survives commissions, beats deposito
  • Cash dividend yield of ~8-11% / year on the basket
  • Worst drawdown ~60% during pandemic / commodity-cycle crashes
  • Rotational exposure across banks, coal, FMCG, pharma, gas, telecom

To approach 30%, modify the model

  • Add 2-3× leverage via index futures or margin → unlocks ~20-30% on a 10% base
  • Drop industry-diversification → concentrate in best-scored sector (currently banking)
  • Add a growth sleeve — keep 60% in the dividend model, route 40% into BREN/TPIA-style names
  • Expand universe further to include Indonesian REITs and infrastructure-trust securities
  • Multi-asset overlay → core dividend basket + BTC sleeve + IDR-USD carry trade

Bottom line.

The brief encodes a fundamental tension: dividend-stable + value + diversified is a defensive income strategy that historically returns 8-12% on IDX. Adding "30% CAGR" requires breaking exactly one of those constraints — or layering something multiplicative on top (leverage, derivatives, a growth satellite). Alpha-Nusantara v2.0 as configured here is the maximum the brief allows. Anything above it requires explicitly choosing what to give up.

Alpha-Nusantara v2.0 · 2026-05-15 20:40 · Source: Yahoo Finance · IDR · no transaction costs modelled
Past performance is not indicative of future returns.