├── .gitattributes
├── .gitignore
├── CONTRIBUTORS.txt
├── LICENSE
├── README.md
├── YahooFinanceAPI.sln
├── YahooFinanceAPI
├── Historical.cs
├── Models
│ ├── Dividend.cs
│ ├── HistoryPrice.cs
│ ├── QuotePrice.cs
│ └── YahooQuote.cs
├── Properties
│ └── AssemblyInfo.cs
├── Quote.cs
├── Token.cs
├── Utils
│ ├── DateTimeConverter.cs
│ └── Json.cs
└── YahooFinanceAPI.csproj
└── build.bat
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | YahooFinanceAPITester/
2 |
3 | ## Ignore Visual Studio temporary files, build results, and
4 | ## files generated by popular Visual Studio add-ons.
5 | # User-specific files
6 | *.suo
7 | *.user
8 | *.userosscache
9 | *.sln.docstates
10 |
11 | # User-specific files (MonoDevelop/Xamarin Studio)
12 | *.userprefs
13 |
14 | # Build results
15 | [Dd]ebug/
16 | [Dd]ebugPublic/
17 | [Rr]elease/
18 | [Rr]eleases/
19 | x64/
20 | x86/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 | [Ll]og/
25 |
26 | # Visual Studio 2015 cache/options directory
27 | .vs/
28 | # Uncomment if you have tasks that create the project's static files in wwwroot
29 | #wwwroot/
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | # DNX
45 | project.lock.json
46 | project.fragment.lock.json
47 | artifacts/
48 |
49 | *_i.c
50 | *_p.c
51 | *_i.h
52 | *.ilk
53 | *.meta
54 | *.obj
55 | *.pch
56 | *.pdb
57 | *.pgc
58 | *.pgd
59 | *.rsp
60 | *.sbr
61 | *.tlb
62 | *.tli
63 | *.tlh
64 | *.tmp
65 | *.tmp_proj
66 | *.log
67 | *.vspscc
68 | *.vssscc
69 | .builds
70 | *.pidb
71 | *.svclog
72 | *.scc
73 |
74 | # Chutzpah Test files
75 | _Chutzpah*
76 |
77 | # Visual C++ cache files
78 | ipch/
79 | *.aps
80 | *.ncb
81 | *.opendb
82 | *.opensdf
83 | *.sdf
84 | *.cachefile
85 | *.VC.db
86 | *.VC.VC.opendb
87 |
88 | # Visual Studio profiler
89 | *.psess
90 | *.vsp
91 | *.vspx
92 | *.sap
93 |
94 | # TFS 2012 Local Workspace
95 | $tf/
96 |
97 | # Guidance Automation Toolkit
98 | *.gpState
99 |
100 | # ReSharper is a .NET coding add-in
101 | _ReSharper*/
102 | *.[Rr]e[Ss]harper
103 | *.DotSettings.user
104 |
105 | # JustCode is a .NET coding add-in
106 | .JustCode
107 |
108 | # TeamCity is a build add-in
109 | _TeamCity*
110 |
111 | # DotCover is a Code Coverage Tool
112 | *.dotCover
113 |
114 | # NCrunch
115 | _NCrunch_*
116 | .*crunch*.local.xml
117 | nCrunchTemp_*
118 |
119 | # MightyMoose
120 | *.mm.*
121 | AutoTest.Net/
122 |
123 | # Web workbench (sass)
124 | .sass-cache/
125 |
126 | # Installshield output folder
127 | [Ee]xpress/
128 |
129 | # DocProject is a documentation generator add-in
130 | DocProject/buildhelp/
131 | DocProject/Help/*.HxT
132 | DocProject/Help/*.HxC
133 | DocProject/Help/*.hhc
134 | DocProject/Help/*.hhk
135 | DocProject/Help/*.hhp
136 | DocProject/Help/Html2
137 | DocProject/Help/html
138 |
139 | # Click-Once directory
140 | publish/
141 |
142 | # Publish Web Output
143 | *.[Pp]ublish.xml
144 | *.azurePubxml
145 | # TODO: Comment the next line if you want to checkin your web deploy settings
146 | # but database connection strings (with potential passwords) will be unencrypted
147 | #*.pubxml
148 | *.publishproj
149 |
150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
151 | # checkin your Azure Web App publish settings, but sensitive information contained
152 | # in these scripts will be unencrypted
153 | PublishScripts/
154 |
155 | # NuGet Packages
156 | *.nupkg
157 | # The packages folder can be ignored because of Package Restore
158 | **/packages/*
159 | # except build/, which is used as an MSBuild target.
160 | !**/packages/build/
161 | # Uncomment if necessary however generally it will be regenerated when needed
162 | #!**/packages/repositories.config
163 | # NuGet v3's project.json files produces more ignoreable files
164 | *.nuget.props
165 | *.nuget.targets
166 |
167 | # Microsoft Azure Build Output
168 | csx/
169 | *.build.csdef
170 |
171 | # Microsoft Azure Emulator
172 | ecf/
173 | rcf/
174 |
175 | # Windows Store app package directories and files
176 | AppPackages/
177 | BundleArtifacts/
178 | Package.StoreAssociation.xml
179 | _pkginfo.txt
180 |
181 | # Visual Studio cache files
182 | # files ending in .cache can be ignored
183 | *.[Cc]ache
184 | # but keep track of directories ending in .cache
185 | !*.[Cc]ache/
186 |
187 | # Others
188 | ClientBin/
189 | ~$*
190 | *~
191 | *.dbmdl
192 | *.dbproj.schemaview
193 | *.jfm
194 | *.pfx
195 | *.publishsettings
196 | node_modules/
197 | orleans.codegen.cs
198 |
199 | # Since there are multiple workflows, uncomment next line to ignore bower_components
200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
201 | #bower_components/
202 |
203 | # RIA/Silverlight projects
204 | Generated_Code/
205 |
206 | # Backup & report files from converting an old project file
207 | # to a newer Visual Studio version. Backup files are not needed,
208 | # because we have git ;-)
209 | _UpgradeReport_Files/
210 | Backup*/
211 | UpgradeLog*.XML
212 | UpgradeLog*.htm
213 |
214 | # SQL Server files
215 | *.mdf
216 | *.ldf
217 |
218 | # Business Intelligence projects
219 | *.rdl.data
220 | *.bim.layout
221 | *.bim_*.settings
222 |
223 | # Microsoft Fakes
224 | FakesAssemblies/
225 |
226 | # GhostDoc plugin setting file
227 | *.GhostDoc.xml
228 |
229 | # Node.js Tools for Visual Studio
230 | .ntvs_analysis.dat
231 |
232 | # Visual Studio 6 build log
233 | *.plg
234 |
235 | # Visual Studio 6 workspace options file
236 | *.opt
237 |
238 | # Visual Studio LightSwitch build output
239 | **/*.HTMLClient/GeneratedArtifacts
240 | **/*.DesktopClient/GeneratedArtifacts
241 | **/*.DesktopClient/ModelManifest.xml
242 | **/*.Server/GeneratedArtifacts
243 | **/*.Server/ModelManifest.xml
244 | _Pvt_Extensions
245 |
246 | # Paket dependency manager
247 | .paket/paket.exe
248 | paket-files/
249 |
250 | # FAKE - F# Make
251 | .fake/
252 |
253 | # JetBrains Rider
254 | .idea/
255 | *.sln.iml
256 |
257 | # CodeRush
258 | .cr/
259 |
260 | # Python Tools for Visual Studio (PTVS)
261 | __pycache__/
262 | *.pyc
--------------------------------------------------------------------------------
/CONTRIBUTORS.txt:
--------------------------------------------------------------------------------
1 | People who have contributed to this project
2 | -------------------------------------------
3 | Project Admin:
4 | * Dennis Lee, https://github.com/dennislwy
5 |
6 | Code Contributors:
7 | * waiholiu, https://github.com/waiholiu
8 |
9 | Code Snippets:
10 | * Dmitry Fedorkov
11 | * ScottCher
12 | * Ali Zahid
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Dennis Lee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YahooFinanceAPI
2 |  [](LICENSE)
3 |
4 | Starting 16 May 2017, Yahoo finance has discontinued its well used service of EOD (end-of-day) data download without notice or warning. This is confirmed by Yahoo employee in this [forum post][1].
5 |
6 | However, EOD data still works on Yahoo finance pages. To download these data, you will now require "crumb" and cookie "B" for authentication. This code will obtain valid cookie and crumb and also downloads EOD price from Yahoo finance.
7 |
8 | For python version, please visit code from [c0redumb](https://github.com/c0redumb/yahoo_quote_download)
9 |
10 | ## Data format changed
11 | The CSV format of the new API has a few difference compared to the original iChart source. Function `Historical.Get` already taken care of this for you, BUT if you plan to use the raw data for further processing (`Historical.GetRaw` function), check your code to make sure that followings differences are taken care of:
12 |
13 | 1. The historical data of Open, High, and Low are already adjusted. In older API download, these data fields are not adjusted.
14 |
15 | 2. The order of data fields in each row is slightly different. The fields of the new API are as following (note that the order of the last two fields are swapped from before).
16 | ```
17 | Date, Open, High, Low, Close, Adjusted Close, Volume
18 | ```
19 |
20 | 3. The order of the rows for historical quote by the new API is chronical (vs counter-chronical as the old API).
21 |
22 | ## Quick Start
23 | 1. Run **build.bat** to build DLL
24 | 2. Copy **bin\YahooFinanceAPI.dll** and **bin\YahooFinanceAPI.xml** files into your Visual Studio project folder
25 | 3. In Visual Studio, add reference **YahooFinanceAPI.dll**
26 |
27 | ## Usage
28 |
29 | ### C#
30 | ```cs
31 | using System.Threading.Tasks;
32 | using YahooFinanceAPI;
33 | using YahooFinanceAPI.Models;
34 |
35 | ...
36 |
37 | private async Task GetHistoricalPrice(string symbol)
38 | {
39 |
40 | //first get a valid token from Yahoo Finance
41 | while (string.IsNullOrEmpty(Token.Cookie) || string.IsNullOrEmpty(Token.Crumb))
42 | {
43 | await Token.RefreshAsync().ConfigureAwait(false);
44 | }
45 |
46 | var hps = await Historical.GetPriceAsync(symbol, DateTime.Now.AddMonths(-1), DateTime.Now).ConfigureAwait(false);
47 |
48 | //do something
49 |
50 | }
51 |
52 | private async Task GetRawHistoricalPrice(string symbol)
53 | {
54 |
55 | //first get a valid token from Yahoo Finance
56 | while (string.IsNullOrEmpty(Token.Cookie) || string.IsNullOrEmpty(Token.Crumb))
57 | {
58 | await Token.RefreshAsync().ConfigureAwait(false);
59 | }
60 |
61 | string csvdata = await Historical.GetRawAsync(symbol, DateTime.Now.AddMonths(-1), DateTime.Now).ConfigureAwait(false);
62 |
63 | //process further
64 |
65 | }
66 | ```
67 |
68 | ### VB
69 | ```vb
70 | Imports System.Threading.Tasks
71 | Imports YahooFinanceAPI
72 | Imports YahooFinanceAPI.Models
73 |
74 | ...
75 |
76 | Private Async Function GetHistoricalPrice(symbol As String) as Task
77 |
78 | 'first get a valid token from Yahoo Finance
79 | While (Token.Cookie = "" OrElse Token.Crumb = "")
80 | Await Token.RefreshAsync().ConfigureAwait(False)
81 | End While
82 |
83 | Dim hps = Await Historical.GetPriceAsync(symbol, DateTime.Now.AddMonths(-1), DateTime.Now).ConfigureAwait(False)
84 |
85 | 'do something
86 |
87 | End Function
88 |
89 | Private Async Function GetHistoricalPriceRaw(symbol As String) as Task
90 |
91 | 'first get a valid token from Yahoo Finance
92 | While (Token.Cookie = "" OrElse Token.Crumb = "")
93 | Await Token.RefreshAsync().ConfigureAwait(False)
94 | End While
95 |
96 | Dim csvdata = Await Historical.GetRawAsync(symbol, DateTime.Now.AddMonths(-1), DateTime.Now).ConfigureAwait(False)
97 |
98 | 'process further
99 |
100 | End Function
101 | ```
102 |
103 | ## References
104 | 1. [Yahoo finance URL not working](http://stackoverflow.com/questions/44030983/yahoo-finance-url-not-working/44036220)
105 | 2. [yahoo_quote_download - Python version](https://github.com/c0redumb/yahoo_quote_download)
106 |
107 | ## Author
108 | This code is written by Dennis Lee
109 |
110 | [1]: https://forums.yahoo.net/t5/Yahoo-Finance-help/Is-Yahoo-Finance-API-broken/m-p/251241/highlight/true#M3116
111 | [2]: https://github.com/c0redumb/yahoo_quote_download
112 |
--------------------------------------------------------------------------------
/YahooFinanceAPI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.16
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YahooFinanceAPI", "YahooFinanceAPI\YahooFinanceAPI.csproj", "{9F664C6A-6D24-45EF-9A9C-3324292E1C46}"
7 | EndProject
8 | Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "YahooFinanceAPITester", "YahooFinanceAPITester\YahooFinanceAPITester.vbproj", "{1322C681-AC1E-4AB0-BF31-8A481726A487}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {9F664C6A-6D24-45EF-9A9C-3324292E1C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {9F664C6A-6D24-45EF-9A9C-3324292E1C46}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {9F664C6A-6D24-45EF-9A9C-3324292E1C46}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {9F664C6A-6D24-45EF-9A9C-3324292E1C46}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {1322C681-AC1E-4AB0-BF31-8A481726A487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1322C681-AC1E-4AB0-BF31-8A481726A487}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1322C681-AC1E-4AB0-BF31-8A481726A487}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1322C681-AC1E-4AB0-BF31-8A481726A487}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {6999EF8F-176B-4D88-8B56-1740C8CD37EE}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/YahooFinanceAPI/Historical.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Net;
5 | using System.Threading.Tasks;
6 | using YahooFinanceAPI.Models;
7 | using YahooFinanceAPI.Utils;
8 |
9 | namespace YahooFinanceAPI
10 | {
11 | ///
12 | /// Class for fetching stock historical price from Yahoo Finance
13 | /// Copyright Dennis Lee
14 | /// 3 Nov 2017
15 | ///
16 | ///
17 | public class Historical
18 | {
19 | #region Public Methods
20 |
21 | ///
22 | /// Get stock historical price from Yahoo Finance
23 | ///
24 | /// Stock ticker symbol
25 | /// Starting datetime
26 | /// Ending datetime
27 | /// List of history price
28 | public static async Task> GetPriceAsync(string symbol, DateTime start, DateTime end)
29 | {
30 | try
31 | {
32 | var csvData = await GetRawAsync(symbol, start, end).ConfigureAwait(false);
33 | if (csvData != null) return await ParsePriceAsync(csvData).ConfigureAwait(false);
34 | }
35 | catch (Exception ex)
36 | {
37 | Debug.Print(ex.Message);
38 | }
39 |
40 | return new List();
41 | }
42 |
43 | ///
44 | /// Get stock historical dividends from Yahoo Finance
45 | ///
46 | /// Stock ticker symbol
47 | /// Starting datetime
48 | /// Ending datetime
49 | /// List of dividends
50 | public static async Task> GetDividendAsync(string symbol, DateTime start, DateTime end)
51 | {
52 | try
53 | {
54 | var csvData = await GetRawAsync(symbol, start, end, "div").ConfigureAwait(false);
55 | if (csvData != null) return await ParseDivAsync(csvData).ConfigureAwait(false);
56 | }
57 | catch (Exception ex)
58 | {
59 | Debug.Print(ex.Message);
60 | }
61 | return new List();
62 | }
63 |
64 | ///
65 | /// Get raw stock historical price from Yahoo Finance
66 | ///
67 | /// Stock ticker symbol
68 | /// Starting datetime
69 | /// Ending datetime
70 | /// Event type (e.g: history, div)
71 | /// Raw history price string
72 | public static async Task GetRawAsync(string symbol, DateTime start, DateTime end, string eventType = "history")
73 | {
74 | string csvData = null;
75 |
76 | try
77 | {
78 | var url = "https://query1.finance.yahoo.com/v7/finance/download/{0}?period1={1}&period2={2}&interval=1d&events={3}&crumb={4}";
79 |
80 | //if no token found, refresh it
81 | if (string.IsNullOrEmpty(Token.Cookie) || string.IsNullOrEmpty(Token.Crumb))
82 | {
83 | if (!await Token.RefreshAsync(symbol).ConfigureAwait(false))
84 | return await GetRawAsync(symbol, start, end).ConfigureAwait(false);
85 | }
86 |
87 | url = string.Format(url, symbol, Math.Round(DateTimeConverter.ToUnixTimestamp(start), 0),
88 | Math.Round(DateTimeConverter.ToUnixTimestamp(end), 0), eventType, Token.Crumb);
89 |
90 | using (var wc = new WebClient())
91 | {
92 | wc.Headers.Add(HttpRequestHeader.Cookie, Token.Cookie);
93 | csvData = await wc.DownloadStringTaskAsync(url).ConfigureAwait(false);
94 | }
95 | }
96 | catch (WebException webEx)
97 | {
98 | var response = (HttpWebResponse)webEx.Response;
99 |
100 | //Re-fetching token
101 | if (response.StatusCode != HttpStatusCode.Unauthorized ||
102 | response.StatusCode != HttpStatusCode.NotFound) throw;
103 | Debug.Print(webEx.Message);
104 | Token.Cookie = "";
105 | Token.Crumb = "";
106 | Debug.Print("Re-fetch token");
107 | return await GetRawAsync(symbol, start, end).ConfigureAwait(false);
108 | }
109 | catch (Exception ex)
110 | {
111 | Debug.Print(ex.Message);
112 | }
113 |
114 | return csvData;
115 | }
116 |
117 | #endregion Public Methods
118 |
119 | #region Private Methods
120 |
121 | ///
122 | /// Parse raw historical price data into list
123 | ///
124 | ///
125 | /// List of historical price
126 | private static async Task> ParsePriceAsync(string csvData)
127 | {
128 | return await Task.Run(() =>
129 | {
130 | var lst = new List();
131 |
132 | try
133 | {
134 | var rows = csvData.Split(Convert.ToChar(10));
135 |
136 | //row(0) was ignored because is column names
137 | //data is read from oldest to latest
138 | for (var i = 1; i <= rows.Length - 1; i++)
139 | {
140 | var row = rows[i];
141 | if (string.IsNullOrEmpty(row)) continue;
142 |
143 | var cols = row.Split(',');
144 | if (cols[1] == "null") continue;
145 |
146 | var itm = new HistoryPrice
147 | {
148 | Date = DateTime.Parse(cols[0]),
149 | Open = Convert.ToDouble(cols[1]),
150 | High = Convert.ToDouble(cols[2]),
151 | Low = Convert.ToDouble(cols[3]),
152 | Close = Convert.ToDouble(cols[4]),
153 | AdjClose = Convert.ToDouble(cols[5])
154 | };
155 |
156 | //fixed issue in some currencies quote (e.g: SGDAUD=X)
157 | if (cols[6] != "null") itm.Volume = Convert.ToInt64(cols[6]);
158 |
159 | lst.Add(itm);
160 | }
161 | }
162 | catch (Exception ex)
163 | {
164 | Debug.Print(ex.Message);
165 | }
166 |
167 | return lst;
168 | }).ConfigureAwait(false);
169 | }
170 |
171 | ///
172 | /// Parse raw dividend data into list
173 | ///
174 | ///
175 | /// List of dividends
176 | private static async Task> ParseDivAsync(string csvData)
177 | {
178 | return await Task.Run(() =>
179 | {
180 | var lst = new List();
181 | try
182 | {
183 | var rows = csvData.Split(Convert.ToChar(10));
184 |
185 | //row(0) was ignored because is column names
186 | //data is read from oldest to latest
187 | for (var i = 1; i <= rows.Length - 1; i++)
188 | {
189 | var row = rows[i];
190 | if (string.IsNullOrEmpty(row)) continue;
191 |
192 | var cols = row.Split(',');
193 | if (cols[1] == "null") continue;
194 |
195 | var itm = new Dividend
196 | {
197 | Date = DateTime.Parse(cols[0]),
198 | Div = Convert.ToDouble(cols[1])
199 | };
200 |
201 | lst.Add(itm);
202 | }
203 | }
204 | catch (Exception ex)
205 | {
206 | Debug.Print(ex.Message);
207 | }
208 |
209 | return lst;
210 | }).ConfigureAwait(false);
211 | }
212 |
213 | #endregion Private Methods
214 | }
215 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Models/Dividend.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace YahooFinanceAPI.Models
4 | {
5 | public class Dividend
6 | {
7 | public DateTime Date { get; set; }
8 | public double Div { get; set; }
9 | }
10 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Models/HistoryPrice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace YahooFinanceAPI.Models
4 | {
5 | public class HistoryPrice
6 | {
7 | public DateTime Date { get; set; }
8 | public double Open { get; set; }
9 | public double High { get; set; }
10 | public double Low { get; set; }
11 | public double Close { get; set; }
12 | public long Volume { get; set; }
13 | public double AdjClose { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Models/QuotePrice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace YahooFinanceAPI.Models
4 | {
5 | public class QuotePrice
6 | {
7 | public string Symbol { get; set; }
8 |
9 | public string Exchange { get; set; }
10 |
11 | public double Open { get; set; }
12 |
13 | public double High { get; set; }
14 |
15 | public double Low { get; set; }
16 |
17 | public double Close { get; set; }
18 |
19 | public long Volume { get; set; }
20 |
21 | public DateTime Timestamp { get; set; } = new DateTime();
22 | }
23 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Models/YahooQuote.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace YahooFinanceAPI.Models
4 | {
5 | internal class YahooQuote
6 | {
7 | public QuoteResponse quoteResponse { get; set; }
8 |
9 | internal class Result
10 | {
11 | public string language { get; set; }
12 | public string quoteType { get; set; }
13 | public string quoteSourceName { get; set; }
14 | public string currency { get; set; }
15 | public double fiftyDayAverage { get; set; }
16 | public double fiftyDayAverageChange { get; set; }
17 | public double fiftyDayAverageChangePercent { get; set; }
18 | public double twoHundredDayAverage { get; set; }
19 | public double twoHundredDayAverageChange { get; set; }
20 | public double twoHundredDayAverageChangePercent { get; set; }
21 | public int sourceInterval { get; set; }
22 | public string exchangeTimezoneName { get; set; }
23 | public string exchangeTimezoneShortName { get; set; }
24 | public int gmtOffSetMilliseconds { get; set; }
25 | public string exchange { get; set; }
26 | public int exchangeDataDelayedBy { get; set; }
27 | public string shortName { get; set; }
28 | public double regularMarketPrice { get; set; }
29 | public int regularMarketTime { get; set; }
30 | public double regularMarketChange { get; set; }
31 | public double regularMarketOpen { get; set; }
32 | public double regularMarketDayHigh { get; set; }
33 | public double regularMarketDayLow { get; set; }
34 | public long regularMarketVolume { get; set; }
35 | public string market { get; set; }
36 | public double regularMarketChangePercent { get; set; }
37 | public string regularMarketDayRange { get; set; }
38 | public double regularMarketPreviousClose { get; set; }
39 | public double bid { get; set; }
40 | public double ask { get; set; }
41 | public int bidSize { get; set; }
42 | public int askSize { get; set; }
43 | public string fullExchangeName { get; set; }
44 | public long averageDailyVolume3Month { get; set; }
45 | public long averageDailyVolume10Day { get; set; }
46 | public string marketState { get; set; }
47 | public bool esgPopulated { get; set; }
48 | public bool tradeable { get; set; }
49 | public double fiftyTwoWeekLowChange { get; set; }
50 | public double fiftyTwoWeekLowChangePercent { get; set; }
51 | public string fiftyTwoWeekRange { get; set; }
52 | public double fiftyTwoWeekHighChange { get; set; }
53 | public double fiftyTwoWeekHighChangePercent { get; set; }
54 | public double fiftyTwoWeekLow { get; set; }
55 | public double fiftyTwoWeekHigh { get; set; }
56 | public int priceHint { get; set; }
57 | public string symbol { get; set; }
58 | }
59 |
60 | internal class QuoteResponse
61 | {
62 | public IList result { get; set; }
63 | public object error { get; set; }
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("YahooFinanceAPI")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Dennis Lee")]
11 | [assembly: AssemblyProduct("YahooFinanceAPI")]
12 | [assembly: AssemblyCopyright("Copyright © Dennis Lee")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("9f664c6a-6d24-45ef-9a9c-3324292e1c46")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.1.0")]
35 | [assembly: AssemblyFileVersion("1.0.1.0")]
--------------------------------------------------------------------------------
/YahooFinanceAPI/Quote.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Net;
4 | using System.Threading.Tasks;
5 | using YahooFinanceAPI.Models;
6 | using YahooFinanceAPI.Utils;
7 |
8 | namespace YahooFinanceAPI
9 | {
10 | public class Quote
11 | {
12 | public static async Task GetPriceAsync(string symbol)
13 | {
14 | try
15 | {
16 | var csvData = await GetRawAsync(symbol).ConfigureAwait(false);
17 | if (csvData != null)
18 | {
19 | var yq = await Json.ToObjectAsync(csvData).ConfigureAwait(false);
20 |
21 | var quote = yq.quoteResponse.result[0];
22 |
23 | var q = new QuotePrice
24 | {
25 | Symbol = quote.symbol,
26 | Exchange = quote.exchange,
27 | Timestamp = DateTimeConverter.ToDateTime(quote.regularMarketTime),
28 | Close = Math.Round(quote.regularMarketPrice, 3),
29 | Open = Math.Round(quote.regularMarketOpen, 3),
30 | High = Math.Round(quote.regularMarketDayHigh, 3),
31 | Low = Math.Round(quote.regularMarketDayLow, 3),
32 | Volume = quote.regularMarketVolume
33 | };
34 |
35 | return q;
36 | }
37 | }
38 | catch (Exception ex)
39 | {
40 | Debug.Print(ex.Message);
41 | }
42 |
43 | return new QuotePrice();
44 | }
45 |
46 | public static async Task GetRawAsync(string symbol)
47 | {
48 | string csvData = null;
49 |
50 | try
51 | {
52 | var url = $"https://query1.finance.yahoo.com/v7/finance/quote?symbols={symbol}";
53 |
54 | using (var wc = new WebClient())
55 | {
56 | csvData = await wc.DownloadStringTaskAsync(url).ConfigureAwait(false);
57 | }
58 | }
59 | catch (Exception ex)
60 | {
61 | Debug.Print(ex.Message);
62 | }
63 |
64 | return csvData;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Token.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Net;
5 | using System.Text.RegularExpressions;
6 | using System.Threading.Tasks;
7 |
8 | namespace YahooFinanceAPI
9 | {
10 | ///
11 | /// Class for fetching token (cookie and crumb) from Yahoo Finance
12 | /// Copyright Dennis Lee
13 | /// 3 Nov 2017
14 | ///
15 | ///
16 | public class Token
17 | {
18 | #region Public Members
19 |
20 | public static string Cookie { get; internal set; }
21 | public static string Crumb { get; internal set; }
22 |
23 | #endregion Public Members
24 |
25 | #region Private Members
26 |
27 | private static Regex _regexCrumb;
28 |
29 | #endregion Private Members
30 |
31 | #region Public Methods
32 |
33 | ///
34 | /// Refresh cookie and crumb value
35 | ///
36 | /// Stock ticker symbol
37 | ///
38 | public static async Task RefreshAsync(string symbol = "SPY")
39 | {
40 | try
41 | {
42 | Cookie = string.Empty;
43 | Crumb = string.Empty;
44 |
45 | const string urlScrape = "https://finance.yahoo.com/quote/{0}?p={0}";
46 |
47 | var url = string.Format(urlScrape, symbol);
48 |
49 | var request = (HttpWebRequest)WebRequest.Create(url);
50 |
51 | request.CookieContainer = new CookieContainer();
52 | request.Method = "GET";
53 |
54 | using (var response = (HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
55 | {
56 | var cookie = response.GetResponseHeader("Set-Cookie").Split(';')[0];
57 |
58 | var html = string.Empty;
59 |
60 | using (var stream = response.GetResponseStream())
61 | {
62 | if (stream != null)
63 | html = await new StreamReader(stream).ReadToEndAsync().ConfigureAwait(false);
64 | }
65 |
66 | if (html.Length < 5000) return false;
67 | var crumb = await GetCrumbAsync(html).ConfigureAwait(false);
68 |
69 | if (crumb != null)
70 | {
71 | Cookie = cookie;
72 | Crumb = crumb;
73 | Debug.Print("Crumb: '{0}', Cookie: '{1}'", crumb, cookie);
74 | return true;
75 | }
76 | }
77 | }
78 | catch (Exception ex)
79 | {
80 | Debug.Print(ex.Message);
81 | }
82 |
83 | return false;
84 | }
85 |
86 | #endregion Public Methods
87 |
88 | #region Private Methods
89 |
90 | ///
91 | /// Get crumb value from HTML
92 | ///
93 | /// HTML code
94 | ///
95 | private static async Task GetCrumbAsync(string html)
96 | {
97 | return await Task.Run(() =>
98 | {
99 | string crumb = null;
100 |
101 | try
102 | {
103 | //initialize on first time use
104 | if (_regexCrumb == null)
105 | _regexCrumb = new Regex("CrumbStore\":{\"crumb\":\"(?.+?)\"}",
106 | RegexOptions.CultureInvariant | RegexOptions.Compiled);
107 |
108 | var matches = _regexCrumb.Matches(html);
109 |
110 | if (matches.Count > 0)
111 | {
112 | crumb = matches[0].Groups["crumb"].Value;
113 |
114 | //fixed unicode character 'SOLIDUS'
115 | if (crumb.Length != 11)
116 | crumb = crumb.Replace("\\u002F", "/");
117 | }
118 | else
119 | {
120 | Debug.Print("Regex no match");
121 | }
122 |
123 | //prevent regex memory leak
124 | matches = null;
125 | }
126 | catch (Exception ex)
127 | {
128 | Debug.Print(ex.Message);
129 | }
130 |
131 | GC.Collect();
132 | return crumb;
133 | }).ConfigureAwait(false);
134 | }
135 |
136 | #endregion Private Methods
137 | }
138 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Utils/DateTimeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace YahooFinanceAPI.Utils
4 | {
5 | internal class DateTimeConverter
6 | {
7 | //credits to ScottCher
8 | //reference http://stackoverflow.com/questions/249760/how-to-convert-a-unix-timestamp-to-datetime-and-vice-versa
9 | public static DateTime ToDateTime(double unixTimeStamp)
10 | {
11 | //Unix timestamp Is seconds past epoch
12 | return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTimeStamp).ToLocalTime();
13 | }
14 |
15 | //credits to Dmitry Fedorkov
16 | //reference http://stackoverflow.com/questions/249760/how-to-convert-a-unix-timestamp-to-datetime-and-vice-versa
17 | public static double ToUnixTimestamp(DateTime datetime)
18 | {
19 | //Unix timestamp Is seconds past epoch
20 | return (datetime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/Utils/Json.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using Newtonsoft.Json.Serialization;
4 | using System.Threading.Tasks;
5 |
6 | namespace YahooFinanceAPI.Utils
7 | {
8 | //credits to Ali Zahid
9 | internal static class Json
10 | {
11 | private static readonly JsonSerializerSettings SerializeToCamelCase = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
12 | private static readonly JsonSerializer Serializer = JsonSerializer.Create(SerializeToCamelCase);
13 |
14 | public static async Task ToObjectAsync(string value)
15 | {
16 | return await Task.Run(() => JsonConvert.DeserializeObject(value, SerializeToCamelCase)).ConfigureAwait(false);
17 | }
18 |
19 | public static async Task ToObjectAsync(JsonReader reader)
20 | {
21 | return await Task.Run(() => Serializer.Deserialize(reader)).ConfigureAwait(false);
22 | }
23 |
24 | public static async Task ToObjectAsync(JToken jToken)
25 | {
26 | return await Task.Run(() => jToken.ToObject(Serializer)).ConfigureAwait(false);
27 | }
28 |
29 | public static async Task StringifyAsync(object value)
30 | {
31 | return await Task.Run(() => JsonConvert.SerializeObject(value, SerializeToCamelCase)).ConfigureAwait(false);
32 | }
33 |
34 | public static async Task StringifyAsync(object value, Formatting formatting)
35 | {
36 | return await Task.Run(() => JsonConvert.SerializeObject(value, formatting, SerializeToCamelCase)).ConfigureAwait(false);
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/YahooFinanceAPI/YahooFinanceAPI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9F664C6A-6D24-45EF-9A9C-3324292E1C46}
8 | Library
9 | Properties
10 | YahooFinanceAPI
11 | YahooFinanceAPI
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 | bin\Release\YahooFinanceAPI.xml
35 |
36 |
37 |
38 | ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | SET COMPILER_VER=2.3.2
3 | SET CSCPATH=%TEMP%\Microsoft.Net.Compilers.%COMPILER_VER%\tools
4 | if not exist "%TEMP%\nuget.exe" powershell -Command "(new-object System.Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%TEMP%\nuget.exe')"
5 | %TEMP%\nuget.exe install YahooFinanceAPI\packages.config -o packages
6 | %TEMP%\nuget.exe install Microsoft.Net.Compilers -version %COMPILER_VER% -o %TEMP%
7 | if not exist ".\bin" mkdir bin
8 | %CSCPATH%\csc /target:library /out:bin\YahooFinanceAPI.dll /recurse:YahooFinanceAPI\*.cs /doc:bin\YahooFinanceAPI.xml
9 | pause
10 |
--------------------------------------------------------------------------------