Skip to main content

Library to compute astronomical bodies positions and planetary aspects between them

Project description

Ketu

PyPI version Python Versions Coverage License: MIT

Ketu is a pure NumPy library for astronomical calculations focused on planetary positions, aspects, and cycle analysis. With no dependencies beyond NumPy, Ketu provides fast, accurate calculations suitable for astrology, biodynamic calendars, and machine learning applications.

This library was originally designed to generate biodynamic calendars and time series based on astrological aspects. It can be used as a basis for building astrology software.

For the full version history and per-release changes, see CHANGELOG.md; for migration recipes between minor versions, see UPGRADING.md.

Features

  • Planetary positions for 14 bodies (Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, Rahu/Mean Node, True North Node, Lilith, Chiron)
  • Data-driven aspect engine — a declarative table of 14 major/minor aspects (Conjunction, Opposition, Trine, Square, Sextile, Quincunx, ... through Quintile, Novile, Decile); harmonic-based selection via aspects_for_harmonics([...]). The default set is the 7 half-circle aspects; full-circle minors are opt-in.
  • Aspect windows - Find when aspects begin, peak, and end
  • Transit calculations - Track transits to natal positions
  • Retrogradation detection and planet motion helpers
  • Time system conversions (UTC, Julian Day)
  • Orb system based on Abu Ma'shar (787-886) and Al-Biruni (973-1050)
  • Interactive CLI for a non-programmatic workflow
  • Python API that fits into your own tooling
  • Pure NumPy - Single dependency for maximum portability and performance

Installation

From PyPI (recommended)

pip install ketu

From source

git clone https://github.com/alkimya/ketu.git
cd ketu
pip install -e .

Quick Start

Interactive mode (CLI)

Run the command below and answer the prompts:

ketu

You will be asked for:

  • A date (ISO format: 2020-12-21)
  • A time (ISO format: 19:20)
  • A timezone (for example Europe/Paris)

The program prints:

  • Positions of every celestial body with zodiac signs
  • All inter-planet aspects with their orbs

Programmatic usage

from datetime import datetime
from zoneinfo import ZoneInfo
import ketu

# Define a datetime
dtime = datetime(2020, 12, 21, 19, 20, tzinfo=ZoneInfo("Europe/Paris"))
jday = ketu.utc_to_julian(dtime)

# Display planetary positions
ketu.print_positions(jday)

# Display aspects
ketu.print_aspects(jday)

Advanced Examples

Compute a planet position

from datetime import datetime
from zoneinfo import ZoneInfo
import ketu

dtime = datetime(2024, 10, 26, 12, 0, tzinfo=ZoneInfo("UTC"))
jday = ketu.utc_to_julian(dtime)

sun_long = ketu.long(jday, 0)
print(f"Sun longitude: {sun_long:.2f}°")

sign, deg, mins, secs = ketu.body_sign(sun_long)
print(f"Position: {ketu.signs[sign]} {deg}°{mins}'{secs}\"")

Check whether a planet is retrograde

import ketu

# Mars (body id = 4)
if ketu.is_retrograde(jday, 4):
    print("Mars is retrograde")
else:
    print("Mars is direct")

Find aspect windows

from datetime import datetime, timedelta
import ketu

# Find Sun-Moon conjunction window
start = ketu.utc_to_julian(datetime(2025, 1, 1, tzinfo=ZoneInfo("UTC")))
end = ketu.utc_to_julian(datetime(2025, 12, 31, tzinfo=ZoneInfo("UTC")))

windows = ketu.find_aspect_window(start, end, body1=0, body2=1, aspect=0)

for window in windows:
    print(f"Conjunction from {ketu.julian_to_utc(window.begin_jd)} "
          f"to {ketu.julian_to_utc(window.end_jd)}")
    print(f"  Exact: {ketu.julian_to_utc(window.exact_jd)}")

Calculate transits to natal positions

import ketu

# Natal positions
natal_date = ketu.utc_to_julian(datetime(1990, 1, 15, 12, 0, tzinfo=ZoneInfo("UTC")))
natal_positions = ketu.get_natal_positions(natal_date)

# Find transits for a specific date
transit_date = ketu.utc_to_julian(datetime(2025, 11, 22, 12, 0, tzinfo=ZoneInfo("UTC")))
transits = ketu.compare_dates_transits(natal_positions, transit_date)

for transit in transits:
    print(f"{transit.transiting_body} {transit.aspect} natal {transit.natal_body}")

Ephemeris Cache (v0.4.0)

For ML pipelines and high-frequency lookups, use the ephemeris cache for 1000x faster position lookups:

