From cef05232a694fececb30bf8849716b36b2669aa4 Mon Sep 17 00:00:00 2001 From: Michael Dvorkin Date: Tue, 23 Jul 2013 11:21:07 -0700 Subject: [PATCH] Refactored quotes --- lib/format.go | 21 +++++++--- lib/line_editor.go | 18 ++++----- lib/profile.go | 2 +- lib/screen.go | 7 ++-- lib/yahoo_quotes.go | 99 +++++++++++++++++++++++++-------------------- mop.go | 13 +++--- 6 files changed, 90 insertions(+), 70 deletions(-) diff --git a/lib/format.go b/lib/format.go index acb20a3..549dbf5 100644 --- a/lib/format.go +++ b/lib/format.go @@ -52,15 +52,15 @@ func FormatMarket(m *Market) string { } //----------------------------------------------------------------------------- -func FormatQuotes(quotes Quotes) string { +func FormatQuotes(q *Quotes) string { vars := struct { Now string Header string - Stocks Quotes + Stocks []Stock }{ time.Now().Format(`3:04:05pm PST`), header(), - prettify(quotes), + prettify(q.stocks), } markup := `{{.Now}} @@ -85,6 +85,7 @@ func FormatQuotes(quotes Quotes) string { return buffer.String() } +//----------------------------------------------------------------------------- func header() string { str := fmt.Sprintf(`%-7s `, `Ticker`) str += fmt.Sprintf(`%9s `, `Last`) @@ -105,9 +106,10 @@ func header() string { return str } -func prettify(quotes Quotes) Quotes { - pretty := make(Quotes, len(quotes)) - for i, q := range quotes { +//----------------------------------------------------------------------------- +func prettify(stocks []Stock) []Stock { + pretty := make([]Stock, len(stocks)) + for i, q := range stocks { pretty[i].Ticker = pad(q.Ticker, -7) pretty[i].LastTrade = pad(with_currency(q.LastTrade), 9) pretty[i].Change = pad(with_currency(q.Change), 9) @@ -127,6 +129,7 @@ func prettify(quotes Quotes) Quotes { return pretty } +//----------------------------------------------------------------------------- func nullify(str string) string { if len(str) == 3 && str[0:3] == `N/A` { return `-` @@ -135,6 +138,7 @@ func nullify(str string) string { } } +//----------------------------------------------------------------------------- func last_of_pair(str string) string { if len(str) >= 6 && str[0:6] != `N/A - ` { return str @@ -143,6 +147,7 @@ func last_of_pair(str string) string { } } +//----------------------------------------------------------------------------- func with_currency(str string) string { if str == `N/A` || str == `0.00` { return `-` @@ -156,6 +161,7 @@ func with_currency(str string) string { } } +//----------------------------------------------------------------------------- func with_percent(str string) string { if str == `N/A` { return `-` @@ -164,6 +170,7 @@ func with_percent(str string) string { } } +//----------------------------------------------------------------------------- func colorize(str string) string { if str == `N/A` { return `-` @@ -174,6 +181,7 @@ func colorize(str string) string { } } +//----------------------------------------------------------------------------- func ticker(str string, change string) string { if change[0:1] == `-` { return `` + str + `` @@ -182,6 +190,7 @@ func ticker(str string, change string) string { } } +//----------------------------------------------------------------------------- func pad(str string, width int) string { re := regexp.MustCompile(`(\.\d+)[MB]?$`) match := re.FindStringSubmatch(str) diff --git a/lib/line_editor.go b/lib/line_editor.go index e9aaa0b..5b09011 100644 --- a/lib/line_editor.go +++ b/lib/line_editor.go @@ -14,13 +14,13 @@ type LineEditor struct { cursor int input string 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.profile = profile + self.quotes = quotes return self } @@ -147,17 +147,17 @@ func (self *LineEditor) execute() { case '+': tickers := self.tokenize() if len(tickers) > 0 { - self.profile.AddTickers(tickers) - self.screen.DrawQuotes(self.profile.Quotes()) + self.quotes.profile.AddTickers(tickers) + self.screen.DrawQuotes(self.quotes) } case '-': tickers := self.tokenize() if len(tickers) > 0 { - before := len(self.profile.Tickers) - self.profile.RemoveTickers(tickers) - after := len(self.profile.Tickers) + before := len(self.quotes.profile.Tickers) + self.quotes.profile.RemoveTickers(tickers) + after := len(self.quotes.profile.Tickers) if after < before { - self.screen.DrawQuotes(self.profile.Quotes()) + self.screen.DrawQuotes(self.quotes) for i := before; i > after; i-- { self.screen.ClearLine(0, i + 4) } diff --git a/lib/profile.go b/lib/profile.go index 5fa4702..96b14bc 100644 --- a/lib/profile.go +++ b/lib/profile.go @@ -47,7 +47,7 @@ func (self *Profile) Save() error { } //----------------------------------------------------------------------------- -func (self *Profile) Quotes() string { +func (self *Profile) ListOfTickers() string { return strings.Join(self.Tickers, `+`) } diff --git a/lib/screen.go b/lib/screen.go index 40059dd..3709877 100644 --- a/lib/screen.go +++ b/lib/screen.go @@ -60,13 +60,12 @@ func (self *Screen) Close() { //----------------------------------------------------------------------------- func (self *Screen) DrawMarket(market *Market) { - self.draw(FormatMarket(market)) + self.draw(FormatMarket(market.Fetch())) } //----------------------------------------------------------------------------- -func (self *Screen) DrawQuotes(stocks string) { - quotes := GetQuotes(stocks) - self.draw(FormatQuotes(quotes)) +func (self *Screen) DrawQuotes(quotes *Quotes) { + self.draw(FormatQuotes(quotes.Fetch())) } //----------------------------------------------------------------------------- diff --git a/lib/yahoo_quotes.go b/lib/yahoo_quotes.go index 2d5e0a4..833aa89 100644 --- a/lib/yahoo_quotes.go +++ b/lib/yahoo_quotes.go @@ -10,10 +10,10 @@ import ( `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 // ?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' // // 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` -type Quote struct { +type Stock struct { Ticker string LastTrade string Change string @@ -55,12 +55,26 @@ type Quote struct { MarketCap 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. - url := fmt.Sprintf(yahoo_quotes_url, tickers) + url := fmt.Sprintf(yahoo_quotes_url, self.profile.ListOfTickers()) response, err := http.Get(url) if err != nil { panic(err) @@ -73,51 +87,48 @@ func GetQuotes(tickers string) Quotes { panic(err) } - return parse(sanitize(body)) -} - -func (q *Quote) Color() string { - if strings.Index(q.Change, "-") == -1 { - return `` - } else { - return `` // `` - } + return self.parse(self.sanitize(body)) } -func sanitize(body []byte) []byte { - return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1) -} - -func parse(body []byte) Quotes { +//----------------------------------------------------------------------------- +func (self *Quotes) parse(body []byte) *Quotes { lines := bytes.Split(body, []byte{'\n'}) - quotes := make(Quotes, len(lines)) + self.stocks = make([]Stock, len(lines)) for i, line := range lines { - // fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line)) - parse_line(line, "es[i]) + columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) + 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{','}) - - quote.Ticker = string(columns[0]) - quote.LastTrade = string(columns[1]) - quote.Change = string(columns[2]) - 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]) +//----------------------------------------------------------------------------- +func (stock *Stock) Color() string { + if strings.Index(stock.Change, "-") == -1 { + return `` + } else { + return `` // `` + } } diff --git a/mop.go b/mop.go index bc84317..cd95946 100644 --- a/mop.go +++ b/mop.go @@ -23,9 +23,10 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile) { }() market := new(mop.Market).Initialize().Fetch() + quotes := new(mop.Quotes).Initialize(market, profile) screen.Clear() screen.DrawMarket(market) - screen.DrawQuotes(profile.Quotes()) + screen.DrawQuotes(quotes) loop: for { @@ -37,7 +38,7 @@ loop: if event.Key == termbox.KeyEsc { break loop } 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) } } else { @@ -48,18 +49,18 @@ loop: } case termbox.EventResize: screen.Resize().Clear() - screen.DrawMarket(market.Fetch()) - screen.DrawQuotes(profile.Quotes()) + screen.DrawMarket(market) + screen.DrawQuotes(quotes) } case <-timestamp_queue.C: screen.DrawTime() case <-quotes_queue.C: - screen.DrawQuotes(profile.Quotes()) + screen.DrawQuotes(quotes) case <-market_queue.C: - screen.DrawMarket(market.Fetch()) + screen.DrawMarket(market) } } }