From 31e1a86795a376ee55109f7d2c4e30457a4e6c7a Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Wed, 25 Oct 2023 15:47:29 -0600 Subject: [PATCH] wip ledger/register.go --- cmd/clitest/main.go | 20 +++++++++++++++ ledger/register.go | 57 +++++++++++++++++++++++++++++++++++++++++ ledger/register_test.go | 39 ++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 ledger/register.go create mode 100644 ledger/register_test.go diff --git a/cmd/clitest/main.go b/cmd/clitest/main.go index 94da0ce..c25d3f3 100644 --- a/cmd/clitest/main.go +++ b/cmd/clitest/main.go @@ -10,7 +10,9 @@ import ( "os" "slices" "sort" + "strconv" "strings" + "time" "github.com/go-echarts/go-echarts/v2/charts" "github.com/go-echarts/go-echarts/v2/opts" @@ -82,6 +84,24 @@ func main() { register[date] = register[date].WithBPIs(bpis) } } + if predictionMonths, err := strconv.ParseInt(r.URL.Query().Get("predictionMonths"), 10, 8); err == nil && predictionMonths > 0 { + predictionDuration := time.Hour * 24 * 365 / 12 * time.Duration(predictionMonths) + if r.URL.Query().Get("predictContributions") != "" { + register = ledger.RegisterWithContributionPrediction(register, predictionDuration) + } + for _, nameRate := range r.URL.Query()["predictCompoundingInterest"] { + splits := strings.Split(nameRate, "=") + if len(splits) != 2 { + panic(splits) + } + name := splits[0] + rate, err := strconv.ParseFloat(splits[1], 64) + if err != nil { + panic(err) + } + register = ledger.RegisterWithCompoundingInterestPrediction(register, predictionDuration, name, rate) + } + } // /MODIFIERS nameCurrencyDateValue := map[string]map[ledger.Currency]map[string]float64{} diff --git a/ledger/register.go b/ledger/register.go new file mode 100644 index 0000000..09154ab --- /dev/null +++ b/ledger/register.go @@ -0,0 +1,57 @@ +package ledger + +import ( + "fmt" + "io" + "log" + "slices" + "time" +) + +func RegisterWithContributionPrediction(reg map[string]Balances, windowAsPercentOfTotalDuration float64) (map[string]Balances, error) { + times, err := registerTimesInUnix(reg) + if err != nil { + return nil, err + } + windowDuration := time.Second * time.Duration(float64(slices.Max(times)-slices.Min(times))*windowAsPercentOfTotalDuration) + log.Println(windowDuration) + + lastReal := time.Unix(slices.Max(times), 0) + lastPredicted := lastReal + for lastPredicted.Before(lastReal.Add(windowDuration)) { + lastPredicted = lastPredicted.Add(time.Hour * 24 * time.Duration((45 - lastPredicted.Day()))) + log.Println(lastPredicted) + } + + result := make(map[string]Balances) + return result, io.EOF +} + +func RegisterWithCompoundingInterestPrediction(reg map[string]Balances, windowAsPercentOfTotalDuration float64, name string, rate float64) (map[string]Balances, error) { + result := make(map[string]Balances) + return result, io.EOF +} + +func registerTimesInUnix(reg map[string]Balances) ([]int64, error) { + result := make([]int64, 0, len(reg)) + for k := range reg { + v, err := registerTime(k) + if err != nil { + return nil, err + } + result = append(result, v.Unix()) + } + return result, nil +} + +func registerTime(s string) (time.Time, error) { + for _, layout := range []string{ + "2006-01-02", + "2006-01", + } { + if t, err := time.ParseInLocation(layout, s, time.Local); err == nil { + return t, err + } + } + return time.Time{}, fmt.Errorf("no layout matching %q", s) +} diff --git a/ledger/register_test.go b/ledger/register_test.go new file mode 100644 index 0000000..b17cc0f --- /dev/null +++ b/ledger/register_test.go @@ -0,0 +1,39 @@ +package ledger + +import ( + "testing" +) + +func TestRegisterPredictContribution(t *testing.T) { + // 1n t0 w weight 4 + // 2n t1 w weight 2 + // 4n t2 w weight 1 + input := map[string]Balances{ + "2001-01": Balances{"X": Balance{USD: 1}}, + "2001-02": Balances{"X": Balance{USD: 2}}, + "2001-03": Balances{"X": Balance{USD: 3}}, + "2001-04": Balances{"X": Balance{USD: 4}}, + "2001-05": Balances{"X": Balance{USD: 5}}, + "2001-06": Balances{"X": Balance{USD: 6}}, + "2001-07": Balances{"X": Balance{USD: 8}}, + "2001-08": Balances{"X": Balance{USD: 10}}, + "2001-09": Balances{"X": Balance{USD: 12}}, + "2001-10": Balances{"X": Balance{USD: 16}}, + } + // 1x4 weight 4 = 16 + // 2x2 weight 2 = 8 + // 4x1 weight 1 = 4 + // (16+8+4) / (4+2+1) = 4 + got, err := RegisterWithContributionPrediction(input, .12) + if err != nil { + t.Fatal(err) + } + if len(got) != len(input)+1 { + t.Error(len(got)) + } + if balance, ok := got["2001-11"]; !ok { + t.Error(ok) + } else if balance["X"][USD] != 20.0 { + t.Error(balance) + } +}