Skip to content

Repository files navigation

Open accuracy benchmark for any astrology API. Public dataset, runnable Python, verified against NASA JPL Horizons DE441.

Astrology API Accuracy Benchmark

Median deviation 0.05 arcseconds across 210 planet positions and 21 birth charts vs NASA JPL Horizons. Maximum deviation 0.78 arcseconds. All 210 reference points within tolerance. See the latest run below.

Reproducible accuracy benchmark for any astrology API. Open dataset of birth charts, runnable Python, deviation measured per planet against NASA JPL Horizons DE441.

Free trial key API Sandbox Methodology More starters License

Latest run

Run 2026-09-29. 210 reference points, 210 within tolerance.

Metric Arcseconds Degrees
Median 0.05 0.0000
Mean 0.09 0.0000
p95 0.29 0.0001
Max 0.78 0.0002

Per-body maximum across all charts. Read this table, not just the pass count: the pass bar is a vendor-neutral floor, so a single body drifting well above its usual value can still pass. Per-body is where a regression shows up first.

Body Max deviation Worst-case chart
Uranus 0.78 arcsec Albert Einstein
Saturn 0.34 arcsec Albert Einstein
Pluto 0.32 arcsec Albert Einstein
Sun 0.30 arcsec Albert Einstein
Mercury 0.30 arcsec Albert Einstein
Venus 0.30 arcsec Albert Einstein
Mars 0.30 arcsec Albert Einstein
Jupiter 0.29 arcsec Albert Einstein
Moon 0.26 arcsec Albert Einstein
Neptune 0.23 arcsec Albert Einstein

The committed results.csv is the snapshot from this run, one row per reference point.

Highlights:

  • Every one of the 210 points is inside 0.8 arcseconds, across charts spanning 1879 to 2011, six continents, both hemispheres, the equator, three high-latitude locations above 60 degrees, half-hour timezone offsets, two DST edge cases, the Samoa 2011 calendar skip, and the Y2K rollover.
  • RoxyAPI reads the NASA JPL DE440 ephemeris directly, the same family of integrations JPL Horizons serves, so what remains is not an ephemeris difference.
  • The worst case on every body is the 1879 chart, and that is a known frame-model term. Horizons reports ecliptic longitudes of date on the IAU 1976/1980 precession and nutation model; the IAU 2006 precession and IAU 2000B nutation model used by current astronomical and astrological software differs from it by about 0.35 arcseconds per century away from the year 2000. The chart furthest from 2000 carries the most of it.
  • The Moon is as tight as the planets. It moves about 13 degrees per day, so any drift in the resolved UTC moment would show up here first, and it does not: this is the direct evidence that the timezone-conversion layer is correct.
  • Pre-1900 charts (Einstein 1879 on LMT, Boston 1900), DST edge cases (New York 2005 spring-forward into the non-existent 0230 hour, fall-back into the ambiguous 0130 hour) and high-latitude charts (Reykjavik 64N, Tromso 70N, Anchorage 61N, Ushuaia 55S) are all inside 0.8 arcseconds.
  • The reference carries seven decimal degrees, about 0.0004 arcseconds, and results.csv keeps the same seven, so every figure above is a measured difference from JPL Horizons rather than rounding in the harness.

Reproduce it with your own key, and keep the block above honest at the same time:

python3 benchmark.py --update-readme

What this benchmark validates

This benchmark validates two specific layers of any astrology API.

1. Timezone conversion layer. Given a local birth time and a timezone, a decimal offset or an IANA zone name, does the API resolve the same UTC moment that NASA JPL Horizons resolves? Wrong timezone math is the most common silent failure in astrology APIs, and it produces wrong planet positions even when the underlying ephemeris is correct.

2. Ephemeris layer. For the correct UTC moment, does the API compute geocentric ecliptic planet longitudes that match NASA JPL Horizons DE441, the authoritative reference for solar system body positions?

How the test runs

