Skip to main content

openephem

CI PyPI Python License: MIT

A permissive, Swiss-Ephemeris-validated ephemeris & chart engine. MIT-licensed, no AGPL — validated to arcseconds against Swiss Ephemeris across 1500 BC – 2500 AD.

Most "open" astrology libraries wrap pyswisseph, which is AGPL: use it in a network service and you must publish your whole app's source (or buy a commercial license). openephem is built entirely on permissive / public-domain sources (Skyfield MIT, JPL/NASA public domain, ESA Hipparcos, IANA tzdata, OSM), so you can ship it in a closed-source product with no copyleft obligation — and it's checked against swisseph so you don't sacrifice accuracy for freedom.

Install

pip install openephem            # core: planets + fixed stars + chart math
pip install "openephem[full]"    # + asteroids (spiceypy) + geocoding (geopy/tz)

Extras: openephem[asteroids] (Chiron/Ceres/Pallas/Juno/Vesta), openephem[geo] (place-name → lat/lon → timezone). Pure Python — no compiler.

Ephemeris data (JPL DE440 ~114 MB, Hipparcos, asteroid SPK kernels) is fetched at runtime, not shipped: Skyfield auto-downloads DE440/Hipparcos on first use; asteroid kernels are generated with openephem-fetch-kernels.

Quick start

from openephem import resolve, assemble, render_svg

moment = resolve(date=(1990, 5, 15), time=(14, 30), place="New York, NY")
chart  = assemble(moment, house_system="Placidus")     # tropical
svg    = render_svg(chart, title="Natal chart")

vedic  = assemble(moment, zodiac="sidereal", ayanamsa="lahiri")  # nakshatras + rashis

Everything degrades gracefully: without the ephemeris data (or the optional deps) you still get houses, angles, and aspects, plus warnings for what's missing.

What it computes

