Initial public commit.
This commit is contained in:
164
moon/moon.go
Normal file
164
moon/moon.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package moon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"code.humancabbage.net/moonmath/coindesk"
|
||||
"github.com/sourcegraph/conc/pool"
|
||||
)
|
||||
|
||||
type Math struct {
|
||||
CurrentPrice coindesk.Price
|
||||
Columns []Column
|
||||
Goals []float64
|
||||
}
|
||||
|
||||
func NewMath(goals []float64, bases []Base) (m Math) {
|
||||
if goals == nil {
|
||||
goals = DefaultGoals
|
||||
}
|
||||
if bases == nil {
|
||||
bases = DefaultBases
|
||||
}
|
||||
m.Goals = goals
|
||||
m.Columns = make([]Column, len(bases))
|
||||
for i := range bases {
|
||||
m.Columns[i].Base = bases[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CDPR(days, gain float64) float64 {
|
||||
if gain <= 0 {
|
||||
return 0
|
||||
}
|
||||
cdpr := math.Pow(gain, 1/days)
|
||||
return cdpr
|
||||
}
|
||||
|
||||
type Projection struct {
|
||||
Dates []time.Time
|
||||
}
|
||||
|
||||
func ProjectDates(
|
||||
from time.Time, currentPrice float64, cdpr float64, goals []float64,
|
||||
) (p Projection) {
|
||||
if cdpr <= 0 {
|
||||
return
|
||||
}
|
||||
logP := math.Log(currentPrice)
|
||||
logR := math.Log(cdpr)
|
||||
for _, goal := range goals {
|
||||
daysToGo := (math.Log(goal) - logP) / logR
|
||||
date := from.Add(time.Hour * 24 * time.Duration(daysToGo))
|
||||
p.Dates = append(p.Dates, date)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Math) Refresh(ctx context.Context) (err error) {
|
||||
resp, err := coindesk.GetAssetTickers(ctx, coindesk.BTC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
m.CurrentPrice = resp.Data[coindesk.BTC].OHLC.Closing
|
||||
|
||||
tasks := pool.New().WithErrors()
|
||||
tasks.WithMaxGoroutines(len(m.Columns))
|
||||
//tasks.WithMaxGoroutines(1)
|
||||
now := time.Now()
|
||||
|
||||
for i := range m.Columns {
|
||||
c := &m.Columns[i]
|
||||
tasks.Go(func() error {
|
||||
c.StartingDate = c.Base.From(now)
|
||||
nextDay := c.StartingDate.Add(time.Hour * 24)
|
||||
resp, err := coindesk.GetPriceValues(ctx,
|
||||
coindesk.BTC, c.StartingDate, nextDay)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.StartingPrice = resp.Data.Entries[0].Price
|
||||
c.Gain = float64(m.CurrentPrice) / float64(c.StartingPrice)
|
||||
days := now.Sub(c.StartingDate).Hours() / 24
|
||||
c.CDPR = CDPR(days, c.Gain)
|
||||
if c.CDPR > 1 {
|
||||
c.Projections = ProjectDates(now, float64(m.CurrentPrice), c.CDPR, m.Goals)
|
||||
} else {
|
||||
c.Projections.Dates = nil
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err = tasks.Wait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Column struct {
|
||||
Base Base
|
||||
StartingDate time.Time
|
||||
StartingPrice coindesk.Price
|
||||
Gain float64
|
||||
CDPR float64
|
||||
Projections Projection
|
||||
}
|
||||
|
||||
var DefaultGoals = []float64{
|
||||
100000,
|
||||
150000,
|
||||
200000,
|
||||
250000,
|
||||
300000,
|
||||
500000,
|
||||
1000000,
|
||||
}
|
||||
|
||||
var DefaultBases = []Base{
|
||||
RelativeBase{"Month", time.Duration(-30) * time.Hour * 24},
|
||||
RelativeBase{"Quarter", time.Duration(-90) * time.Hour * 24},
|
||||
RelativeBase{"Half-Year", time.Duration(-182) * time.Hour * 24},
|
||||
RelativeBase{"Year", time.Duration(-365) * time.Hour * 24},
|
||||
ConstantBase{"2020-", time.Unix(1577836800, 0)},
|
||||
ConstantBase{"2019-", time.Unix(1546300800, 0)},
|
||||
ConstantBase{"2018-", time.Unix(1514764800, 0)},
|
||||
ConstantBase{"2017-", time.Unix(1483228800, 0)},
|
||||
}
|
||||
|
||||
// Base is a temporal point of comparison used for price projection.
|
||||
type Base interface {
|
||||
From(now time.Time) time.Time
|
||||
Name() string
|
||||
}
|
||||
|
||||
// ConstantBase is a base that is a constant time, e.g. 2020-01-01.
|
||||
type ConstantBase struct {
|
||||
name string
|
||||
time time.Time
|
||||
}
|
||||
|
||||
func (cb ConstantBase) From(_ time.Time) time.Time {
|
||||
return cb.time
|
||||
}
|
||||
|
||||
func (cb ConstantBase) Name() string {
|
||||
return cb.name
|
||||
}
|
||||
|
||||
// RelativeBase is a base that is relative, e.g. "90 days ago."
|
||||
type RelativeBase struct {
|
||||
name string
|
||||
offset time.Duration
|
||||
}
|
||||
|
||||
func (rb RelativeBase) From(now time.Time) time.Time {
|
||||
then := now.Add(time.Duration(rb.offset))
|
||||
return then
|
||||
}
|
||||
|
||||
func (rb RelativeBase) Name() string {
|
||||
return rb.name
|
||||
}
|
23
moon/moon_test.go
Normal file
23
moon/moon_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package moon_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.humancabbage.net/moonmath/moon"
|
||||
)
|
||||
|
||||
func TestCDPR(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProjection(t *testing.T) {
|
||||
p := moon.ProjectDates(time.Now(), 68900, 1.0055, []float64{
|
||||
100000,
|
||||
150000,
|
||||
200000,
|
||||
250000,
|
||||
300000,
|
||||
350000,
|
||||
})
|
||||
_ = p
|
||||
}
|
Reference in New Issue
Block a user