Skip to content
96Astro API

Blog

How we measure accuracy against NASA JPL Horizons

· 96Astro API team · Calculation methods, Accuracy

A reproducible comparison of our planet positions with JPL Horizons from 1900 to 2100: what we measured, what we found, and what it does not cover.

"Accurate to the arc-second" is easy to write and hard to check. We wanted a claim anyone could check, so we compared our planet positions with NASA JPL Horizons, published the script, and committed the reference values next to it. This post explains what we measured, what we found, and what the comparison does not cover.

What we compared

  • Ours: the Swiss Ephemeris (through pyswisseph), called with the same flags the 96Astro calculation engine uses: geocentric, apparent positions (light-time, aberration, light deflection and nutation applied), tropical ecliptic of date.
  • Reference: JPL Horizons, the public ephemeris service of NASA's Jet Propulsion Laboratory, asked for the apparent ecliptic longitude of date as seen from the Earth's centre.
  • Bodies: the Sun, the Moon and the planets from Mercury to Pluto.
  • Moments: one per year from 1900 to 2100, 201 in all, with the day and hour of each year drawn from a fixed random seed, so every run compares the same moments.

Both sides are evaluated at the same Terrestrial Time, so the comparison measures the positions themselves. Delta T, the difference between atomic time and Earth-rotation time that every civil date goes through, is checked separately.

We compare tropical longitude because the ayanamsha (the offset to sidereal longitude) is a definition rather than a measurement: there is nothing for a reference ephemeris to check. Every sidereal position is the tropical one minus the ayanamsha of the request.

What we found

With the Swiss Ephemeris data files (the ones the live API uses), the largest difference from Horizons for any body at any of the 201 moments was 0.24 arc-seconds, and the mean about 0.09″. For scale, one arc-second is 1/3600 of a degree, a nakshatra pada is 12,000″ wide, and the Moon moves about half an arc-second every second.

Two details stood out:

  • The residual is the same for every body, and the same again when the Swiss Ephemeris reads JPL's own DE441 file. Because that run uses the same planetary data as Horizons, the small common residual comes from the reduction to apparent place (Horizons uses the IAU 1976/1980 precession and nutation models for this quantity; the Swiss Ephemeris uses newer ones), not from the planet positions.
  • The Swiss Ephemeris also has a built-in fallback, the Moshier ephemeris, used silently when the data files are missing. It is still good (at most about 2.2″, for Neptune and the Moon), but it is not what we intend to serve. So we probed the live API at moments where the two sources disagree by more than the API's output precision: its answers matched the data files.

Delta T: for the 127 past moments in the set, the Swiss Ephemeris value differed from Horizons' by 0.13 s on average and 0.68 s at most, which moves the Moon by at most about 0.37″. For future dates Delta T is a prediction in every ephemeris, so comparing two predictions would prove nothing, and we do not.

Run it yourself

The script is tools/accuracy/compare_jpl.py in our repository. It needs Python and pyswisseph; the Horizons answers are cached in a committed JSON file, so a re-run can be checked offline against the raw reference values, or refreshed from Horizons. A second script, probe_deployed.py, repeats the live-API check. The accuracy page shows the full per-body tables, regenerated from the script's output.

What this does not measure

Planet positions are the foundation, not the building. These figures say nothing about whether a dasha period, a yoga or a matching score follows its classical rule. Those are tested separately: by the calculation engine's own tests, and by an audit we ran while mapping every engine operation to the API in October 2026. That audit logged 39 findings, from misread fields to tables with wrong entries; each was fixed with a regression test or kept out of the public API until it was. Changes that alter results are listed in the changelog.

Why it matters for your app

If your users compare your app's chart with another program's, the planets will agree to well under an arc-second when the settings match. The differences they will see come from settings: the ayanamsha, the lunar node (true or mean), the house system and the time zone. Show those settings next to the chart, and most "your app is wrong" reports answer themselves.