Horoscope object

The data structures of the six scopes, plus palace lookups that need not be handed the astrolabe again.

A horoscope projects the natal chart onto a point in time. The same chart shows a different palace layout in different years — which is exactly what "the decadal scope has moved to that palace" means.

h, _ := chart.Horoscope("2025-6-1", 0)

Horoscope holds the natal chart that produced it, so none of the query methods need the astrolabe passed in again.

The examples on this page start from an "en-US" natal chart, so the display values in the output are English.

Fields

FieldTypeSpanDescription
SolarDate / LunarDatestringThe solar string and the Chinese lunar spelling of the target date. The birth date lives on the natal chart; read it from h.Astrolabe().SolarDate
DecadalHoroscopeScopeTen yearsThe decadal scope; the childhood scope for the years before it begins
AgeHoroscopeScopeOne yearThe age scope, moving one palace per nominal year
YearlyHoroscopeScopeOne yearThe yearly scope, its palace fixed by the year's pillar
MonthlyHoroscopeScopeOne monthThe monthly scope
DailyHoroscopeScopeOne dayThe daily scope
HourlyHoroscopeScopeOne double-hourThe hourly scope

The age scope versus the yearly scope

Both advance once per year, but they start differently: the age scope starts from the birth-year branch and steps forward with the nominal age, while the yearly scope simply asks which palace that year's pillar falls in. The two lines are independent, and Zi Wei practice usually reads them together.

HoroscopeScope

FieldTypeDescription
IndexintWhich palace this scope lands on (a palace index)
NamestringDisplay name of the scope, translated into the output language
NameKeystringScope key: decadal / childhood (before the decadals begin) / turn (age fortune) / yearly / monthly / daily / hourly. Predicate on this, never on the translation
HeavenlyStem / HeavenlyStemKeystringStem of the scope, which determines the mutagens it flies
EarthlyBranch / EarthlyBranchKeystringBranch of the scope
PalaceNames / PalaceNameKeys[]stringThe twelve palace names re-derived with this scope's palace as the Soul palace, indexed by palace index
Mutagen / MutagenStarKeys[]stringThe stars this scope's stem transforms, in the order lu, quan, ke, ji; MutagenStarKeys holds the mutated stars' star keys, synonymous with the palace field of the same name
Stars[][]StarThe scope stars of this layer; nil for layers that have none
NominalAgeintAge scope only: the nominal age. 0 on every other layer
YearlyDecStar*YearlyDecStarYearly scope only: the Sui-qian and Jiang-qian gods. nil on every other layer
type YearlyDecStar struct {
    Suiqian12       []string `json:"suiqian12"`        // Sui-qian gods, translated, by palace index
    Suiqian12Keys   []string `json:"suiqian12Keys"`    // their keys
    Jiangqian12     []string `json:"jiangqian12"`      // Jiang-qian gods, translated
    Jiangqian12Keys []string `json:"jiangqian12Keys"`  // their keys
}

All six scopes share one type

Rather than giving the age and yearly scopes types of their own, the Go side puts NominalAge and YearlyDecStar into the shared HoroscopeScope, where the other layers leave them at their zero values. Call sites can therefore write generic logic parameterized by scope.

YearlyDecStar is a pointer and is nil outside the yearly scope

h.Decadal.YearlyDecStar is nil, and reading a field on it panics. Only h.Yearly.YearlyDecStar is non-nil — check before you walk the layers.

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println(h.Decadal.YearlyDecStar == nil, h.Yearly.YearlyDecStar != nil)
fmt.Println(h.Yearly.YearlyDecStar.Suiqian12[:3])
fmt.Println(h.Yearly.YearlyDecStar.Jiangqian12Keys[:3])
fmt.Println(h.Decadal.NominalAge, h.Age.NominalAge)

Output

true true
[blessed sorrowing illness]
[jiesha zhaisha tiansha]
0 26

PalaceIndexByName

func (item *HoroscopeScope) PalaceIndexByName(nameKeyOrName string) int

Looks a palace index up by palace-name key, or by palace name in the current language, among the twelve palaces as re-derived for that scope; returns -1 when nothing matches.

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println(h.Decadal.PalaceIndexByName(iztro.PalaceSoul))
fmt.Println(h.Decadal.PalaceIndexByName(iztro.PalaceWealth))
fmt.Println(h.Decadal.PalaceIndexByName("nosuch"))

