moving ledger predictions to /ana
parent
e19eb89274
commit
2bc17fccf2
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -124,39 +124,6 @@ func registerWithContributionPredictionForNameForCurrency(reg Register, window t
|
||||||
return nil
|
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) {
|
func RegisterWithCompoundingInterestPrediction(reg Register, window time.Duration, pattern string, apy float64) (Register, error) {
|
||||||
lastBalances := make(Balances)
|
lastBalances := make(Balances)
|
||||||
p := regexp.MustCompile(pattern)
|
p := regexp.MustCompile(pattern)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package ledger
|
package ledger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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 {
|
func newTestRegister() map[string]Balances {
|
||||||
s := func(t time.Time) string {
|
s := func(t time.Time) string {
|
||||||
return t.Format("2006-01")
|
return t.Format("2006-01")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue