├── .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 | ![Language](https://img.shields.io/badge/.NET%20Framework-4.5-blue.svg?style=flat) [![License](https://img.shields.io/badge/License-MIT%20License-blue.svg?style=flat)](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 | --------------------------------------------------------------------------------