IDX Trader Suite, deployed at saham.rominur.com, is an Indonesian-language analysis workstation for short-term traders on the Indonesia Stock Exchange (IDX). It offers eighteen desks — five screeners, three market views, six per-stock views, comparison, backtesting, a position calculator and a trading journal — built in plain Node.js with no npm dependencies, served by a single serverless function and a static front end with no build step. This paper describes how one handler serves both a local server and the cloud function; a cache whose lifetimes follow the exchange’s trading sessions, in front of a metered upstream API; a scalping engine that encodes the exchange’s tick-size and auto-reject rules so that every stop and target is a price that can actually be ordered; an order-flow reading of the trade tape; the technical and 200-day-average screeners; an in-browser backtester with gap-aware stops; and the limits of the current deployment.
A scalper on the IDX works inside rules that most generic charting tools ignore. Prices move in fractions (fraksi) that depend on the price itself, so a stock at Rp 68 moves one rupiah at a time — almost 1.5% a tick — while one at Rp 4,270 moves in tens. Each day a stock may rise no further than an auto-reject limit (ARA) of 20 to 35% above the previous close, and a stock near that limit fills its offer queue and becomes hard to buy or sell. Local trading vocabulary — HAKA for buying at the offer, HAKI for selling at the bid, bandarmologi for reading broker accumulation — describes signals that come from the trade tape, not the candle.
IDX Trader Suite gathers these into one workstation, written for that audience in Indonesian, with the market clock and all prices in Western Indonesian Time and the id-ID number format. Its footer states the boundary plainly: Alat bantu analisa, bukan rekomendasi investasi — an analysis aid, not investment advice.
| Group | Desks |
|---|---|
| Screener | Scalper, Swing, SwingMA200, Teknikal, Aliran Asing (foreign flow) |
| Pasar | Market, Heatmap, Watchlist |
| Per saham | Analisa Saham, Bandarmologi, Running Trade, Fundamental, Insider, Musiman (seasonality) |
| Riset | Bandingkan (compare up to six stocks), Backtest |
| Alat | Kalkulator (position size, break-even, ARA/ARB ladder, averaging), Jurnal Trading |
The project’s package.json has no dependencies. All server logic is one module, lib/app.js, that takes a request and returns a response. Locally, a thin node:http server serves the static front end, guards against path traversal, and passes API paths to the handler; on Vercel, one function wraps the same handler, and a rewrite sends every /api/* path to it with the original path carried in a query parameter. There is one code path to test and one to deploy, and cold starts are small because there is nothing to load.
The front end is vanilla ES modules with no bundler. A hash router lazily imports one of eighteen view modules, so opening the calculator does not load the backtester, and every state worth sharing is in the URL — #/bandar/BBRI opens broker analysis for Bank Rakyat Indonesia. Candlestick charts use TradingView’s Lightweight Charts from a CDN; sparklines, histograms and the heatmap’s squarified treemap are drawn by hand in SVG. Stock search autocompletes from the cached list of issuers and costs no API calls.
All market data comes from one metered third-party API, IDX Edge PRO, called with a key held in a server environment variable and never sent to the browser. The handler treats that quota as the scarce resource. Upstream calls pass through a semaphore of five, time out after 25 seconds, and are retried once after 800 ms on a network error or a 5xx response. The remaining quota is read from the upstream’s rate-limit headers, kept per Jakarta calendar day, and shown in the header bar, turning amber and then red as it falls.
Responses are cached twice: in the function’s memory and on disk (locally in a cache directory, on Vercel in /tmp), with concurrent requests for the same key merged into one upstream call. What matters is that lifetimes depend on whether the market is trading. A small clock encodes the IDX schedule in WIB — pre-opening from 08:45, session one to 12:00 (11:30 on Fridays), session two from 13:30 (14:00 on Fridays) to 15:50, pre-closing until 16:15 — and every TTL asks it first.
| Data | Market open | Market closed |
|---|---|---|
| Live quote | 15 s | 15 s |
| Trade tape | 30 s | 1 h |
| End-of-day screener data | 30 min (CDN 15 min) | 6 h (CDN 1 h) |
| Issuer universe | 3 h | |
| Price history | 24 h, keyed by data date | |
| Insiders; seasonality and financial statements | 6 h; 24 h | |
A scan whose stocks partly failed is still returned, but its CDN lifetime is cut to 60 seconds so the gap is not frozen for an hour. In the browser, the scalper’s auto-live mode refreshes the twenty best candidates every five minutes by default, pauses while the market is closed, and turns itself off when the remaining quota drops below one hundred calls.
The scalper scans the sixty most liquid stocks, chosen by a value proxy — turnover ratio times market capitalisation — of at least Rp 3 billion and a price of at least Rp 50. For each, a pure function builds a row from 250 days of history and, during trading hours, a partial candle from the live quote. It computes relative volume against the mean value of the previous twenty days, a fourteen-day ATR, the tick as a percentage of price, where the close sits in the day’s range, VWAP, a five-day-high breakout, foreign net flow, the distance to the auto-reject limit and the length of the current up-streak.
Tick size follows the IDX table: Rp 1 below 200, 2 below 500, 5 below 2,000, 10 below 5,000 and 25 above. The auto-reject limit is 35% of the previous close up to Rp 200, 25% up to Rp 5,000 and 20% above, floored to a valid tick. The trade plan is derived from both:
SL = floorTick(price − max(2 ticks, 0.4 × ATR)) TP1 = min(ARA, ceilTick(price + max(3 ticks, 0.6 × ATR))) TP2 = min(ARA, ceilTick(price + max(5 ticks, 1.0 × ATR))) R:R = (TP1 − entry) / (entry − SL)
The minimum tick distances matter most for cheap stocks, where 0.4 ATR can be smaller than one tick; rounding the stop down and the targets up keeps every level orderable; and capping at the ARA stops the plan from targeting a price the exchange will reject.
| Component | Weight | Rule |
|---|---|---|
| Liquidity | 25 | log10 of 20-day average value, from Rp 1 billion (0) to Rp 50 billion (full) |
| Volatility | 20 | ATR% rising to 8 points at 2% and 20 at 4%; full to 8%; then −2 per point, floor 8 |
| Relative volume | 20 | (RVOL − 0.8) / 2.2, clamped |
| Momentum | 20 | change/5% (±8) + close position (7) + above VWAP (5) |
| Tick cost | 15 | (2 − tick%) / 1.7, clamped |
| Adjustments | ± | +5 breakout, +3 foreign net buy, +3 also on the swing list; −12 within 2% of ARA, −5 if down 7% or more |
The volatility term is deliberately not monotonic: a scalper needs movement, but above 8% daily ATR the stock is more likely to gap through a stop than to trend. The tick-cost term prices the structural disadvantage of low-priced stocks, where the spread alone can exceed the target. Signal tags accompany each row in plain Indonesian — Breakout 5H, > VWAP, Asing net buy, Dekat ARA, Fraksi mahal — so the score can be read, not just trusted.
Opening a stock shows its candles with the stop and both targets drawn as price lines, and an order-flow panel built from the latest three hundred trades (three pages of the tape). Trades executed at the offer count as aggressive buying and those at the bid as aggressive selling; the HAKA share of traded value is reported for the whole window and for the last fifty trades, with a verdict of Buyer agresif at 60% or more, Seller agresif at 40% or less, and Seimbang between. The same pass computes the window VWAP, foreign net value from the buyer and seller type flags, the five largest net-buying and net-selling brokers, and the eight largest prints.
The technical screener works on the last 120 bars: simple averages of 5, 20 and 50 days, Wilder’s fourteen-day RSI, and MACD 12/26/9. It classifies trend (strong uptrend, uptrend, sideways, downtrend), flags golden and death crosses of the 20 and 50-day averages within five days, MACD crosses within three, RSI extremes, new 120-day highs, twenty-day breakouts on 1.5× volume and pullbacks to the 20-day average, and scores trend, RSI in the 50–70 band, positive MACD histogram, twenty-day return, volume and proximity to the high.
SwingMA200 looks for stocks resting just above a rising 200-day average: distance from the average (by default between 0 and 12%), its slope over about twenty days, the number of days above it, and the closest approach in the last ten days to detect a retest. A histogram in 3% bins shows where the whole universe sits relative to its 200-day line. The foreign-flow desk sums foreign net value over one, five, twenty and sixty days, measures the signed streak of consecutive buying or selling days, and reports foreign participation as a share of volume.
The backtester runs on up to 500 daily bars without any further API cost. Four strategies are provided — a moving-average cross (10/30), RSI reversal (buy below 30, sell above 65), a twenty-day breakout with a ten-day low exit, and a MACD cross. Every order is filled at the next day’s open, after the signal, with default fees of 0.15% to buy and 0.25% to sell, as charged by Indonesian brokers. The stop loss, 7% by default, exits at the lower of the open and the stop, so a gap down is booked at the open rather than at a price that never traded. The result is an equity curve against buy-and-hold, with maximum drawdown, win rate, profit factor and time in the market, and the page states its own assumptions: no slippage and no order queue.
The comparison desk rebases up to six stocks to zero and reports annualised volatility, a Sharpe ratio without a risk-free rate, maximum drawdown, the share of up days and pairwise correlations. The calculator sizes a position from the rupiah amount at risk, in lots of one hundred shares, computes break-even including both fees and rounded up to a tick, and draws the ARA and ARB ladder. The watchlist, calculator inputs and journal — with net-of-fee profit, per-strategy statistics and CSV import and export — are stored only in localStorage.
The largest concern is the metered quota. The public deployment has no password (one can be enabled with an environment variable) and no per-client rate limit; its protections are the two cache layers and the per-instance semaphore. A visitor can request a forced rescan that bypasses both caches, and query strings that vary the stock list or tape page also miss the CDN, so the daily quota can be spent by anyone who studies the API. When the optional password is enabled, it becomes a static token that never expires and travels as a URL parameter so it can form part of the CDN cache key — convenient, but it lands in logs and browser history, and the login route has no throttling.
On a serverless platform, the in-memory cache, the /tmp files, the quota counter and the semaphore all live per instance, so they are approximate across instances and disappear on cold starts. The market clock knows weekends but not exchange holidays, so on a holiday it treats the market as open and uses short cache lifetimes. The page sets no Content Security Policy, loads its chart library without a subresource-integrity hash, and inserts a few upstream fields and imported journal fields into the page without escaping. The engine is written as pure functions to be testable, but there are no tests yet, and the code is not under version control or published.
Finally, the tool’s view of the market is only as good as one upstream feed, and its automatic analysis text is that feed’s, displayed as received. Scores, signals and backtests describe the past; they are aids to a trader’s judgment, as the footer says, not recommendations.
IDX Trader Suite is eighteen desks with no dependencies because it asks little of its infrastructure: one handler, one function, a static front end, and a cache that knows when the exchange is open. Its value is in encoding the local market’s rules where general-purpose tools do not — a tick table and an auto-reject limit that shape every stop and target, a score that penalises the queue at the limit and the cost of a tick, and a tape reading in the vocabulary Indonesian traders already use.