From 7d872ca92a8a34746ed38c54b7e91c3664cc0ff2 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Fri, 27 Oct 2023 18:50:31 -0600 Subject: [PATCH] drop legacyContributions legacyInterest --- ana/legacy_contributions.go | 124 ------------------------------- ana/legacy_contributions_test.go | 53 ------------- ana/legacy_interest.go | 60 --------------- ana/legacy_interest_test.go | 26 ------- 4 files changed, 263 deletions(-) delete mode 100644 ana/legacy_contributions.go delete mode 100644 ana/legacy_contributions_test.go delete mode 100644 ana/legacy_interest.go delete mode 100644 ana/legacy_interest_test.go diff --git a/ana/legacy_contributions.go b/ana/legacy_contributions.go deleted file mode 100644 index ac9c259..0000000 --- a/ana/legacy_contributions.go +++ /dev/null @@ -1,124 +0,0 @@ -package ana - -import ( - "maps" - "slices" - "sort" - "time" - - "gogs.inhome.blapointe.com/ana-ledger/ledger" -) - -func RegisterWithContributionPrediction(reg ledger.Register, window time.Duration) (ledger.Register, error) { - result := make(ledger.Register) - result.PushAll(reg) - for _, name := range result.Names() { - err := registerWithContributionPredictionForName(result, window, name) - if err != nil { - return nil, err - } - } - return result, nil -} - -func registerWithContributionPredictionForName(reg ledger.Register, window time.Duration, name string) error { - latest := make(ledger.Balance) - for _, d := range reg.Dates() { - if _, ok := reg[d][name]; ok { - latest = reg[d][name] - } - } - for _, predictionTime := range predictionTimes(window) { - k := predictionTime.Format("2006-01") - if _, ok := reg[k]; !ok { - reg[k] = make(ledger.Balances) - } - reg[k][name] = maps.Clone(latest) - } - for c := range latest { - err := registerWithContributionPredictionForNameForCurrency(reg, window, name, c) - if err != nil { - return err - } - } - return nil -} - -func registerWithContributionPredictionForNameForCurrency(reg ledger.Register, window time.Duration, name string, currency ledger.Currency) error { - type contribution struct { - t time.Time - v float64 - } - contributions := make([]contribution, 0) - for d := range reg { - t, err := dateToTime(d) - if err != nil { - return err - } - if time.Since(t) > time.Hour*24*180 || time.Now().Before(t) { // only include -6months..now - continue - } - if v, ok := reg[d][name][currency]; ok && (len(contributions) == 0 || contributions[len(contributions)-1].v != v) { - contributions = append(contributions, contribution{t: t, v: v}) - } - } - sort.Slice(contributions, func(i, j int) bool { - return contributions[i].t.Before(contributions[j].t) - }) - if len(contributions) < 5 { - return nil - } - - getMedianValueDelta := func(contributions []contribution) float64 { - values := make([]float64, len(contributions)) - for i := 1; i < len(contributions); i++ { - values[i] = contributions[i].v - contributions[i-1].v - } - slices.Sort(values) - return values[len(values)/2] - } - getMedianLapse := func(contributions []contribution) time.Duration { - lapses := make([]time.Duration, len(contributions)-1) - for i := 1; i < len(contributions); i++ { - lapses = append(lapses, contributions[i].t.Sub(contributions[i-1].t)) - } - slices.Sort(lapses) - return lapses[len(lapses)/2] - } - contributionsSlice := func(percent float64) []contribution { - wouldBe := int(percent * float64(len(contributions))) - if wouldBe == 0 { - wouldBe = 2 - } - return contributions[len(contributions)-1-wouldBe:] - } - - eighth := contributionsSlice(7.0 / 8.0) - quarter := contributionsSlice(3.0 / 4.0) - half := contributionsSlice(1.0 / 2.0) - medianValueDelta := func() float64 { - medians := []float64{ - getMedianValueDelta(eighth), - getMedianValueDelta(quarter), - getMedianValueDelta(half), - } - slices.Sort(medians) - return medians[1] - }() - medianLapse := func() time.Duration { - medians := []time.Duration{ - getMedianLapse(eighth), - getMedianLapse(quarter), - getMedianLapse(half), - } - slices.Sort(medians) - return medians[1] - }() - - for _, predictionTime := range predictionTimes(window) { - k := predictionTime.Format("2006-01") - expectedDelta := float64(predictionTime.Sub(time.Now())) * medianValueDelta / float64(medianLapse) - reg[k][name][currency] += expectedDelta - } - return nil -} diff --git a/ana/legacy_contributions_test.go b/ana/legacy_contributions_test.go deleted file mode 100644 index 78b886c..0000000 --- a/ana/legacy_contributions_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package ana - -import ( - "testing" - "time" - - "gogs.inhome.blapointe.com/ana-ledger/ledger" -) - -func TestRegisterPrediction(t *testing.T) { - t.Run("contribution", func(t *testing.T) { - input := newTestRegister() - - got, err := RegisterWithContributionPrediction(input, time.Hour*24*365) - if err != nil { - t.Fatal(err) - } - t.Logf("%+v", got) - - if len(got) != len(input)+13 { - t.Error(len(got)) - } - - for _, date := range got.Dates() { - for _, name := range got.Names() { - t.Logf("%s | %s = %+v", date, name, got[date][name]) - if ti, _ := dateToTime(date); ti.After(time.Now().Add(time.Hour*24*60)) && got[date][name]["XYZ"] == 0 { - t.Error("predicting future contributions lost unmodified currency", got[date][name]) - } - } - } - }) -} - -func newTestRegister() map[string]ledger.Balances { - s := func(t time.Time) string { - return t.Format("2006-01") - } - day := time.Hour * 24 - lastYear := time.Now().Add(-1 * day * time.Duration(time.Now().YearDay())) - return map[string]ledger.Balances{ - s(lastYear.Add(day * 0)): ledger.Balances{"X": ledger.Balance{ledger.USD: 1}}, - s(lastYear.Add(day * 32)): ledger.Balances{"X": ledger.Balance{ledger.USD: 2}}, - s(lastYear.Add(day * 64)): ledger.Balances{"X": ledger.Balance{ledger.USD: 3}}, - s(lastYear.Add(day * 94)): ledger.Balances{"X": ledger.Balance{ledger.USD: 4}}, - s(lastYear.Add(day * 124)): ledger.Balances{"X": ledger.Balance{ledger.USD: 5}}, - s(lastYear.Add(day * 154)): ledger.Balances{"X": ledger.Balance{ledger.USD: 6}}, - s(lastYear.Add(day * 184)): ledger.Balances{"X": ledger.Balance{ledger.USD: 8}}, - s(lastYear.Add(day * 214)): ledger.Balances{"X": ledger.Balance{ledger.USD: 10}}, - s(lastYear.Add(day * 244)): ledger.Balances{"X": ledger.Balance{ledger.USD: 12}}, - s(lastYear.Add(day * 274)): ledger.Balances{"X": ledger.Balance{ledger.USD: 16, "XYZ": 1}}, - } -} diff --git a/ana/legacy_interest.go b/ana/legacy_interest.go deleted file mode 100644 index 8433841..0000000 --- a/ana/legacy_interest.go +++ /dev/null @@ -1,60 +0,0 @@ -package ana - -import ( - "maps" - "math" - "regexp" - "time" - - "gogs.inhome.blapointe.com/ana-ledger/ledger" -) - -func RegisterWithCompoundingInterestPrediction(reg ledger.Register, window time.Duration, pattern string, apy float64) (ledger.Register, error) { - lastBalances := make(ledger.Balances) - p := regexp.MustCompile(pattern) - for _, d := range reg.Dates() { - if t, _ := dateToTime(d); time.Now().Before(t) { - continue - } - for name := range reg[d] { - if p.MatchString(name) { - lastBalances[name] = reg[d][name] - } - } - } - - predictedTimes := predictionTimes(window) - result := maps.Clone(reg) - for _, predictionTime := range predictedTimes { - k := predictionTime.Format("2006-01") - if _, ok := result[k]; !ok { - result[k] = make(ledger.Balances) - } - for k2, v2 := range lastBalances { - if _, ok := result[k][k2]; !ok { - result[k][k2] = maps.Clone(v2) - } - } - } - - addedSoFar := make(ledger.Balances) - for _, predictionTime := range predictedTimes { - k := predictionTime.Format("2006-01") - for name := range lastBalances { - if _, ok := addedSoFar[name]; !ok { - addedSoFar[name] = make(ledger.Balance) - } - for currency := range result[k][name] { - // A = P(1 + r/n)**nt - p := result[k][name][currency] + addedSoFar[name][currency] - r := apy - n := 12.0 - t := 1.0 / 12.0 - result[k][name][currency] = p * math.Pow(1.0+(r/n), n*t) - addedSoFar[name][currency] += (result[k][name][currency] - p) - } - } - } - - return result, nil -} diff --git a/ana/legacy_interest_test.go b/ana/legacy_interest_test.go deleted file mode 100644 index 26be7a3..0000000 --- a/ana/legacy_interest_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package ana - -import ( - "testing" - "time" -) - -func TestInterest(t *testing.T) { - input := newTestRegister() - - got, err := RegisterWithCompoundingInterestPrediction(input, time.Hour*24*365, "X", .04) - if err != nil { - t.Fatal(err) - } - t.Logf("%+v", got) - - if len(got) <= len(input) { - t.Error(len(got)) - } - - for _, date := range got.Dates() { - for name, balance := range got[date] { - t.Logf("%s | %s %s", date, name, balance.Debug()) - } - } -}