Refactored quotes

master
Michael Dvorkin 12 years ago
parent fd46f19683
commit cef05232a6
  1. 21
      lib/format.go
  2. 18
      lib/line_editor.go
  3. 2
      lib/profile.go
  4. 7
      lib/screen.go
  5. 99
      lib/yahoo_quotes.go
  6. 13
      mop.go

@ -52,15 +52,15 @@ func FormatMarket(m *Market) string {
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func FormatQuotes(quotes Quotes) string { func FormatQuotes(q *Quotes) string {
vars := struct { vars := struct {
Now string Now string
Header string Header string
Stocks Quotes Stocks []Stock
}{ }{
time.Now().Format(`3:04:05pm PST`), time.Now().Format(`3:04:05pm PST`),
header(), header(),
prettify(quotes), prettify(q.stocks),
} }
markup := `<right><white>{{.Now}}</white></right> markup := `<right><white>{{.Now}}</white></right>
@ -85,6 +85,7 @@ func FormatQuotes(quotes Quotes) string {
return buffer.String() return buffer.String()
} }
//-----------------------------------------------------------------------------
func header() string { func header() string {
str := fmt.Sprintf(`<u>%-7s `, `Ticker`) str := fmt.Sprintf(`<u>%-7s `, `Ticker`)
str += fmt.Sprintf(`%9s `, `Last`) str += fmt.Sprintf(`%9s `, `Last`)
@ -105,9 +106,10 @@ func header() string {
return str return str
} }
func prettify(quotes Quotes) Quotes { //-----------------------------------------------------------------------------
pretty := make(Quotes, len(quotes)) func prettify(stocks []Stock) []Stock {
for i, q := range quotes { pretty := make([]Stock, len(stocks))
for i, q := range stocks {
pretty[i].Ticker = pad(q.Ticker, -7) pretty[i].Ticker = pad(q.Ticker, -7)
pretty[i].LastTrade = pad(with_currency(q.LastTrade), 9) pretty[i].LastTrade = pad(with_currency(q.LastTrade), 9)
pretty[i].Change = pad(with_currency(q.Change), 9) pretty[i].Change = pad(with_currency(q.Change), 9)
@ -127,6 +129,7 @@ func prettify(quotes Quotes) Quotes {
return pretty return pretty
} }
//-----------------------------------------------------------------------------
func nullify(str string) string { func nullify(str string) string {
if len(str) == 3 && str[0:3] == `N/A` { if len(str) == 3 && str[0:3] == `N/A` {
return `-` return `-`
@ -135,6 +138,7 @@ func nullify(str string) string {
} }
} }
//-----------------------------------------------------------------------------
func last_of_pair(str string) string { func last_of_pair(str string) string {
if len(str) >= 6 && str[0:6] != `N/A - ` { if len(str) >= 6 && str[0:6] != `N/A - ` {
return str return str
@ -143,6 +147,7 @@ func last_of_pair(str string) string {
} }
} }
//-----------------------------------------------------------------------------
func with_currency(str string) string { func with_currency(str string) string {
if str == `N/A` || str == `0.00` { if str == `N/A` || str == `0.00` {
return `-` return `-`
@ -156,6 +161,7 @@ func with_currency(str string) string {
} }
} }
//-----------------------------------------------------------------------------
func with_percent(str string) string { func with_percent(str string) string {
if str == `N/A` { if str == `N/A` {
return `-` return `-`
@ -164,6 +170,7 @@ func with_percent(str string) string {
} }
} }
//-----------------------------------------------------------------------------
func colorize(str string) string { func colorize(str string) string {
if str == `N/A` { if str == `N/A` {
return `-` return `-`
@ -174,6 +181,7 @@ func colorize(str string) string {
} }
} }
//-----------------------------------------------------------------------------
func ticker(str string, change string) string { func ticker(str string, change string) string {
if change[0:1] == `-` { if change[0:1] == `-` {
return `<red>` + str + `</red>` return `<red>` + str + `</red>`
@ -182,6 +190,7 @@ func ticker(str string, change string) string {
} }
} }
//-----------------------------------------------------------------------------
func pad(str string, width int) string { func pad(str string, width int) string {
re := regexp.MustCompile(`(\.\d+)[MB]?$`) re := regexp.MustCompile(`(\.\d+)[MB]?$`)
match := re.FindStringSubmatch(str) match := re.FindStringSubmatch(str)

@ -14,13 +14,13 @@ type LineEditor struct {
cursor int cursor int
input string input string
screen *Screen screen *Screen
profile *Profile quotes *Quotes
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *LineEditor) Initialize(screen *Screen, profile *Profile) *LineEditor { func (self *LineEditor) Initialize(screen *Screen, quotes *Quotes) *LineEditor {
self.screen = screen self.screen = screen
self.profile = profile self.quotes = quotes
return self return self
} }
@ -147,17 +147,17 @@ func (self *LineEditor) execute() {
case '+': case '+':
tickers := self.tokenize() tickers := self.tokenize()
if len(tickers) > 0 { if len(tickers) > 0 {
self.profile.AddTickers(tickers) self.quotes.profile.AddTickers(tickers)
self.screen.DrawQuotes(self.profile.Quotes()) self.screen.DrawQuotes(self.quotes)
} }
case '-': case '-':
tickers := self.tokenize() tickers := self.tokenize()
if len(tickers) > 0 { if len(tickers) > 0 {
before := len(self.profile.Tickers) before := len(self.quotes.profile.Tickers)
self.profile.RemoveTickers(tickers) self.quotes.profile.RemoveTickers(tickers)
after := len(self.profile.Tickers) after := len(self.quotes.profile.Tickers)
if after < before { if after < before {
self.screen.DrawQuotes(self.profile.Quotes()) self.screen.DrawQuotes(self.quotes)
for i := before; i > after; i-- { for i := before; i > after; i-- {
self.screen.ClearLine(0, i + 4) self.screen.ClearLine(0, i + 4)
} }

@ -47,7 +47,7 @@ func (self *Profile) Save() error {
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Profile) Quotes() string { func (self *Profile) ListOfTickers() string {
return strings.Join(self.Tickers, `+`) return strings.Join(self.Tickers, `+`)
} }

@ -60,13 +60,12 @@ func (self *Screen) Close() {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Screen) DrawMarket(market *Market) { func (self *Screen) DrawMarket(market *Market) {
self.draw(FormatMarket(market)) self.draw(FormatMarket(market.Fetch()))
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Screen) DrawQuotes(stocks string) { func (self *Screen) DrawQuotes(quotes *Quotes) {
quotes := GetQuotes(stocks) self.draw(FormatQuotes(quotes.Fetch()))
self.draw(FormatQuotes(quotes))
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

@ -10,10 +10,10 @@ import (
`strings` `strings`
) )
// See http://www.gummy-stuff.org/Yahoo-data.htm // See http://www.gummy-stuff.org/Yahoo-stocks.htm
// Also http://query.yahooapis.com/v1/public/yql // Also http://query.yahooapis.com/v1/public/yql
// ?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in(%22ALU%22,%22AAPL%22) // ?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in(%22ALU%22,%22AAPL%22)
// &env=http%3A%2F%2Fdatatables.org%2Falltables.env // &env=http%3A%2F%2Fstockstables.org%2Falltables.env
// &format=json' // &format=json'
// //
// Current, Change, Open, High, Low, 52-W High, 52-W Low, Volume, AvgVolume, P/E, Yield, Market Cap. // Current, Change, Open, High, Low, 52-W High, 52-W Low, Volume, AvgVolume, P/E, Yield, Market Cap.
@ -36,7 +36,7 @@ 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 Quote struct { type Stock struct {
Ticker string Ticker string
LastTrade string LastTrade string
Change string Change string
@ -55,12 +55,26 @@ type Quote struct {
MarketCap string MarketCap string
MarketCapX string MarketCapX string
} }
type Quotes []Quote
func GetQuotes(tickers string) Quotes { type Quotes struct {
market *Market
profile *Profile
stocks []Stock
}
//-----------------------------------------------------------------------------
func (self *Quotes) Initialize(market *Market, profile *Profile) *Quotes {
self.market = market
self.profile = profile
return self
}
//-----------------------------------------------------------------------------
func (self *Quotes) Fetch() *Quotes {
// Format the URL and send the request. // Format the URL and send the request.
url := fmt.Sprintf(yahoo_quotes_url, tickers) url := fmt.Sprintf(yahoo_quotes_url, self.profile.ListOfTickers())
response, err := http.Get(url) response, err := http.Get(url)
if err != nil { if err != nil {
panic(err) panic(err)
@ -73,51 +87,48 @@ func GetQuotes(tickers string) Quotes {
panic(err) panic(err)
} }
return parse(sanitize(body)) return self.parse(self.sanitize(body))
}
func (q *Quote) Color() string {
if strings.Index(q.Change, "-") == -1 {
return `</green><green>`
} else {
return `` // `</red><red>`
}
} }
func sanitize(body []byte) []byte { //-----------------------------------------------------------------------------
return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1) func (self *Quotes) parse(body []byte) *Quotes {
}
func parse(body []byte) Quotes {
lines := bytes.Split(body, []byte{'\n'}) lines := bytes.Split(body, []byte{'\n'})
quotes := make(Quotes, len(lines)) self.stocks = make([]Stock, len(lines))
for i, line := range lines { for i, line := range lines {
// fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line)) columns := bytes.Split(bytes.TrimSpace(line), []byte{','})
parse_line(line, &quotes[i]) self.stocks[i].Ticker = string(columns[0])
self.stocks[i].LastTrade = string(columns[1])
self.stocks[i].Change = string(columns[2])
self.stocks[i].ChangePercent = string(columns[3])
self.stocks[i].Open = string(columns[4])
self.stocks[i].Low = string(columns[5])
self.stocks[i].High = string(columns[6])
self.stocks[i].Low52 = string(columns[7])
self.stocks[i].High52 = string(columns[8])
self.stocks[i].Volume = string(columns[9])
self.stocks[i].AvgVolume = string(columns[10])
self.stocks[i].PeRatio = string(columns[11])
self.stocks[i].PeRatioX = string(columns[12])
self.stocks[i].Dividend = string(columns[13])
self.stocks[i].Yield = string(columns[14])
self.stocks[i].MarketCap = string(columns[15])
self.stocks[i].MarketCapX = string(columns[16])
} }
return quotes return self
}
//-----------------------------------------------------------------------------
func (self *Quotes) sanitize(body []byte) []byte {
return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1)
} }
func parse_line(line []byte, quote *Quote) { //-----------------------------------------------------------------------------
columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) func (stock *Stock) Color() string {
if strings.Index(stock.Change, "-") == -1 {
quote.Ticker = string(columns[0]) return `</green><green>`
quote.LastTrade = string(columns[1]) } else {
quote.Change = string(columns[2]) return `` // `</red><red>`
quote.ChangePercent = string(columns[3]) }
quote.Open = string(columns[4])
quote.Low = string(columns[5])
quote.High = string(columns[6])
quote.Low52 = string(columns[7])
quote.High52 = string(columns[8])
quote.Volume = string(columns[9])
quote.AvgVolume = string(columns[10])
quote.PeRatio = string(columns[11])
quote.PeRatioX = string(columns[12])
quote.Dividend = string(columns[13])
quote.Yield = string(columns[14])
quote.MarketCap = string(columns[15])
quote.MarketCapX = string(columns[16])
} }

@ -23,9 +23,10 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile) {
}() }()
market := new(mop.Market).Initialize().Fetch() market := new(mop.Market).Initialize().Fetch()
quotes := new(mop.Quotes).Initialize(market, profile)
screen.Clear() screen.Clear()
screen.DrawMarket(market) screen.DrawMarket(market)
screen.DrawQuotes(profile.Quotes()) screen.DrawQuotes(quotes)
loop: loop:
for { for {
@ -37,7 +38,7 @@ loop:
if event.Key == termbox.KeyEsc { if event.Key == termbox.KeyEsc {
break loop break loop
} else if event.Ch == '+' || event.Ch == '-' { } else if event.Ch == '+' || event.Ch == '-' {
line_editor = new(mop.LineEditor).Initialize(screen, profile) line_editor = new(mop.LineEditor).Initialize(screen, quotes)
line_editor.Prompt(event.Ch) line_editor.Prompt(event.Ch)
} }
} else { } else {
@ -48,18 +49,18 @@ loop:
} }
case termbox.EventResize: case termbox.EventResize:
screen.Resize().Clear() screen.Resize().Clear()
screen.DrawMarket(market.Fetch()) screen.DrawMarket(market)
screen.DrawQuotes(profile.Quotes()) screen.DrawQuotes(quotes)
} }
case <-timestamp_queue.C: case <-timestamp_queue.C:
screen.DrawTime() screen.DrawTime()
case <-quotes_queue.C: case <-quotes_queue.C:
screen.DrawQuotes(profile.Quotes()) screen.DrawQuotes(quotes)
case <-market_queue.C: case <-market_queue.C:
screen.DrawMarket(market.Fetch()) screen.DrawMarket(market)
} }
} }
} }

Loading…
Cancel
Save