Skip to content

Commit

Permalink
fix: currency conversion for groups
Browse files Browse the repository at this point in the history
  • Loading branch information
achannarasappa committed Dec 19, 2021
1 parent 60d7559 commit 858eea3
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 81 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/muesli/reflow v0.3.0
github.com/muesli/termenv v0.9.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.10.5
github.com/onsi/gomega v1.17.0
github.com/spf13/afero v1.5.1
github.com/spf13/cobra v1.1.1
github.com/spf13/viper v1.7.0
Expand All @@ -42,11 +42,11 @@ require (
github.com/subosito/gotenv v1.2.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.25.0 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/ini.v1 v1.51.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,17 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down Expand Up @@ -210,12 +214,15 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
Expand Down Expand Up @@ -340,8 +347,11 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -457,6 +467,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
Expand Down
26 changes: 0 additions & 26 deletions internal/asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,32 +131,6 @@ func getHoldingFromAssetQuote(assetQuote c.AssetQuote, lotsBySymbol map[string]A

}

// GetSymbols retrieves a unique slice of symbols from the watchlist and lots sections of the config
func GetSymbols(config c.Config) []string {

symbols := make(map[string]bool)
symbolsUnique := make([]string, 0)

for _, symbol := range config.Watchlist {
if !symbols[symbol] {
symbols[symbol] = true
symbolsUnique = append(symbolsUnique, symbol)
}
}

if config.ShowHoldings {
for _, lot := range config.Lots {
if !symbols[lot.Symbol] {
symbols[lot.Symbol] = true
symbolsUnique = append(symbolsUnique, lot.Symbol)
}
}
}

return symbolsUnique

}

func getLots(lots []c.Lot) map[string]AggregatedLot {

if lots == nil {
Expand Down
37 changes: 0 additions & 37 deletions internal/asset/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,41 +192,4 @@ var _ = Describe("Asset", func() {
})

})

Describe("GetSymbols", func() {

It("should return a slice of symbols", func() {

inputConfig := c.Config{
Watchlist: []string{"GOOG", "ARKW"},
Lots: []c.Lot{
{Symbol: "ABNB", UnitCost: 100, Quantity: 10},
{Symbol: "ARKW", UnitCost: 200, Quantity: 10},
},
ShowHoldings: true,
}
output := GetSymbols(inputConfig)
expected := []string{
"ABNB",
"ARKW",
"GOOG",
}
Expect(output).To(ContainElements(expected))
})

When("holdings are hidden", func() {
It("should not show symbols for holdings", func() {
inputConfig := c.Config{
Watchlist: []string{"GOOG", "ARKW"},
ShowHoldings: false,
}
output := GetSymbols(inputConfig)
expected := []string{
"ARKW",
"GOOG",
}
Expect(output).To(ContainElements(expected))
})
})
})
})
11 changes: 4 additions & 7 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import (
"fmt"
"strings"

"github.com/achannarasappa/ticker/internal/asset"
c "github.com/achannarasappa/ticker/internal/common"
quoteYahoo "github.com/achannarasappa/ticker/internal/quote/yahoo"
"github.com/achannarasappa/ticker/internal/quote"
"github.com/achannarasappa/ticker/internal/ui/util"

"github.com/adrg/xdg"
Expand Down Expand Up @@ -74,8 +73,8 @@ func GetContext(d c.Dependencies, options Options, configPath string) (c.Context
}

config = getConfig(config, options, *d.HttpClient)
reference, err = getReference(config, *d.HttpClient)
groups := getGroups(config)
reference, err = getReference(config, groups, *d.HttpClient)

if err != nil {
return c.Context{}, err
Expand Down Expand Up @@ -113,11 +112,9 @@ func readConfig(fs afero.Fs, configPathOption string) (c.Config, error) {
return config, nil
}

func getReference(config c.Config, client resty.Client) (c.Reference, error) {
func getReference(config c.Config, assetGroups []c.AssetGroup, client resty.Client) (c.Reference, error) {

symbols := asset.GetSymbols(config)

currencyRates, err := quoteYahoo.GetCurrencyRates(client, symbols, config.Currency)
currencyRates, err := quote.GetAssetGroupsCurrencyRates(client, assetGroups, config.Currency)
styles := util.GetColorScheme(config.ColorScheme)

return c.Reference{
Expand Down
96 changes: 88 additions & 8 deletions internal/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"io/ioutil"
"os"
"strings"

"github.com/mitchellh/go-homedir"
. "github.com/onsi/ginkgo"
Expand Down Expand Up @@ -131,8 +132,13 @@ var _ = Describe("Cli", func() {
InputConfigFileContents: "watchlist:\n - GME\n - BB",
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Config": g.MatchFields(g.IgnoreExtras, g.Fields{
"Watchlist": Equal([]string{"GME", "BB"}),
"Groups": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("default"),
"Watchlist": Equal([]string{"GME", "BB"}),
}),
}),
}),
}),
}),
Expand All @@ -142,8 +148,13 @@ var _ = Describe("Cli", func() {
InputConfigFileContents: "",
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Config": g.MatchFields(g.IgnoreExtras, g.Fields{
"Watchlist": Equal([]string{"BIO", "BB"}),
"Groups": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("default"),
"Watchlist": Equal([]string{"BIO", "BB"}),
}),
}),
}),
}),
}),
Expand All @@ -153,8 +164,77 @@ var _ = Describe("Cli", func() {
InputConfigFileContents: "watchlist:\n - GME",
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Config": g.MatchFields(g.IgnoreExtras, g.Fields{
"Watchlist": Equal([]string{"BB"}),
"Groups": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("default"),
"Watchlist": Equal([]string{"BB"}),
}),
}),
}),
}),
}),

