Skip to content

Commit

Permalink
refactor: combined position and position summary calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
achannarasappa committed Feb 14, 2021
1 parent 6d522e7 commit de5a846
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 153 deletions.
11 changes: 8 additions & 3 deletions internal/currency/currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,14 @@ func GetCurrencyRates(client resty.Client, symbols []string, targetCurrency stri
return getCurrencyRatesFromCurrencyPairSymbols(client, currencyPairSymbols)
}

func GetCurrencyRateFromContext(ctx c.Context, fromCurrency string) (float64, string) {
func GetCurrencyRateFromContext(ctx c.Context, fromCurrency string) (float64, float64, string) {
if currencyRate, ok := ctx.Reference.CurrencyRates[fromCurrency]; ok {
return currencyRate.Rate, currencyRate.ToCurrency
if ctx.Config.Currency != "" {
return currencyRate.Rate, currencyRate.Rate, currencyRate.ToCurrency
}

return 1.0, currencyRate.Rate, currencyRate.ToCurrency

}
return 1.0, fromCurrency
return 1.0, 1.0, fromCurrency
}
41 changes: 37 additions & 4 deletions internal/currency/currency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var _ = Describe("Currency", func() {
})

Describe("GetCurrencyRateFromContext", func() {
It("should return identity currency information when a rate is not found in reference data", func() {
It("should return default currency information when a rate is not found in reference data", func() {
inputCtx := c.Context{
Reference: c.Reference{
CurrencyRates: c.CurrencyRates{
Expand All @@ -72,15 +72,19 @@ var _ = Describe("Currency", func() {
},
},
}
outputRate, outputCurrencyCode := GetCurrencyRateFromContext(inputCtx, "EUR")
outputRate, outputDefaultRate, outputCurrencyCode := GetCurrencyRateFromContext(inputCtx, "EUR")
Expect(outputRate).To(Equal(1.0))
Expect(outputDefaultRate).To(Equal(1.0))
Expect(outputCurrencyCode).To(Equal("EUR"))
})
})

When("there is a matching currency in reference data", func() {
It("should return information needed to convert currency", func() {
It("should return rate to convert", func() {
inputCtx := c.Context{
Config: c.Config{
Currency: "EUR",
},
Reference: c.Reference{
CurrencyRates: c.CurrencyRates{
"USD": c.CurrencyRate{
Expand All @@ -96,8 +100,37 @@ var _ = Describe("Currency", func() {
},
},
}
outputRate, outputCurrencyCode := GetCurrencyRateFromContext(inputCtx, "USD")
outputRate, outputDefaultRate, outputCurrencyCode := GetCurrencyRateFromContext(inputCtx, "USD")
Expect(outputRate).To(Equal(1.25))
Expect(outputDefaultRate).To(Equal(1.25))
Expect(outputCurrencyCode).To(Equal("EUR"))
})
})

When("the currency is not set", func() {
It("should return rate to convert", func() {
inputCtx := c.Context{
Config: c.Config{
Currency: "",
},
Reference: c.Reference{
CurrencyRates: c.CurrencyRates{
"USD": c.CurrencyRate{
FromCurrency: "USD",
ToCurrency: "EUR",
Rate: 1.25,
},
"GBP": c.CurrencyRate{
FromCurrency: "GBP",
ToCurrency: "EUR",
Rate: 2,
},
},
},
}
outputRate, outputDefaultRate, outputCurrencyCode := GetCurrencyRateFromContext(inputCtx, "USD")
Expect(outputRate).To(Equal(1.0))
Expect(outputDefaultRate).To(Equal(1.25))
Expect(outputCurrencyCode).To(Equal("EUR"))
})
})
Expand Down
82 changes: 49 additions & 33 deletions internal/position/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ type AggregatedLot struct {
OrderIndex int
}

type positionSummaryBase struct {
value float64
cost float64
dayChange float64
}

type positionAcc struct {
positionSummaryBase positionSummaryBase
positions []Position
}

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

if lots == nil {
Expand Down Expand Up @@ -83,58 +94,63 @@ func GetSymbols(symbols []string, aggregatedLots map[string]AggregatedLot) []str

}

func GetPositions(ctx c.Context, aggregatedLots map[string]AggregatedLot) func([]Quote) map[string]Position {
return func(quotes []Quote) map[string]Position {
func GetPositions(ctx c.Context, aggregatedLots map[string]AggregatedLot) func([]Quote) (map[string]Position, PositionSummary) {
return func(quotes []Quote) (map[string]Position, PositionSummary) {

positions := gubrak.
positionsReduced := (gubrak.
From(quotes).
Reduce(func(acc []Position, quote Quote) []Position {
Reduce(func(acc positionAcc, quote Quote) positionAcc {

if aggLot, ok := aggregatedLots[quote.Symbol]; ok {
currencyRate, currencyCode := currency.GetCurrencyRateFromContext(ctx, quote.Currency)

currencyRate, currencyRateDefault, currencyCode := currency.GetCurrencyRateFromContext(ctx, quote.Currency)

totalChange := (quote.Price * aggLot.Quantity) - (aggLot.Cost * currencyRate)
return append(acc, Position{
totalChangePercant := (totalChange / (aggLot.Cost * currencyRate)) * 100

position := Position{
AggregatedLot: aggLot,
Value: quote.Price * aggLot.Quantity,
DayChange: quote.Change * aggLot.Quantity,
DayChangePercent: quote.ChangePercent,
TotalChange: totalChange,
TotalChangePercent: (totalChange / (aggLot.Cost * currencyRate)) * 100,
TotalChangePercent: totalChangePercant,
Currency: quote.Currency,
CurrencyConverted: currencyCode,
})
}

acc.positions = append(acc.positions, position)
acc.positionSummaryBase = getPositionSummaryBase(position, acc.positionSummaryBase, currencyRateDefault)

}

return acc
}, make([]Position, 0)).

}, positionAcc{}).
Result()).(positionAcc)

positionSummary := PositionSummary{
Value: positionsReduced.positionSummaryBase.value,
Cost: positionsReduced.positionSummaryBase.cost,
Change: positionsReduced.positionSummaryBase.value - positionsReduced.positionSummaryBase.cost,
DayChange: positionsReduced.positionSummaryBase.cost,
ChangePercent: (positionsReduced.positionSummaryBase.value / positionsReduced.positionSummaryBase.cost) * 100,
DayChangePercent: (positionsReduced.positionSummaryBase.dayChange / positionsReduced.positionSummaryBase.value) * 100,
}

positions := gubrak.From(positionsReduced.positions).
KeyBy(func(position Position) string {
return position.Symbol
}).
Result()

return (positions).(map[string]Position)
return (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 {
currencyRate := 1.0
if ctx.Config.Currency == "" {
currencyRate, _ = currency.GetCurrencyRateFromContext(ctx, position.Currency)
}
acc.Value += (position.Value * currencyRate)
acc.Cost += (position.Cost * currencyRate)
acc.DayChange += (position.DayChange * currencyRate)
return acc
}, PositionSummary{}).
Result()

positionSummary := (positionValueCost).(PositionSummary)

positionSummary.Change = positionSummary.Value - positionSummary.Cost
positionSummary.ChangePercent = (positionSummary.Value / positionSummary.Cost) * 100
positionSummary.DayChangePercent = (positionSummary.DayChange / positionSummary.Value) * 100

return positionSummary

func getPositionSummaryBase(position Position, acc positionSummaryBase, currencyRateDefault float64) positionSummaryBase {
acc.value += (position.Value * currencyRateDefault)
acc.cost += (position.Cost * currencyRateDefault)
acc.dayChange += (position.DayChange * currencyRateDefault)
return acc
}
Loading

0 comments on commit de5a846

Please sign in to comment.