diff --git a/ana/bpi.go b/ana/bpi.go new file mode 100644 index 0000000..2a7d6fe --- /dev/null +++ b/ana/bpi.go @@ -0,0 +1,42 @@ +package ana + +import ( + "maps" + "regexp" + "time" + + "gogs.inhome.blapointe.com/ana-ledger/ledger" +) + +func BPIsWithFixedGrowthPrediction(bpis ledger.BPIs, window time.Duration, pattern string, apy float64) (ledger.BPIs, error) { + last := map[ledger.Currency]struct { + t string + v float64 + }{} + for currency, bpi := range bpis { + for date, value := range bpi { + if date > last[currency].t { + was := last[currency] + was.t = date + was.v = value + last[currency] = was + } + } + } + + result := make(ledger.BPIs) + p := regexp.MustCompile(pattern) + for currency, v := range bpis { + result[currency] = maps.Clone(v) + if p.MatchString(string(currency)) { + for _, predictionTime := range predictionTimes(window) { + k2 := predictionTime.Format("2006-01") + was := last[currency] + was.v *= 1.0 + (apy / 12.0) + result[currency][k2] = was.v + last[currency] = was + } + } + } + return result, nil +} diff --git a/ana/bpi_test.go b/ana/bpi_test.go new file mode 100644 index 0000000..aa754a3 --- /dev/null +++ b/ana/bpi_test.go @@ -0,0 +1,35 @@ +package ana + +import ( + "slices" + "testing" + "time" + + "gogs.inhome.blapointe.com/ana-ledger/ledger" +) + +func TestBPIPrediction(t *testing.T) { + t.Run("fixed growth", func(t *testing.T) { + bpis := ledger.BPIs{ + ledger.USD: ledger.BPI{ + "2001-01": -1000, + "2001-02": 100, + }, + } + + got, err := BPIsWithFixedGrowthPrediction(bpis, time.Hour*24*365, string(ledger.USD), 0.06) + if err != nil { + t.Fatal(err) + } + + dates := []string{} + for d := range got[ledger.USD] { + dates = append(dates, d) + } + slices.Sort(dates) + + for _, d := range dates { + t.Logf("%s | %s %.2f", ledger.USD, d, got[ledger.USD][d]) + } + }) +} diff --git a/ana/window.go b/ana/window.go new file mode 100644 index 0000000..4ef1b9c --- /dev/null +++ b/ana/window.go @@ -0,0 +1,13 @@ +package ana + +import "time" + +func predictionTimes(window time.Duration) []time.Time { + result := []time.Time{} + last := time.Now() + for last.Before(time.Now().Add(window)) { + last = last.Add(-1 * time.Hour * 24 * time.Duration(last.Day())).Add(time.Hour * 24 * 33) + result = append(result, last) + } + return result +} diff --git a/ledger/predict.go b/ledger/predict.go index 5810c12..5635f7c 100644 --- a/ledger/predict.go +++ b/ledger/predict.go @@ -124,39 +124,6 @@ func registerWithContributionPredictionForNameForCurrency(reg Register, window t return nil } -func BPIsWithFixedGrowthPrediction(bpis BPIs, window time.Duration, pattern string, apy float64) (BPIs, error) { - last := map[Currency]struct { - t string - v float64 - }{} - for currency, bpi := range bpis { - for date, value := range bpi { - if date > last[currency].t { - was := last[currency] - was.t = date - was.v = value - last[currency] = was - } - } - } - - result := make(BPIs) - p := regexp.MustCompile(pattern) - for currency, v := range bpis { - result[currency] = maps.Clone(v) - if p.MatchString(string(currency)) { - for _, predictionTime := range predictionTimes(window) { - k2 := predictionTime.Format("2006-01") - was := last[currency] - was.v *= 1.0 + (apy / 12.0) - result[currency][k2] = was.v - last[currency] = was - } - } - } - return result, nil -} - func RegisterWithCompoundingInterestPrediction(reg Register, window time.Duration, pattern string, apy float64) (Register, error) { lastBalances := make(Balances) p := regexp.MustCompile(pattern) diff --git a/ledger/predict_test.go b/ledger/predict_test.go index fbb8dda..39c7720 100644 --- a/ledger/predict_test.go +++ b/ledger/predict_test.go @@ -1,7 +1,6 @@ package ledger import ( - "slices" "testing" "time" ) @@ -51,32 +50,6 @@ func TestRegisterPrediction(t *testing.T) { }) } -func TestBPIPrediction(t *testing.T) { - t.Run("fixed growth", func(t *testing.T) { - bpis := BPIs{ - USD: BPI{ - "2001-01": -1000, - "2001-02": 100, - }, - } - - got, err := BPIsWithFixedGrowthPrediction(bpis, time.Hour*24*365, string(USD), 0.06) - if err != nil { - t.Fatal(err) - } - - dates := []string{} - for d := range got[USD] { - dates = append(dates, d) - } - slices.Sort(dates) - - for _, d := range dates { - t.Logf("%s | %s %.2f", USD, d, got[USD][d]) - } - }) -} - func newTestRegister() map[string]Balances { s := func(t time.Time) string { return t.Format("2006-01")