ana-ledger/ledger/register.go

127 lines
3.4 KiB
Go

package ledger
import (
"fmt"
"io"
"log"
"maps"
"slices"
"time"
)
func RegisterWithContributionPrediction(reg map[string]Balances, windowAsPercentOfTotalDuration float64) (map[string]Balances, error) {
times, err := registerTimesInUnix(reg)
if err != nil {
return nil, err
}
datesToPredict := func() []string {
result := make([]string, 0)
windowDuration := time.Second * time.Duration(float64(slices.Max(times)-slices.Min(times))*windowAsPercentOfTotalDuration)
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())))
result = append(result, lastPredicted.Format("2006-01"))
}
return result
}()
log.Print(datesToPredict)
namesDatesBalance := func() map[string]map[string]Balance {
result := make(map[string]map[string]Balance)
for date, balances := range reg {
for name, balance := range balances {
if _, ok := result[name]; !ok {
result[name] = make(map[string]Balance)
}
result[name][date] = balance
}
}
return result
}()
result := maps.Clone(reg)
for name, datesBalance := range namesDatesBalance {
dates := func() []int64 {
result := make([]int64, 0)
for k := range datesBalance {
v, _ := registerTime(k)
result = append(result, v.Unix())
}
slices.Sort(result)
return result
}()
weightedAverageContribution := func() map[Currency]float64 {
half := dates[len(dates)/2]
threeQuarter := dates[int(3.0*(len(dates)/4.0))]
sevenEighths := dates[int(7.0*(len(dates)/8.0))]
get := func(a, b int64) []Balance {
result := make([]Balance, 0)
for date, balance := range datesBalance {
v, _ := registerTime(date)
if v2 := v.Unix(); a <= v2 && v2 <= b {
result = append(result, balance)
}
}
return result
}
halfUp := get(half, threeQuarter)
threeQuarterUp := get(threeQuarter, sevenEighths)
sevenEighthsUp := get(sevenEighths, time.Now().Add(time.Hour*24*365).Unix())
weightedSum := make(map[Currency]float64, 0)
pushes := 0
pushWithWeight := func(b []Balance, weight int) {
for i, b2 := range b[1:] {
for c := range b2 {
v := b2[c] - b[i][c]
for i := 0; i < weight; i++ {
weightedSum[c] += v
pushes += 1
}
}
}
}
pushWithWeight(halfUp, 1)
pushWithWeight(threeQuarterUp, 2)
pushWithWeight(sevenEighthsUp, 4)
for k, v := range weightedSum {
weightedSum[k] = v / float64(pushes)
}
return weightedSum
}()
panic(fmt.Sprintf("%s: %v", name, weightedAverageContribution))
}
return result, nil
}
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)
}