Scoring model
Every weight, every metric, and the assumptions behind the ranking
How a score is built
- Each instrument is measured on 29 raw metrics computed from its own price history and filings.
- Every continuous metric is converted to a percentile rank within its own market — not scored against an absolute threshold. A P/E of 30 means different things on the S&P 500 and the KLCI, and any fixed cut-off that suits one market empties or floods the other.
- Boolean signals score 0 or 100. RSI is banded rather than ranked, so an overbought 95 scores below a healthy 60 instead of winning.
- Metrics roll up into six dimensions, then into one weighted total. A metric with no data drops out and its weight is redistributed, rather than counting as zero.
What this does not tell you
- The weights are unvalidated. They are initial research values. No backtest has been run against them — that is Phase 3. Until then the ranking is a shortlist for research, not evidence that the model works.
- A percentile is relative. In a uniformly expensive, uniformly deteriorating market the top-ranked name still scores near 100. High means “best available here”, never “good”.
- No position sizing, stops or execution. This is Phases 1–2 only: data infrastructure and screening.
Dimensions and weights
Fundamental quality
20% of totalGrowth, profitability, leverage and valuation from the most recent trailing-twelve-month figures the market had seen as of the run date.
| Metric | Direction | Weight in dimension |
|---|
| Revenue growth YoY | Higher is better | 10% |
| Earnings growth YoY | Higher is better | 10% |
| EPS growth YoY | Higher is better | 10% |
| Return on equity | Higher is better | 15% |
| Net margin | Higher is better | 10% |
| Free cash flow margin | Higher is better | 10% |
| Debt to equity | Lower is better | 15% |
| P/E | Lower is better | 10% |
| P/B | Lower is better | 10% |
Technical trend
25% of totalWhere price sits against its own moving averages, and whether the shorter-term structure confirms the longer-term one.
| Metric | Direction | Weight in dimension |
|---|
| Price above 50-day MA | Yes / no | 15% |
| Price above 200-day MA | Yes / no | 20% |
| 50-day above 200-day | Yes / no | 20% |
| MACD above signal | Yes / no | 15% |
| RSI (14) | Best between 45 and 70 | 15% |
| Position in 20-day range | Higher is better | 15% |
Momentum & structure
25% of totalTrailing performance across three horizons, weighted toward the medium term, plus how steadily that performance was delivered.
| Metric | Direction | Weight in dimension |
|---|
| 20-day return | Higher is better | 15% |
| 60-day return | Higher is better | 25% |
| 120-day return | Higher is better | 25% |
| Trend consistency | Higher is better | 20% |
| Near 52-week high | Higher is better | 15% |
Relative strength
15% of totalPerformance against the market benchmark. The one dimension that still discriminates when every absolute return is negative.
| Metric | Direction | Weight in dimension |
|---|
| Excess return vs index, 60d | Higher is better | 40% |
| Excess return vs index, 120d | Higher is better | 35% |
| RS line slope, 60d | Higher is better | 25% |
Volume confirmation
10% of totalWhether the move is backed by participation, and whether the name is liquid enough to actually trade.
| Metric | Direction | Weight in dimension |
|---|
| Volume expansion (20d vs 60d) | Higher is better | 50% |
| Avg daily turnover | Higher is better | 50% |
Risk profile
5% of totalVolatility, historic drawdown and gap exposure. Every metric here is inverted: a calmer instrument scores higher.
| Metric | Direction | Weight in dimension |
|---|
| Annualised volatility | Lower is better | 30% |
| Max drawdown, 1y | Lower is better | 30% |
| Largest overnight gap | Lower is better | 20% |
| ATR as % of price | Lower is better | 20% |
Gates applied before scoring
| Gate | Rule | Why |
|---|
| Minimum history | 200 daily bars | The 200-day moving average is the longest window the model reads. |
| Liquidity, US | 5,000,000 USD/day | Average daily traded value over 20 sessions. A name that cannot be entered and exited at size is not an opportunity, and leaving it in distorts every percentile around it. The floors differ because Bursa is an order of magnitude thinner — one shared floor would empty it. |
| Liquidity, Bursa | 500,000 MYR/day |
Weights are stored in trading.weight_profiles and read at run time, so changing how the model ranks needs no deploy and every past run stays reproducible against the weights it actually used.