Skip to content

Commit

Permalink
feat: sort by position (#67)
Browse files Browse the repository at this point in the history
* feat: sort by position

* Readme

* test: Complete coverage

* refactor: Add functions names

* refactor: Change sort parameter to "value"

* test: Change expected value to reflect changes

* test: Test sorting with value with no quotes
  • Loading branch information
alexisloiselle authored Feb 6, 2021
1 parent 9a81feb commit 5e2e31b
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 57 deletions.
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func init() {
rootCmd.Flags().BoolVar(&extraInfoFundamentals, "show-fundamentals", false, "display open price, high, low, and volume for each quote")
rootCmd.Flags().BoolVar(&showSummary, "show-summary", false, "display summary of total gain and loss for positions")
rootCmd.Flags().StringVar(&proxy, "proxy", "", "proxy URL for requests (default is none)")
rootCmd.Flags().StringVar(&sort, "sort", "", "sort quotes on the UI. Set \"alpha\" to sort by ticker name. keep empty to sort according to change percent")
rootCmd.Flags().StringVar(&sort, "sort", "", "sort quotes on the UI. Set \"alpha\" to sort by ticker name. Set \"value\" to sort by position value. Keep empty to sort according to change percent")
}

func initConfig() {
Expand Down
94 changes: 94 additions & 0 deletions internal/sorter/sorter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package sorter

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

"github.com/novalagung/gubrak/v2"
)

type Sorter func(quotes []Quote, positions map[string]Position) []Quote

func NewSorter(sort string) Sorter {
if sorter, ok := sortDict[sort]; ok {
return sorter
} else {
return sortByChange
}
}

var sortDict = map[string]Sorter{
"alpha": sortByTicker,
"value": sortByValue,
}

func sortByTicker(quotes []Quote, positions map[string]Position) []Quote {
if len(quotes) <= 0 {
return quotes
}

result := gubrak.
From(quotes).
OrderBy(func(v Quote) string {
return v.Symbol
}).
Result()

return (result).([]Quote)
}

func sortByValue(quotes []Quote, positions map[string]Position) []Quote {
if len(quotes) <= 0 {
return quotes
}

activeQuotes, inactiveQuotes := splitActiveQuotes(quotes)

cActiveQuotes := gubrak.From(activeQuotes)
cInactiveQuotes := gubrak.From(inactiveQuotes)

positionsSorter := func(v Quote) float64 {
return positions[v.Symbol].Value
}

cActiveQuotes.OrderBy(positionsSorter, false)
cInactiveQuotes.OrderBy(positionsSorter, false)

result := cActiveQuotes.
Concat(cInactiveQuotes.Result()).
Result()

return (result).([]Quote)
}

func sortByChange(quotes []Quote, positions map[string]Position) []Quote {
if len(quotes) <= 0 {
return quotes
}

activeQuotes, inactiveQuotes := splitActiveQuotes(quotes)

cActiveQuotes := gubrak.
From(activeQuotes)

cActiveQuotes.OrderBy(func(v Quote) float64 {
return v.ChangePercent
}, false)

result := cActiveQuotes.
Concat(inactiveQuotes).
Result()

return (result).([]Quote)
}

func splitActiveQuotes(quotes []Quote) (interface{}, interface{}) {
activeQuotes, inactiveQuotes, _ := gubrak.
From(quotes).
Partition(func(v Quote) bool {
return v.IsActive
}).
ResultAndError()

return activeQuotes, inactiveQuotes
}
13 changes: 13 additions & 0 deletions internal/sorter/sorter_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package sorter_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestSorter(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Sorter Suite")
}
152 changes: 152 additions & 0 deletions internal/sorter/sorter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package sorter_test

import (
. "github.com/achannarasappa/ticker/internal/position"
. "github.com/achannarasappa/ticker/internal/quote"
. "github.com/achannarasappa/ticker/internal/sorter"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Sorter", func() {

Describe("NewSorter", func() {
bitcoinQuote := Quote{
ResponseQuote: ResponseQuote{
Symbol: "BTC-USD",
ShortName: "Bitcoin",
RegularMarketPreviousClose: 10000.0,
RegularMarketOpen: 10000.0,
RegularMarketDayRange: "10000 - 10000",
},
Price: 50000.0,
Change: 10000.0,
ChangePercent: 20.0,
IsActive: true,
IsRegularTradingSession: true,
}
twQuote := Quote{
ResponseQuote: ResponseQuote{
Symbol: "TW",
ShortName: "ThoughtWorks",
},
Price: 109.04,
Change: 3.53,
ChangePercent: 5.65,
IsActive: true,
IsRegularTradingSession: false,
}
googleQuote := Quote{
ResponseQuote: ResponseQuote{
Symbol: "GOOG",
ShortName: "Google Inc.",
},
Price: 2523.53,
Change: -32.02,
ChangePercent: -1.35,
IsActive: true,
IsRegularTradingSession: false,
}
msftQuote := Quote{
ResponseQuote: ResponseQuote{
Symbol: "MSFT",
ShortName: "Microsoft Corporation",
},
Price: 242.01,
Change: -0.99,
ChangePercent: -0.41,
IsActive: false,
IsRegularTradingSession: false,
}
quotes := []Quote{
bitcoinQuote,
twQuote,
googleQuote,
msftQuote,
}

positions := map[string]Position{
"BTC-USD": {
Value: 50000.0,
},
"GOOG": {
Value: 2523.53,
},
}
When("providing no sort parameter", func() {
It("should sort by default (change percent)", func() {
sorter := NewSorter("")

sortedQuotes := sorter(quotes, positions)
expected := []Quote{
bitcoinQuote,
twQuote,
googleQuote,
msftQuote,
}

Expect(sortedQuotes).To(Equal(expected))
})
})
When("providing \"alpha\" as a sort parameter", func() {
It("should sort by alphabetical order", func() {
sorter := NewSorter("alpha")

sortedQuotes := sorter(quotes, positions)
expected := []Quote{
bitcoinQuote,
googleQuote,
msftQuote,
twQuote,
}

Expect(sortedQuotes).To(Equal(expected))
})
})
When("providing \"position\" as a sort parameter", func() {
It("should sort position value, with inactive quotes last", func() {
sorter := NewSorter("value")

sortedQuotes := sorter(quotes, positions)
expected := []Quote{
bitcoinQuote,
googleQuote,
twQuote,
msftQuote,
}

Expect(sortedQuotes).To(Equal(expected))
})
})
When("providing no quotes", func() {
When("default sorter", func() {
It("should return no quotes", func() {
sorter := NewSorter("")

sortedQuotes := sorter([]Quote{}, map[string]Position{})
expected := []Quote{}
Expect(sortedQuotes).To(Equal(expected))
})
})
When("alpha sorter", func() {
It("should return no quotes", func() {
sorter := NewSorter("alpha")

sortedQuotes := sorter([]Quote{}, map[string]Position{})
expected := []Quote{}
Expect(sortedQuotes).To(Equal(expected))
})
})
When("value sorter", func() {
It("should return no quotes", func() {
sorter := NewSorter("value")

sortedQuotes := sorter([]Quote{}, map[string]Position{})
expected := []Quote{}
Expect(sortedQuotes).To(Equal(expected))
})
})
})
})
})
Loading

0 comments on commit 5e2e31b

Please sign in to comment.