from ketu.cache import EphemerisCache
from datetime import datetime, timezone

# Initialize cache (stores in ~/.ketu/ephemeris_cache/)
cache = EphemerisCache()

# Pre-compute a range of months (one-time operation)
# ~1-2 seconds per month, persisted to disk
for year in range(2020, 2026):
    for month in range(1, 13):
        cache.ensure_month(year, month)

# Fast O(1) lookups (0.006ms vs 10ms computation)
timestamp = datetime(2025, 6, 15, 14, 30, tzinfo=timezone.utc)

# Get single body position (lon, lat, distance, speed)
sun_pos = cache.get_position(timestamp, body_id=0)
print(f"Sun longitude: {sun_pos[0]:.2f}°")

# Get all 14 bodies at once
all_positions = cache.get_all_positions(timestamp)
# Returns dict: {body_id: (lon, lat, dist, speed), ...}

CLI for pre-computing cache:

# Pre-compute 2020-2030 (takes ~3-4 minutes)
python scripts/precompute_ephemeris.py --years 2020-2030

# Single year
python scripts/precompute_ephemeris.py --year 2025

# Force recompute
python scripts/precompute_ephemeris.py --year 2025 --force

Performance:

  • Lookup: 0.006ms (with interpolation)
  • Compute: 10ms
  • Speedup: 1000x
  • Disk usage: ~50KB per month

Documentation

The full documentation is hosted on Read the Docs.

Included sections:

  • Installation: detailed setup instructions
  • Quickstart: guided tour of the basics
  • Concepts: astrological and astronomical background
  • API Reference: all functions documented
  • Examples: advanced usage patterns
  • Developer Guide: architecture and performance details

Documentation Quality Gates

Documentation quality is enforced by CI on every push:

  • interrogate ≥95% (blocking) — every public function, class, and module has a docstring.
  • numpydoc validate (warning, blocking from v1.2.0) — docstrings follow the NumPy convention.

Run both locally before pushing: make doc-gates.

Requirements

  • Python 3.10 or higher
  • numpy ≥ 1.20.0 — numerical routines and arrays

That's it! Ketu has no other dependencies.

Supported bodies

Body ID Orb Average speed (°/day)
Sun 0 12° 0.986
Moon 1 12° 13.176
Mercury 2 1.383
Venus 3 10° 1.200
Mars 4 0.524
Jupiter 5 10° 0.083
Saturn 6 10° 0.034
Uranus 7 0.012
Neptune 8 0.007
Pluto 9 0.004
Rahu (Mean Node) 10 -0.052954
Ketu (Mean South Node) 11 -0.052954
Lilith (Black Moon) 12 0.113
Chiron 13 0.019

Supported aspects

Aspect Angle Orb coefficient
Conjunction 1
Semi-sextile 30° 1/6
Sextile 60° 1/3
Square 90° 1/2
Trine 120° 2/3
Quincunx 150° 5/6
Opposition 180° 1

These 7 half-circle aspects (harmonics 1, 2, 3, 6) are the library default. The full table also carries 7 full-circle minor aspects (Quintile, Decile, Novile, Binovile, Quadrinovile, Biquintile, Tredecile — harmonics 5, 9, 10), which are opt-in via aspects_for_harmonics([...]) or the EXTENDED preset.

Performance

The pure NumPy implementation provides excellent performance:

  • Time series (365 days): 208x faster than loop-based approach
  • Aspect calculations: 14.55x faster with vectorization
  • Single planet position: 67x faster with optimized algorithms
  • Moon position: 59x faster with custom perturbation calculations

See docs/en/performance.md for detailed benchmarks.

Accuracy

The implementation provides good accuracy for astrological purposes:

  • Planetary positions: ±0.1° for inner planets, ±0.5° for outer planets
  • Moon position: ±0.5° (includes major perturbations)
  • Aspect timing: ±2 minutes for exact aspects
  • Best accuracy range: 1800-2200 CE

Architecture

