From d745d1b12d2c98339e67af182020539e95999ca2 Mon Sep 17 00:00:00 2001 From: Michael Dvorkin Date: Thu, 5 Sep 2013 22:00:55 -0700 Subject: [PATCH] First golint pass for yahoo_quotes.go --- yahoo_quotes.go | 145 ++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 85 deletions(-) diff --git a/yahoo_quotes.go b/yahoo_quotes.go index 94ce114..35b4691 100644 --- a/yahoo_quotes.go +++ b/yahoo_quotes.go @@ -1,7 +1,6 @@ // Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. -//----------------------------------------------------------------------------- +// Use of this source code is governed by a MIT-style license that can +// be found in the LICENSE file. package mop @@ -15,50 +14,32 @@ import ( ) // 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%2Fstockstables.org%2Falltables.env -// &format=json' +// &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. -// l1: last trade -// c6: change rt -// k2: change % rt -// o: open -// g: day's low -// h: day's high -// j: 52w low -// k: 52w high -// v: volume -// a2: avg volume -// r2: p/e rt -// r: p/e -// d: dividend/share -// y: wield -// j3: market cap rt -// j1: market cap - -const quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1` +const quotesURL = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1` type Stock struct { - Ticker string - LastTrade string - Change string - ChangePct string - Open string - Low string - High string - Low52 string - High52 string - Volume string - AvgVolume string - PeRatio string - PeRatioX string - Dividend string - Yield string - MarketCap string - MarketCapX string - Advancing bool + Ticker string // Stock ticker. + LastTrade string // l1: last trade. + Change string // c6: change real time. + ChangePct string // k2: percent change real time. + Open string // o: market open price. + Low string // g: day's low. + High string // h: day's high. + Low52 string // j: 52-weeks low. + High52 string // k: 52-weeks high. + Volume string // v: volume. + AvgVolume string // a2: average volume. + PeRatio string // r2: P/E ration real time. + PeRatioX string // r: P/E ration (fallback when real time is N/A). + Dividend string // d: dividend. + Yield string // y: dividend yield. + MarketCap string // j3: market cap real time. + MarketCapX string // j1: market cap (fallback when real time is N/A). + Advancing bool // True when change is >= $0. } type Quotes struct { @@ -69,27 +50,26 @@ type Quotes struct { } //----------------------------------------------------------------------------- -func (self *Quotes) Initialize(market *Market, profile *Profile) *Quotes { - self.market = market - self.profile = profile - self.errors = `` +func (quotes *Quotes) Initialize(market *Market, profile *Profile) *Quotes { + quotes.market = market + quotes.profile = profile + quotes.errors = `` - return self + return quotes } // Fetch the latest stock quotes and parse raw fetched data into array of // []Stock structs. -//----------------------------------------------------------------------------- -func (self *Quotes) Fetch() (this *Quotes) { - this = self // <-- This ensures we return correct self after recover() from panic() attack. - if self.is_ready() { +func (quotes *Quotes) Fetch() (this *Quotes) { + this = quotes // <-- This ensures we return correct quotes after recover() from panic() attack. + if quotes.isReady() { defer func() { if err := recover(); err != nil { - self.errors = fmt.Sprintf("\n\n\n\nError fetching stock quotes...\n%s", err) + quotes.errors = fmt.Sprintf("\n\n\n\nError fetching stock quotes...\n%s", err) } }() - url := fmt.Sprintf(quotes_url, strings.Join(self.profile.Tickers, `+`)) + url := fmt.Sprintf(quotesURL, strings.Join(quotes.profile.Tickers, `+`)) response, err := http.Get(url) if err != nil { panic(err) @@ -101,85 +81,80 @@ func (self *Quotes) Fetch() (this *Quotes) { panic(err) } - self.parse(sanitize(body)) + quotes.parse(sanitize(body)) } - return self + return quotes } //----------------------------------------------------------------------------- -func (self *Quotes) Ok() (bool, string) { - return self.errors == ``, self.errors +func (quotes *Quotes) Ok() (bool, string) { + return quotes.errors == ``, quotes.errors } //----------------------------------------------------------------------------- -func (self *Quotes) AddTickers(tickers []string) (added int, err error) { - if added, err = self.profile.AddTickers(tickers); err == nil && added > 0 { - self.stocks = nil // Force fetch. +func (quotes *Quotes) AddTickers(tickers []string) (added int, err error) { + if added, err = quotes.profile.AddTickers(tickers); err == nil && added > 0 { + quotes.stocks = nil // Force fetch. } return } //----------------------------------------------------------------------------- -func (self *Quotes) RemoveTickers(tickers []string) (removed int, err error) { - if removed, err = self.profile.RemoveTickers(tickers); err == nil && removed > 0 { - self.stocks = nil // Force fetch. +func (quotes *Quotes) RemoveTickers(tickers []string) (removed int, err error) { + if removed, err = quotes.profile.RemoveTickers(tickers); err == nil && removed > 0 { + quotes.stocks = nil // Force fetch. } return } -// "Private" methods. - -// Return true if we haven't fetched the quotes yet *or* the stock market is -// still open and we might want to grab the latest quotes. In both cases we -// make sure the list of requested tickers is not empty. -//----------------------------------------------------------------------------- -func (self *Quotes) is_ready() bool { - return (self.stocks == nil || !self.market.IsClosed) && len(self.profile.Tickers) > 0 +// isReady returns true if we haven't fetched the quotes yet *or* the stock +// market is still open and we might want to grab the latest quotes. In both +// cases we make sure the list of requested tickers is not empty. +func (quotes *Quotes) isReady() bool { + return (quotes.stocks == nil || !quotes.market.IsClosed) && len(quotes.profile.Tickers) > 0 } //----------------------------------------------------------------------------- -func (self *Quotes) parse(body []byte) *Quotes { +func (quotes *Quotes) parse(body []byte) *Quotes { lines := bytes.Split(body, []byte{'\n'}) - self.stocks = make([]Stock, len(lines)) + quotes.stocks = make([]Stock, len(lines)) // // Get the total number of fields in the Stock struct. Skip the last // Advanicing field which is not fetched. // - number_of_fields := reflect.ValueOf(self.stocks[0]).NumField() - 1 + fieldsCount := reflect.ValueOf(quotes.stocks[0]).NumField() - 1 // // Split each line into columns, then iterate over the Stock struct // fields to assign column values. // for i, line := range lines { columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) - for j := 0; j < number_of_fields; j++ { - // ex. self.stocks[i].Ticker = string(columns[0]) - reflect.ValueOf(&self.stocks[i]).Elem().Field(j).SetString(string(columns[j])) + for j := 0; j < fieldsCount; j++ { + // ex. quotes.stocks[i].Ticker = string(columns[0]) + reflect.ValueOf("es.stocks[i]).Elem().Field(j).SetString(string(columns[j])) } // // Try realtime value and revert to the last known if the // realtime is not available. // - if self.stocks[i].PeRatio == `N/A` && self.stocks[i].PeRatioX != `N/A` { - self.stocks[i].PeRatio = self.stocks[i].PeRatioX + if quotes.stocks[i].PeRatio == `N/A` && quotes.stocks[i].PeRatioX != `N/A` { + quotes.stocks[i].PeRatio = quotes.stocks[i].PeRatioX } - if self.stocks[i].MarketCap == `N/A` && self.stocks[i].MarketCapX != `N/A` { - self.stocks[i].MarketCap = self.stocks[i].MarketCapX + if quotes.stocks[i].MarketCap == `N/A` && quotes.stocks[i].MarketCapX != `N/A` { + quotes.stocks[i].MarketCap = quotes.stocks[i].MarketCapX } // // Stock is advancing if the change is not negative (i.e. $0.00 // is also "advancing"). // - self.stocks[i].Advancing = (self.stocks[i].Change[0:1] != `-`) + quotes.stocks[i].Advancing = (quotes.stocks[i].Change[0:1] != `-`) } - return self + return quotes } -// Utility methods. - //----------------------------------------------------------------------------- func sanitize(body []byte) []byte { return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1)