Output

2
10
-1

It returns -1 rather than 00 is a legitimate palace index (the Yin palace). Always check for a negative before indexing chart.Palaces with it.

Example

h, _ := chart.Horoscope("2025-6-1", 0)

for _, item := range []iztro.HoroscopeScope{h.Decadal, h.Monthly, h.Daily, h.Hourly} {
    fmt.Printf("%s lands on palace %d with pillar %s%s\n",
        item.Name, item.Index, item.HeavenlyStem, item.EarthlyBranch)
}

fmt.Println("age scope nominal age", h.Age.NominalAge)
fmt.Println("decadal mutagens", h.Decadal.Mutagen)
fmt.Println("yearly Sui-qian gods", h.Yearly.YearlyDecStar.Suiqian12[:3])

Output

decadal lands on palace 2 with pillar gengchen
monthly lands on palace 3 with pillar renwoo
daily lands on palace 8 with pillar xinchou
hourly lands on palace 8 with pillar wuzi
age scope nominal age 26
decadal mutagens [sun general moon fortunate]
yearly Sui-qian gods [blessed sorrowing illness]

AgePalace

Purpose Get the palace the age scope occupies this year.

Zi Wei meaning The age scope is a line advancing year by year; whichever palace it lands on becomes the focus for that year.

Signature

func (h *Horoscope) AgePalace() *Palace

Return value *Palace — a palace on the natal chart.

Example

h, _ := chart.Horoscope("2025-6-1", 0)
fmt.Println(h.AgePalace().Name)

Output

property

Palace

Purpose Get one of the twelve palaces as re-derived under a given horoscope scope.

Zi Wei meaning Once the decadal scope reaches a palace, the twelve palaces are re-anchored with that palace as the "decadal Soul palace". "The decadal Spouse palace" refers to that re-anchored naming, and it is usually not the same palace as the natal Spouse palace.

Signature

func (h *Horoscope) Palace(nameKeyOrName string, scope string) *Palace

Parameters

ParameterTypeRequiredDefaultDescription
nameKeyOrNamestringYesThe palace-name key or translated name to fetch
scopestringYesWhich scope's twelve palaces to search

Return value *Palace — a palace on the natal chart (the same cell carries different names under different scopes). With ScopeOrigin, these are the natal twelve palaces. nil when nothing matches.

Example

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println("the decadal Soul palace is the natal", h.Palace(iztro.PalaceSoul, iztro.ScopeDecadal).Name)
fmt.Println("the natal Soul palace is", h.Palace(iztro.PalaceSoul, iztro.ScopeOrigin).Name)

Output

the decadal Soul palace is the natal spouse
the natal Soul palace is soul

Edge cases and pitfalls

What comes back is the cell on the natal chart

On the returned palace object, Name is still the natal palace name (spouse in the example), because it is that cell on the natal chart. To see what the cell is called at the decadal layer, read h.Decadal.PalaceNames[index].


SurroundPalaces

Purpose Get the surrounded palaces of a palace under a given horoscope scope.

Signature

func (h *Horoscope) SurroundPalaces(nameKeyOrName string, scope string) *SurroundedPalaces

Parameters Same as Palace.

Return value *SurroundedPalaces; its predicates are on Surrounded palaces.

Example

h, _ := chart.Horoscope("2025-6-1", 0)
sp := h.SurroundPalaces(iztro.PalaceWealth, iztro.ScopeYearly)

fmt.Println("the surrounded set of the yearly Wealth palace is anchored on the natal", sp.Target.Name)

Output

the surrounded set of the yearly Wealth palace is anchored on the natal health

HasHoroscopeStars / HasOneOfHoroscopeStars / NotHaveHoroscopeStars

Purpose Test whether a palace under a given scope holds the given scope stars.

Zi Wei meaning Scope stars are a group produced by each horoscope layer: Tiankui, Tianyue, Wenchang, Wenqu, Lucun, Qingyang, Tuoluo, Tianma, Hongluan and Tianxi. They carry different names in different layers — Yunkui and Yunyue at the decadal layer, Liukui and Liuyue at the yearly layer — with the same meaning applied to their own time span.

Signature

