// 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. package mop import ( `fmt` `bytes` `io/ioutil` `net/http` `regexp` `strings` ) const url = `http://finance.yahoo.com/marketupdate/overview` type Market struct { IsClosed bool 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 regex *regexp.Regexp errors string } //----------------------------------------------------------------------------- func (self *Market) Initialize() *Market { self.IsClosed = false self.Dow = make(map[string]string) self.Nasdaq = make(map[string]string) self.Sp500 = make(map[string]string) self.Advances = make(map[string]string) self.Declines = make(map[string]string) self.Unchanged = make(map[string]string) self.Highs = make(map[string]string) self.Lows = make(map[string]string) self.errors = `` const any = `\s*<.+?>` const some = `<.+?` const space = `\s*` const color = `#([08c]{6});">\s*` const price = `([\d\.,]+)` const percent = `\(([\d\.,%]+)\)` rules := []string{ `(Dow)`, any, price, some, color, price, some, percent, any, `(Nasdaq)`, any, price, some, color, price, some, percent, any, `(S&P 500)`, any, price, some, color, 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, } self.regex = regexp.MustCompile(strings.Join(rules, ``)) return self } //----------------------------------------------------------------------------- func (self *Market) Fetch() (this *Market) { this = self // <-- This ensures we return correct self in case of panic attack. defer func() { if err := recover(); err != nil { self.errors = fmt.Sprintf("Error fetching market data...\n%s", err) } }() response, err := http.Get(url) if err != nil { panic(err) } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { panic(err) } body = self.check_if_market_open(body) return self.extract(self.trim(body)) } //----------------------------------------------------------------------------- func (self *Market) Format() string { return new(Layout).Initialize().Market(self) } //----------------------------------------------------------------------------- func (self *Market) Ok() (bool, string) { return self.errors == ``, self.errors } // private //----------------------------------------------------------------------------- func (self *Market) check_if_market_open(body []byte) []byte { start := bytes.Index(body, []byte(`id="yfs_market_time"`)) finish := start + bytes.Index(body[start:], []byte(``)) snippet := body[start:finish] self.IsClosed = bytes.Contains(snippet, []byte(`closed`)) || bytes.Contains(snippet, []byte(`open in`)) return body[finish:] } //----------------------------------------------------------------------------- func (self *Market) trim(body []byte) []byte { start := bytes.Index(body, []byte(`