accept --cpi=FILE --cpiy=YEAR to translate money to target year
cicd / ci (push) Successful in 1m30s Details

main
Bel LaPointe 2025-05-07 09:55:16 -06:00
parent 0d91cd63db
commit 2f8dba4e23
5 changed files with 48 additions and 11 deletions

View File

@ -1,9 +1,11 @@
package cli package cli
type Config struct { type Config struct {
Files FileList Files FileList
BPI string BPI string
Query struct { CPI string
CPIYear int
Query struct {
Period Period Period Period
Sort string Sort string
NoRounding bool NoRounding bool

View File

@ -30,6 +30,8 @@ func Main() {
fs.BoolVar(&config.Query.USDOnly, "usd", false, "filter to usd") fs.BoolVar(&config.Query.USDOnly, "usd", false, "filter to usd")
fs.BoolVar(&config.Query.NoExchanging, "no-exchanging", true, "omit currency exchanges") fs.BoolVar(&config.Query.NoExchanging, "no-exchanging", true, "omit currency exchanges")
fs.StringVar(&config.BPI, "bpi", "", "path to bpi") fs.StringVar(&config.BPI, "bpi", "", "path to bpi")
fs.StringVar(&config.CPI, "cpi", "", "path to cpi")
fs.IntVar(&config.CPIYear, "cpiy", 0, "use cpi to convert usd to this year's value")
if err := fs.Parse(os.Args[1:]); err != nil { if err := fs.Parse(os.Args[1:]); err != nil {
panic(err) panic(err)
} }
@ -89,6 +91,23 @@ func Main() {
bpis = b bpis = b
} }
cpiNormalizer := ana.NewNormalizer()
if config.CPI != "" && config.CPIYear > 0 {
c, err := ledger.NewBPIs(config.CPI)
if err != nil {
panic(err)
}
cpi := c["CPI"]
cpiy := cpi.Lookup(fmt.Sprintf("%d-06-01", config.CPIYear))
if cpiy == nil {
panic(fmt.Errorf("no cpi for year %d", config.CPIYear))
}
for date, value := range cpi {
cpiNormalizer = cpiNormalizer.With(".*", date, value/(*cpiy))
}
}
if config.Query.Normalize { if config.Query.Normalize {
deltas = ana.NewDefaultNormalizer().Normalize(deltas) deltas = ana.NewDefaultNormalizer().Normalize(deltas)
} }
@ -113,13 +132,14 @@ func Main() {
WithBPIs(bpis). WithBPIs(bpis).
KindaLike(q). KindaLike(q).
KindaGroup(group). KindaGroup(group).
Nonzero() Nonzero().
Normalize(cpiNormalizer, "9")
FPrintBalances(w, "", balances, nil, config.Query.USDOnly, config.Query.Normalize, time.Now().Format("2006-01-02"), false, maxAccW) FPrintBalances(w, "", balances, nil, config.Query.USDOnly, config.Query.Normalize, time.Now().Format("2006-01-02"), false, maxAccW)
case "reg": case "reg":
transactions := deltas.Transactions() transactions := deltas.Transactions()
cumulative := make(ledger.Balances) cumulative := make(ledger.Balances)
for _, transaction := range transactions { for _, transaction := range transactions {
balances := ledger.Deltas(transaction).Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero() balances := ledger.Deltas(transaction).Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero().Normalize(cpiNormalizer, transaction[0].Date)
shouldPrint := false shouldPrint := false
shouldPrint = shouldPrint || len(balances) > 2 shouldPrint = shouldPrint || len(balances) > 2
if config.Query.NoExchanging { if config.Query.NoExchanging {
@ -220,7 +240,7 @@ func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger
if !normalized { if !normalized {
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative) fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative)
} else { } else {
factor := normalizer.NormalizeFactor(ledger.Delta{Name: key, Date: date}) factor := normalizer.NormalizeFactor(key, date)
trailingMax := maxes[currency] - math.Abs(balances[key][currency]) trailingMax := maxes[currency] - math.Abs(balances[key][currency])
fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative, cumulative*factor, factor, printableCurrency, factor*trailingMax) fmt.Fprintf(w, format, printableKey, printableCurrency, balances[key][currency], printableCurrency, cumulative, cumulative*factor, factor, printableCurrency, factor*trailingMax)
} }

View File

@ -135,7 +135,7 @@ func (router Router) APITransactions(w http.ResponseWriter, r *http.Request) {
v := normalized[k] v := normalized[k]
if v := math.Abs(v["$"]); v < biggest { if v := math.Abs(v["$"]); v < biggest {
normalizedDelta := biggest - v normalizedDelta := biggest - v
normalizedFactor := normalizer.NormalizeFactor(ledger.Delta{Name: k, Date: time.Now().Format("2006-01-02")}) normalizedFactor := normalizer.NormalizeFactor(k, time.Now().Format("2006-01-02"))
normalized[fmt.Sprintf(`(%s trailing $)`, k)] = ledger.Balance{"$": normalizedDelta * normalizedFactor} normalized[fmt.Sprintf(`(%s trailing $)`, k)] = ledger.Balance{"$": normalizedDelta * normalizedFactor}
} }
} }

View File

@ -68,15 +68,15 @@ func (n Normalizer) Normalize(deltas ledger.Deltas) ledger.Deltas {
} }
func (n Normalizer) NormalizeDelta(delta ledger.Delta) ledger.Delta { func (n Normalizer) NormalizeDelta(delta ledger.Delta) ledger.Delta {
delta.Value /= n.NormalizeFactor(delta) delta.Value /= n.NormalizeFactor(delta.Name, delta.Date)
return delta return delta
} }
func (n Normalizer) NormalizeFactor(delta ledger.Delta) float64 { func (n Normalizer) NormalizeFactor(name, date string) float64 {
for pattern := range n.m { for pattern := range n.m {
if regexp.MustCompile(pattern).MatchString(delta.Name) { if regexp.MustCompile(pattern).MatchString(name) {
for _, normalize := range n.m[pattern] { for _, normalize := range n.m[pattern] {
if normalize.startDate < delta.Date { if normalize.startDate < date {
return normalize.factor return normalize.factor
} }
} }

View File

@ -9,6 +9,10 @@ import (
"time" "time"
) )
type Normalizer interface {
NormalizeFactor(string, string) float64
}
type Balances map[string]Balance type Balances map[string]Balance
type Balance map[Currency]float64 type Balance map[Currency]float64
@ -246,3 +250,14 @@ func (balance Balance) Debug() string {
} }
return strings.Join(result, " + ") return strings.Join(result, " + ")
} }
func (balances Balances) Normalize(n Normalizer, date string) Balances {
result := make(Balances)
for name, balance := range balances {
result[name] = make(Balance)
for currency, value := range balance {
result[name][currency] = value / n.NormalizeFactor(name, date)
}
}
return result
}