// groups
Entry("when groups are defined", Case{
InputOptions: cli.Options{},
InputConfigFileContents: strings.Join([]string{
"groups:",
" - name: crypto",
" watchlist:",
" - SHIB-USD",
" - BTC-USD",
" holdings:",
" - symbol: SOL1-USD",
" quantity: 17",
" unit_cost: 159.10",
}, "\n"),
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Groups": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("crypto"),
"Watchlist": Equal([]string{"SHIB-USD", "BTC-USD"}),
"Holdings": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"Symbol": Equal("SOL1-USD"),
"Quantity": Equal(17.0),
"UnitCost": Equal(159.10),
}),
}),
}),
}),
}),
}),
}),

Entry("when groups and watchlist are defined", Case{
InputOptions: cli.Options{},
InputConfigFileContents: strings.Join([]string{
"watchlist:",
" - TSLA",
"groups:",
" - name: crypto",
" watchlist:",
" - SOL1-USD",
" - BTC-USD",
}, "\n"),
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Groups": g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{
"0": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("default"),
"Watchlist": Equal([]string{"TSLA"}),
}),
}),
"1": g.MatchFields(g.IgnoreExtras, g.Fields{
"ConfigAssetGroup": g.MatchFields(g.IgnoreExtras, g.Fields{
"Name": Equal("crypto"),
"Watchlist": Equal([]string{"SOL1-USD", "BTC-USD"}),
}),
}),
}),
}),
}),
Expand Down Expand Up @@ -251,12 +331,12 @@ var _ = Describe("Cli", func() {
}),

Entry("when show-separator is set in options", Case{
InputOptions: cli.Options{Separate: false},
InputOptions: cli.Options{Separate: true},
InputConfigFileContents: "",
AssertionErr: BeNil(),
AssertionCtx: g.MatchFields(g.IgnoreExtras, g.Fields{
"Config": g.MatchFields(g.IgnoreExtras, g.Fields{
"Separate": Equal(false),
"Separate": Equal(true),
}),
}),
}),
Expand Down
57 changes: 57 additions & 0 deletions internal/quote/quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package quote
import (
c "github.com/achannarasappa/ticker/internal/common"
quoteYahoo "github.com/achannarasappa/ticker/internal/quote/yahoo"
"github.com/go-resty/resty/v2"
)

func getQuoteBySource(dep c.Dependencies, symbolBySource c.AssetGroupSymbolsBySource) []c.AssetQuote {
Expand Down Expand Up @@ -34,3 +35,59 @@ func GetAssetGroupQuote(dep c.Dependencies) func(c.AssetGroup) c.AssetGroupQuote
}
}
}

func getUniqueSymbolsBySource(assetGroups []c.AssetGroup) []c.AssetGroupSymbolsBySource {

symbols := make(map[c.QuoteSource]map[string]bool)
symbolsUnique := make(map[c.QuoteSource][]string)
var assetGroupSymbolsBySource []c.AssetGroupSymbolsBySource
for _, assetGroup := range assetGroups {

for _, symbolGroup := range assetGroup.SymbolsBySource {

for _, symbol := range symbolGroup.Symbols {

source := symbolGroup.Source

if symbols[source] == nil {
symbols[source] = map[string]bool{}
}

if !symbols[source][symbol] {
symbols[source][symbol] = true
symbolsUnique[source] = append(symbolsUnique[source], symbol)
}
}

}

}

for source, symbols := range symbolsUnique {
assetGroupSymbolsBySource = append(assetGroupSymbolsBySource, c.AssetGroupSymbolsBySource{
Source: source,
Symbols: symbols,
})
}

return assetGroupSymbolsBySource

}

// GetAssetGroupsCurrencyRates gets the currency rates by source across all asset groups
func GetAssetGroupsCurrencyRates(client resty.Client, assetGroups []c.AssetGroup, targetCurrency string) (c.CurrencyRates, error) {

var err error
var currencyRates c.CurrencyRates
uniqueSymbolsBySource := getUniqueSymbolsBySource(assetGroups)

for _, source := range uniqueSymbolsBySource {

if source.Source == c.QuoteSourceYahoo && err == nil {
currencyRates, err = quoteYahoo.GetCurrencyRates(client, source.Symbols, targetCurrency)
}

}

return currencyRates, err
}
Loading

0 comments on commit 858eea3

Please sign in to comment.