For every chart in charts.csv:

  1. Read the local birth time, latitude, longitude, and timezone (a decimal offset or an IANA zone name).
  2. Convert local time plus offset to a UTC moment using standard datetime math.
  3. Query NASA JPL Horizons for the geocentric ecliptic longitude of each body at that UTC moment. These are the reference values written to expected.csv.
  4. POST the original local-time inputs to the target astrology API. The API performs its own timezone conversion and ephemeris computation.
  5. Compare the API output to the JPL reference for each body. Compute the angular deviation in arcseconds and degrees, with 0/360 wraparound handled correctly.

Worked example: Obama natal chart

Step Value
Local birth 1961-08-04 19:24:00, Honolulu HI, timezone -10
UTC moment 1961-08-05 05:24:00 UTC
JPL Horizons Sun longitude 132.5479089 degrees (Leo 12.5479089)
RoxyAPI Sun longitude 132.5479205 degrees
Deviation 0.04 arcseconds (0.00001 degrees), within the 0.01 degree tolerance

Tolerance bands

Body Tolerance Why
Sun, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto 0.01° (36 arcsec) Wide enough for the legitimate arcsecond-level disagreement between two good ephemeris implementations, tight enough to fail an API using a geometric rather than an apparent ephemeris
Moon 0.02° (72 arcsec) The Moon moves about 13°/day, so this absorbs a couple of minutes of birth-time interpretation

These bands are a vendor-neutral pass bar, not a regression guard. They are deliberately NOT set to the measured worst case of any one implementation: a band sized to one engine is a bar only that engine clears, which would make a benchmark that invites you to point it at a competitor dishonest. The bar catches the class of defect that matters, wrong timezone resolution, a geometric ephemeris, a wrong-epoch element set. For regressions, read the per-body table in the latest run: a body drifting from 0.1 to 20 arcseconds still passes a 36 arcsecond bar.

What this benchmark does not validate

The benchmark tests the foundational planet-position layer. It deliberately does not validate:

  • House cusps (Placidus, Koch, Whole Sign, Equal). Observer-frame angles computed from sidereal time and obliquity, not body positions. JPL does not publish them.
  • Ascendant and Midheaven. Same reason as house cusps. Sensitive to exact birth-time precision.
  • Ayanamsa and sidereal zodiac. Domain-specific transforms applied above the planet layer.
  • Aspects, dashas, doshas, interpretations. Derived calculations layered above raw positions.

Validation for those layers lives in the broader RoxyAPI test suite documented at roxyapi.com/methodology, verified against domain-specific authorities.

Quick start

git clone https://github.com/RoxyAPI/astrology-api-benchmark.git
cd astrology-api-benchmark

export API_KEY=your_roxyapi_key   # https://roxyapi.com/contact for a free test key

python3 benchmark.py

Two ways to test free:

The benchmark script uses Python 3 standard library only, no pip install required.

Run against a different API

The script speaks plain HTTP. Anything that accepts { date, time, latitude, longitude, timezone } as JSON and returns a { planets: [{ name, sign, degree | longitude }] } shape will work.

python3 benchmark.py \
  --base-url https://example-api.com/api \
  --natal-path /astrology/natal-chart

If the response shape differs, adapt extract_body_longitude in benchmark.py, the only place in the script that knows the response shape.

Why the chart names matter

JPL Horizons does not know who anyone is. Feed it (date, time, latitude, longitude, timezone), it returns geocentric ecliptic longitudes. The chart label is human metadata. We use named AA-rated celebrity charts so any reader can cross-check our birth-time inputs against the same astro-databank entries we sourced them from. If our chart inputs disagree with the public record, our credibility falls regardless of internal mathematical consistency.

The synthetic edge-case charts (DST transitions, polar latitudes, pre-1900 dates, half-hour offsets, calendar-skip days) are explicitly labeled as test fixtures designed to exercise specific timezone-handling conditions. Their value is coverage, not celebrity provenance.

Reference dataset

Reference values are pulled from NASA JPL Horizons DE441 for 21 charts: 8 named celebrity charts plus 13 synthetic edge-case scenarios. Each longitude in expected.csv keeps the full precision Horizons publishes, seven decimal degrees, about 0.0004 arcseconds. Rodden Ratings cite the astro-databank data-quality system.

