Column sorting

master
Michael Dvorkin 12 years ago
parent 4d4ed17228
commit e0b8453680
  1. 122
      lib/layout.go
  2. 91
      lib/sorter.go
  3. 7
      lib/yahoo_market.go
  4. 70
      lib/yahoo_quotes.go

@ -8,6 +8,7 @@ import (
`regexp` `regexp`
`strings` `strings`
`text/template` `text/template`
`sort`
`time` `time`
) )
@ -24,23 +25,23 @@ type Layout struct {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Layout) Initialize() *Layout { func (self *Layout) Initialize() *Layout {
self.columns = make([]Column, TotalColumns) self.columns = []Column{
{ -7, `Ticker`},
self.columns[0] = Column{ -7, `Ticker`} { 10, `Last`},
self.columns[1] = Column{ 10, `Last`} { 10, `Change`},
self.columns[2] = Column{ 10, `Change`} { 10, `%Change`},
self.columns[3] = Column{ 10, `%Change`} { 10, `Open`},
self.columns[4] = Column{ 10, `Open`} { 10, `Low`},
self.columns[5] = Column{ 10, `Low`} { 10, `High`},
self.columns[6] = Column{ 10, `High`} { 10, `52w Low`},
self.columns[7] = Column{ 10, `52w Low`} { 10, `52w High`},
self.columns[8] = Column{ 10, `52w High`} { 11, `Volume`},
self.columns[9] = Column{ 11, `Volume`} { 11, `AvgVolume`},
self.columns[10] = Column{ 11, `AvgVolume`} { 10, `P/E`},
self.columns[11] = Column{ 10, `P/E`} { 10, `Dividend`},
self.columns[12] = Column{ 10, `Dividend`} { 10, `Yield`},
self.columns[13] = Column{ 10, `Yield`} { 11, `MktCap`},
self.columns[14] = Column{ 11, `MktCap`} }
return self return self
} }
@ -68,7 +69,7 @@ func (self *Layout) Market(m *Market) string {
markup += "\n" markup += "\n"
markup += `{{.Advances.name}}: {{.Advances.nyse}} ({{.Advances.nysep}}) on NYSE and {{.Advances.nasdaq}} ({{.Advances.nasdaqp}}) on Nasdaq. ` markup += `{{.Advances.name}}: {{.Advances.nyse}} ({{.Advances.nysep}}) on NYSE and {{.Advances.nasdaq}} ({{.Advances.nasdaqp}}) on Nasdaq. `
markup += `{{.Declines.name}}: {{.Declines.nyse}} ({{.Declines.nysep}}) on NYSE and {{.Declines.nasdaq}} ({{.Declines.nasdaqp}}) on Nasdaq` markup += `{{.Declines.name}}: {{.Declines.nyse}} ({{.Declines.nysep}}) on NYSE and {{.Declines.nasdaq}} ({{.Declines.nasdaqp}}) on Nasdaq`
if !m.Open { if m.IsClosed {
markup += `<right>U.S. markets closed</right>` markup += `<right>U.S. markets closed</right>`
} }
markup += "\n" markup += "\n"
@ -105,7 +106,7 @@ func (self *Layout) Quotes(quotes *Quotes) string {
{{.Header}} {{.Header}}
{{range.Stocks}}{{.Color}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePercent}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}} {{range.Stocks}}{{.Color}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePct}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}}
{{end}}` {{end}}`
//markup += fmt.Sprintf("[%v]", quotes.profile.Grouped) //markup += fmt.Sprintf("[%v]", quotes.profile.Grouped)
template, err := template.New(`quotes`).Parse(markup) template, err := template.New(`quotes`).Parse(markup)
@ -140,24 +141,71 @@ func (self *Layout) Header(profile *Profile) string {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Layout) prettify(quotes *Quotes) []Stock { func (self *Layout) prettify(quotes *Quotes) []Stock {
var sorts []sort.Interface
pretty := make([]Stock, len(quotes.stocks)) pretty := make([]Stock, len(quotes.stocks))
for i, q := range group(quotes) {
pretty[i].Ticker = pad(q.Ticker, self.columns[0].width) //for i, q := range group(quotes) {
pretty[i].LastTrade = pad(with_currency(q.LastTrade), self.columns[1].width) for i, q := range quotes.stocks {
pretty[i].Change = pad(with_currency(q.Change), self.columns[2].width) pretty[i].Ticker = pad(q.Ticker, self.columns[0].width)
pretty[i].ChangePercent = pad(last_of_pair(q.ChangePercent), self.columns[3].width) pretty[i].LastTrade = pad(with_currency(q.LastTrade), self.columns[1].width)
pretty[i].Open = pad(with_currency(q.Open), self.columns[4].width) pretty[i].Change = pad(with_currency(q.Change), self.columns[2].width)
pretty[i].Low = pad(with_currency(q.Low), self.columns[5].width) pretty[i].ChangePct = pad(last_of_pair(q.ChangePct), self.columns[3].width)
pretty[i].High = pad(with_currency(q.High), self.columns[6].width) pretty[i].Open = pad(with_currency(q.Open), self.columns[4].width)
pretty[i].Low52 = pad(with_currency(q.Low52), self.columns[7].width) pretty[i].Low = pad(with_currency(q.Low), self.columns[5].width)
pretty[i].High52 = pad(with_currency(q.High52), self.columns[8].width) pretty[i].High = pad(with_currency(q.High), self.columns[6].width)
pretty[i].Volume = pad(q.Volume, self.columns[9].width) pretty[i].Low52 = pad(with_currency(q.Low52), self.columns[7].width)
pretty[i].AvgVolume = pad(q.AvgVolume, self.columns[10].width) pretty[i].High52 = pad(with_currency(q.High52), self.columns[8].width)
pretty[i].PeRatio = pad(nullify(q.PeRatioX), self.columns[11].width) pretty[i].Volume = pad(q.Volume, self.columns[9].width)
pretty[i].Dividend = pad(with_currency(q.Dividend), self.columns[12].width) pretty[i].AvgVolume = pad(q.AvgVolume, self.columns[10].width)
pretty[i].Yield = pad(with_percent(q.Yield), self.columns[13].width) pretty[i].PeRatio = pad(nullify(q.PeRatioX), self.columns[11].width)
pretty[i].MarketCap = pad(with_currency(q.MarketCapX), self.columns[14].width) pretty[i].Dividend = pad(with_currency(q.Dividend), self.columns[12].width)
pretty[i].Yield = pad(with_percent(q.Yield), self.columns[13].width)
pretty[i].MarketCap = pad(with_currency(q.MarketCapX), self.columns[14].width)
}
if quotes.profile.Ascending {
sorts = []sort.Interface{
ByTickerAsc { pretty },
ByLastTradeAsc { pretty },
ByChangeAsc { pretty },
ByChangePctAsc { pretty },
ByOpenAsc { pretty },
ByLowAsc { pretty },
ByHighAsc { pretty },
ByLow52Asc { pretty },
ByHigh52Asc { pretty },
ByVolumeAsc { pretty },
ByAvgVolumeAsc { pretty },
ByPeRatioAsc { pretty },
//ByPeRatioXAsc { pretty },
ByDividendAsc { pretty },
ByYieldAsc { pretty },
ByMarketCapAsc { pretty },
//ByMarketCapXAsc { pretty },
}
} else {
sorts = []sort.Interface{
ByTickerDesc { pretty },
ByLastTradeDesc { pretty },
ByChangeDesc { pretty },
ByChangePctDesc { pretty },
ByOpenDesc { pretty },
ByLowDesc { pretty },
ByHighDesc { pretty },
ByLow52Desc { pretty },
ByHigh52Desc { pretty },
ByVolumeDesc { pretty },
ByAvgVolumeDesc { pretty },
ByPeRatioDesc { pretty },
//ByPeRatioXDesc { pretty },
ByDividendDesc { pretty },
ByYieldDesc { pretty },
ByMarketCapDesc { pretty },
//ByMarketCapXDesc { pretty },
}
} }
sort.Sort(sorts[quotes.profile.SortColumn])
return pretty return pretty
} }
@ -188,9 +236,9 @@ func group(quotes *Quotes) []Stock {
func arrow_for(column int, profile *Profile) string { func arrow_for(column int, profile *Profile) string {
if column == profile.SortColumn { if column == profile.SortColumn {
if profile.Ascending { if profile.Ascending {
return string('\U00002193')
} else {
return string('\U00002191') return string('\U00002191')
} else {
return string('\U00002193')
} }
} }
return `` return ``

@ -0,0 +1,91 @@
// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
package mop
import (
`strings`
`strconv`
)
type Sortable []Stock
func (list Sortable) Len() int { return len(list) }
func (list Sortable) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
type ByTickerAsc struct { Sortable }
type ByLastTradeAsc struct { Sortable }
type ByChangeAsc struct { Sortable }
type ByChangePctAsc struct { Sortable }
type ByOpenAsc struct { Sortable }
type ByLowAsc struct { Sortable }
type ByHighAsc struct { Sortable }
type ByLow52Asc struct { Sortable }
type ByHigh52Asc struct { Sortable }
type ByVolumeAsc struct { Sortable }
type ByAvgVolumeAsc struct { Sortable }
type ByPeRatioAsc struct { Sortable }
type ByPeRatioXAsc struct { Sortable }
type ByDividendAsc struct { Sortable }
type ByYieldAsc struct { Sortable }
type ByMarketCapAsc struct { Sortable }
type ByMarketCapXAsc struct { Sortable }
type ByTickerDesc struct { Sortable }
type ByLastTradeDesc struct { Sortable }
type ByChangeDesc struct { Sortable }
type ByChangePctDesc struct { Sortable }
type ByOpenDesc struct { Sortable }
type ByLowDesc struct { Sortable }
type ByHighDesc struct { Sortable }
type ByLow52Desc struct { Sortable }
type ByHigh52Desc struct { Sortable }
type ByVolumeDesc struct { Sortable }
type ByAvgVolumeDesc struct { Sortable }
type ByPeRatioDesc struct { Sortable }
type ByPeRatioXDesc struct { Sortable }
type ByDividendDesc struct { Sortable }
type ByYieldDesc struct { Sortable }
type ByMarketCapDesc struct { Sortable }
type ByMarketCapXDesc struct { Sortable }
func (list ByTickerAsc) Less(i, j int) bool { return list.Sortable[i].Ticker < list.Sortable[j].Ticker }
func (list ByLastTradeAsc) Less(i, j int) bool { return list.Sortable[i].LastTrade < list.Sortable[j].LastTrade }
func (list ByChangeAsc) Less(i, j int) bool { return z(list.Sortable[i].Change) < z(list.Sortable[j].Change) }
func (list ByChangePctAsc) Less(i, j int) bool { return z(list.Sortable[i].ChangePct) < z(list.Sortable[j].ChangePct) }
func (list ByOpenAsc) Less(i, j int) bool { return list.Sortable[i].Open < list.Sortable[j].Open }
func (list ByLowAsc) Less(i, j int) bool { return list.Sortable[i].Low < list.Sortable[j].Low }
func (list ByHighAsc) Less(i, j int) bool { return list.Sortable[i].High < list.Sortable[j].High }
func (list ByLow52Asc) Less(i, j int) bool { return list.Sortable[i].Low52 < list.Sortable[j].Low52 }
func (list ByHigh52Asc) Less(i, j int) bool { return list.Sortable[i].High52 < list.Sortable[j].High52 }
func (list ByVolumeAsc) Less(i, j int) bool { return list.Sortable[i].Volume < list.Sortable[j].Volume }
func (list ByAvgVolumeAsc) Less(i, j int) bool { return list.Sortable[i].AvgVolume < list.Sortable[j].AvgVolume }
func (list ByPeRatioAsc) Less(i, j int) bool { return list.Sortable[i].PeRatio < list.Sortable[j].PeRatio }
func (list ByPeRatioXAsc) Less(i, j int) bool { return list.Sortable[i].PeRatioX < list.Sortable[j].PeRatioX }
func (list ByDividendAsc) Less(i, j int) bool { return list.Sortable[i].Dividend < list.Sortable[j].Dividend }
func (list ByYieldAsc) Less(i, j int) bool { return list.Sortable[i].Yield < list.Sortable[j].Yield }
func (list ByMarketCapAsc) Less(i, j int) bool { return list.Sortable[i].MarketCap < list.Sortable[j].MarketCap }
func (list ByMarketCapXAsc) Less(i, j int) bool { return list.Sortable[i].MarketCapX < list.Sortable[j].MarketCapX }
func (list ByTickerDesc) Less(i, j int) bool { return list.Sortable[j].Ticker < list.Sortable[i].Ticker }
func (list ByLastTradeDesc) Less(i, j int) bool { return list.Sortable[j].LastTrade < list.Sortable[i].LastTrade }
func (list ByChangeDesc) Less(i, j int) bool { return z(list.Sortable[j].Change) < z(list.Sortable[i].Change) }
func (list ByChangePctDesc) Less(i, j int) bool { return z(list.Sortable[j].ChangePct) < z(list.Sortable[i].ChangePct) }
func (list ByOpenDesc) Less(i, j int) bool { return list.Sortable[j].Open < list.Sortable[i].Open }
func (list ByLowDesc) Less(i, j int) bool { return list.Sortable[j].Low < list.Sortable[i].Low }
func (list ByHighDesc) Less(i, j int) bool { return list.Sortable[j].High < list.Sortable[i].High }
func (list ByLow52Desc) Less(i, j int) bool { return list.Sortable[j].Low52 < list.Sortable[i].Low52 }
func (list ByHigh52Desc) Less(i, j int) bool { return list.Sortable[j].High52 < list.Sortable[i].High52 }
func (list ByVolumeDesc) Less(i, j int) bool { return list.Sortable[j].Volume < list.Sortable[i].Volume }
func (list ByAvgVolumeDesc) Less(i, j int) bool { return list.Sortable[j].AvgVolume < list.Sortable[i].AvgVolume }
func (list ByPeRatioDesc) Less(i, j int) bool { return list.Sortable[j].PeRatio < list.Sortable[i].PeRatio }
func (list ByPeRatioXDesc) Less(i, j int) bool { return list.Sortable[j].PeRatioX < list.Sortable[i].PeRatioX }
func (list ByDividendDesc) Less(i, j int) bool { return list.Sortable[j].Dividend < list.Sortable[i].Dividend }
func (list ByYieldDesc) Less(i, j int) bool { return list.Sortable[j].Yield < list.Sortable[i].Yield }
func (list ByMarketCapDesc) Less(i, j int) bool { return list.Sortable[j].MarketCap < list.Sortable[i].MarketCap }
func (list ByMarketCapXDesc) Less(i, j int) bool { return list.Sortable[j].MarketCapX < list.Sortable[i].MarketCapX }
func z(str string) float32 {
float := strings.Replace(strings.Trim(str, ` %`), `$`, ``, 1)
value,_ := strconv.ParseFloat(float, 32)
return float32(value)
}

@ -11,7 +11,7 @@ import (
) )
type Market struct { type Market struct {
Open bool IsClosed bool
Dow map[string]string Dow map[string]string
Nasdaq map[string]string Nasdaq map[string]string
Sp500 map[string]string Sp500 map[string]string
@ -24,7 +24,7 @@ type Market struct {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Market) Initialize() *Market { func (self *Market) Initialize() *Market {
self.Open = true self.IsClosed = false
self.Dow = make(map[string]string) self.Dow = make(map[string]string)
self.Nasdaq = make(map[string]string) self.Nasdaq = make(map[string]string)
self.Sp500 = make(map[string]string) self.Sp500 = make(map[string]string)
@ -65,7 +65,8 @@ func (self *Market) Format() string {
func (self *Market) check_if_market_open(body []byte) []byte { func (self *Market) check_if_market_open(body []byte) []byte {
start := bytes.Index(body, []byte(`id="yfs_market_time"`)) start := bytes.Index(body, []byte(`id="yfs_market_time"`))
finish := start + bytes.Index(body[start:], []byte(`</span>`)) finish := start + bytes.Index(body[start:], []byte(`</span>`))
self.Open = !bytes.Contains(body[start:finish], []byte(`closed`)) snippet := body[start:finish]
self.IsClosed = bytes.Contains(snippet, []byte(`closed`)) || bytes.Contains(snippet, []byte(`open in`))
return body[finish:] return body[finish:]
} }

@ -37,23 +37,23 @@ import (
const yahoo_quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1` const yahoo_quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1`
type Stock struct { type Stock struct {
Ticker string Ticker string
LastTrade string LastTrade string
Change string Change string
ChangePercent string ChangePct string
Open string Open string
Low string Low string
High string High string
Low52 string Low52 string
High52 string High52 string
Volume string Volume string
AvgVolume string AvgVolume string
PeRatio string PeRatio string
PeRatioX string PeRatioX string
Dividend string Dividend string
Yield string Yield string
MarketCap string MarketCap string
MarketCapX string MarketCapX string
} }
type Quotes struct { type Quotes struct {
@ -72,7 +72,7 @@ func (self *Quotes) Initialize(market *Market, profile *Profile) *Quotes {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Quotes) Fetch() *Quotes { func (self *Quotes) Fetch() *Quotes {
if self.market.Open || self.stocks == nil { if !self.market.IsClosed || self.stocks == nil {
// Format the URL and send the request. // Format the URL and send the request.
url := fmt.Sprintf(yahoo_quotes_url, self.profile.ListOfTickers()) url := fmt.Sprintf(yahoo_quotes_url, self.profile.ListOfTickers())
response, err := http.Get(url) response, err := http.Get(url)
@ -121,23 +121,23 @@ func (self *Quotes) parse(body []byte) *Quotes {
for i, line := range lines { for i, line := range lines {
columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) columns := bytes.Split(bytes.TrimSpace(line), []byte{','})
self.stocks[i].Ticker = string(columns[0]) self.stocks[i].Ticker = string(columns[0])
self.stocks[i].LastTrade = string(columns[1]) self.stocks[i].LastTrade = string(columns[1])
self.stocks[i].Change = string(columns[2]) self.stocks[i].Change = string(columns[2])
self.stocks[i].ChangePercent = string(columns[3]) self.stocks[i].ChangePct = string(columns[3])
self.stocks[i].Open = string(columns[4]) self.stocks[i].Open = string(columns[4])
self.stocks[i].Low = string(columns[5]) self.stocks[i].Low = string(columns[5])
self.stocks[i].High = string(columns[6]) self.stocks[i].High = string(columns[6])
self.stocks[i].Low52 = string(columns[7]) self.stocks[i].Low52 = string(columns[7])
self.stocks[i].High52 = string(columns[8]) self.stocks[i].High52 = string(columns[8])
self.stocks[i].Volume = string(columns[9]) self.stocks[i].Volume = string(columns[9])
self.stocks[i].AvgVolume = string(columns[10]) self.stocks[i].AvgVolume = string(columns[10])
self.stocks[i].PeRatio = string(columns[11]) self.stocks[i].PeRatio = string(columns[11])
self.stocks[i].PeRatioX = string(columns[12]) self.stocks[i].PeRatioX = string(columns[12])
self.stocks[i].Dividend = string(columns[13]) self.stocks[i].Dividend = string(columns[13])
self.stocks[i].Yield = string(columns[14]) self.stocks[i].Yield = string(columns[14])
self.stocks[i].MarketCap = string(columns[15]) self.stocks[i].MarketCap = string(columns[15])
self.stocks[i].MarketCapX = string(columns[16]) self.stocks[i].MarketCapX = string(columns[16])
} }
return self return self

Loading…
Cancel
Save