浏览代码

stocks endpoint created

woat 6 年前
父节点
当前提交
b2807b879f

+ 14
- 0
server/pom.xml 查看文件

@@ -51,6 +51,20 @@
51 51
 			<groupId>com.fasterxml.jackson.core</groupId>
52 52
 			<artifactId>jackson-databind</artifactId>
53 53
 		</dependency>
54
+
55
+		<dependency>
56
+			<groupId>pl.zankowski</groupId>
57
+			<artifactId>iextrading4j-all</artifactId>
58
+			<version>2.2.2</version>
59
+		</dependency>
60
+
61
+		<dependency>
62
+			<groupId>com.github.tomakehurst</groupId>
63
+			<artifactId>wiremock</artifactId>
64
+			<version>1.18</version>
65
+			<scope>test</scope>
66
+		</dependency>
67
+
54 68
 	</dependencies>
55 69
 
56 70
 	<build>

+ 1
- 0
server/src/main/java/com/stockr/server/news/NewsControllerAdvice.java 查看文件

@@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
9 9
 
10 10
 import java.io.IOException;
11 11
 
12
+// TODO move controller advice as global(?)
12 13
 @ControllerAdvice(basePackageClasses = NewsControllerAdvice.class)
13 14
 public class NewsControllerAdvice {
14 15
     private ObjectMapper om = new ObjectMapper();

+ 2
- 0
server/src/main/java/com/stockr/server/news/NewsService.java 查看文件

@@ -10,6 +10,7 @@ import org.springframework.web.client.RestTemplate;
10 10
 
11 11
 import java.util.ArrayList;
12 12
 
13
+
13 14
 @Service
14 15
 public class NewsService {
15 16
     // TODO - hide key(?)
@@ -17,6 +18,7 @@ public class NewsService {
17 18
     private final RestTemplate rt;
18 19
     private HttpEntity entity;
19 20
 
21
+
20 22
     public NewsService(RestTemplateBuilder rtb) {
21 23
         initHeaders();
22 24
         rt = rtb.build();

+ 28
- 0
server/src/main/java/com/stockr/server/stocks/Stocks.java 查看文件

@@ -0,0 +1,28 @@
1
+package com.stockr.server.stocks;
2
+
3
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4
+import lombok.Getter;
5
+import lombok.NoArgsConstructor;
6
+import lombok.Setter;
7
+import pl.zankowski.iextrading4j.api.stocks.*;
8
+
9
+import java.util.List;
10
+
11
+// Wrapper for BatchStocks
12
+@Getter @Setter
13
+@NoArgsConstructor
14
+@JsonIgnoreProperties
15
+public class Stocks {
16
+    // This is NOT from the com.stockr.server.news package
17
+    List<News> news;
18
+    List<Chart> chart;
19
+    Company company;
20
+    Quote quote;
21
+
22
+    Stocks(BatchStocks bs) {
23
+        this.news = bs.getNews();
24
+        this.chart = bs.getChart();
25
+        this.company = bs.getCompany();
26
+        this.quote = bs.getQuote();
27
+    }
28
+}

+ 19
- 0
server/src/main/java/com/stockr/server/stocks/StocksController.java 查看文件

@@ -0,0 +1,19 @@
1
+package com.stockr.server.stocks;
2
+
3
+import org.springframework.beans.factory.annotation.Autowired;
4
+import org.springframework.web.bind.annotation.GetMapping;
5
+import org.springframework.web.bind.annotation.RequestMapping;
6
+import org.springframework.web.bind.annotation.RequestParam;
7
+import org.springframework.web.bind.annotation.RestController;
8
+
9
+@RestController
10
+@RequestMapping("stocks")
11
+public class StocksController {
12
+    @Autowired
13
+    private StocksService stocksService;
14
+
15
+    @GetMapping//root
16
+    public Stocks getStocks(@RequestParam("ticker") String ticker) {
17
+        return stocksService.getStocks(ticker);
18
+    }
19
+}

+ 27
- 0
server/src/main/java/com/stockr/server/stocks/StocksService.java 查看文件

@@ -0,0 +1,27 @@
1
+package com.stockr.server.stocks;
2
+
3
+import org.springframework.context.annotation.Bean;
4
+import org.springframework.stereotype.Service;
5
+import pl.zankowski.iextrading4j.api.stocks.BatchStocks;
6
+import pl.zankowski.iextrading4j.client.IEXTradingClient;
7
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksRequestBuilder;
8
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksType;
9
+
10
+@Service
11
+public class StocksService {
12
+    private final IEXTradingClient iex = IEXTradingClient.create();
13
+
14
+    public Stocks getStocks(String ticker) {
15
+        return new Stocks(getBatchFromTicker(ticker));
16
+    }
17
+
18
+    private BatchStocks getBatchFromTicker(String ticker) {
19
+        return iex.executeRequest(new BatchStocksRequestBuilder()
20
+                .withSymbol(ticker)
21
+                .addType(BatchStocksType.COMPANY)
22
+                .addType(BatchStocksType.CHART)
23
+                .addType(BatchStocksType.NEWS)
24
+                .addType(BatchStocksType.QUOTE)
25
+                .build());
26
+    }
27
+}

+ 23
- 0
server/src/test/java/com/stockr/server/iextrading/IEXTradingApiTest.java 查看文件

@@ -0,0 +1,23 @@
1
+package com.stockr.server.iextrading;
2
+
3
+import org.junit.Test;
4
+import pl.zankowski.iextrading4j.api.stocks.BatchStocks;
5
+import pl.zankowski.iextrading4j.client.IEXTradingClient;
6
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksRequestBuilder;
7
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksType;
8
+
9
+import static org.junit.Assert.*;
10
+
11
+public class IEXTradingApiTest {
12
+    @Test
13
+    public void constructor_ShouldFillFields() {
14
+        IEXTradingClient iex = IEXTradingClient.create();
15
+        BatchStocks bs = iex.executeRequest(new BatchStocksRequestBuilder()
16
+                .withSymbol("AAPL")
17
+                .addType(BatchStocksType.QUOTE)
18
+                .addType(BatchStocksType.CHART)
19
+                .build());
20
+
21
+        assertNotNull(bs);
22
+    }
23
+}

+ 0
- 3
server/src/test/java/com/stockr/server/news/NewsControllerTest.java 查看文件

@@ -1,6 +1,5 @@
1 1
 package com.stockr.server.news;
2 2
 
3
-import static org.hamcrest.Matchers.containsString;
4 3
 import static org.mockito.Mockito.when;
5 4
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
6 5
 import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
@@ -14,8 +13,6 @@ import org.junit.runner.RunWith;
14 13
 import org.springframework.beans.factory.annotation.Autowired;
15 14
 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
16 15
 import org.springframework.boot.test.mock.mockito.MockBean;
17
-import org.springframework.http.HttpHeaders;
18
-import org.springframework.http.HttpStatus;
19 16
 import org.springframework.test.context.junit4.SpringRunner;
20 17
 import org.springframework.test.web.servlet.MockMvc;
21 18
 

+ 47
- 0
server/src/test/java/com/stockr/server/stocks/StocksControllerTest.java 查看文件

@@ -0,0 +1,47 @@
1
+package com.stockr.server.stocks;
2
+
3
+import com.stockr.server.stocks.Stocks;
4
+import com.stockr.server.stocks.StocksController;
5
+import com.stockr.server.stocks.StocksService;
6
+import org.junit.Test;
7
+import org.junit.runner.RunWith;
8
+import org.springframework.beans.factory.annotation.Autowired;
9
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
10
+import org.springframework.boot.test.mock.mockito.MockBean;
11
+import org.springframework.test.context.junit4.SpringRunner;
12
+import org.springframework.test.web.servlet.MockMvc;
13
+import pl.zankowski.iextrading4j.api.stocks.News;
14
+
15
+import static org.mockito.Mockito.when;
16
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
17
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
18
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
19
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
20
+
21
+@RunWith(SpringRunner.class)
22
+@WebMvcTest(StocksController.class)
23
+public class StocksControllerTest {
24
+
25
+    @Autowired
26
+    private MockMvc mockMvc;
27
+
28
+    @MockBean
29
+    private StocksService service;
30
+
31
+    @Test
32
+    public void stocks_ShouldUseMethod_getStocks() throws Exception {
33
+        when(service.getStocks("test")).thenReturn(new Stocks());
34
+        this.mockMvc.perform(get("/stocks?ticker=test"))
35
+                .andDo(print())
36
+                .andExpect(status().isOk())
37
+                .andExpect(handler().methodName("getStocks"));
38
+    }
39
+
40
+    @Test
41
+    public void stocks_ShouldThrowBadRequest_GivenNoTicker() throws Exception {
42
+        when(service.getStocks("test")).thenReturn(new Stocks());
43
+        this.mockMvc.perform(get("/stocks"))
44
+                .andDo(print())
45
+                .andExpect(status().isBadRequest());
46
+    }
47
+}

+ 16
- 0
server/src/test/java/com/stockr/server/stocks/StocksServiceTest.java 查看文件

@@ -0,0 +1,16 @@
1
+package com.stockr.server.stocks;
2
+
3
+import org.junit.Test;
4
+
5
+import static org.junit.Assert.*;
6
+
7
+public class StocksServiceTest {
8
+    private StocksService ss = new StocksService();
9
+
10
+    @Test
11
+    public void getStocks_ShouldReceiveCorrectCompanyName() {
12
+        // TODO mock this...
13
+        Stocks s = ss.getStocks("tsla");
14
+        assertEquals(s.getCompany().getCompanyName(), "Tesla Inc.");
15
+    }
16
+}

+ 30
- 0
server/src/test/java/com/stockr/server/stocks/StocksTest.java 查看文件

@@ -0,0 +1,30 @@
1
+package com.stockr.server.stocks;
2
+
3
+import org.junit.Test;
4
+import pl.zankowski.iextrading4j.api.stocks.BatchStocks;
5
+import pl.zankowski.iextrading4j.client.IEXTradingClient;
6
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksRequestBuilder;
7
+import pl.zankowski.iextrading4j.client.rest.request.stocks.BatchStocksType;
8
+
9
+import static org.junit.Assert.*;
10
+
11
+public class StocksTest {
12
+    @Test
13
+    public void constructor_ShouldFillFields() {
14
+        // TODO mock this...
15
+        IEXTradingClient iex = IEXTradingClient.create();
16
+        BatchStocks bs = iex.executeRequest(new BatchStocksRequestBuilder()
17
+                .withSymbol("AAPL")
18
+                .addType(BatchStocksType.NEWS)
19
+                .addType(BatchStocksType.COMPANY)
20
+                .addType(BatchStocksType.QUOTE)
21
+                .addType(BatchStocksType.CHART)
22
+                .build());
23
+
24
+        Stocks s = new Stocks(bs);
25
+        assertNotNull(s.getChart());
26
+        assertNotNull(s.getCompany());
27
+        assertNotNull(s.getQuote());
28
+        assertNotNull(s.getNews());
29
+    }
30
+}

+ 380
- 0
server/src/test/resources/stocks/BatchStocksResponse.json 查看文件

@@ -0,0 +1,380 @@
1
+{
2
+  "company": {
3
+    "symbol": "AAPL",
4
+    "companyName": "Apple Inc.",
5
+    "exchange": "Nasdaq Global Select",
6
+    "industry": "Computer Hardware",
7
+    "website": "http://www.apple.com",
8
+    "description": "Apple Inc is designs, manufactures and markets mobile communication and media devices and personal computers, and sells a variety of related software, services, accessories, networking solutions and third-party digital content and applications.",
9
+    "CEO": "Timothy D. Cook",
10
+    "issueType": "cs",
11
+    "sector": "Technology",
12
+    "tags": [
13
+      "Technology",
14
+      "Consumer Electronics",
15
+      "Computer Hardware"
16
+    ]
17
+  },
18
+  "quote": {
19
+    "symbol": "AAPL",
20
+    "companyName": "Apple Inc.",
21
+    "primaryExchange": "Nasdaq Global Select",
22
+    "sector": "Technology",
23
+    "calculationPrice": "close",
24
+    "open": 191.16,
25
+    "openTime": 1531488600789,
26
+    "close": 191.33,
27
+    "closeTime": 1531512000377,
28
+    "high": 191.84,
29
+    "low": 190.9,
30
+    "latestPrice": 191.33,
31
+    "latestSource": "Close",
32
+    "latestTime": "July 13, 2018",
33
+    "latestUpdate": 1531512000377,
34
+    "latestVolume": 12503162,
35
+    "iexRealtimePrice": null,
36
+    "iexRealtimeSize": null,
37
+    "iexLastUpdated": null,
38
+    "delayedPrice": 191.33,
39
+    "delayedPriceTime": 1531512000377,
40
+    "extendedPrice": 191.37,
41
+    "extendedChange": 0.04,
42
+    "extendedChangePercent": 0.00021,
43
+    "extendedPriceTime": 1531515465618,
44
+    "previousClose": 191.03,
45
+    "change": 0.3,
46
+    "changePercent": 0.00157,
47
+    "iexMarketPercent": null,
48
+    "iexVolume": null,
49
+    "avgTotalVolume": 23067206,
50
+    "iexBidPrice": null,
51
+    "iexBidSize": null,
52
+    "iexAskPrice": null,
53
+    "iexAskSize": null,
54
+    "marketCap": 940413353540,
55
+    "peRatio": 18.47,
56
+    "week52High": 194.2,
57
+    "week52Low": 147.3,
58
+    "ytdChange": 0.1211037665263325
59
+  },
60
+  "news": [
61
+    {
62
+      "datetime": "2018-07-15T09:39:21-04:00",
63
+      "headline": "DNB: Overall Very Good Q2 Results",
64
+      "source": "SeekingAlpha",
65
+      "url": "https://api.iextrading.com/1.0/stock/aapl/article/7896719890823430",
66
+      "summary": "   On Thursday, July 12, 2018, Norway's largest bank, DNB ASA ( OTCPK:DNBHF ),  reported  its second quarter 2018 results. Overall these results were quite good, which is likely at least partly due to the beneficial effect that high oil prices have on the Norwegian economy. Of course, DNB does op…",
67
+      "related": "AAPL,Computer Hardware,CON31167138,DNBHF,Europe,INTHPINK,NASDAQ01,NORWAY01,PYPL,Computing and Information Technology,WESTEURO",
68
+      "image": "https://api.iextrading.com/1.0/stock/aapl/news-image/7896719890823430"
69
+    },
70
+    {
71
+      "datetime": "2018-07-15T09:19:31-04:00",
72
+      "headline": "Despite Analyst Concerns, Apple Continues To Innovate",
73
+      "source": "SeekingAlpha",
74
+      "url": "https://api.iextrading.com/1.0/stock/aapl/article/4814103171270426",
75
+      "summary": "   On July 13, an analyst at Bernstein  suggested  Apple ( AAPL ) is underinvesting in innovation. This suggestion is based on a regression that shows that Apple's gross margins are higher than you'd expect, given the spending on research and development. In my view, this mistakes a strength for …",
76
+      "related": "AAPL,Computer Hardware,CON31167138,NASDAQ01,Computing and Information Technology",
77
+      "image": "https://api.iextrading.com/1.0/stock/aapl/news-image/4814103171270426"
78
+    },
79
+    {
80
+      "datetime": "2018-07-15T04:40:49-04:00",
81
+      "headline": "H-B-Oh No!",
82
+      "source": "SeekingAlpha",
83
+      "url": "https://api.iextrading.com/1.0/stock/aapl/article/7156981525796639",
84
+      "summary": "    From the age of 2540, my range of emotions could generously be described as narrow. I loved nobody, and the only real emotions I felt were satisfaction or disappointment from my ambition as I howled in the money storm. My approach to life could best be summarized as &#…",
85
+      "related": "AAPL,AMZN,CON102,DIS,ENT10210,GOOG,GOOGL,MED10210023,NASDAQ01,NFLX,T,TWX",
86
+      "image": "https://api.iextrading.com/1.0/stock/aapl/news-image/7156981525796639"
87
+    },
88
+    {
89
+      "datetime": "2018-07-15T04:24:35-04:00",
90
+      "headline": "Podcast: Microsoft Surface Go, Apple MacBook Pro, PC Market, Microsoft Teams",
91
+      "source": "SeekingAlpha",
92
+      "url": "https://api.iextrading.com/1.0/stock/aapl/article/7203713200495502",
93
+      "summary": "   This weeks Tech.pinions podcast features Carolina Milanesi and Bob ODonnell discussing Microsofts (MSFT) new Surface Go mini 2-in-1 device and Apples (AAPL) updated MacBook Pros, analyzing the recent the PC market shipment numbers, and talking about the latest v…",
94
+      "related": "AAPL,APPSOFTW,MSFT,NASDAQ01,SOF31165134,Computing and Information Technology",
95
+      "image": "https://api.iextrading.com/1.0/stock/aapl/news-image/7203713200495502"
96
+    }
97
+  ],
98
+  "chart": [
99
+    {
100
+      "date": "2018-06-15",
101
+      "open": 190.03,
102
+      "high": 190.16,
103
+      "low": 188.26,
104
+      "close": 188.84,
105
+      "volume": 61719160,
106
+      "unadjustedVolume": 61719160,
107
+      "change": -1.96,
108
+      "changePercent": -1.027,
109
+      "vwap": 189.0795,
110
+      "label": "Jun 15",
111
+      "changeOverTime": 0
112
+    },
113
+    {
114
+      "date": "2018-06-18",
115
+      "open": 187.88,
116
+      "high": 189.22,
117
+      "low": 187.2,
118
+      "close": 188.74,
119
+      "volume": 18484865,
120
+      "unadjustedVolume": 18484865,
121
+      "change": -0.1,
122
+      "changePercent": -0.053,
123
+      "vwap": 188.6013,
124
+      "label": "Jun 18",
125
+      "changeOverTime": -0.0005295488244015797
126
+    },
127
+    {
128
+      "date": "2018-06-19",
129
+      "open": 185.14,
130
+      "high": 186.33,
131
+      "low": 183.45,
132
+      "close": 185.69,
133
+      "volume": 33578455,
134
+      "unadjustedVolume": 33578455,
135
+      "change": -3.05,
136
+      "changePercent": -1.616,
137
+      "vwap": 185.1633,
138
+      "label": "Jun 19",
139
+      "changeOverTime": -0.01668078796865074
140
+    },
141
+    {
142
+      "date": "2018-06-20",
143
+      "open": 186.35,
144
+      "high": 187.2,
145
+      "low": 185.73,
146
+      "close": 186.5,
147
+      "volume": 20628701,
148
+      "unadjustedVolume": 20628701,
149
+      "change": 0.81,
150
+      "changePercent": 0.436,
151
+      "vwap": 186.5042,
152
+      "label": "Jun 20",
153
+      "changeOverTime": -0.012391442490997688
154
+    },
155
+    {
156
+      "date": "2018-06-21",
157
+      "open": 187.25,
158
+      "high": 188.35,
159
+      "low": 184.94,
160
+      "close": 185.46,
161
+      "volume": 25711898,
162
+      "unadjustedVolume": 25711898,
163
+      "change": -1.04,
164
+      "changePercent": -0.558,
165
+      "vwap": 186.1556,
166
+      "label": "Jun 21",
167
+      "changeOverTime": -0.017898750264774388
168
+    },
169
+    {
170
+      "date": "2018-06-22",
171
+      "open": 186.12,
172
+      "high": 186.15,
173
+      "low": 184.7,
174
+      "close": 184.92,
175
+      "volume": 27200447,
176
+      "unadjustedVolume": 27200447,
177
+      "change": -0.54,
178
+      "changePercent": -0.291,
179
+      "vwap": 185.291,
180
+      "label": "Jun 22",
181
+      "changeOverTime": -0.02075831391654319
182
+    },
183
+    {
184
+      "date": "2018-06-25",
185
+      "open": 183.4,
186
+      "high": 184.92,
187
+      "low": 180.73,
188
+      "close": 182.17,
189
+      "volume": 31663096,
190
+      "unadjustedVolume": 31663096,
191
+      "change": -2.75,
192
+      "changePercent": -1.487,
193
+      "vwap": 182.3332,
194
+      "label": "Jun 25",
195
+      "changeOverTime": -0.03532090658758746
196
+    },
197
+    {
198
+      "date": "2018-06-26",
199
+      "open": 182.99,
200
+      "high": 186.53,
201
+      "low": 182.54,
202
+      "close": 184.43,
203
+      "volume": 24569201,
204
+      "unadjustedVolume": 24569201,
205
+      "change": 2.26,
206
+      "changePercent": 1.241,
207
+      "vwap": 184.7429,
208
+      "label": "Jun 26",
209
+      "changeOverTime": -0.023353103156110975
210
+    },
211
+    {
212
+      "date": "2018-06-27",
213
+      "open": 185.2278,
214
+      "high": 187.28,
215
+      "low": 184.03,
216
+      "close": 184.16,
217
+      "volume": 25285328,
218
+      "unadjustedVolume": 25285328,
219
+      "change": -0.27,
220
+      "changePercent": -0.146,
221
+      "vwap": 185.5126,
222
+      "label": "Jun 27",
223
+      "changeOverTime": -0.024782884981995375
224
+    },
225
+    {
226
+      "date": "2018-06-28",
227
+      "open": 184.1,
228
+      "high": 186.21,
229
+      "low": 183.8,
230
+      "close": 185.5,
231
+      "volume": 17365235,
232
+      "unadjustedVolume": 17365235,
233
+      "change": 1.34,
234
+      "changePercent": 0.728,
235
+      "vwap": 185.1422,
236
+      "label": "Jun 28",
237
+      "changeOverTime": -0.017686930735013786
238
+    },
239
+    {
240
+      "date": "2018-06-29",
241
+      "open": 186.29,
242
+      "high": 187.19,
243
+      "low": 182.91,
244
+      "close": 185.11,
245
+      "volume": 22737666,
246
+      "unadjustedVolume": 22737666,
247
+      "change": -0.39,
248
+      "changePercent": -0.21,
249
+      "vwap": 185.9543,
250
+      "label": "Jun 29",
251
+      "changeOverTime": -0.019752171150179992
252
+    },
253
+    {
254
+      "date": "2018-07-02",
255
+      "open": 183.82,
256
+      "high": 187.3,
257
+      "low": 183.42,
258
+      "close": 187.18,
259
+      "volume": 17731343,
260
+      "unadjustedVolume": 17731343,
261
+      "change": 2.07,
262
+      "changePercent": 1.118,
263
+      "vwap": 186.1952,
264
+      "label": "Jul 2",
265
+      "changeOverTime": -0.008790510485066705
266
+    },
267
+    {
268
+      "date": "2018-07-03",
269
+      "open": 187.79,
270
+      "high": 187.95,
271
+      "low": 183.54,
272
+      "close": 183.92,
273
+      "volume": 13954806,
274
+      "unadjustedVolume": 13954806,
275
+      "change": -3.26,
276
+      "changePercent": -1.742,
277
+      "vwap": 185.8296,
278
+      "label": "Jul 3",
279
+      "changeOverTime": -0.02605380216055929
280
+    },
281
+    {
282
+      "date": "2018-07-05",
283
+      "open": 185.26,
284
+      "high": 186.41,
285
+      "low": 184.28,
286
+      "close": 185.4,
287
+      "volume": 16604248,
288
+      "unadjustedVolume": 16604248,
289
+      "change": 1.48,
290
+      "changePercent": 0.805,
291
+      "vwap": 185.4736,
292
+      "label": "Jul 5",
293
+      "changeOverTime": -0.018216479559415365
294
+    },
295
+    {
296
+      "date": "2018-07-06",
297
+      "open": 185.42,
298
+      "high": 188.434,
299
+      "low": 185.2,
300
+      "close": 187.97,
301
+      "volume": 17485245,
302
+      "unadjustedVolume": 17485245,
303
+      "change": 2.57,
304
+      "changePercent": 1.386,
305
+      "vwap": 187.3411,
306
+      "label": "Jul 6",
307
+      "changeOverTime": -0.004607074772294029
308
+    },
309
+    {
310
+      "date": "2018-07-09",
311
+      "open": 189.5,
312
+      "high": 190.68,
313
+      "low": 189.3,
314
+      "close": 190.58,
315
+      "volume": 19756634,
316
+      "unadjustedVolume": 19756634,
317
+      "change": 2.61,
318
+      "changePercent": 1.389,
319
+      "vwap": 190.19,
320
+      "label": "Jul 9",
321
+      "changeOverTime": 0.009214149544588058
322
+    },
323
+    {
324
+      "date": "2018-07-10",
325
+      "open": 190.71,
326
+      "high": 191.28,
327
+      "low": 190.1801,
328
+      "close": 190.35,
329
+      "volume": 15939149,
330
+      "unadjustedVolume": 15939149,
331
+      "change": -0.23,
332
+      "changePercent": -0.121,
333
+      "vwap": 190.6699,
334
+      "label": "Jul 10",
335
+      "changeOverTime": 0.00799618724846426
336
+    },
337
+    {
338
+      "date": "2018-07-11",
339
+      "open": 188.5,
340
+      "high": 189.7799,
341
+      "low": 187.61,
342
+      "close": 187.88,
343
+      "volume": 18831470,
344
+      "unadjustedVolume": 18831470,
345
+      "change": -2.47,
346
+      "changePercent": -1.298,
347
+      "vwap": 188.3475,
348
+      "label": "Jul 11",
349
+      "changeOverTime": -0.005083668714255496
350
+    },
351
+    {
352
+      "date": "2018-07-12",
353
+      "open": 189.53,
354
+      "high": 191.41,
355
+      "low": 189.31,
356
+      "close": 191.03,
357
+      "volume": 18041131,
358
+      "unadjustedVolume": 18041131,
359
+      "change": 3.15,
360
+      "changePercent": 1.677,
361
+      "vwap": 190.6589,
362
+      "label": "Jul 12",
363
+      "changeOverTime": 0.011597119254395242
364
+    },
365
+    {
366
+      "date": "2018-07-13",
367
+      "open": 191.08,
368
+      "high": 191.84,
369
+      "low": 190.9,
370
+      "close": 191.33,
371
+      "volume": 12519792,
372
+      "unadjustedVolume": 12519792,
373
+      "change": 0.3,
374
+      "changePercent": 0.157,
375
+      "vwap": 191.424,
376
+      "label": "Jul 13",
377
+      "changeOverTime": 0.013185765727600133
378
+    }
379
+  ]
380
+}