Bodies Sun–Pluto, Moon, mean/true Node, mean/osculating Lilith, Chiron + Ceres/Pallas/Juno/Vesta, 32 named fixed stars
Houses Placidus, Koch, Regiomontanus, Campanus, Whole Sign, Equal, Porphyry, + Asc/MC/Vertex/East Point
Aspects majors + optional minors, configurable orbs, applying/separating
Profections annual/monthly/daily profected place + sign + domicile ruler (Lord of the Year/Month/Day) — pure data, no interpretation
Firdaria Persian firdaria time-lords (sect-based order), major + sub periods with a dated timeline and the active lord(s) — pure data
Zodiacal Releasing Valens releasing from any of the seven Hermetic Lots (Fortune default), L1–L4 periods with Loosing-of-the-Bond and peak (angular-from-Fortune) flags — pure data
Decennials Valens decennial time-lords — seven 10y-9m general periods (Chaldean order from a start planet, default the Lot of Fortune's ruler), each sub-divided into planetary minor-year sub-periods — pure data
Vimśottarī daśā Vedic Moon-nakṣatra time-lords — balance at birth + nested Mahā/Antar/Pratyantar (and deeper) periods with dated timelines and the active lords — pure data
Vārga charts divisional (aṃśa) charts re-mapping each body's sidereal longitude to its divisional sign (D-9 navāṃśa, etc.) over an extensible rule registry — pure data
Zodiacs tropical and Vedic sidereal (Lahiri, Fagan-Bradley, Krishnamurti, Raman) + nakshatras/padas/rashis
Time & place timezone/DST/historical/LMT (IANA tzdata), Julian↔Gregorian calendar, offline coord→timezone, place geocoding
Output serializable chart dict, self-contained SVG chart wheel, zero-dep HTTP API

Validation — parity vs swisseph: PASS (1500 BC – 2500 AD)

12169 instants over ~4000 years, Skyfield candidate vs swisseph authority with ΔT aligned so the test isolates the ephemeris. Candidate ephemeris: JPL DE441 (covers −13200…+17191), so a single kernel spans the whole range. Across the full span the median error is ~0.15" and the 95th percentile ~2"; the table below is the worst case per group over the full 4000 years:

Group max err Group max err
Sun + Jupiter–Pluto < 3.5" Mean / True Node 8.5" / 38.6"
Mercury / Venus / Mars < 14" Mean / Oscu Lilith 51" / 4"
Moon < 80" (note) 32 fixed stars < 52" (Castor)
Chiron + Ceres/Pallas/Juno/Vesta < 11" (AD only, note) Houses (all 7) < 21"

Zero real sign-flips. Within 1900–2100 the whole set agrees to milliarcsec– tenths (Sun max 0.002", Moon 0.003", houses < 3.5", Castor 1.5" — the tight --profile modern gate); the table is the worst case over 4000 years, dominated by physical / documented antiquity effects (all astrologically negligible — 80" is 0.022° — none a code error), which grow with the baseline and so are larger than the year-0 figures:

  • ΔT diverges past ~2100 (extrapolation) and is ~3 h by year 0 (larger before) — a real timekeeping uncertainty, aligned out in the parity test; production uses Skyfield's ΔT (agrees with swisseph 1900–2100).
  • Moon / inner planets in deep antiquity — DE431 (swisseph) vs DE441 (candidate) ephemeris-vintage divergence, ~2–3× the year-0 size over a 3500-yr baseline.
  • Asteroids — validated over their JPL-Horizons kernel range (AD only; the kernels don't reach BC), JPL vs swisseph different orbit solutions drifting ≤ 11" (0.003°) over centuries.
  • Fixed stars — high-proper-motion multiples (Castor, Altair) as swisseph's vs Hipparcos's proper motions accumulate ~linearly over the 3500-yr baseline (Castor 29"→52", Altair 16"→46").

The extended range uses the widened-but-documented --profile ancient tolerances (the tight defaults still gate the modern 0–2500 run). Pre-1 AD sidereal time uses a dedicated long-term correction branch in houses.py — the modern polynomial diverges if extrapolated past year 0.

How the tricky quantities match swisseph (all coefficients fit offline vs swisseph — the numbers are astronomical facts, not copyrightable): osculating Node/Lilith from Skyfield's of-date ecliptic; mean Node/Lilith = Meeus mean elements + nutation-in-longitude (+ the 2·(perigee−node) term for Lilith); houses use apparent sidereal time (with a long-term precession correction) + true obliquity; asteroids read Horizons SPK type 21 (which jplephem can't) via spiceypy, then Skyfield does the of-date conversion.

Reproduce it yourself — see Development & validation below.

Chart API + SVG

openephem-serve --port 8080          # zero-dependency stdlib HTTP service

POST /chart → chart JSON + embedded SVG; POST /chart.svg → image; GET /health. Body:

{"date":[1990,5,15],"time":[14,30],"place":"New York, NY","house_system":"Placidus",
 "zodiac":"tropical"}

Run it behind your web server and add auth there — the service does none itself.

Layout

src/openephem/        # the installable, MIT, swisseph-free package
  planets_skyfield  asteroids_skyfield  fixed_stars   # position engines
  houses  aspects  vedic                              # chart math (pure stdlib)
  timeplace  chart  wheel  service  fetch_kernels     # pipeline + output
validation/           # dev tools — NOT installed; import pyswisseph (AGPL)
  generate_oracle.py  run_parity.py

Development & validation

The validation harness compares the permissive engines against swisseph. It is not part of the shipped package; running it is your own choice and needs pyswisseph (AGPL) installed separately:

pip install -e ".[full]" pyswisseph        # editable install + swisseph, locally
openephem-fetch-kernels --out ./kernels    # asteroid SPK kernels (Horizons)

# Modern range (0–2500), tight default tolerances — the CI gate:
python validation/generate_oracle.py --ephe-path ./ephe --fixed-stars \
    --start 0 --end 2500 --step-days 120 --out ./fixtures
python validation/run_parity.py --fixtures ./fixtures --de440 de440.bsp --kernel-dir ./kernels

# Extended range (1500 BC – 2500 AD): needs the full JPL DE441 kernel and the
# swisseph BC ".se1" files (…m06/m12/m18); use the widened, documented tolerances:
#   curl -O https://ssd.jpl.nasa.gov/ftp/eph/planets/bsp/de441.bsp   # 3.3 GB, covers −13200…+17191
python validation/generate_oracle.py --ephe-path ./ephe --fixed-stars \
    --start -1499 --end 2499 --step-days 120 --out ./fixtures_1500bc
python validation/run_parity.py --fixtures ./fixtures_1500bc --de440 de441.bsp \
    --kernel-dir ./kernels --profile ancient

Swiss Ephemeris .se1 data (AD blocks _00…_24 and the BC "minus" blocks …m06/m12/m18 for the ancient range) and sefstars.txt are not included — download them from the swisseph distribution. Asteroids are validated over their Horizons-kernel range only (AD; they don't reach BC, and the 3.3 GB DE441 exceeds CSPICE's 2 GB DAF limit — use the smaller de440s.bsp for the asteroid pass). No AGPL code or data is redistributed in this repo.

Tests

pip install -e ".[test]" && pytest

A fast, offline, data-free suite (houses, aspects, vedic, timeplace, wheel, chart — no network, no ephemeris files). Exactness tests that compare the house systems against swe_houses run automatically when pyswisseph is installed and skip otherwise, so the MIT test run needs no AGPL dependency. CI (GitHub Actions) runs it on Python 3.10–3.13 (Linux + Windows) and proves the wheel builds and installs.

Licensing

MIT (see LICENSE). Third-party libraries/data keep their own licenses (Skyfield MIT, spiceypy/CSPICE, Moshier PD, JPL/NASA PD, ESA Hipparcos, OpenStreetMap ODbL, IANA tzdata PD) — full notices in references.txt. Swiss Ephemeris (AGPL) is not distributed here; it is used only by the optional offline validation tools.

Out of scope (by design)

  • Interpretation / "reading" layer — turning a computed chart into meaning is editorial content, not computation; it belongs to the consuming application.
  • Site integration (WordPress, auth, hosting) — this is a self-contained engine + service; wiring it into a website is the consumer's job.

Authors

© 2026 Elizabeth Huston, Ph.D. and Noah Christian, Ph.D.
Contact: elpisastrology@gmail.com · elpisastrology.com and noahchristian@gmail.com

Metadata

Release files for openephem 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openephem 0.3.0
File Size Uploaded
openephem-0.3.0.tar.gz 85.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openephem 0.3.0
File Interpreter ABI Platform
openephem-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 164.8 kB

Release files / openephem-0.3.0.tar.gz

Download URL openephem-0.3.0.tar.gz
Size 85.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d337e3d4c0f834fe1e52a88804371ad0230908b5d0c8916fb3a664ec65fa046b
BLAKE2b-256 checksum
How to use checksums
31749393c01b0db59740018c67ef344fcef97fea322b5fec0d0895d32ab6eeb1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / openephem-0.3.0-py3-none-any.whl

Download URL openephem-0.3.0-py3-none-any.whl
Size 79.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3d7cf3836a5afbaa4931a446a34a7bbe84185aae5057c448ff92b9e7db9f01b3
BLAKE2b-256 checksum
How to use checksums
a63f2e0a1ba03d7b64dee7c75c1928513b2d294aee703284d4083080fabda4b2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page