Skip to content

Commit

Permalink
Working on #9, completed query with search string
Browse files Browse the repository at this point in the history
  • Loading branch information
Karl Wan committed Sep 20, 2017
1 parent ca69506 commit 72b94ae
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 1 deletion.
12 changes: 11 additions & 1 deletion YahooFinanceApi.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

using YahooFinanceApi.Lookup;

namespace YahooFinanceApi.Tests
{
public class UnitTest1
Expand All @@ -15,6 +17,14 @@ public UnitTest1()
CultureInfo.CurrentCulture = new CultureInfo("nl-nl");
}

[Fact]
public void SymbolListTest()
{
const string Symbol = "aap";
var symbols = YahooLookup.GetLookupSymbolsAsync(Symbol, LookupType.Stocks, MarketType.US_Canada).Result;
Assert.True(symbols.Any(s => s.CompanyName == "Advance Auto Parts, Inc."));
}

[Fact]
public void HistoricalExceptionTest()
{
Expand Down
4 changes: 4 additions & 0 deletions YahooFinanceApi/Helper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
Expand All @@ -23,5 +24,8 @@ public static string GetRandomString(int length)
const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
return string.Join("", Enumerable.Range(0, length).Select(i => Chars[new Random().Next(Chars.Length)]));
}

public static IEnumerable<string> AddSuffixes(this string prefix)
=> "abcdefghijklmnopqrstuvwxyz".Select(a => prefix + a);
}
}
32 changes: 32 additions & 0 deletions YahooFinanceApi/Lookup/LookupSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;

namespace YahooFinanceApi.Lookup
{
public class LookupSymbol
{
public string Symbol { get; }
public string CompanyName { get; }
//public decimal LastValue { get; }
//public decimal Change { get; }
//public decimal ChangePercent { get; }
public string IndustryName { get; }
public string IndustryLink { get; }
public string Type { get; }
public string Exchange { get; }

public LookupSymbol(string symbol, string companyName, /*decimal lastValue, decimal change, decimal changePercent, */
string industryName, string industryLink, string type, string exchange)
{
Exchange = exchange;
Type = type;
IndustryLink = industryLink;
IndustryName = industryName;
//ChangePercent = changePercent;
//Change = change;
//LastValue = lastValue;
CompanyName = companyName;
Symbol = symbol;
}
}
}
23 changes: 23 additions & 0 deletions YahooFinanceApi/Lookup/LookupType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Runtime.Serialization;

namespace YahooFinanceApi.Lookup
{
public enum LookupType
{
[EnumMember(Value = "A")]
All,
[EnumMember(Value = "S")]
Stocks,
[EnumMember(Value = "M")]
MutualFunds,
[EnumMember(Value = "E")]
ETFs,
[EnumMember(Value = "I")]
Indices,
[EnumMember(Value = "F")]
Futures,
[EnumMember(Value = "C")]
Currencies
}
}
13 changes: 13 additions & 0 deletions YahooFinanceApi/Lookup/MarketType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Runtime.Serialization;

namespace YahooFinanceApi.Lookup
{
public enum MarketType
{
[EnumMember(Value = "ALL")]
All,
[EnumMember(Value = "US")]
US_Canada
}
}
97 changes: 97 additions & 0 deletions YahooFinanceApi/Lookup/YahooLookup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Flurl.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace YahooFinanceApi.Lookup
{
public static class YahooLookup
{
const string LookupUrl = "https://finance.yahoo.com/_finance_doubledown/api/resource/finance.yfinlist.symbol_lookup";
const string SearchTag = "s";
const string LookupTypeTag = "t";
const string MarketTag = "m";
const string OffsetTag = "b";
const string IsIncludeSimilarTag = "p";

public static async Task<IEnumerable<LookupSymbol>> GetLookupSymbolsAsync(string search, LookupType lookupType, MarketType marketType, CancellationToken token = default(CancellationToken))
{
Func<string, int, Task<Stream>> responseFunc = (s, i) => GetSymbolListResponseStreamAsync(s, lookupType, marketType, i, token);
var childSearches = await GetLookupSearchesAsync(search, lookupType, marketType, token);

var list = new List<LookupSymbol>();
foreach (var childSearch in childSearches)
{
int offset = 0;
while (true)
{
using (var s = await responseFunc(childSearch, offset))
using (var sr = new StreamReader(s))
{
var o = JObject.Parse(sr.ReadToEnd());
var symbols = o["result"].ToArray();
list.AddRange(symbols.Select(sym => JsonConvert.DeserializeObject<LookupSymbol>(sym.ToString())));

var nav = o["navLink"];
var navAsDict = (IDictionary<string, JToken>)nav;
if (!navAsDict.ContainsKey("nextPage") || !navAsDict.ContainsKey("lastPage"))
break;

offset = nav["nextPage"]["start"].Value<int>();
}
}
}

return list;
}

public static async Task<IEnumerable<string>> GetLookupSearchesAsync(string search, LookupType lookupType, MarketType marketType, CancellationToken token = default(CancellationToken))
{
Func<int, Task<Stream>> responseFunc = i => GetSymbolListResponseStreamAsync(search, lookupType, marketType, i, token);
var list = new List<string>();

if (await IsLookupSizeTooLargeAsync())
{
foreach (var subSearch in search.AddSuffixes())
list.AddRange(await GetLookupSearchesAsync(subSearch, lookupType, marketType, token));
return list;
}

return new string[] { search };

async Task<bool> IsLookupSizeTooLargeAsync()
{
const int LookupSizeLimit = 2000;

using (var s = await responseFunc(0))
using (var sr = new StreamReader(s))
{
var o = JObject.Parse(sr.ReadToEnd());
var nav = o["navLink"];
var navAsDict = (IDictionary<string, JToken>)nav;
if (!navAsDict.ContainsKey("lastPage"))
return false;

return nav["lastPage"]["start"].Value<int>() >= LookupSizeLimit;
}
}
}

public static async Task<Stream> GetSymbolListResponseStreamAsync(string search, LookupType lookupType, MarketType marketType, int offset, CancellationToken token = default(CancellationToken))
=> await new StringBuilder()
.Append(LookupUrl)
.Append($";{SearchTag}={search}")
.Append($";{LookupTypeTag}={lookupType.Name()}")
.Append($";{MarketTag}={marketType.Name()}")
.Append($";{OffsetTag}={offset}")
.Append($";{IsIncludeSimilarTag}=1")
.ToString()
.GetStreamAsync(token);
}
}
3 changes: 3 additions & 0 deletions YahooFinanceApi/YahooFinanceApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@
<PackageReference Include="Flurl" Version="2.2.1" />
<PackageReference Include="Flurl.Http" Version="1.1.1" />
</ItemGroup>
<ItemGroup>
<Folder Include="Lookup\" />
</ItemGroup>
</Project>

0 comments on commit 72b94ae

Please sign in to comment.