Formatting stock data fetched from Yahoo

master
Michael Dvorkin 11 years ago
parent dd91d958d4
commit b498decc9c
  1. 112
      lib/format.go
  2. 2
      lib/profile.go
  3. 4
      lib/screen.go
  4. 110
      lib/yahoo_finance.go

@ -1,32 +1,33 @@
// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. // Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// +build ignore
package mop package mop
import ( import (
"bytes"
"fmt" "fmt"
"bytes"
"regexp"
"strings"
"text/template" "text/template"
"time" "time"
) )
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func Format(message []Message) string { func Format(quotes Quotes) string {
vars := struct { vars := struct {
Now string Now string
Stocks []Message Header string
Stocks Quotes
}{ }{
time.Now().Format("3:04:05pm PST"), time.Now().Format("3:04:05pm PST"),
prettify(message), header(),
prettify(quotes),
} }
markup := markup :=
`Hello<right>{{.Now}}</right> `Hello<right>{{.Now}}</right>
Ticker Last trade Change % Change Dividend Yield {{.Header}}
{{range .Stocks}}{{.Color}}{{.Ticker}} {{.LastTrade}} {{.Change}} {{.ChangePercent}} {{.Dividend}} {{.Yield}} {{range .Stocks}}{{.Color}}{{.Ticker}} {{.LastTrade}} {{.Change}} {{.ChangePercent}} {{.Open}} {{.Low}} {{.High}} {{.Low52}} {{.High52}} {{.Volume}} {{.AvgVolume}} {{.PeRatio}} {{.Dividend}} {{.Yield}} {{.MarketCap}}
{{end}}...` {{end}}...`
template, err := template.New("screen").Parse(markup) template, err := template.New("screen").Parse(markup)
@ -43,41 +44,67 @@ Ticker Last trade Change % Change Dividend Yield
return buffer.String() return buffer.String()
} }
func color(m Message) string { func header() string {
return "x" str := fmt.Sprintf("%-7s ", "Ticker")
str += fmt.Sprintf("%9s ", "Last")
str += fmt.Sprintf("%9s ", "Change")
str += fmt.Sprintf("%9s ", "%Change")
str += fmt.Sprintf("%9s ", "Open")
str += fmt.Sprintf("%9s ", "Low")
str += fmt.Sprintf("%9s ", "High")
str += fmt.Sprintf("%9s ", "52w Low")
str += fmt.Sprintf("%9s ", "52w High")
str += fmt.Sprintf("%10s ", "Volume")
str += fmt.Sprintf("%10s ", "AvgVolume")
str += fmt.Sprintf("%9s ", "P/E")
str += fmt.Sprintf("%9s ", "Dividend")
str += fmt.Sprintf("%9s ", "Yield")
str += fmt.Sprintf("%10s", "MktCap")
return str
} }
func prettify(message []Message) []Message { func prettify(quotes Quotes) Quotes {
pretty := make([]Message, len(message)) pretty := make(Quotes, len(quotes))
for i, m := range message { for i, q := range quotes {
pretty[i].Ticker = pad(m.Ticker, -10) pretty[i].Ticker = pad(q.Ticker, -7)
pretty[i].LastTrade = pad(with_currency(m.LastTrade), 10) pretty[i].LastTrade = pad(with_currency(q.LastTrade), 9)
pretty[i].CurrentPrice = pad(with_currency(m.CurrentPrice), 10) pretty[i].Change = pad(with_currency(q.Change), 9)
pretty[i].Change = pad(with_currency(m.Change), 10) pretty[i].ChangePercent = pad(last_of_pair(q.ChangePercent), 9)
pretty[i].ChangePercent = pad(with_percent(m.ChangePercent), 10) pretty[i].Open = pad(with_currency(q.Open), 9)
// ExLastTrade string `json:"el"` pretty[i].Low = pad(with_currency(q.Low), 9)
// ExCurrentPrice string `json:"el_cur"` pretty[i].High = pad(with_currency(q.High), 9)
// ExLastTradeDateTime string `json:"elt"` pretty[i].Low52 = pad(with_currency(q.Low52), 9)
// ExChange string `json:"ec"` pretty[i].High52 = pad(with_currency(q.High52), 9)
// ExChangePercentage string `json:"ecp"` pretty[i].Volume = pad(q.Volume, 10)
pretty[i].Dividend = pad(with_currency(nullify(m.Dividend)), 10) pretty[i].AvgVolume = pad(q.AvgVolume, 10)
pretty[i].Yield = pad(with_currency(nullify(m.Yield)), 10) pretty[i].PeRatio = pad(nullify(q.PeRatioX), 9)
pretty[i].Dividend = pad(with_currency(q.Dividend), 9)
pretty[i].Yield = pad(with_percent(q.Yield), 9)
pretty[i].MarketCap = pad(with_currency(q.MarketCapX), 10)
} }
// fmt.Printf("%q", pretty)
return pretty return pretty
} }
func nullify(str string) string { func nullify(str string) string {
if len(str) > 0 { if len(str) == 3 && str[0:3] == "N/A" {
return "-"
} else {
return str
}
}
func last_of_pair(str string) string {
if len(str) >= 6 && str[0:6] != "N/A - " {
return str return str
} else { } else {
return "-" return str[6:]
} }
} }
func with_currency(str string) string { func with_currency(str string) string {
if str == "-" { if str == "N/A" || str == "0.00" {
return str return "-"
} else { } else {
switch str[0:1] { switch str[0:1] {
case "+", "-": case "+", "-":
@ -89,18 +116,16 @@ func with_currency(str string) string {
} }
func with_percent(str string) string { func with_percent(str string) string {
if str == "-" { if str == "N/A" {
return str return "-"
} else if str[0:1] != "-" {
return "+" + str + "%"
} else { } else {
return str + "%" return str + "%"
} }
} }
func colorize(str string) string { func colorize(str string) string {
if str == "-" { if str == "N/A" {
return str return "-"
} else if str[0:1] == "-" { } else if str[0:1] == "-" {
return "<red>" + str + "</red>" return "<red>" + str + "</red>"
} else { } else {
@ -117,5 +142,14 @@ 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]?$`)
match := re.FindStringSubmatch(str)
if len(match) > 0 {
switch len(match[1]) {
case 2: str = strings.Replace(str, match[1], match[1] + "0", 1)
case 4, 5: str = strings.Replace(str, match[1], match[1][0:3], 1)
}
}
return fmt.Sprintf("%*s", width, str) return fmt.Sprintf("%*s", width, str)
} }

@ -4,5 +4,5 @@ package mop
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func LoadProfile() string { func LoadProfile() string {
return "AAPL+ATVI+C+COH+GOOG+HPQ+IBM+MA+TSLA+V+YHOO+ININ+CRM+SAAS" return "AAPL+ALU+ATVI+C+COH+GOOG+HPQ+IBM+MA+TSLA+V+YHOO+ININ+CRM+SAAS"
} }

@ -29,14 +29,14 @@ var tags = map[string]termbox.Attribute{
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func Draw(stocks string) { func Draw(stocks string) {
message := Get(stocks) quotes := Get(stocks)
// for _, m := range message { // for _, m := range message {
// fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change) // fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change)
// } // }
// fmt.Printf("%s\n", Format(message)) // fmt.Printf("%s\n", Format(message))
drawScreen(message.Format()) drawScreen(Format(quotes))
} }
// //

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"time" "time"
"bytes" "bytes"
"strings"
"net/http" "net/http"
"io/ioutil" "io/ioutil"
// "strings" // "strings"
@ -13,7 +14,7 @@ import (
// See http://www.gummy-stuff.org/Yahoo-data.htm // See http://www.gummy-stuff.org/Yahoo-data.htm
// 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.
// b2: ask rt // l1: last trade
// c6: change rt // c6: change rt
// k2: change % rt // k2: change % rt
// o: open // o: open
@ -25,33 +26,36 @@ import (
// a2: avg volume // a2: avg volume
// r2: p/e rt // r2: p/e rt
// r: p/e // r: p/e
// d: dividend/share
// y: wield // y: wield
// j3: market cap rt // j3: market cap rt
// j1: market cap // j1: market cap
const yahoo_finance_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,b2c6k2oghjkva2r2ryj3j1` const yahoo_finance_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1`
// "AAPL", 602.93, "+2.31", "N/A - +0.55%", 420.95, 417.45, 422.98, 385.10, 705.07, 8604594, 15205700, N/A, 9.99, 2.63, N/A, 395.0B // "AAPL", 417.42, "-3.38", "N/A - -0.80%", 420.33, 415.35, 423.29, 385.10, 705.07, 9788680, 15181900, N/A, 10.04, 11.00, 2.61, N/A, 391.8B
// "GOOG", 0.00, "+4.12", "N/A - +0.47%", 879.90, 878.50, 889.17, 562.09, 920.60, 1048628, 2353530, N/A, 26.40, N/A, N/A, 294.1B // "ALU", 1.83, "+0.07", "N/A - +3.98%", 1.77, 1.75, 1.83, 0.91, 2.01, 7957103, 11640700, N/A, N/A, 0.00, N/A, N/A, 4.156B
// "PG", 94.58, "+0.13", "N/A - +0.17%", 78.28, 77.4301, 78.75, 60.86, 82.54, 5347846, 9929320, N/A, 17.58, 2.92, N/A, 215.3B // "IBM", 194.93, "+1.68", "N/A - +0.87%", 192.83, 192.3501, 195.16, 181.85, 215.90, 2407971, 4376120, N/A, 13.33, 3.50, 1.81, N/A, 216.1B
// "TSLA", 120.09, "+4.85", "N/A - +4.21%", 118.75, 115.70, 120.28, 25.52, 121.89, 6827497, 9464530, N/A, N/A, 0.00, N/A, N/A, 13.877B
type Quote struct { type Quote struct {
Ticker []byte Ticker string
Ask []byte LastTrade string
Change []byte Change string
ChangePercent []byte ChangePercent string
Open []byte Open string
Low []byte Low string
High []byte High string
Low52 []byte Low52 string
High52 []byte High52 string
Volume []byte Volume string
AvgVolume []byte AvgVolume string
PeRatio []byte PeRatio string
PeRatioX []byte PeRatioX string
Yield []byte Dividend string
MarketCap []byte Yield string
MarketCapX []byte MarketCap string
MarketCapX string
} }
type Quotes []Quote type Quotes []Quote
@ -74,7 +78,6 @@ func Get(tickers string) Quotes {
// Fetch response and get its body. // Fetch response and get its body.
defer response.Body.Close() defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
fmt.Println("\n\n\n\n\n\rFetched quotes: " + time.Now().Format("3:04:05pm PST"))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -83,13 +86,19 @@ func Get(tickers string) Quotes {
return quotes return quotes
} }
func (q *Quote) Color() string {
if strings.Index(q.Change, "-") == -1 {
return "</green><green>"
} else {
return "" // "</red><red>"
}
}
func sanitize(body []byte) []byte { func sanitize(body []byte) []byte {
return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1) return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1)
} }
// "AAPL", 602.93, "+2.31", "N/A - +0.55%", 420.95, 417.45, 422.98, 385.10, 705.07, 8604594, 15205700, N/A, 9.99, 2.63, N/A, 395.0B
func parse(body []byte) Quotes { func parse(body []byte) Quotes {
// fmt.Printf("[%s]\n", body)
lines := bytes.Split(body, []byte{'\n'}) lines := bytes.Split(body, []byte{'\n'})
quotes := make(Quotes, len(lines)) quotes := make(Quotes, len(lines))
@ -102,36 +111,35 @@ func parse(body []byte) Quotes {
} }
func parse_line(line []byte, quote *Quote) { func parse_line(line []byte, quote *Quote) {
// var quote Quote columns := bytes.Split(bytes.TrimSpace(line), []byte{','})
columns := bytes.Split(line, []byte{','})
// fmt.Printf("{%s} -> [%d]", string(line), len(columns))
quote.Ticker = columns[0] quote.Ticker = string(columns[0])
quote.Ask = columns[1] quote.LastTrade = string(columns[1])
quote.Change = columns[2] quote.Change = string(columns[2])
quote.ChangePercent = columns[3] quote.ChangePercent = string(columns[3])
quote.Open = columns[4] quote.Open = string(columns[4])
quote.Low = columns[5] quote.Low = string(columns[5])
quote.High = columns[6] quote.High = string(columns[6])
quote.Low52 = columns[7] quote.Low52 = string(columns[7])
quote.High52 = columns[8] quote.High52 = string(columns[8])
quote.Volume = columns[9] quote.Volume = string(columns[9])
quote.AvgVolume = columns[10] quote.AvgVolume = string(columns[10])
quote.PeRatio = columns[11] quote.PeRatio = string(columns[11])
quote.PeRatioX = columns[12] quote.PeRatioX = string(columns[12])
quote.Yield = columns[13] quote.Dividend = string(columns[13])
quote.MarketCap = columns[14] quote.Yield = string(columns[14])
quote.MarketCapX = columns[15] quote.MarketCap = string(columns[15])
quote.MarketCapX = string(columns[16])
} }
func (quotes Quotes) Format() string { // func (quotes Quotes) Format() string {
str := time.Now().Format("3:04:05pm PST\n") // str := time.Now().Format("3:04:05pm PST\n")
//
for _, q := range quotes { // for _, q := range quotes {
str += fmt.Sprintf("%s - %s - %s - %s\n", q.Ticker, q.Ask, q.Change, q.ChangePercent) // str += fmt.Sprintf("%s - %s - %s - %s\n", q.Ticker, q.Ask, q.Change, q.ChangePercent)
} // }
return str // return str
} // }
// //
// http://query.yahooapis.com/v1/public/yql // http://query.yahooapis.com/v1/public/yql

Loading…
Cancel
Save