kundali-chart-mcp 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/azure-function/function_app.py +93 -0
- package/azure-function/host.json +15 -0
- package/azure-function/kundali_bridge.py +952 -0
- package/azure-function/python/kundali_lib/__init__.py +1 -0
- package/azure-function/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/ephemeris.py +30 -0
- package/azure-function/python/kundali_lib/geocoder.py +82 -0
- package/azure-function/python/kundali_lib/vedic/__init__.py +1 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/arishta.py +465 -0
- package/azure-function/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/azure-function/python/kundali_lib/vedic/avasthas.py +292 -0
- package/azure-function/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/azure-function/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/azure-function/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/azure-function/python/kundali_lib/vedic/chart.py +126 -0
- package/azure-function/python/kundali_lib/vedic/chart_types.py +338 -0
- package/azure-function/python/kundali_lib/vedic/compatibility.py +705 -0
- package/azure-function/python/kundali_lib/vedic/constants.py +108 -0
- package/azure-function/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/azure-function/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/azure-function/python/kundali_lib/vedic/doshas.py +453 -0
- package/azure-function/python/kundali_lib/vedic/gandanta.py +213 -0
- package/azure-function/python/kundali_lib/vedic/gochara.py +277 -0
- package/azure-function/python/kundali_lib/vedic/hora.py +263 -0
- package/azure-function/python/kundali_lib/vedic/houses.py +30 -0
- package/azure-function/python/kundali_lib/vedic/jaimini.py +361 -0
- package/azure-function/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/azure-function/python/kundali_lib/vedic/kartari.py +243 -0
- package/azure-function/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/azure-function/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/azure-function/python/kundali_lib/vedic/muhurta.py +414 -0
- package/azure-function/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/azure-function/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/azure-function/python/kundali_lib/vedic/panchanga.py +297 -0
- package/azure-function/python/kundali_lib/vedic/planets.py +55 -0
- package/azure-function/python/kundali_lib/vedic/shadbala.py +500 -0
- package/azure-function/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/azure-function/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/azure-function/python/kundali_lib/vedic/tajaka.py +482 -0
- package/azure-function/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/azure-function/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/azure-function/python/kundali_lib/vedic/yogas.py +935 -0
- package/azure-function/python/kundali_lib/vedic/zodiac.py +42 -0
- package/azure-function/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/azure-function/requirements.txt +9 -0
- package/index.js +747 -0
- package/kundali-chart-mcp.js +159 -0
- package/kundali_bridge.py +952 -0
- package/package.json +41 -0
- package/python/kundali_lib/__init__.py +1 -0
- package/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/python/kundali_lib/ephemeris.py +30 -0
- package/python/kundali_lib/geocoder.py +82 -0
- package/python/kundali_lib/vedic/__init__.py +1 -0
- package/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/arishta.py +465 -0
- package/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/python/kundali_lib/vedic/avasthas.py +292 -0
- package/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/python/kundali_lib/vedic/chart.py +126 -0
- package/python/kundali_lib/vedic/chart_types.py +338 -0
- package/python/kundali_lib/vedic/compatibility.py +705 -0
- package/python/kundali_lib/vedic/constants.py +108 -0
- package/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/python/kundali_lib/vedic/doshas.py +453 -0
- package/python/kundali_lib/vedic/gandanta.py +213 -0
- package/python/kundali_lib/vedic/gochara.py +277 -0
- package/python/kundali_lib/vedic/hora.py +263 -0
- package/python/kundali_lib/vedic/houses.py +30 -0
- package/python/kundali_lib/vedic/jaimini.py +361 -0
- package/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/python/kundali_lib/vedic/kartari.py +243 -0
- package/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/python/kundali_lib/vedic/muhurta.py +414 -0
- package/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/python/kundali_lib/vedic/panchanga.py +297 -0
- package/python/kundali_lib/vedic/planets.py +55 -0
- package/python/kundali_lib/vedic/shadbala.py +500 -0
- package/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/python/kundali_lib/vedic/tajaka.py +482 -0
- package/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/python/kundali_lib/vedic/yogas.py +935 -0
- package/python/kundali_lib/vedic/zodiac.py +42 -0
- package/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/remote-server.js +590 -0
- package/requirements.txt +8 -0
- package/setup.sh +218 -0
|
@@ -0,0 +1,935 @@
|
|
|
1
|
+
"""Identification of major Vedic astrological Yogas from a birth chart."""
|
|
2
|
+
|
|
3
|
+
# ---------------------------------------------------------------------------
|
|
4
|
+
# Reference data
|
|
5
|
+
# ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
RASHIS = [
|
|
8
|
+
"Aries",
|
|
9
|
+
"Taurus",
|
|
10
|
+
"Gemini",
|
|
11
|
+
"Cancer",
|
|
12
|
+
"Leo",
|
|
13
|
+
"Virgo",
|
|
14
|
+
"Libra",
|
|
15
|
+
"Scorpio",
|
|
16
|
+
"Sagittarius",
|
|
17
|
+
"Capricorn",
|
|
18
|
+
"Aquarius",
|
|
19
|
+
"Pisces",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
RASHI_LORDS = {
|
|
23
|
+
"Aries": "Mars",
|
|
24
|
+
"Taurus": "Venus",
|
|
25
|
+
"Gemini": "Mercury",
|
|
26
|
+
"Cancer": "Moon",
|
|
27
|
+
"Leo": "Sun",
|
|
28
|
+
"Virgo": "Mercury",
|
|
29
|
+
"Libra": "Venus",
|
|
30
|
+
"Scorpio": "Mars",
|
|
31
|
+
"Sagittarius": "Jupiter",
|
|
32
|
+
"Capricorn": "Saturn",
|
|
33
|
+
"Aquarius": "Saturn",
|
|
34
|
+
"Pisces": "Jupiter",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
EXALTATION = {
|
|
38
|
+
"Sun": "Aries",
|
|
39
|
+
"Moon": "Taurus",
|
|
40
|
+
"Mars": "Capricorn",
|
|
41
|
+
"Mercury": "Virgo",
|
|
42
|
+
"Jupiter": "Cancer",
|
|
43
|
+
"Venus": "Pisces",
|
|
44
|
+
"Saturn": "Libra",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
DEBILITATION = {
|
|
48
|
+
"Sun": "Libra",
|
|
49
|
+
"Moon": "Scorpio",
|
|
50
|
+
"Mars": "Cancer",
|
|
51
|
+
"Mercury": "Pisces",
|
|
52
|
+
"Jupiter": "Capricorn",
|
|
53
|
+
"Venus": "Virgo",
|
|
54
|
+
"Saturn": "Aries",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Reverse map: which planet gets exalted in a given sign
|
|
58
|
+
EXALTED_IN_SIGN = {v: k for k, v in EXALTATION.items()}
|
|
59
|
+
|
|
60
|
+
KENDRA_HOUSES = {1, 4, 7, 10}
|
|
61
|
+
TRIKONA_HOUSES = {1, 5, 9}
|
|
62
|
+
DUSTHANA_HOUSES = {6, 8, 12}
|
|
63
|
+
|
|
64
|
+
CLASSICAL_PLANETS = {"Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"}
|
|
65
|
+
BENEFIC_PLANETS = {"Moon", "Mercury", "Jupiter", "Venus"}
|
|
66
|
+
NODES = {"Rahu", "Ketu"}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------------------------
|
|
70
|
+
# Internal helpers
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _get_planet(positions: list, name: str) -> dict | None:
|
|
75
|
+
for p in positions:
|
|
76
|
+
if p["name"] == name:
|
|
77
|
+
return p
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _planet_house(positions: list, name: str) -> int | None:
|
|
82
|
+
p = _get_planet(positions, name)
|
|
83
|
+
return p["house"] if p else None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _planet_rashi(positions: list, name: str) -> str | None:
|
|
87
|
+
p = _get_planet(positions, name)
|
|
88
|
+
return p.get("rashi") if p else None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _house_lord(houses: dict, house_num: int) -> str:
|
|
92
|
+
"""Return the planet that lords the given house number."""
|
|
93
|
+
rashi = houses.get(f"House_{house_num}")
|
|
94
|
+
if rashi:
|
|
95
|
+
return RASHI_LORDS.get(rashi, "")
|
|
96
|
+
return ""
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _house_rashi(houses: dict, house_num: int) -> str:
|
|
100
|
+
return houses.get(f"House_{house_num}", "")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _nth_house_from(base: int, n: int) -> int:
|
|
104
|
+
"""Return the house number that is n houses away from base (1-indexed)."""
|
|
105
|
+
return ((base - 1 + n - 1) % 12) + 1
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _planets_in_house(positions: list, house_num: int) -> list:
|
|
109
|
+
return [p["name"] for p in positions if p["house"] == house_num]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _kendra_houses_from(base_house: int) -> set:
|
|
113
|
+
return {
|
|
114
|
+
_nth_house_from(base_house, 1),
|
|
115
|
+
_nth_house_from(base_house, 4),
|
|
116
|
+
_nth_house_from(base_house, 7),
|
|
117
|
+
_nth_house_from(base_house, 10),
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _yoga_dict(
|
|
122
|
+
name: str,
|
|
123
|
+
yoga_type: str,
|
|
124
|
+
description: str,
|
|
125
|
+
planets: list,
|
|
126
|
+
present: bool,
|
|
127
|
+
strength: str,
|
|
128
|
+
) -> dict:
|
|
129
|
+
return {
|
|
130
|
+
"name": name,
|
|
131
|
+
"type": yoga_type,
|
|
132
|
+
"description": description,
|
|
133
|
+
"planets_involved": planets,
|
|
134
|
+
"present": present,
|
|
135
|
+
"strength": strength,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _strength_from_flag(strong: bool, moderate: bool) -> str:
|
|
140
|
+
if strong:
|
|
141
|
+
return "Strong"
|
|
142
|
+
if moderate:
|
|
143
|
+
return "Moderate"
|
|
144
|
+
return "Weak"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
# Pancha Mahapurusha Yogas
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _check_pancha_mahapurusha(
|
|
153
|
+
positions: list, planet_name: str, own_signs: set, exalt_sign: str | None
|
|
154
|
+
) -> tuple:
|
|
155
|
+
"""Return (present, strength)."""
|
|
156
|
+
p = _get_planet(positions, planet_name)
|
|
157
|
+
if not p:
|
|
158
|
+
return False, "Weak"
|
|
159
|
+
rashi = p.get("rashi", "")
|
|
160
|
+
house = p.get("house")
|
|
161
|
+
if house is None:
|
|
162
|
+
return False, "Weak"
|
|
163
|
+
in_own = rashi in own_signs
|
|
164
|
+
in_exalt = rashi == exalt_sign
|
|
165
|
+
in_kendra = house in KENDRA_HOUSES
|
|
166
|
+
present = (in_own or in_exalt) and in_kendra
|
|
167
|
+
if present:
|
|
168
|
+
strength = "Strong" if in_exalt else "Moderate"
|
|
169
|
+
else:
|
|
170
|
+
strength = "Weak"
|
|
171
|
+
return present, strength
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _pancha_mahapurusha_yogas(positions: list) -> list:
|
|
175
|
+
yogas = []
|
|
176
|
+
|
|
177
|
+
configs = [
|
|
178
|
+
(
|
|
179
|
+
"Ruchaka",
|
|
180
|
+
"Mars",
|
|
181
|
+
{"Aries", "Scorpio"},
|
|
182
|
+
"Capricorn",
|
|
183
|
+
"Mars in own sign (Aries/Scorpio) or exaltation (Capricorn) in a kendra house.",
|
|
184
|
+
),
|
|
185
|
+
(
|
|
186
|
+
"Bhadra",
|
|
187
|
+
"Mercury",
|
|
188
|
+
{"Gemini", "Virgo"},
|
|
189
|
+
"Virgo",
|
|
190
|
+
"Mercury in own sign (Gemini/Virgo) or exaltation (Virgo) in a kendra house.",
|
|
191
|
+
),
|
|
192
|
+
(
|
|
193
|
+
"Hamsa",
|
|
194
|
+
"Jupiter",
|
|
195
|
+
{"Sagittarius", "Pisces"},
|
|
196
|
+
"Cancer",
|
|
197
|
+
"Jupiter in own sign (Sagittarius/Pisces) or exaltation (Cancer) in a kendra house.",
|
|
198
|
+
),
|
|
199
|
+
(
|
|
200
|
+
"Malavya",
|
|
201
|
+
"Venus",
|
|
202
|
+
{"Taurus", "Libra"},
|
|
203
|
+
"Pisces",
|
|
204
|
+
"Venus in own sign (Taurus/Libra) or exaltation (Pisces) in a kendra house.",
|
|
205
|
+
),
|
|
206
|
+
(
|
|
207
|
+
"Sasa",
|
|
208
|
+
"Saturn",
|
|
209
|
+
{"Capricorn", "Aquarius"},
|
|
210
|
+
"Libra",
|
|
211
|
+
"Saturn in own sign (Capricorn/Aquarius) or exaltation (Libra) in a kendra house.",
|
|
212
|
+
),
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
for yoga_name, planet, own_signs, exalt_sign, desc in configs:
|
|
216
|
+
present, strength = _check_pancha_mahapurusha(
|
|
217
|
+
positions, planet, own_signs, exalt_sign
|
|
218
|
+
)
|
|
219
|
+
yogas.append(
|
|
220
|
+
_yoga_dict(
|
|
221
|
+
yoga_name,
|
|
222
|
+
"Benefic",
|
|
223
|
+
desc,
|
|
224
|
+
[planet],
|
|
225
|
+
present,
|
|
226
|
+
strength if present else "Weak",
|
|
227
|
+
)
|
|
228
|
+
)
|
|
229
|
+
return yogas
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# ---------------------------------------------------------------------------
|
|
233
|
+
# Sun / Moon yogas
|
|
234
|
+
# ---------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _sun_moon_yogas(positions: list) -> list:
|
|
238
|
+
yogas = []
|
|
239
|
+
|
|
240
|
+
sun = _get_planet(positions, "Sun")
|
|
241
|
+
moon = _get_planet(positions, "Moon")
|
|
242
|
+
mercury = _get_planet(positions, "Mercury")
|
|
243
|
+
jupiter = _get_planet(positions, "Jupiter")
|
|
244
|
+
mars = _get_planet(positions, "Mars")
|
|
245
|
+
|
|
246
|
+
# Budha-Aditya Yoga
|
|
247
|
+
if sun and mercury:
|
|
248
|
+
present = sun["house"] == mercury["house"]
|
|
249
|
+
# Weaker if Mercury is combust (very close to Sun); rough proxy: combust if within 8°
|
|
250
|
+
combust = (
|
|
251
|
+
present and abs(sun.get("longitude", 0) - mercury.get("longitude", 0)) < 8
|
|
252
|
+
)
|
|
253
|
+
strength = "Moderate" if combust else ("Strong" if present else "Weak")
|
|
254
|
+
yogas.append(
|
|
255
|
+
_yoga_dict(
|
|
256
|
+
"Budha-Aditya Yoga",
|
|
257
|
+
"Benefic",
|
|
258
|
+
"Sun and Mercury conjunction. Confers intelligence and communication skills.",
|
|
259
|
+
["Sun", "Mercury"],
|
|
260
|
+
present,
|
|
261
|
+
strength,
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Gaja Kesari Yoga
|
|
266
|
+
if moon and jupiter:
|
|
267
|
+
diff = (moon["house"] - jupiter["house"]) % 12
|
|
268
|
+
present = diff in {0, 3, 6, 9}
|
|
269
|
+
strength = "Strong" if diff == 0 else ("Moderate" if present else "Weak")
|
|
270
|
+
yogas.append(
|
|
271
|
+
_yoga_dict(
|
|
272
|
+
"Gaja Kesari Yoga",
|
|
273
|
+
"Benefic",
|
|
274
|
+
"Moon and Jupiter in kendra from each other. Bestows fame, wisdom, and prosperity.",
|
|
275
|
+
["Moon", "Jupiter"],
|
|
276
|
+
present,
|
|
277
|
+
strength,
|
|
278
|
+
)
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# Chandra-Mangala Yoga
|
|
282
|
+
if moon and mars:
|
|
283
|
+
present = moon["house"] == mars["house"]
|
|
284
|
+
yogas.append(
|
|
285
|
+
_yoga_dict(
|
|
286
|
+
"Chandra-Mangala Yoga",
|
|
287
|
+
"Benefic",
|
|
288
|
+
"Moon and Mars conjunction. Gives financial acumen and strong will.",
|
|
289
|
+
["Moon", "Mars"],
|
|
290
|
+
present,
|
|
291
|
+
"Moderate" if present else "Weak",
|
|
292
|
+
)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# Sunapha / Anapha / Durudhura / Kemadruma (all require Moon)
|
|
296
|
+
if moon:
|
|
297
|
+
moon_house = moon["house"]
|
|
298
|
+
second_from_moon = _nth_house_from(moon_house, 2)
|
|
299
|
+
twelfth_from_moon = _nth_house_from(moon_house, 12)
|
|
300
|
+
|
|
301
|
+
# Planets in 2nd/12th from Moon (excluding Sun)
|
|
302
|
+
in_2nd = [
|
|
303
|
+
p["name"]
|
|
304
|
+
for p in positions
|
|
305
|
+
if p["house"] == second_from_moon and p["name"] != "Sun"
|
|
306
|
+
]
|
|
307
|
+
in_12th = [
|
|
308
|
+
p["name"]
|
|
309
|
+
for p in positions
|
|
310
|
+
if p["house"] == twelfth_from_moon and p["name"] != "Sun"
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
# Sunapha
|
|
314
|
+
present_sunapha = len(in_2nd) > 0
|
|
315
|
+
yogas.append(
|
|
316
|
+
_yoga_dict(
|
|
317
|
+
"Sunapha Yoga",
|
|
318
|
+
"Benefic",
|
|
319
|
+
"Planet (other than Sun) in 2nd house from Moon. Brings wealth and self-reliance.",
|
|
320
|
+
["Moon"] + in_2nd,
|
|
321
|
+
present_sunapha,
|
|
322
|
+
"Moderate" if present_sunapha else "Weak",
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Anapha
|
|
327
|
+
present_anapha = len(in_12th) > 0
|
|
328
|
+
yogas.append(
|
|
329
|
+
_yoga_dict(
|
|
330
|
+
"Anapha Yoga",
|
|
331
|
+
"Benefic",
|
|
332
|
+
"Planet (other than Sun) in 12th house from Moon. Confers health and generosity.",
|
|
333
|
+
["Moon"] + in_12th,
|
|
334
|
+
present_anapha,
|
|
335
|
+
"Moderate" if present_anapha else "Weak",
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Durudhura
|
|
340
|
+
present_duru = present_sunapha and present_anapha
|
|
341
|
+
yogas.append(
|
|
342
|
+
_yoga_dict(
|
|
343
|
+
"Durudhura Yoga",
|
|
344
|
+
"Benefic",
|
|
345
|
+
"Planets in both 2nd and 12th from Moon. Grants abundance and enjoyment of life.",
|
|
346
|
+
["Moon"] + list(set(in_2nd + in_12th)),
|
|
347
|
+
present_duru,
|
|
348
|
+
"Strong" if present_duru else "Weak",
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# Kemadruma (Malefic) — no planet in 2nd or 12th from Moon AND Moon not in kendra
|
|
353
|
+
moon_in_kendra = moon_house in KENDRA_HOUSES
|
|
354
|
+
present_kema = (
|
|
355
|
+
(not present_sunapha) and (not present_anapha) and (not moon_in_kendra)
|
|
356
|
+
)
|
|
357
|
+
yogas.append(
|
|
358
|
+
_yoga_dict(
|
|
359
|
+
"Kemadruma Yoga",
|
|
360
|
+
"Malefic",
|
|
361
|
+
"No planet in 2nd or 12th from Moon and Moon not in kendra. Weakens the Moon significantly.",
|
|
362
|
+
["Moon"],
|
|
363
|
+
present_kema,
|
|
364
|
+
"Strong" if present_kema else "Weak",
|
|
365
|
+
)
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return yogas
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
# ---------------------------------------------------------------------------
|
|
372
|
+
# Wealth / Raj Yogas
|
|
373
|
+
# ---------------------------------------------------------------------------
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _raj_and_wealth_yogas(positions: list, houses: dict) -> list:
|
|
377
|
+
yogas = []
|
|
378
|
+
|
|
379
|
+
# --- Raj Yoga ---
|
|
380
|
+
kendra_houses = [1, 4, 7, 10]
|
|
381
|
+
trikona_houses_list = [1, 5, 9]
|
|
382
|
+
kendra_lord_map = {h: _house_lord(houses, h) for h in kendra_houses}
|
|
383
|
+
trikona_lord_map = {h: _house_lord(houses, h) for h in trikona_houses_list}
|
|
384
|
+
|
|
385
|
+
raj_pairs = []
|
|
386
|
+
for kh in kendra_houses:
|
|
387
|
+
kl = kendra_lord_map[kh]
|
|
388
|
+
if not kl:
|
|
389
|
+
continue
|
|
390
|
+
for th in trikona_houses_list:
|
|
391
|
+
if kh == th:
|
|
392
|
+
continue
|
|
393
|
+
tl = trikona_lord_map[th]
|
|
394
|
+
if not tl:
|
|
395
|
+
continue
|
|
396
|
+
if kl == tl:
|
|
397
|
+
# Same planet is yoga karaka (lords both kendra & trikona)
|
|
398
|
+
raj_pairs.append((kl, tl))
|
|
399
|
+
continue
|
|
400
|
+
kl_house = _planet_house(positions, kl)
|
|
401
|
+
tl_house = _planet_house(positions, tl)
|
|
402
|
+
# Conjunction
|
|
403
|
+
if kl_house is not None and tl_house is not None and kl_house == tl_house:
|
|
404
|
+
raj_pairs.append((kl, tl))
|
|
405
|
+
continue
|
|
406
|
+
# Exchange
|
|
407
|
+
kl_rashi = _planet_rashi(positions, kl)
|
|
408
|
+
tl_rashi = _planet_rashi(positions, tl)
|
|
409
|
+
if kl_rashi and tl_rashi:
|
|
410
|
+
if RASHI_LORDS.get(kl_rashi) == tl and RASHI_LORDS.get(tl_rashi) == kl:
|
|
411
|
+
raj_pairs.append((kl, tl))
|
|
412
|
+
|
|
413
|
+
raj_present = len(raj_pairs) > 0
|
|
414
|
+
raj_planets = list({p for pair in raj_pairs for p in pair})
|
|
415
|
+
yogas.append(
|
|
416
|
+
_yoga_dict(
|
|
417
|
+
"Raj Yoga",
|
|
418
|
+
"Benefic",
|
|
419
|
+
"Lord of a kendra house (1,4,7,10) conjunct or exchange with lord of a trikona house (1,5,9). "
|
|
420
|
+
"Confers power, authority, and success.",
|
|
421
|
+
raj_planets,
|
|
422
|
+
raj_present,
|
|
423
|
+
"Strong" if len(raj_pairs) > 1 else ("Moderate" if raj_present else "Weak"),
|
|
424
|
+
)
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# --- Dhana Yoga ---
|
|
428
|
+
lord_2 = _house_lord(houses, 2)
|
|
429
|
+
lord_11 = _house_lord(houses, 11)
|
|
430
|
+
dhana_present = False
|
|
431
|
+
if lord_2 and lord_11 and lord_2 != lord_11:
|
|
432
|
+
h2 = _planet_house(positions, lord_2)
|
|
433
|
+
h11 = _planet_house(positions, lord_11)
|
|
434
|
+
if h2 is not None and h11 is not None:
|
|
435
|
+
if h2 == h11:
|
|
436
|
+
dhana_present = True
|
|
437
|
+
else:
|
|
438
|
+
# Mutual kendra or trikona
|
|
439
|
+
diff = (h2 - h11) % 12
|
|
440
|
+
if diff in {0, 3, 6, 9}:
|
|
441
|
+
dhana_present = True
|
|
442
|
+
elif lord_2 and lord_11 and lord_2 == lord_11:
|
|
443
|
+
dhana_present = True # Same planet lords both 2nd and 11th
|
|
444
|
+
yogas.append(
|
|
445
|
+
_yoga_dict(
|
|
446
|
+
"Dhana Yoga",
|
|
447
|
+
"Benefic",
|
|
448
|
+
"Lords of 2nd and 11th conjoined or in mutual kendra/trikona. Brings great wealth.",
|
|
449
|
+
[lord_2, lord_11] if lord_2 and lord_11 else [],
|
|
450
|
+
dhana_present,
|
|
451
|
+
"Moderate" if dhana_present else "Weak",
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
# --- Lakshmi Yoga ---
|
|
456
|
+
lord_5 = _house_lord(houses, 5)
|
|
457
|
+
lord_9 = _house_lord(houses, 9)
|
|
458
|
+
venus = _get_planet(positions, "Venus")
|
|
459
|
+
lakshmi_present = False
|
|
460
|
+
lakshmi_strength = "Weak"
|
|
461
|
+
if venus:
|
|
462
|
+
venus_rashi = venus.get("rashi", "")
|
|
463
|
+
venus_house = venus.get("house")
|
|
464
|
+
venus_in_own = venus_rashi in {"Taurus", "Libra"}
|
|
465
|
+
venus_in_exalt = venus_rashi == "Pisces"
|
|
466
|
+
venus_in_kendra_or_trikona = venus_house in (KENDRA_HOUSES | TRIKONA_HOUSES)
|
|
467
|
+
venus_is_lord_5_or_9 = "Venus" in {lord_5, lord_9}
|
|
468
|
+
if (
|
|
469
|
+
venus_is_lord_5_or_9
|
|
470
|
+
and (venus_in_own or venus_in_exalt)
|
|
471
|
+
and venus_in_kendra_or_trikona
|
|
472
|
+
):
|
|
473
|
+
lakshmi_present = True
|
|
474
|
+
lakshmi_strength = "Strong" if venus_in_exalt else "Moderate"
|
|
475
|
+
yogas.append(
|
|
476
|
+
_yoga_dict(
|
|
477
|
+
"Lakshmi Yoga",
|
|
478
|
+
"Benefic",
|
|
479
|
+
"Venus (lord of 5th or 9th) in own/exaltation sign in kendra or trikona. "
|
|
480
|
+
"Blesses with beauty, luxury, and spiritual grace.",
|
|
481
|
+
["Venus"],
|
|
482
|
+
lakshmi_present,
|
|
483
|
+
lakshmi_strength,
|
|
484
|
+
)
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
# --- Saraswati Yoga ---
|
|
488
|
+
saraswati_houses = KENDRA_HOUSES | TRIKONA_HOUSES | {2, 11}
|
|
489
|
+
sj = _planet_house(positions, "Jupiter")
|
|
490
|
+
sv = _planet_house(positions, "Venus")
|
|
491
|
+
sm = _planet_house(positions, "Mercury")
|
|
492
|
+
saraswati_present = (
|
|
493
|
+
sj in saraswati_houses and sv in saraswati_houses and sm in saraswati_houses
|
|
494
|
+
)
|
|
495
|
+
yogas.append(
|
|
496
|
+
_yoga_dict(
|
|
497
|
+
"Saraswati Yoga",
|
|
498
|
+
"Benefic",
|
|
499
|
+
"Jupiter, Venus, and Mercury all in kendra or trikona (including 2nd/11th). "
|
|
500
|
+
"Confers great learning, eloquence, and artistic talent.",
|
|
501
|
+
["Jupiter", "Venus", "Mercury"],
|
|
502
|
+
saraswati_present,
|
|
503
|
+
"Strong" if saraswati_present else "Weak",
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
return yogas
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
# ---------------------------------------------------------------------------
|
|
511
|
+
# Benefic Yogas (Vesi / Voshi / Obhayachari / Amala / Pancha-Mahabhuta)
|
|
512
|
+
# ---------------------------------------------------------------------------
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _benefic_yogas(positions: list, houses: dict) -> list:
|
|
516
|
+
yogas = []
|
|
517
|
+
|
|
518
|
+
sun = _get_planet(positions, "Sun")
|
|
519
|
+
|
|
520
|
+
# Vesi / Voshi / Obhayachari
|
|
521
|
+
if sun:
|
|
522
|
+
sun_house = sun["house"]
|
|
523
|
+
second_from_sun = _nth_house_from(sun_house, 2)
|
|
524
|
+
twelfth_from_sun = _nth_house_from(sun_house, 12)
|
|
525
|
+
|
|
526
|
+
in_2nd_sun = [
|
|
527
|
+
p["name"]
|
|
528
|
+
for p in positions
|
|
529
|
+
if p["house"] == second_from_sun and p["name"] != "Moon"
|
|
530
|
+
]
|
|
531
|
+
in_12th_sun = [
|
|
532
|
+
p["name"]
|
|
533
|
+
for p in positions
|
|
534
|
+
if p["house"] == twelfth_from_sun and p["name"] != "Moon"
|
|
535
|
+
]
|
|
536
|
+
|
|
537
|
+
present_vesi = len(in_2nd_sun) > 0
|
|
538
|
+
yogas.append(
|
|
539
|
+
_yoga_dict(
|
|
540
|
+
"Vesi Yoga",
|
|
541
|
+
"Benefic",
|
|
542
|
+
"Planet (other than Moon) in 2nd house from Sun. Grants wealth and political success.",
|
|
543
|
+
["Sun"] + in_2nd_sun,
|
|
544
|
+
present_vesi,
|
|
545
|
+
"Moderate" if present_vesi else "Weak",
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
present_voshi = len(in_12th_sun) > 0
|
|
550
|
+
yogas.append(
|
|
551
|
+
_yoga_dict(
|
|
552
|
+
"Voshi Yoga",
|
|
553
|
+
"Benefic",
|
|
554
|
+
"Planet (other than Moon) in 12th house from Sun. Brings fame and noble character.",
|
|
555
|
+
["Sun"] + in_12th_sun,
|
|
556
|
+
present_voshi,
|
|
557
|
+
"Moderate" if present_voshi else "Weak",
|
|
558
|
+
)
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
present_obhaya = present_vesi and present_voshi
|
|
562
|
+
yogas.append(
|
|
563
|
+
_yoga_dict(
|
|
564
|
+
"Obhayachari Yoga",
|
|
565
|
+
"Benefic",
|
|
566
|
+
"Planets in both 2nd and 12th from Sun. Bestows kingly attributes and leadership.",
|
|
567
|
+
["Sun"] + list(set(in_2nd_sun + in_12th_sun)),
|
|
568
|
+
present_obhaya,
|
|
569
|
+
"Strong" if present_obhaya else "Weak",
|
|
570
|
+
)
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
# Amala Yoga — only benefics in 10th from Lagna or Moon
|
|
574
|
+
tenth_from_lagna = 10
|
|
575
|
+
planets_in_10th = _planets_in_house(positions, tenth_from_lagna)
|
|
576
|
+
amala_lagna = len(planets_in_10th) > 0 and all(
|
|
577
|
+
p in BENEFIC_PLANETS for p in planets_in_10th
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
moon = _get_planet(positions, "Moon")
|
|
581
|
+
amala_moon = False
|
|
582
|
+
if moon:
|
|
583
|
+
tenth_from_moon = _nth_house_from(moon["house"], 10)
|
|
584
|
+
planets_in_10th_moon = _planets_in_house(positions, tenth_from_moon)
|
|
585
|
+
amala_moon = len(planets_in_10th_moon) > 0 and all(
|
|
586
|
+
p in BENEFIC_PLANETS for p in planets_in_10th_moon
|
|
587
|
+
)
|
|
588
|
+
amala_present = amala_lagna or amala_moon
|
|
589
|
+
yogas.append(
|
|
590
|
+
_yoga_dict(
|
|
591
|
+
"Amala Yoga",
|
|
592
|
+
"Benefic",
|
|
593
|
+
"Only benefic planets (Moon, Mercury, Jupiter, Venus) occupy the 10th from Lagna or Moon. "
|
|
594
|
+
"Ensures a spotless reputation and virtuous career.",
|
|
595
|
+
list(set(planets_in_10th)),
|
|
596
|
+
amala_present,
|
|
597
|
+
"Strong" if amala_present else "Weak",
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
# Pancha-Mahabhuta Yoga — all kendras occupied
|
|
602
|
+
kendra_occupied = all(
|
|
603
|
+
len(_planets_in_house(positions, h)) > 0 for h in KENDRA_HOUSES
|
|
604
|
+
)
|
|
605
|
+
all_kendra_planets = [
|
|
606
|
+
p for h in KENDRA_HOUSES for p in _planets_in_house(positions, h)
|
|
607
|
+
]
|
|
608
|
+
yogas.append(
|
|
609
|
+
_yoga_dict(
|
|
610
|
+
"Pancha-Mahabhuta Yoga",
|
|
611
|
+
"Benefic",
|
|
612
|
+
"All kendra houses (1,4,7,10) are occupied by planets, representing all 5 elements. "
|
|
613
|
+
"Bestows a well-rounded, powerful personality.",
|
|
614
|
+
all_kendra_planets,
|
|
615
|
+
kendra_occupied,
|
|
616
|
+
"Strong" if kendra_occupied else "Weak",
|
|
617
|
+
)
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
return yogas
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
# ---------------------------------------------------------------------------
|
|
624
|
+
# Malefic Yogas
|
|
625
|
+
# ---------------------------------------------------------------------------
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def _malefic_yogas(positions: list, houses: dict) -> list:
|
|
629
|
+
yogas = []
|
|
630
|
+
|
|
631
|
+
# --- Daridra Yoga ---
|
|
632
|
+
good_houses = [1, 2, 4, 5, 7, 9, 10, 11]
|
|
633
|
+
dusthana_lords = {
|
|
634
|
+
_house_lord(houses, h) for h in [6, 8, 12] if _house_lord(houses, h)
|
|
635
|
+
}
|
|
636
|
+
good_lords = {_house_lord(houses, h) for h in good_houses if _house_lord(houses, h)}
|
|
637
|
+
daridra_planets = []
|
|
638
|
+
for dl in dusthana_lords:
|
|
639
|
+
for gl in good_lords:
|
|
640
|
+
if dl == gl:
|
|
641
|
+
continue
|
|
642
|
+
dl_house = _planet_house(positions, dl)
|
|
643
|
+
gl_house = _planet_house(positions, gl)
|
|
644
|
+
if dl_house is not None and gl_house is not None and dl_house == gl_house:
|
|
645
|
+
daridra_planets.extend([dl, gl])
|
|
646
|
+
daridra_present = len(daridra_planets) > 0
|
|
647
|
+
yogas.append(
|
|
648
|
+
_yoga_dict(
|
|
649
|
+
"Daridra Yoga",
|
|
650
|
+
"Malefic",
|
|
651
|
+
"Lords of dusthana houses (6th, 8th, 12th) conjunct with lords of good houses. "
|
|
652
|
+
"Can bring poverty, debts, and misfortune.",
|
|
653
|
+
list(set(daridra_planets)),
|
|
654
|
+
daridra_present,
|
|
655
|
+
"Strong" if daridra_present else "Weak",
|
|
656
|
+
)
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
# --- Shakata Yoga ---
|
|
660
|
+
moon = _get_planet(positions, "Moon")
|
|
661
|
+
jupiter = _get_planet(positions, "Jupiter")
|
|
662
|
+
shakata_present = False
|
|
663
|
+
if moon and jupiter:
|
|
664
|
+
diff_from_moon = (jupiter["house"] - moon["house"]) % 12 + 1
|
|
665
|
+
shakata_present = diff_from_moon in {6, 8, 12}
|
|
666
|
+
yogas.append(
|
|
667
|
+
_yoga_dict(
|
|
668
|
+
"Shakata Yoga",
|
|
669
|
+
"Malefic",
|
|
670
|
+
"Jupiter in 6th, 8th, or 12th house from Moon. Causes fluctuating fortune and obstacles.",
|
|
671
|
+
["Moon", "Jupiter"],
|
|
672
|
+
shakata_present,
|
|
673
|
+
"Strong" if shakata_present else "Weak",
|
|
674
|
+
)
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
# --- Guru Chandal Yoga ---
|
|
678
|
+
rahu = _get_planet(positions, "Rahu")
|
|
679
|
+
ketu = _get_planet(positions, "Ketu")
|
|
680
|
+
guru_chandal_planets = ["Jupiter"]
|
|
681
|
+
guru_chandal = False
|
|
682
|
+
if jupiter:
|
|
683
|
+
if rahu and rahu["house"] == jupiter["house"]:
|
|
684
|
+
guru_chandal = True
|
|
685
|
+
guru_chandal_planets.append("Rahu")
|
|
686
|
+
if ketu and ketu["house"] == jupiter["house"]:
|
|
687
|
+
guru_chandal = True
|
|
688
|
+
guru_chandal_planets.append("Ketu")
|
|
689
|
+
yogas.append(
|
|
690
|
+
_yoga_dict(
|
|
691
|
+
"Guru Chandal Yoga",
|
|
692
|
+
"Malefic",
|
|
693
|
+
"Jupiter conjunct Rahu or Ketu. Can corrupt Jupiter's wisdom and cause ethical confusion.",
|
|
694
|
+
guru_chandal_planets,
|
|
695
|
+
guru_chandal,
|
|
696
|
+
"Strong" if guru_chandal else "Weak",
|
|
697
|
+
)
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
# --- Grahan Yoga ---
|
|
701
|
+
sun = _get_planet(positions, "Sun")
|
|
702
|
+
moon_p = _get_planet(positions, "Moon")
|
|
703
|
+
grahan_planets = []
|
|
704
|
+
if sun and rahu and sun["house"] == rahu["house"]:
|
|
705
|
+
grahan_planets.extend(["Sun", "Rahu"])
|
|
706
|
+
if sun and ketu and sun["house"] == ketu["house"]:
|
|
707
|
+
grahan_planets.extend(["Sun", "Ketu"])
|
|
708
|
+
if moon_p and rahu and moon_p["house"] == rahu["house"]:
|
|
709
|
+
grahan_planets.extend(["Moon", "Rahu"])
|
|
710
|
+
if moon_p and ketu and moon_p["house"] == ketu["house"]:
|
|
711
|
+
grahan_planets.extend(["Moon", "Ketu"])
|
|
712
|
+
grahan_present = len(grahan_planets) > 0
|
|
713
|
+
yogas.append(
|
|
714
|
+
_yoga_dict(
|
|
715
|
+
"Grahan Yoga",
|
|
716
|
+
"Malefic",
|
|
717
|
+
"Sun or Moon conjunct Rahu or Ketu (eclipse yoga). Afflicts the luminaries and causes setbacks.",
|
|
718
|
+
list(set(grahan_planets)),
|
|
719
|
+
grahan_present,
|
|
720
|
+
"Strong" if grahan_present else "Weak",
|
|
721
|
+
)
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
return yogas
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
# ---------------------------------------------------------------------------
|
|
728
|
+
# Other Notable Yogas
|
|
729
|
+
# ---------------------------------------------------------------------------
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def _other_yogas(positions: list, houses: dict) -> list:
|
|
733
|
+
yogas = []
|
|
734
|
+
|
|
735
|
+
moon = _get_planet(positions, "Moon")
|
|
736
|
+
|
|
737
|
+
# --- Neecha Bhanga Raj Yoga ---
|
|
738
|
+
neecha_bhanga_planets = []
|
|
739
|
+
for planet, debil_sign in DEBILITATION.items():
|
|
740
|
+
p = _get_planet(positions, planet)
|
|
741
|
+
if not p:
|
|
742
|
+
continue
|
|
743
|
+
if p.get("rashi") != debil_sign:
|
|
744
|
+
continue
|
|
745
|
+
# Planet is debilitated; check cancellation conditions
|
|
746
|
+
# Condition 1: Lord of the debilitation sign is in kendra from Lagna
|
|
747
|
+
debil_lord = RASHI_LORDS.get(debil_sign, "")
|
|
748
|
+
debil_lord_house = _planet_house(positions, debil_lord)
|
|
749
|
+
lord_in_kendra = (
|
|
750
|
+
debil_lord_house in KENDRA_HOUSES if debil_lord_house else False
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
# Condition 2: Planet exalted in the same sign is in kendra from Lagna or Moon
|
|
754
|
+
exalt_planet = EXALTED_IN_SIGN.get(debil_sign, "")
|
|
755
|
+
exalt_planet_house = (
|
|
756
|
+
_planet_house(positions, exalt_planet) if exalt_planet else None
|
|
757
|
+
)
|
|
758
|
+
exalt_in_kendra_lagna = (
|
|
759
|
+
(exalt_planet_house in KENDRA_HOUSES) if exalt_planet_house else False
|
|
760
|
+
)
|
|
761
|
+
exalt_in_kendra_moon = False
|
|
762
|
+
if moon and exalt_planet_house:
|
|
763
|
+
moon_kendras = _kendra_houses_from(moon["house"])
|
|
764
|
+
exalt_in_kendra_moon = exalt_planet_house in moon_kendras
|
|
765
|
+
|
|
766
|
+
if lord_in_kendra or exalt_in_kendra_lagna or exalt_in_kendra_moon:
|
|
767
|
+
neecha_bhanga_planets.append(planet)
|
|
768
|
+
|
|
769
|
+
nbr_present = len(neecha_bhanga_planets) > 0
|
|
770
|
+
yogas.append(
|
|
771
|
+
_yoga_dict(
|
|
772
|
+
"Neecha Bhanga Raj Yoga",
|
|
773
|
+
"Benefic",
|
|
774
|
+
"Debilitated planet's weakness is cancelled by the lord of debilitation sign or the "
|
|
775
|
+
"exaltation ruler being in kendra. Turns weakness into a source of strength.",
|
|
776
|
+
neecha_bhanga_planets,
|
|
777
|
+
nbr_present,
|
|
778
|
+
"Strong"
|
|
779
|
+
if len(neecha_bhanga_planets) > 1
|
|
780
|
+
else ("Moderate" if nbr_present else "Weak"),
|
|
781
|
+
)
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
# --- Viparita Raj Yoga ---
|
|
785
|
+
lord_6 = _house_lord(houses, 6)
|
|
786
|
+
lord_8 = _house_lord(houses, 8)
|
|
787
|
+
lord_12 = _house_lord(houses, 12)
|
|
788
|
+
l6h = _planet_house(positions, lord_6) if lord_6 else None
|
|
789
|
+
l8h = _planet_house(positions, lord_8) if lord_8 else None
|
|
790
|
+
l12h = _planet_house(positions, lord_12) if lord_12 else None
|
|
791
|
+
|
|
792
|
+
viparita_conditions = [
|
|
793
|
+
l6h in {8, 12} if l6h else False,
|
|
794
|
+
l8h in {6, 12} if l8h else False,
|
|
795
|
+
l12h in {6, 8} if l12h else False,
|
|
796
|
+
]
|
|
797
|
+
vip_count = sum(viparita_conditions)
|
|
798
|
+
vip_present = vip_count > 0
|
|
799
|
+
vip_planets = []
|
|
800
|
+
if viparita_conditions[0] and lord_6:
|
|
801
|
+
vip_planets.append(lord_6)
|
|
802
|
+
if viparita_conditions[1] and lord_8:
|
|
803
|
+
vip_planets.append(lord_8)
|
|
804
|
+
if viparita_conditions[2] and lord_12:
|
|
805
|
+
vip_planets.append(lord_12)
|
|
806
|
+
yogas.append(
|
|
807
|
+
_yoga_dict(
|
|
808
|
+
"Viparita Raj Yoga",
|
|
809
|
+
"Benefic",
|
|
810
|
+
"Lord of 6th in 8th/12th, lord of 8th in 6th/12th, or lord of 12th in 6th/8th. "
|
|
811
|
+
"Adversity ultimately turns into power and success.",
|
|
812
|
+
vip_planets,
|
|
813
|
+
vip_present,
|
|
814
|
+
"Strong" if vip_count >= 2 else ("Moderate" if vip_present else "Weak"),
|
|
815
|
+
)
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
# --- Parivartana Yoga (Exchange) ---
|
|
819
|
+
planet_data = {p["name"]: p for p in positions if p["name"] in CLASSICAL_PLANETS}
|
|
820
|
+
sorted_names = sorted(planet_data.keys())
|
|
821
|
+
parivartana_yogas = []
|
|
822
|
+
|
|
823
|
+
for i, name1 in enumerate(sorted_names):
|
|
824
|
+
for name2 in sorted_names[i + 1 :]:
|
|
825
|
+
p1 = planet_data[name1]
|
|
826
|
+
p2 = planet_data[name2]
|
|
827
|
+
p1_rashi = p1.get("rashi", "")
|
|
828
|
+
p2_rashi = p2.get("rashi", "")
|
|
829
|
+
# Check mutual exchange
|
|
830
|
+
if (
|
|
831
|
+
RASHI_LORDS.get(p1_rashi) == name2
|
|
832
|
+
and RASHI_LORDS.get(p2_rashi) == name1
|
|
833
|
+
):
|
|
834
|
+
h1 = p1["house"]
|
|
835
|
+
h2 = p2["house"]
|
|
836
|
+
is_kendra_1 = h1 in KENDRA_HOUSES
|
|
837
|
+
is_kendra_2 = h2 in KENDRA_HOUSES
|
|
838
|
+
is_trikona_1 = h1 in TRIKONA_HOUSES
|
|
839
|
+
is_trikona_2 = h2 in TRIKONA_HOUSES
|
|
840
|
+
is_dusthana_1 = h1 in DUSTHANA_HOUSES
|
|
841
|
+
is_dusthana_2 = h2 in DUSTHANA_HOUSES
|
|
842
|
+
|
|
843
|
+
if (
|
|
844
|
+
(is_kendra_1 and is_kendra_2)
|
|
845
|
+
or (is_kendra_1 and is_trikona_2)
|
|
846
|
+
or (is_trikona_1 and is_kendra_2)
|
|
847
|
+
):
|
|
848
|
+
subtype = "Maha Parivartana Yoga"
|
|
849
|
+
ytype = "Benefic"
|
|
850
|
+
elif (is_kendra_1 and is_dusthana_2) or (is_dusthana_1 and is_kendra_2):
|
|
851
|
+
subtype = "Kahala Parivartana Yoga"
|
|
852
|
+
ytype = "Neutral"
|
|
853
|
+
elif is_dusthana_1 or is_dusthana_2:
|
|
854
|
+
subtype = "Dainya Parivartana Yoga"
|
|
855
|
+
ytype = "Malefic"
|
|
856
|
+
else:
|
|
857
|
+
subtype = "Parivartana Yoga"
|
|
858
|
+
ytype = "Neutral"
|
|
859
|
+
|
|
860
|
+
parivartana_yogas.append(
|
|
861
|
+
_yoga_dict(
|
|
862
|
+
subtype,
|
|
863
|
+
ytype,
|
|
864
|
+
f"Exchange between {name1} (house {h1}) and {name2} (house {h2}). "
|
|
865
|
+
"Planets act as if in each other's signs, amplifying their combined energy.",
|
|
866
|
+
[name1, name2],
|
|
867
|
+
True,
|
|
868
|
+
"Moderate",
|
|
869
|
+
)
|
|
870
|
+
)
|
|
871
|
+
|
|
872
|
+
yogas.extend(parivartana_yogas)
|
|
873
|
+
return yogas
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
# ---------------------------------------------------------------------------
|
|
877
|
+
# Main public function
|
|
878
|
+
# ---------------------------------------------------------------------------
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def get_yogas(base_chart: dict) -> dict:
|
|
882
|
+
"""
|
|
883
|
+
Identify major Vedic astrological Yogas from a birth chart.
|
|
884
|
+
|
|
885
|
+
Args:
|
|
886
|
+
base_chart: Full chart dict with keys:
|
|
887
|
+
planetary_positions, ascendant, houses, moon_sign, sun_sign
|
|
888
|
+
|
|
889
|
+
Returns:
|
|
890
|
+
dict with benefic_yogas, malefic_yogas, and summary.
|
|
891
|
+
"""
|
|
892
|
+
positions = base_chart.get("planetary_positions", [])
|
|
893
|
+
houses = base_chart.get("houses", {})
|
|
894
|
+
|
|
895
|
+
all_yogas: list[dict] = []
|
|
896
|
+
all_yogas.extend(_pancha_mahapurusha_yogas(positions))
|
|
897
|
+
all_yogas.extend(_sun_moon_yogas(positions))
|
|
898
|
+
all_yogas.extend(_raj_and_wealth_yogas(positions, houses))
|
|
899
|
+
all_yogas.extend(_benefic_yogas(positions, houses))
|
|
900
|
+
all_yogas.extend(_malefic_yogas(positions, houses))
|
|
901
|
+
all_yogas.extend(_other_yogas(positions, houses))
|
|
902
|
+
|
|
903
|
+
benefic_yogas = [y for y in all_yogas if y["type"] == "Benefic" and y["present"]]
|
|
904
|
+
malefic_yogas = [y for y in all_yogas if y["type"] == "Malefic" and y["present"]]
|
|
905
|
+
neutral_present = [y for y in all_yogas if y["type"] == "Neutral" and y["present"]]
|
|
906
|
+
|
|
907
|
+
total_present = len(benefic_yogas) + len(malefic_yogas) + len(neutral_present)
|
|
908
|
+
|
|
909
|
+
if len(benefic_yogas) > len(malefic_yogas) * 2:
|
|
910
|
+
quality = "highly auspicious"
|
|
911
|
+
elif len(benefic_yogas) > len(malefic_yogas):
|
|
912
|
+
quality = "largely auspicious"
|
|
913
|
+
elif len(malefic_yogas) > len(benefic_yogas):
|
|
914
|
+
quality = "challenging with notable malefic influences"
|
|
915
|
+
else:
|
|
916
|
+
quality = "mixed"
|
|
917
|
+
|
|
918
|
+
strong_benefic = [y["name"] for y in benefic_yogas if y["strength"] == "Strong"]
|
|
919
|
+
strong_malefic = [y["name"] for y in malefic_yogas if y["strength"] == "Strong"]
|
|
920
|
+
|
|
921
|
+
summary_parts = [
|
|
922
|
+
f"Found {total_present} active yoga(s): "
|
|
923
|
+
f"{len(benefic_yogas)} benefic, {len(malefic_yogas)} malefic, "
|
|
924
|
+
f"{len(neutral_present)} neutral. The overall chart is {quality}."
|
|
925
|
+
]
|
|
926
|
+
if strong_benefic:
|
|
927
|
+
summary_parts.append(f"Strong benefic yogas: {', '.join(strong_benefic)}.")
|
|
928
|
+
if strong_malefic:
|
|
929
|
+
summary_parts.append(f"Strong malefic yogas: {', '.join(strong_malefic)}.")
|
|
930
|
+
|
|
931
|
+
return {
|
|
932
|
+
"benefic_yogas": benefic_yogas,
|
|
933
|
+
"malefic_yogas": malefic_yogas,
|
|
934
|
+
"summary": " ".join(summary_parts),
|
|
935
|
+
}
|