Skip to content

Commit 06eefc9

Browse files
committed
feat: account for holdings that do not exist from source
1 parent 1277a79 commit 06eefc9

File tree

6 files changed

+127
-11
lines changed

6 files changed

+127
-11
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
/.idea/
33
/api/templates/go-experimental/
44
/cookies.json
5+
*.gob
6+
*.exe

cmd/crypto-sync/sync.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"errors"
5+
"log"
56

67
"github.com/pelletier/go-toml"
78
"github.com/pelletier/go-toml/query"
@@ -33,6 +34,7 @@ func (s *SyncCmd) Run(ctx *Context) error {
3334
)
3435
allHoldings := make([]holdings.Holding, 0, 2)
3536
for _, holding := range s.Holdings {
37+
log.Println("Fetching holdings from ", holding)
3638
holdingsProvider, err := holdings.GetProvider(holding)
3739
if err != nil {
3840
return err

internal/common/compare.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package common
2+
3+
import "github.com/shopspring/decimal"
4+
5+
func MustParseFloatStringFloat64(val string) float64 {
6+
quantity, err := decimal.NewFromString(val)
7+
if err != nil {
8+
panic(err)
9+
}
10+
quantityFloat, _ := quantity.Float64()
11+
return quantityFloat
12+
}

internal/common/compare_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package common
2+
3+
import (
4+
"bytes"
5+
"encoding/gob"
6+
"io/ioutil"
7+
"testing"
8+
9+
"github.com/davecgh/go-spew/spew"
10+
11+
"github.com/will7200/go-crypto-sync/internal/holdings"
12+
"github.com/will7200/go-crypto-sync/pkg/personalcapital"
13+
)
14+
15+
func ReadGlob(p interface{}, filename string) {
16+
b, err := ioutil.ReadFile(filename)
17+
if err != nil {
18+
panic(err)
19+
}
20+
err = gob.NewDecoder(bytes.NewBuffer(b)).Decode(p)
21+
if err != nil {
22+
panic(err)
23+
}
24+
}
25+
26+
func TestAlgo(t *testing.T) {
27+
var pcHoldings personalcapital.GetHoldingsResponse
28+
var _holdings holdings.Holdings
29+
ReadGlob(&pcHoldings, "pc_holdings.gob")
30+
ReadGlob(&_holdings, "coinbase_holdings.gob")
31+
//for _, pcHolding := range pcHoldings.Holdings {
32+
// spew.Dump(_holdings.HasCurrencyName(pcHolding.Ticker))
33+
//}
34+
spew.Dump(pcHoldings.Holdings)
35+
spew.Dump(_holdings)
36+
spew.Dump(_holdings.HasCurrencyMap(func(l holdings.IHolding) string {
37+
return l.CurrencyName()
38+
}, func(r holdings.IHolding) string {
39+
return r.CurrencyName()
40+
}, PCHoldingsToIHoldings(pcHoldings.Holdings)...))
41+
42+
}
43+
44+
func PCHoldingsToIHoldings(h []personalcapital.HoldingsType) []holdings.IHolding {
45+
a := make([]holdings.IHolding, len(h))
46+
for i := 0; i < len(h); i++ {
47+
a[i] = h[i]
48+
}
49+
return a
50+
}

internal/holdings/account.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,45 @@ func (h Holdings) HasCurrencyName(name string) bool {
5151
}
5252

5353
type HasInfo struct {
54-
Exists bool
55-
LPos int
56-
RPos int
54+
LPos int
55+
RPos int
56+
}
57+
58+
func (hi HasInfo) FoundBoth() bool {
59+
return hi.LPos != -1 && hi.RPos != -1
60+
}
61+
62+
func (hi HasInfo) LeftOnly() bool {
63+
return hi.LPos != -1 && hi.RPos == -1
64+
}
65+
66+
func (hi HasInfo) RightOnly() bool {
67+
return hi.LPos == -1 && hi.RPos != -1
5768
}
5869

5970
func (h Holdings) HasCurrencyMap(left func(l IHolding) string, right func(r IHolding) string, ih ...IHolding) map[string]HasInfo {
6071
mb := make(map[string]HasInfo, len(h))
6172
for index, v := range h {
6273
mb[strings.ToLower(left(v))] = HasInfo{
63-
Exists: false,
64-
LPos: index,
65-
RPos: -1,
74+
LPos: index,
75+
RPos: -1,
6676
}
6777
}
6878
for index, v := range ih {
6979
key := strings.ToLower(right(v))
7080
if val, ok := mb[key]; ok {
71-
if val.Exists {
81+
if val.RPos != -1 {
7282
panic("conflicting entries")
7383
}
74-
val.Exists = true
7584
val.RPos = index
7685
mb[key] = val
86+
} else {
87+
if len(key) > 0 {
88+
mb[key] = HasInfo{
89+
LPos: -1,
90+
RPos: index,
91+
}
92+
}
7793
}
7894
}
7995
return mb

internal/pc/client.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ var (
2323
_ = spew.Dump
2424
)
2525

26+
// Sync source holdings to personal capital account
27+
// Currently cookies will be saved in the working directory of where this command is run
2628
func Sync(email, password string, holds holdings.Holdings, pricing holdings.Price) {
2729

2830
// Get saved cookies if available
29-
var cookies []*(http.Cookie)
31+
var cookies []*http.Cookie
3032
personalcapital.LoadSession(&cookies, "cookies.json")
3133

3234
// Setup a cookie jar so the session can be saved
@@ -85,6 +87,7 @@ func Sync(email, password string, holds holdings.Holdings, pricing holdings.Pric
8587
log.Println(key, value)
8688
// Handle special case if is us dollar
8789
if key == "us dollar" {
90+
log.Printf("updating PC cash amount\n")
8891
left := holds[value.LPos]
8992
quantity, err := decimal.NewFromString(left.TotalSharesString())
9093
if err != nil {
@@ -97,7 +100,8 @@ func Sync(email, password string, holds holdings.Holdings, pricing holdings.Pric
97100
}
98101
continue
99102
}
100-
if value.Exists {
103+
if value.FoundBoth() {
104+
log.Printf("%s found in pc, updating holding\n", holds[value.LPos].CurrencySymbolName())
101105
left, right := holds[value.LPos], pcHoldings.Holdings[value.RPos]
102106
quantity, err := decimal.NewFromString(left.TotalSharesString())
103107
if err != nil {
@@ -125,7 +129,8 @@ func Sync(email, password string, holds holdings.Holdings, pricing holdings.Pric
125129
if err != nil {
126130
panic(err)
127131
}
128-
} else {
132+
} else if value.LeftOnly() {
133+
log.Printf("%s not found in pc, create new holding\n", holds[value.LPos].CurrencySymbolName())
129134
quantity, err := decimal.NewFromString(holds[value.LPos].TotalSharesString())
130135
if err != nil {
131136
panic(err)
@@ -159,6 +164,35 @@ func Sync(email, password string, holds holdings.Holdings, pricing holdings.Pric
159164
if err != nil {
160165
panic(err)
161166
}
167+
} else if value.RightOnly() {
168+
right := pcHoldings.Holdings[value.RPos]
169+
currencySymbol := strings.TrimSpace(strings.Split(right.CurrencySymbolName(), "-")[0])
170+
log.Printf("%s not found from source, setting quantity to zero\n", currencySymbol)
171+
quantity, err := decimal.NewFromString("0.00")
172+
if err != nil {
173+
panic(err)
174+
}
175+
quantityFloat, _ := quantity.Float64()
176+
p, err := pricing.GetExchange(currencySymbol, "USD")
177+
if err != nil {
178+
panic(err)
179+
}
180+
pf, err := decimal.NewFromString(p)
181+
if err != nil {
182+
panic(err)
183+
}
184+
priceFloat, _ := pf.Float64()
185+
v := pf.Mul(quantity)
186+
valueFloat, _ := v.Float64()
187+
d := HoldingTypeToHoldingRequest(right)
188+
d.PriceSource = "COINBASE"
189+
d.Quantity = quantityFloat
190+
d.Value = valueFloat
191+
d.Price = priceFloat
192+
_, err = apiClient.Holdings.UpdateHoldings(context.Background(), d)
193+
if err != nil {
194+
panic(err)
195+
}
162196
}
163197
}
164198
personalcapital.SaveSession(client, cfg.Host, "cookies.json")

0 commit comments

Comments
 (0)