forked from mop-tracker/mop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcnn_market.go
183 lines (148 loc) · 5.5 KB
/
cnn_market.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) 2013-2016 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 (
`bytes`
`fmt`
`io/ioutil`
`net/http`
`regexp`
`strings`
)
const marketURL = `http://money.cnn.com/data/markets/`
// Market stores current market information displayed in the top three lines of
// the screen. The market data is fetched and parsed from the HTML page above.
type Market struct {
IsClosed bool // True when U.S. markets are closed.
Dow map[string]string // Hash of Dow Jones indicators.
Nasdaq map[string]string // Hash of NASDAQ indicators.
Sp500 map[string]string // Hash of S&P 500 indicators.
Tokyo map[string]string
HongKong map[string]string
London map[string]string
Frankfurt map[string]string
Yield map[string]string
Oil map[string]string
Yen map[string]string
Euro map[string]string
Gold map[string]string
regex *regexp.Regexp // Regex to parse market data from HTML.
errors string // Error(s), if any.
}
// Returns new initialized Market struct.
func NewMarket() *Market {
market := &Market{}
market.IsClosed = false
market.Dow = make(map[string]string)
market.Nasdaq = make(map[string]string)
market.Sp500 = make(map[string]string)
market.Tokyo = make(map[string]string)
market.HongKong = make(map[string]string)
market.London = make(map[string]string)
market.Frankfurt = make(map[string]string)
market.Yield = make(map[string]string)
market.Oil = make(map[string]string)
market.Yen = make(map[string]string)
market.Euro = make(map[string]string)
market.Gold = make(map[string]string)
market.errors = ``
const any = `\s*(?:.+?)`
const price = `>([\d\.,]+)</span>`
const percent = `>([\+\-]?[\d\.,]+%?)<`
rules := []string{
`>Dow<`, any, percent, any, price, any, percent, any,
`>Nasdaq<`, any, percent, any, price, any, percent, any,
`">S&P<`, any, percent, any, price, any, percent, any,
`>Nikkei 225<`, any, percent, any, price, any, percent, any,
`>Hang Seng<`, any, percent, any, price, any, percent, any,
`>FTSE 100<`, any, percent, any, price, any, percent, any,
`>DAX<`, any, percent, any, price, any, percent, any,
`>10-year yield<`, any, price, any, percent, any,
`>Oil<`, any, price, any, percent, any,
`>Yen<`, any, price, any, percent, any,
`>Euro<`, any, price, any, percent, any,
`>Gold<`, any, price, any, percent, any,
}
market.regex = regexp.MustCompile(strings.Join(rules, ``))
return market
}
// Fetch downloads HTML page from the 'marketURL', parses it, and stores resulting data
// in internal hashes. If download or data parsing fails Fetch populates 'market.errors'.
func (market *Market) Fetch() (self *Market) {
self = market // <-- This ensures we return correct market after recover() from panic().
defer func() {
if err := recover(); err != nil {
market.errors = fmt.Sprintf("Error fetching market data...\n%s", err)
}
}()
response, err := http.Get(marketURL)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
body = market.isMarketOpen(body)
return market.extract(market.trim(body))
}
// Ok returns two values: 1) boolean indicating whether the error has occured,
// and 2) the error text itself.
func (market *Market) Ok() (bool, string) {
return market.errors == ``, market.errors
}
//-----------------------------------------------------------------------------
func (market *Market) isMarketOpen(body []byte) []byte {
// TBD -- CNN page doesn't seem to have market open/close indicator.
return body
}
//-----------------------------------------------------------------------------
func (market *Market) trim(body []byte) []byte {
start := bytes.Index(body, []byte(`Markets Overview`))
finish := bytes.LastIndex(body, []byte(`Gainers`))
snippet := bytes.Replace(body[start:finish], []byte{'\n'}, []byte{}, -1)
snippet = bytes.Replace(snippet, []byte(`&`), []byte{'&'}, -1)
return snippet
}
//-----------------------------------------------------------------------------
func (market *Market) extract(snippet []byte) *Market {
matches := market.regex.FindStringSubmatch(string(snippet))
if len(matches) < 31 {
panic(`Unable to parse ` + marketURL)
}
market.Dow[`change`] = matches[1]
market.Dow[`latest`] = matches[2]
market.Dow[`percent`] = matches[3]
market.Nasdaq[`change`] = matches[4]
market.Nasdaq[`latest`] = matches[5]
market.Nasdaq[`percent`] = matches[6]
market.Sp500[`change`] = matches[7]
market.Sp500[`latest`] = matches[8]
market.Sp500[`percent`] = matches[9]
market.Tokyo[`change`] = matches[10]
market.Tokyo[`latest`] = matches[11]
market.Tokyo[`percent`] = matches[12]
market.HongKong[`change`] = matches[13]
market.HongKong[`latest`] = matches[14]
market.HongKong[`percent`] = matches[15]
market.London[`change`] = matches[16]
market.London[`latest`] = matches[17]
market.London[`percent`] = matches[18]
market.Frankfurt[`change`] = matches[19]
market.Frankfurt[`latest`] = matches[20]
market.Frankfurt[`percent`] = matches[21]
market.Yield[`name`] = `10-year Yield`
market.Yield[`latest`] = matches[22]
market.Yield[`change`] = matches[23]
market.Oil[`latest`] = matches[24]
market.Oil[`change`] = matches[25]
market.Yen[`latest`] = matches[26]
market.Yen[`change`] = matches[27]
market.Euro[`latest`] = matches[28]
market.Euro[`change`] = matches[29]
market.Gold[`latest`] = matches[30]
market.Gold[`change`] = matches[31]
return market
}