Chart Birth Rodden
Barack Obama Aug 4, 1961, 7:24 PM, Honolulu HI AA
Beyonce Knowles Sep 4, 1981, 9:47 PM, Houston TX AA
Albert Einstein Mar 14, 1879, 11:30 AM, Ulm Germany (LMT) AA
Marilyn Monroe Jun 1, 1926, 9:30 AM, Los Angeles CA AA
Steve Jobs Feb 24, 1955, 7:15 PM, San Francisco CA AA
Princess Diana Jul 1, 1961, 7:45 PM, Sandringham UK A
John F Kennedy May 29, 1917, 3:00 PM, Brookline MA A
Elon Musk Jun 28, 1971, 7:30 AM, Pretoria South Africa B

Plus 13 synthetic charts covering Reykjavik (64°N), Tromsø (70°N), Anchorage (61°N), Ushuaia (-55°S), Sydney AEDT, Tokyo JST, Mumbai IST half-hour offset, Quito on the equator, New York DST spring-forward + fall-back, Boston 1900 pre-WW1 era, Greenwich Y2K rollover, Samoa post-2011 calendar skip.

That is 210 reference points (10 planets × 21 charts). Adding more charts is one-line work in charts.csv plus a re-run of regenerate_expected.py against JPL Horizons. See Adding charts below.

Adding charts

Two steps per chart:

  1. Append a row to charts.csv with chart_id,name,date,time,latitude,longitude,timezone,rodden_rating,description. Use AA-rated birth data (timed and verified) when possible. C-rated and lower data is too noisy for accuracy benchmarks.
  2. Run python3 regenerate_expected.py. It queries JPL Horizons for every body at the exact moment of every chart and rewrites expected.csv.

The regeneration script is rate-limited at 1 query/second to stay courteous to the JPL Horizons API. 10 bodies per chart, so a fresh chart adds about 10 seconds of regeneration time.

python3 regenerate_expected.py

Roadmap for the dataset itself:

  • DST boundary births (spring forward, fall back, both ambiguous and non-existent times)
  • Pre-1970 dates (LMT and colonial offset edge cases)
  • High and polar latitudes (above 66° N/S, where Placidus degenerates)
  • Southern hemisphere births
  • Vedic / sidereal extension (separate expected-vedic.csv referenced against DrikPanchang)

PRs that grow the dataset along any of these axes are welcome.

Why this exists

Astrology APIs make accuracy claims, but almost none publish a reproducible benchmark. The reader is asked to trust a methodology page or a tolerance number with no way to verify it. This repo flips that: a public dataset of chart inputs, expected planet longitudes pulled directly from NASA JPL Horizons (the authoritative ephemeris reference for solar system bodies), and a Python script that anyone can run against any astrology API to see the actual deviation.

It is also vendor-agnostic. The default target is RoxyAPI, but swapping --base-url and --natal-path points the same script at any HTTP API that returns planet longitudes for a natal chart.

How this fits with RoxyAPI

This is the reproducible companion to the 828 gold-standard tests methodology and the /methodology page. The methodology page describes how RoxyAPI verifies its own calculations. This repo turns that into something anyone can run, fork, extend, or point at a different API.

RoxyAPI gives you natal charts, kundli, daily horoscopes, forecast, human design, Chinese astrology, feng shui, Mesoamerican astrology, Vastu, numerology, Kabbalah, tarot, biorhythm, Ayurveda, I Ching, crystals, dreams, and angel numbers behind one API key. Verified against NASA JPL Horizons. Try the API sandbox without signing up, request a free trial key, or see pricing.

Contributing

PRs welcome for:

  • Additional AA-rated chart fixtures (with adversarial coverage from the roadmap above)
  • Vedic / sidereal extension (separate expected-vedic.csv against DrikPanchang)
  • Adapters for response shapes other than the default
  • Visualization scripts (deviation histograms, per-body box plots)

License

MIT. Birth data is publicly known. Reference values are pulled from JPL Horizons DE441 and cited per row in expected.csv.

About

Reproducible MIT-licensed accuracy benchmark for any astrology API. 210 planet positions across 21 charts verified against NASA JPL Horizons DE441.

Topics

Resources

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages