Skip to content

Commit

Permalink
fix: default to converting summary value/change to single currency (USD)
Browse files Browse the repository at this point in the history
  • Loading branch information
achannarasappa committed Feb 14, 2021
1 parent 708cb9d commit 034157d
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 28 deletions.
4 changes: 1 addition & 3 deletions internal/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import (
"github.com/achannarasappa/ticker/internal/cli"
. "github.com/achannarasappa/ticker/internal/cli"
c "github.com/achannarasappa/ticker/internal/common"
_ "github.com/achannarasappa/ticker/internal/currency"
. "github.com/achannarasappa/ticker/internal/position"
"github.com/achannarasappa/ticker/test/http"
_ "github.com/achannarasappa/ticker/test/http"
)
Expand Down Expand Up @@ -403,7 +401,7 @@ var _ = Describe("Cli", func() {
It("should not return an error", func() {
options.Watchlist = ""
ctx.Config = c.Config{
Lots: []Lot{
Lots: []c.Lot{
{
Symbol: "SYM",
UnitCost: 1.0,
Expand Down
7 changes: 6 additions & 1 deletion internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package common

import (
. "github.com/achannarasappa/ticker/internal/currency"
. "github.com/achannarasappa/ticker/internal/position"
"github.com/go-resty/resty/v2"
"github.com/spf13/afero"
)
Expand Down Expand Up @@ -33,3 +32,9 @@ type Dependencies struct {
Fs afero.Fs
HttpClient *resty.Client
}

type Lot struct {
Symbol string `yaml:"symbol"`
UnitCost float64 `yaml:"unit_cost"`
Quantity float64 `yaml:"quantity"`
}
20 changes: 11 additions & 9 deletions internal/position/position.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package position

import (
c "github.com/achannarasappa/ticker/internal/common"
. "github.com/achannarasappa/ticker/internal/quote"

"github.com/novalagung/gubrak/v2"
Expand All @@ -13,6 +14,7 @@ type Position struct {
DayChangePercent float64
TotalChange float64
TotalChangePercent float64
Currency string
}

type PositionSummary struct {
Expand All @@ -24,27 +26,21 @@ type PositionSummary struct {
DayChangePercent float64
}

type Lot struct {
Symbol string `yaml:"symbol"`
UnitCost float64 `yaml:"unit_cost"`
Quantity float64 `yaml:"quantity"`
}

type AggregatedLot struct {
Symbol string
Cost float64
Quantity float64
}

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

if lots == nil {
return map[string]AggregatedLot{}
}

aggregatedLots := gubrak.
From(lots).
Reduce(func(acc map[string]AggregatedLot, lot Lot) map[string]AggregatedLot {
Reduce(func(acc map[string]AggregatedLot, lot c.Lot) map[string]AggregatedLot {

aggregatedLot, ok := acc[lot.Symbol]
if !ok {
Expand Down Expand Up @@ -113,10 +109,16 @@ func GetPositions(aggregatedLots map[string]AggregatedLot) func([]Quote) map[str
}
}

func GetPositionSummary(positions map[string]Position) PositionSummary {
func GetPositionSummary(ctx c.Context, positions map[string]Position) PositionSummary {

positionValueCost := gubrak.From(positions).
Reduce(func(acc PositionSummary, position Position, key string) PositionSummary {
if currencyRate, ok := ctx.Reference.CurrencyRates[position.Currency]; ok {
acc.Value += (position.Value * currencyRate.Rate)
acc.Cost += (position.Cost * currencyRate.Rate)
acc.DayChange += (position.DayChange * currencyRate.Rate)
return acc
}
acc.Value += position.Value
acc.Cost += position.Cost
acc.DayChange += position.DayChange
Expand Down
30 changes: 22 additions & 8 deletions internal/position/position_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package position_test

import (
c "github.com/achannarasappa/ticker/internal/common"
"github.com/achannarasappa/ticker/internal/currency"
. "github.com/achannarasappa/ticker/internal/position"
. "github.com/achannarasappa/ticker/internal/quote"

Expand All @@ -12,7 +14,7 @@ var _ = Describe("Position", func() {

Describe("GetLots", func() {
It("should return a map of aggregated lots", func() {
input := []Lot{
input := []c.Lot{
{Symbol: "ABNB", UnitCost: 146.00, Quantity: 35},
{Symbol: "ARKW", UnitCost: 152.25, Quantity: 20},
{Symbol: "ARKW", UnitCost: 152.25, Quantity: 20},
Expand All @@ -27,7 +29,7 @@ var _ = Describe("Position", func() {

When("lots are not set", func() {
It("returns en empty aggregated lot", func() {
var input []Lot = nil
var input []c.Lot = nil
output := GetLots(input)
expected := map[string]AggregatedLot{}
Expect(output).To(Equal(expected))
Expand Down Expand Up @@ -97,7 +99,7 @@ var _ = Describe("Position", func() {

Describe("GetPositionSummary", func() {
It("should return a summary of positions", func() {
input := map[string]Position{
inputPositions := map[string]Position{
"ARKW": {
AggregatedLot: AggregatedLot{
Symbol: "ARKW",
Expand All @@ -124,14 +126,26 @@ var _ = Describe("Position", func() {
},
Value: 2000,
DayChange: 200,
Currency: "EUR",
},
}
output := GetPositionSummary(input)
inputCtx := c.Context{
Reference: c.Reference{
CurrencyRates: currency.CurrencyRates{
"EUR": currency.CurrencyRate{
FromCurrency: "EUR",
ToCurrency: "USD",
Rate: 1.5,
},
},
},
}
output := GetPositionSummary(inputCtx, inputPositions)
expected := PositionSummary{
Value: 6000,
Cost: 3000,
Change: 3000,
DayChange: 600,
Value: 7000,
Cost: 3500,
Change: 3500,
DayChange: 700,
ChangePercent: 200,
DayChangePercent: 10,
}
Expand Down
16 changes: 9 additions & 7 deletions internal/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
)

type Model struct {
ctx c.Context
ready bool
headerHeight int
getQuotes func() []quote.Quote
Expand All @@ -53,18 +54,19 @@ func (m Model) updateQuotes() tea.Cmd {
})
}

func NewModel(dep c.Dependencies, context c.Context) Model {
func NewModel(dep c.Dependencies, ctx c.Context) Model {

aggregatedLots := position.GetLots(context.Config.Lots)
symbols := position.GetSymbols(context.Config.Watchlist, aggregatedLots)
aggregatedLots := position.GetLots(ctx.Config.Lots)
symbols := position.GetSymbols(ctx.Config.Watchlist, aggregatedLots)

return Model{
headerHeight: getVerticalMargin(context.Config),
ctx: ctx,
headerHeight: getVerticalMargin(ctx.Config),
ready: false,
requestInterval: context.Config.RefreshInterval,
requestInterval: ctx.Config.RefreshInterval,
getQuotes: quote.GetQuotes(*dep.HttpClient, symbols),
getPositions: position.GetPositions(aggregatedLots),
watchlist: watchlist.NewModel(context.Config.Separate, context.Config.ExtraInfoExchange, context.Config.ExtraInfoFundamentals, context.Config.Sort),
watchlist: watchlist.NewModel(ctx.Config.Separate, ctx.Config.ExtraInfoExchange, ctx.Config.ExtraInfoFundamentals, ctx.Config.Sort),
summary: summary.NewModel(),
}
}
Expand Down Expand Up @@ -116,7 +118,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
positions := m.getPositions(msg.quotes)
m.watchlist.Quotes = msg.quotes
m.watchlist.Positions = positions
m.summary.Summary = position.GetPositionSummary(positions)
m.summary.Summary = position.GetPositionSummary(m.ctx, positions)
m.lastUpdateTime = msg.time
if m.ready {
m.viewport.SetContent(m.watchlist.View())
Expand Down

0 comments on commit 034157d

Please sign in to comment.