diff --git a/dj.go b/dj.go
new file mode 100644
index 0000000..ad47ef0
--- /dev/null
+++ b/dj.go
@@ -0,0 +1,278 @@
+// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
+//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package main
+import (
+ "fmt"
+ "bytes"
+ "regexp"
+ "strings"
+ "text/template"
+)
+type Market struct {
+ Dow map[string]string
+ Nasdaq map[string]string
+ Sp500 map[string]string
+ Advances map[string]string
+ Declines map[string]string
+ Unchanged map[string]string
+ Highs map[string]string
+ Lows map[string]string
+}
+//-----------------------------------------------------------------------------
+func main() {
+ html := `
+...
+
+
+
+
+Advances & Declines
+
+
+
+ |
+NYSE |
+NASDAQ |
+
+
+
+Advances |
+2,992
+ (72%)
+ |
+1,445
+ (57%)
+ |
+
+
+Declines |
+1,040
+ (25%)
+ |
+950
+ (38%)
+ |
+
+
+Unchanged |
+113
+ (3%)
+ |
+128
+ (5%)
+ |
+
+
+Up Vol* |
+2,582
+ (74%)
+ |
+950
+ (60%)
+ |
+
+
+Down Vol* |
+863
+ (25%)
+ |
+625
+ (39%)
+ |
+
+
+Unch. Vol* |
+46
+ (1%)
+ |
+20
+ (1%)
+ |
+
+
+New Hi's |
+350 |
+314 |
+
+
+New Lo's |
+117 |
+19 |
+
+
+
+...
+
+
+NYSE |
+LAST |
+CHANGE |
+
+`
+ start := strings.Index(html, ``
+ const some = `<.+?`
+ const space = `\s*`
+ const arrow = `"(Up|Down)">\s*`
+ const price = `([\d\.,]+)`
+ const percent = `\(([\d\.,%]+)\)`
+
+ regex := []string{
+ "(Dow)", any, price, some, arrow, any, price, some, percent, any,
+ "(Nasdaq)", any, price, some, arrow, any, price, some, percent, any,
+ "(S&P 500)", any, price, some, arrow, any, price, some, percent, any,
+ "(Advances)", any, price, space, percent, any, price, space, percent, any,
+ "(Declines)", any, price, space, percent, any, price, space, percent, any,
+ "(Unchanged)", any, price, space, percent, any, price, space, percent, any,
+ "(New Hi's)", any, price, any, price, any,
+ "(New Lo's)", any, price, any, price, any,
+ }
+
+ re := regexp.MustCompile(strings.Join(regex, ""))
+ matches := re.FindAllStringSubmatch(html, -1)
+
+ if len(matches) > 0 {
+ fmt.Printf("%d matches\n", len(matches[0]))
+ for i, str := range matches[0][1:] {
+ fmt.Printf("%d) [%s]\n", i, str)
+ }
+ } else {
+ println("No matches")
+ }
+
+ m := Market{
+ Dow: make(map[string]string),
+ Nasdaq: make(map[string]string),
+ Sp500: make(map[string]string),
+ Advances: make(map[string]string),
+ Declines: make(map[string]string),
+ Unchanged: make(map[string]string),
+ Highs: make(map[string]string),
+ Lows: make(map[string]string),
+ }
+ m.Dow[`name`] = matches[0][1]
+ m.Dow[`latest`] = matches[0][2]
+ m.Dow[`change`] = matches[0][4]
+ if matches[0][3] == "Up" {
+ m.Dow[`change`] = "+" + matches[0][4]
+ m.Dow[`percent`] = "+" + matches[0][5]
+ } else {
+ m.Dow[`change`] = "-" + matches[0][4]
+ m.Dow[`percent`] = "-" + matches[0][5]
+ }
+
+ m.Nasdaq[`name`] = matches[0][6]
+ m.Nasdaq[`latest`] = matches[0][7]
+ if matches[0][8] == "Up" {
+ m.Nasdaq[`change`] = "+" + matches[0][9]
+ m.Nasdaq[`percent`] = "+" + matches[0][10]
+ } else {
+ m.Nasdaq[`change`] = "-" + matches[0][9]
+ m.Nasdaq[`percent`] = "-" + matches[0][10]
+ }
+
+ m.Sp500[`name`] = matches[0][11]
+ m.Sp500[`latest`] = matches[0][12]
+ if matches[0][13] == "Up" {
+ m.Sp500[`change`] = "+" + matches[0][14]
+ m.Sp500[`percent`] = "+" + matches[0][15]
+ } else {
+ m.Sp500[`change`] = "-" + matches[0][14]
+ m.Sp500[`percent`] = "-" + matches[0][15]
+ }
+
+ m.Advances[`name`] = matches[0][16]
+ m.Advances[`nyse`] = matches[0][17]
+ m.Advances[`nysep`] = matches[0][18]
+ m.Advances[`nasdaq`] = matches[0][19]
+ m.Advances[`nasdaqp`] = matches[0][20]
+
+ m.Declines[`name`] = matches[0][21]
+ m.Declines[`nyse`] = matches[0][22]
+ m.Declines[`nysep`] = matches[0][23]
+ m.Declines[`nasdaq`] = matches[0][24]
+ m.Declines[`nasdaqp`] = matches[0][25]
+
+ m.Unchanged[`name`] = matches[0][26]
+ m.Unchanged[`nyse`] = matches[0][27]
+ m.Unchanged[`nysep`] = matches[0][28]
+ m.Unchanged[`nasdaq`] = matches[0][29]
+ m.Unchanged[`nasdaqp`] = matches[0][30]
+
+ m.Highs[`name`] = matches[0][31]
+ m.Highs[`nyse`] = matches[0][32]
+ m.Highs[`nasdaq`] = matches[0][33]
+ m.Lows[`name`] = matches[0][34]
+ m.Lows[`nyse`] = matches[0][35]
+ m.Lows[`nasdaq`] = matches[0][36]
+ fmt.Printf("%q\n", m)
+ println(Format(m))
+}
+
+//-----------------------------------------------------------------------------
+func Format(m Market) string {
+ markup := `{{.Dow.name}}: {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, `
+ markup += `{{.Sp500.name}}: {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, `
+ markup += `{{.Nasdaq.name}}: {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}`
+ markup += "\n"
+ 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 += "\n"
+ markup += `New highs: {{.Highs.nyse}} on NYSE and {{.Highs.nasdaq}} on Nasdaq. `
+ markup += `New lows: {{.Lows.nyse}} on NYSE and {{.Lows.nasdaq}} on Nasdaq.`
+ template, err := template.New("screen").Parse(markup)
+ if err != nil {
+ panic(err)
+ }
+
+ buffer := new(bytes.Buffer)
+ err = template.Execute(buffer, m)
+ if err != nil {
+ panic(err)
+ }
+
+ return buffer.String()
+}
diff --git a/lib/format.go b/lib/format.go
index c169df8..a3da2ba 100644
--- a/lib/format.go
+++ b/lib/format.go
@@ -12,7 +12,32 @@ import (
)
//-----------------------------------------------------------------------------
-func Format(quotes Quotes) string {
+func FormatMarket(m Market) string {
+ markup := `{{.Dow.name}}: {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, `
+ markup += `{{.Sp500.name}}: {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, `
+ markup += `{{.Nasdaq.name}}: {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}`
+ markup += "\n"
+ 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 += "\n"
+ markup += `New highs: {{.Highs.nyse}} on NYSE and {{.Highs.nasdaq}} on Nasdaq. `
+ markup += `New lows: {{.Lows.nyse}} on NYSE and {{.Lows.nasdaq}} on Nasdaq.`
+ template, err := template.New("market").Parse(markup)
+ if err != nil {
+ panic(err)
+ }
+
+ buffer := new(bytes.Buffer)
+ err = template.Execute(buffer, m)
+ if err != nil {
+ panic(err)
+ }
+
+ return buffer.String()
+}
+
+//-----------------------------------------------------------------------------
+func FormatQuotes(quotes Quotes) string {
vars := struct {
Now string
Header string
@@ -23,14 +48,15 @@ func Format(quotes Quotes) string {
prettify(quotes),
}
- markup :=
- `Hello{{.Now}}
+ markup := `{{.Now}}
+
+
{{.Header}}
{{range .Stocks}}{{.Color}}{{.Ticker}} {{.LastTrade}} {{.Change}} {{.ChangePercent}} {{.Open}} {{.Low}} {{.High}} {{.Low52}} {{.High52}} {{.Volume}} {{.AvgVolume}} {{.PeRatio}} {{.Dividend}} {{.Yield}} {{.MarketCap}}
{{end}}...`
- template, err := template.New("screen").Parse(markup)
+ template, err := template.New("quotes").Parse(markup)
if err != nil {
panic(err)
}
diff --git a/lib/screen.go b/lib/screen.go
index 2ec9049..4c679de 100644
--- a/lib/screen.go
+++ b/lib/screen.go
@@ -29,15 +29,27 @@ var tags = map[string]termbox.Attribute{
}
//-----------------------------------------------------------------------------
-func Draw(stocks string) {
- quotes := Get(stocks)
+func DrawMarket() {
+ market := GetMarket()
// for _, m := range message {
// fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change)
// }
// fmt.Printf("%s\n", Format(message))
- drawScreen(Format(quotes))
+ drawScreen(FormatMarket(market))
+}
+
+//-----------------------------------------------------------------------------
+func DrawQuotes(stocks string) {
+ quotes := GetQuotes(stocks)
+
+ // for _, m := range message {
+ // fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change)
+ // }
+ // fmt.Printf("%s\n", Format(message))
+
+ drawScreen(FormatQuotes(quotes))
}
//-----------------------------------------------------------------------------
@@ -120,7 +132,6 @@ func drawLine(x int, y int, str string) {
//-----------------------------------------------------------------------------
func drawScreen(str string) {
- termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
for row, line := range strings.Split(str, "\n") {
drawLine(0, row, line)
}
diff --git a/lib/yahoo_market.go b/lib/yahoo_market.go
new file mode 100644
index 0000000..186c0f6
--- /dev/null
+++ b/lib/yahoo_market.go
@@ -0,0 +1,150 @@
+// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
+//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package mop
+
+import (
+ //"fmt"
+ "bytes"
+ "regexp"
+ "strings"
+ "net/http"
+ "io/ioutil"
+)
+
+type Market struct {
+ Dow map[string]string
+ Nasdaq map[string]string
+ Sp500 map[string]string
+ Advances map[string]string
+ Declines map[string]string
+ Unchanged map[string]string
+ Highs map[string]string
+ Lows map[string]string
+}
+
+const yahoo_market_url = `http://finance.yahoo.com/marketupdate/overview`
+
+func GetMarket() Market {
+ response, err := http.Get(yahoo_market_url)
+ if err != nil {
+ panic(err)
+ }
+
+ // Fetch response and get its body.
+ defer response.Body.Close()
+ body, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ panic(err)
+ }
+
+ return extract(trim(body))
+}
+
+func trim(body []byte) []byte {
+ start := bytes.Index(body, []byte("`
+ const some = `<.+?`
+ const space = `\s*`
+ const arrow = `"(Up|Down)">\s*`
+ const price = `([\d\.,]+)`
+ const percent = `\(([\d\.,%]+)\)`
+
+ regex := []string{
+ "(Dow)", any, price, some, arrow, any, price, some, percent, any,
+ "(Nasdaq)", any, price, some, arrow, any, price, some, percent, any,
+ "(S&P 500)", any, price, some, arrow, any, price, some, percent, any,
+ "(Advances)", any, price, space, percent, any, price, space, percent, any,
+ "(Declines)", any, price, space, percent, any, price, space, percent, any,
+ "(Unchanged)", any, price, space, percent, any, price, space, percent, any,
+ "(New Hi's)", any, price, any, price, any,
+ "(New Lo's)", any, price, any, price, any,
+ }
+
+ re := regexp.MustCompile(strings.Join(regex, ""))
+ matches := re.FindAllStringSubmatch(string(snippet), -1)
+
+ // if len(matches) > 0 {
+ // fmt.Printf("%d matches\n", len(matches[0]))
+ // for i, str := range matches[0][1:] {
+ // fmt.Printf("%d) [%s]\n", i, str)
+ // }
+ // } else {
+ // println("No matches")
+ // }
+
+ m := Market{
+ Dow: make(map[string]string),
+ Nasdaq: make(map[string]string),
+ Sp500: make(map[string]string),
+ Advances: make(map[string]string),
+ Declines: make(map[string]string),
+ Unchanged: make(map[string]string),
+ Highs: make(map[string]string),
+ Lows: make(map[string]string),
+ }
+ m.Dow[`name`] = matches[0][1]
+ m.Dow[`latest`] = matches[0][2]
+ m.Dow[`change`] = matches[0][4]
+ if matches[0][3] == "Up" {
+ m.Dow[`change`] = "+" + matches[0][4]
+ m.Dow[`percent`] = "+" + matches[0][5]
+ } else {
+ m.Dow[`change`] = "-" + matches[0][4]
+ m.Dow[`percent`] = "-" + matches[0][5]
+ }
+
+ m.Nasdaq[`name`] = matches[0][6]
+ m.Nasdaq[`latest`] = matches[0][7]
+ if matches[0][8] == "Up" {
+ m.Nasdaq[`change`] = "+" + matches[0][9]
+ m.Nasdaq[`percent`] = "+" + matches[0][10]
+ } else {
+ m.Nasdaq[`change`] = "-" + matches[0][9]
+ m.Nasdaq[`percent`] = "-" + matches[0][10]
+ }
+
+ m.Sp500[`name`] = matches[0][11]
+ m.Sp500[`latest`] = matches[0][12]
+ if matches[0][13] == "Up" {
+ m.Sp500[`change`] = "+" + matches[0][14]
+ m.Sp500[`percent`] = "+" + matches[0][15]
+ } else {
+ m.Sp500[`change`] = "-" + matches[0][14]
+ m.Sp500[`percent`] = "-" + matches[0][15]
+ }
+
+ m.Advances[`name`] = matches[0][16]
+ m.Advances[`nyse`] = matches[0][17]
+ m.Advances[`nysep`] = matches[0][18]
+ m.Advances[`nasdaq`] = matches[0][19]
+ m.Advances[`nasdaqp`] = matches[0][20]
+
+ m.Declines[`name`] = matches[0][21]
+ m.Declines[`nyse`] = matches[0][22]
+ m.Declines[`nysep`] = matches[0][23]
+ m.Declines[`nasdaq`] = matches[0][24]
+ m.Declines[`nasdaqp`] = matches[0][25]
+
+ m.Unchanged[`name`] = matches[0][26]
+ m.Unchanged[`nyse`] = matches[0][27]
+ m.Unchanged[`nysep`] = matches[0][28]
+ m.Unchanged[`nasdaq`] = matches[0][29]
+ m.Unchanged[`nasdaqp`] = matches[0][30]
+
+ m.Highs[`name`] = matches[0][31]
+ m.Highs[`nyse`] = matches[0][32]
+ m.Highs[`nasdaq`] = matches[0][33]
+ m.Lows[`name`] = matches[0][34]
+ m.Lows[`nyse`] = matches[0][35]
+ m.Lows[`nasdaq`] = matches[0][36]
+
+ return m;
+}
diff --git a/lib/yahoo_finance.go b/lib/yahoo_quotes.go
similarity index 97%
rename from lib/yahoo_finance.go
rename to lib/yahoo_quotes.go
index e38dcfa..f49e329 100644
--- a/lib/yahoo_finance.go
+++ b/lib/yahoo_quotes.go
@@ -8,7 +8,6 @@ import (
"strings"
"net/http"
"io/ioutil"
- // "strings"
)
// See http://www.gummy-stuff.org/Yahoo-data.htm
@@ -30,7 +29,7 @@ import (
// j3: market cap rt
// j1: market cap
-const yahoo_finance_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`
// "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
// "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
@@ -58,12 +57,11 @@ type Quote struct {
}
type Quotes []Quote
-// func Get(tickers []string) Quotes {
-func Get(tickers string) Quotes {
+func GetQuotes(tickers string) Quotes {
// Format the URL and send the request.
- // url := fmt.Sprintf(yahoo_finance_url, strings.Join(tickers, "+"))
- url := fmt.Sprintf(yahoo_finance_url, tickers)
+ // url := fmt.Sprintf(yahoo_quotes_url, strings.Join(tickers, "+"))
+ url := fmt.Sprintf(yahoo_quotes_url, tickers)
response, err := http.Get(url)
if err != nil {
panic(err)
diff --git a/mop.go b/mop.go
index bde1081..8a7a926 100644
--- a/mop.go
+++ b/mop.go
@@ -19,8 +19,9 @@ func initTermbox() {
//-----------------------------------------------------------------------------
func mainLoop(profile string) {
keyboard_queue := make(chan termbox.Event)
- quotes_queue := time.NewTicker(5 * time.Second)
timestamp_queue := time.NewTicker(1 * time.Second)
+ quotes_queue := time.NewTicker(5 * time.Second)
+ market_queue := time.NewTicker(12 * time.Second)
go func() {
for {
@@ -28,7 +29,9 @@ func mainLoop(profile string) {
}
}()
- mop.Draw(profile)
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ mop.DrawMarket()
+ mop.DrawQuotes(profile)
loop:
for {
select {
@@ -39,14 +42,19 @@ loop:
break loop
}
case termbox.EventResize:
- mop.Draw(profile)
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ mop.DrawMarket()
+ mop.DrawQuotes(profile)
}
- case <-quotes_queue.C:
- mop.Draw(profile)
-
case <-timestamp_queue.C:
mop.DrawTime()
+
+ case <-quotes_queue.C:
+ mop.DrawQuotes(profile)
+
+ case <-market_queue.C:
+ mop.DrawMarket()
}
}
}