ketu/
├── __init__.py          # Main API
├── core.py              # Data structures (bodies, aspects, signs)
├── calculations.py      # High-level calculation functions
├── complex.py           # Complex-number engine for cycle analysis
├── display.py           # Display utilities
├── lunar_calendar.py    # Biodynamic / lunar calendar helpers
├── aspects/             # Data-driven aspect engine (presets, harmonics)
├── charts/              # compute_chart / CHART_DTYPE abstraction
├── houses/              # Six house systems (Placidus, Whole Sign, ...)
├── synastry/            # Inter-chart aspect cross-products
├── composite/           # Midpoint composite charts
├── returns/             # Solar and lunar returns
├── parts/               # Arabic Parts framework
├── cycles/              # Planetary cycle series (NumPy structured arrays)
├── cli/                 # Interactive command-line interface
├── cache/               # High-performance ephemeris cache
├── data/                # Embedded Chiron Chebyshev coefficients (.npz)
└── ephemeris/           # Astronomical calculations
    ├── time.py          # Time conversions
    ├── orbital.py       # Orbital mechanics (re-export hub)
    ├── coordinates.py   # Coordinate transformations
    ├── planets.py       # Planetary position calculations (per-body strategies)
    └── chiron.py        # Pure-NumPy Chiron Chebyshev evaluator

Roadmap

  • Removal of dependency on pyswisseph
  • Pure numpy implementation of planetary calculations
  • Search for exact aspects between two dates
  • Aspect windows and timing
  • Transit calculations
  • High-performance ephemeris cache
  • Complex number engine for cycle analysis
  • Configurable aspects and six house systems
  • Chart abstraction (compute_chart / CHART_DTYPE)
  • Relational charts (synastry, midpoint composite)
  • Predictive charts (solar and lunar returns)
  • Arabic Parts framework
  • Chiron as the 14th body (pure-NumPy Chebyshev evaluation)
  • Data-driven aspect engine with harmonic-based selection
  • Equatorial declination δ, montant/descendant, OOB helpers (declination, is_ascending_declination, is_out_of_bounds)
  • Dynamic harmonic CLI (--harmonics h7) + H{h}-{k} naming contract + find_aspect_timing(dyn_coef=)
  • Declination aspects — parallels & contra-parallels on the δ axis (ketu.declination: find_declination_aspects, declination_aspect_masks)
  • Fictitious-point longitude orbs — Rahu/Ketu/Lilith orb 0° → 2°; tautological Rahu-Ketu Opposition suppressed (_is_tautological_node_opposition)

Contribution

Contributions are welcome! Feel free to:

  • Open an issue to report a bug or suggest a feature
  • Submit a pull request
  • Improve the documentation

See CONTRIBUTING.md for more details.

License

This project is licensed under MIT. See the LICENSE file for more details.

Contact

Loc Cosnier - @alkimya

Project: https://github.com/alkimya/ketu

Acknowledgments

  • solarsystem by Ioannis Nasios — The pure Python astronomy library that inspired and served as the mathematical foundation for Ketu's NumPy ephemeris engine. Kepler's equation solver, perturbation terms, coordinate transformations, and Moon calculations all trace back to this elegant, dependency-free library. Thank you!
  • Claude by Anthropic — The pure NumPy rewrite, from orbital mechanics to aspect detection, was developed in collaboration with Claude. Architecture, algorithms, tests, documentation were produced through extensive pair programming sessions.
  • GSD (Get Shit Done) — The project management workflow that structured the development of Ketu v1.0.0 into phases with research, planning, execution, and verification steps.
  • Original orbital calculations based on Paul Schlyter's work
  • Inspired by the accuracy and reliability of Swiss Ephemeris
  • Built with the power of NumPy for scientific computing

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ketu-1.7.0.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ketu-1.7.0-py3-none-any.whl (804.9 kB view details)

Uploaded Python 3

File details

Details for the file ketu-1.7.0.tar.gz.

File metadata

  • Download URL: ketu-1.7.0.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ketu-1.7.0.tar.gz
Algorithm Hash digest
SHA256 99939a9d955cc2a6a2f29cbae4f970945320d59f26b5c5d66d8f05d5a056bb9c
MD5 2c9b6914cb5c275105f4b983e307de7c
BLAKE2b-256 02bdcc77694c16e3410ea3aae0d25bc280cfb9e0b525575fecbaaabb130249da

See more details on using hashes here.

Provenance

The following attestation bundles were made for ketu-1.7.0.tar.gz:

Publisher: publish.yml on alkimya/ketu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ketu-1.7.0-py3-none-any.whl.

File metadata

  • Download URL: ketu-1.7.0-py3-none-any.whl
  • Upload date:
  • Size: 804.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ketu-1.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 710109285b7ef4e932dbba94957d5aa8b6cb0b5675f0166f0c0d0cc8ddd4a93e
MD5 879bfc0f9219a1b243884b7d334249ed
BLAKE2b-256 4ebe3c167fc29c86fbdb5760946156dd52d420ff299d4b5ed6305888de3bc35c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ketu-1.7.0-py3-none-any.whl:

Publisher: publish.yml on alkimya/ketu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page