func (h *Horoscope) HasHoroscopeStars(nameKeyOrName string, scope string, stars []string) bool
func (h *Horoscope) HasOneOfHoroscopeStars(nameKeyOrName string, scope string, stars []string) bool
func (h *Horoscope) NotHaveHoroscopeStars(nameKeyOrName string, scope string, stars []string) bool

Parameters

ParameterTypeRequiredDefaultDescription
nameKeyOrNamestringYesThe palace name under that scope
scopestringYesThe horoscope scope
stars[]stringYesA slice of scope star keys, which must use that layer's names

Return value

MethodMeaning
HasHoroscopeStarsAll of them are present
HasOneOfHoroscopeStarsAt least one is present
NotHaveHoroscopeStarsNone is present

Example

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println(h.HasHoroscopeStars(iztro.PalaceSoul, iztro.ScopeDecadal, []string{"yunlu"}))
fmt.Println(h.HasOneOfHoroscopeStars(iztro.PalaceSoul, iztro.ScopeDecadal, []string{"yunlu", "yunyang"}))
fmt.Println(h.NotHaveHoroscopeStars(iztro.PalaceSoul, iztro.ScopeDecadal, []string{"yuntuo"}))

Output

false
false
true

Edge cases and pitfalls


HasHoroscopeMutagen

Purpose Test whether a palace under a given scope carries a mutagen flown by that scope's stem.

Zi Wei meaning Every horoscope layer has a stem of its own, and it transforms four stars just as the birth-year stem does. A question like "does the decadal Lu land in the decadal Wealth palace?" is asking about this.

Signature

func (h *Horoscope) HasHoroscopeMutagen(nameKeyOrName string, scope string, mutagenKey string) bool

Parameters

ParameterTypeRequiredDefaultDescription
nameKeyOrNamestringYesThe palace name under that scope
scopestringYesThe horoscope scope
mutagenKeystringYesA mutagen key

Return value bool. It checks whether the star transformed by that layer's stem is among the major or minor stars of the target palace (adjective stars are not scanned).

Example

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println(h.HasHoroscopeMutagen(iztro.PalaceSoul, iztro.ScopeDecadal, iztro.MutagenLu))
fmt.Println(h.Decadal.Mutagen)

Output

false
[sun general moon fortunate]

The decadal stem is geng, and geng sends Lu to Taiyang, Quan to Wuqu, Ke to Taiyin and Ji to Tiantong.

Edge cases and pitfalls

Always false when scope is ScopeOrigin

The natal layer has no "layer stem" — the natal mutagens are already marked on the stars' own MutagenKey. HasHoroscopeMutagen(name, iztro.ScopeOrigin, m) therefore returns false outright, which does not mean the natal chart lacks that mutagen. For natal mutagens use the palace's HasMutagen.


ScopeItem / Astrolabe

Purpose Get the HoroscopeScope for a scope key, or get back to the natal chart.

Signature

func (h *Horoscope) ScopeItem(scope string) *HoroscopeScope
func (h *Horoscope) Astrolabe() *Astrolabe

Return value ScopeItem returns nil for ScopeOrigin or an unknown scope — the natal chart is not a horoscope layer.

Example

h, _ := chart.Horoscope("2025-6-1", 0)

fmt.Println(h.ScopeItem(iztro.ScopeDecadal).Name)
fmt.Println(h.ScopeItem(iztro.ScopeOrigin))
fmt.Println(h.Astrolabe().SolarDate)

Output

decadal
<nil>
2000-8-16

Edge cases and pitfalls

ScopeItem is for writing generic logic parameterized by scope, which is tidier than a chain of switch scope. Remember to check for nil.


ToText

Purpose The horoscope's semantic text: a complete description for language models and people.

Signature

func (h *Horoscope) ToText() (string, error)
func (h *Horoscope) ToTextContext(ctx context.Context) (string, error)

Return value string — sectioned plain text in the chart's charting language; each scope carries a patterns line and flowing-star lines from its own perspective. The full format is on Semantic text.

Example

h, _ := chart.Horoscope("2025-1-1", 0)
text, _ := h.ToText()

fmt.Println(string([]rune(text)[:39]))

Output

=== Horoscope ===
Target Date: 2025-1-1

For the pattern hits as text, see PatternsToText on Patterns.

On this page