Contents Lesson 9 of 16

6 min read · foundations

Why ask a server for a moving average you could compute yourself?

A moving average is a mean. Anyone can write it. So it is worth being clear about what /technical/{ticker} is actually for, before the rest of this unit shows you how to get it wrong.

What the endpoint offers

One required parameter, function, chosen from twenty values:

sma   ema   wma   volatility   stochastic   rsi    stddev
stochrsi   slope   dmi   adx   macd   atr   cci   sar
beta   bbands   splitadjusted   avgvol   avgvolccy

The response is an array of {date, ...} objects whose extra fields depend on the function: sma returns sma; macd returns macd, signal and divergence (not macd_signal and macd_hist, whatever you may have read — check the keys you actually received); bbands returns uband, mband and lband; stochastic returns k_values and d_values (read 29 September 2026; k_values is the slow %K); and splitadjusted returns split-adjusted OHLCV.

Real values for AAPL.US, on data through 2026-07-27, fetched on that date. Every one of them is computed on the adjusted column, so re-fetching the identical window after the next ex-dividend returns slightly different numbers — the reason is two sections down:

function=sma,  period=50    2026-07-27:  306.9922
function=sma,  period=200   last value:  276.0692
function=rsi,  period=14    last value:   67.2912
function=macd (12, 26, 9)   last value:    8.9310
function=atr,  period=14    last value:    8.1406
function=adx,  period=14    last value:   27.6999
Interactive line chart: AAPL.US (1Y)

The server is checkable, and you should check it

Ask for function=sma&period=2 and check it against two closes you pulled separately. Run in July 2026 the served value was 334.965, and the last two close values for AAPL.US were 336.91 on 2026-07-27 and 333.02 on 2026-07-24 — (336.91 + 333.02) ÷ 2 = 334.965 exactly.

Run the same request for the same two days now and the server returns 334.6763, which is not the mean of those closes. It is the mean of their adjusted_close values, 336.6197 and 332.7330. Nothing broke: a dividend went ex in the meantime, the adjusted column was rewritten, and the indicator moved with it.

So the audit answers two questions, and the second one only once the two columns have parted company: the formula, and which price column it ran on. The answer for the price indicators is adjusted_close, which makes them total-return figures. It is not universal — splitadjusted returns split-adjusted OHLCV, avgvol returns a share count, and splitadjusted_only=1 restricts selected functions to splits alone. Run the check against both columns per function, and know that it tells you nothing about the column on a window where no ex-date has passed since.

So why not compute them yourself?

Not because the arithmetic is hard. Because the alternative is: download and store full price history for every symbol you want an indicator on, keep it current, handle every corporate action correctly, and then reimplement each indicator's conventions — which smoothing does this EMA use, is this RSI Wilder's or a simple mean, does this ATR seed from a simple average? Those conventions differ between libraries, and two "RSI(14)" series from two sources routinely disagree in the third decimal and occasionally in the first.

One request per symbol per indicator moves all of that into one place with one set of conventions. That is the trade: less code and more consistency, in exchange for a dependency and a per-call cost.

The costs, stated plainly

One function per request. There is no multi-indicator response and no multi-symbol response. A dashboard covering 20 symbols with 3 indicators each is 60 requests, every refresh — and this endpoint is metered at 5 API calls per request, so it is 300 calls against the daily quota and 60 against the per-minute request ceiling. Those are two different currencies, as the API Foundations course sets out, and the arithmetic is worth doing before you build the dashboard rather than after.

What these numbers mean — when a 50-day average crossing a 200-day average is worth anyone's attention, what an RSI of 67 does and does not imply — is the subject of the Technical Analysis domain, and specifically its "Indicators that Matter" course. This unit is about obtaining them without changing them by accident.

Try it now

  1. The first table is /technical/AAPL.US?function=sma&period=2 over 24 to 27 July 2026, the same two sessions as above; the second is /eod for those sessions, both close columns. Average the two close values yourself, then the two adjusted_close values. Whichever one matches is the column the endpoint used — and if both match, no ex-date has passed since your window and the test has told you nothing yet.
Live API response: mda1 apple sma2 july 2026
Live API response: mda1 apple two closes july 2026
  1. Here is bbands with period=20 over 3 August to 25 September 2026. Confirm you get three fields per row rather than one. Then read the date of the first row: this endpoint computes only over the bars inside your window and does not reach back for the warm-up, so give it a from at least period bars earlier than you need. Count the sessions the window lost. Asking for a 200-day average across that same window returned 200 and an empty array on 28 September 2026, not an error.
Live API response: mda1 apple bbands window
  1. Count the requests your intended dashboard costs per refresh, then per day. Do it now, on paper.