Skip to content

Commit 96115d3

Browse files
committed
Security Profile
1 parent cb999f4 commit 96115d3

4 files changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace YahooFinanceApi.Tests;
9+
10+
public class ProfileTests
11+
{
12+
[Fact]
13+
public async Task TestProfileAsync()
14+
{
15+
const string AAPL = "AAPL";
16+
17+
var aaplProfile = await Yahoo.QueryProfileAsync(AAPL);
18+
19+
Assert.NotNull(aaplProfile.Address1);
20+
Assert.NotNull(aaplProfile.AuditRisk);
21+
Assert.NotNull(aaplProfile.BoardRisk);
22+
Assert.NotNull(aaplProfile.City);
23+
Assert.NotNull(aaplProfile.CompanyOfficers);
24+
Assert.NotNull(aaplProfile.CompensationAsOfEpochDate);
25+
Assert.NotNull(aaplProfile.CompensationRisk);
26+
Assert.NotNull(aaplProfile.Country);
27+
Assert.NotNull(aaplProfile.FullTimeEmployees);
28+
Assert.NotNull(aaplProfile.GovernanceEpochDate);
29+
Assert.NotNull(aaplProfile.Industry);
30+
Assert.NotNull(aaplProfile.IndustryDisp);
31+
Assert.NotNull(aaplProfile.IndustryKey);
32+
Assert.NotNull(aaplProfile.LongBusinessSummary);
33+
Assert.NotNull(aaplProfile.MaxAge);
34+
Assert.NotNull(aaplProfile.State);
35+
Assert.NotNull(aaplProfile.Zip);
36+
Assert.NotNull(aaplProfile.Phone);
37+
Assert.NotNull(aaplProfile.Website);
38+
Assert.NotNull(aaplProfile.Sector);
39+
Assert.NotNull(aaplProfile.SectorKey);
40+
Assert.NotNull(aaplProfile.SectorDisp);
41+
Assert.NotNull(aaplProfile.ShareHolderRightsRisk);
42+
Assert.NotNull(aaplProfile.OverallRisk);
43+
}
44+
}

YahooFinanceApi/ProfileFields.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace YahooFinanceApi;
2+
3+
public enum ProfileFields
4+
{
5+
Address1,
6+
City,
7+
State,
8+
Zip,
9+
Country,
10+
Phone,
11+
Website,
12+
Industry,
13+
IndustryKey,
14+
IndustryDisp,
15+
Sector,
16+
SectorKey,
17+
SectorDisp,
18+
LongBusinessSummary,
19+
FullTimeEmployees,
20+
CompanyOfficers,
21+
AuditRisk,
22+
BoardRisk,
23+
CompensationRisk,
24+
ShareHolderRightsRisk,
25+
OverallRisk,
26+
GovernanceEpochDate,
27+
CompensationAsOfEpochDate,
28+
MaxAge,
29+
}

YahooFinanceApi/SecurityProfile.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace YahooFinanceApi;
5+
6+
public class SecurityProfile
7+
{
8+
public IReadOnlyDictionary<string, dynamic> Fields { get; private set; }
9+
10+
// ctor
11+
internal SecurityProfile(IReadOnlyDictionary<string, dynamic> fields) => Fields = fields;
12+
13+
public dynamic this[string fieldName] => Fields[fieldName];
14+
public dynamic this[ProfileFields field] => Fields[field.ToString()];
15+
16+
public string Address1 => this[ProfileFields.Address1];
17+
public string City => this[ProfileFields.City];
18+
public string State => this[ProfileFields.State];
19+
public string Zip => this[ProfileFields.Zip];
20+
public string Country => this[ProfileFields.Country];
21+
public string Phone => this[ProfileFields.Phone];
22+
public string Website => this[ProfileFields.Website];
23+
public string Industry => this[ProfileFields.Industry];
24+
public string IndustryKey => this[ProfileFields.IndustryKey];
25+
public string IndustryDisp => this[ProfileFields.IndustryDisp];
26+
public string Sector => this[ProfileFields.Sector];
27+
public string SectorKey => this[ProfileFields.SectorKey];
28+
public string SectorDisp => this[ProfileFields.SectorDisp];
29+
public string LongBusinessSummary => this[ProfileFields.LongBusinessSummary];
30+
public long FullTimeEmployees => this[ProfileFields.FullTimeEmployees];
31+
public List<dynamic> CompanyOfficers => this[ProfileFields.CompanyOfficers];
32+
public long AuditRisk => this[ProfileFields.AuditRisk];
33+
public long BoardRisk => this[ProfileFields.BoardRisk];
34+
public long CompensationRisk => this[ProfileFields.CompensationRisk];
35+
public long ShareHolderRightsRisk => this[ProfileFields.ShareHolderRightsRisk];
36+
public long OverallRisk => this[ProfileFields.OverallRisk];
37+
public DateTime GovernanceEpochDate => DateTimeOffset.FromUnixTimeSeconds((long)this[ProfileFields.GovernanceEpochDate]).LocalDateTime;
38+
public DateTime CompensationAsOfEpochDate => DateTimeOffset.FromUnixTimeSeconds((long)this[ProfileFields.CompensationAsOfEpochDate]).LocalDateTime;
39+
public long MaxAge => this[ProfileFields.MaxAge];
40+
}

YahooFinanceApi/Yahoo - Profile.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Flurl;
2+
using Flurl.Http;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace YahooFinanceApi
11+
{
12+
public sealed partial class Yahoo
13+
{
14+
15+
public static async Task<SecurityProfile> QueryProfileAsync(string symbol, CancellationToken token = default)
16+
{
17+
await YahooSession.InitAsync(token);
18+
19+
var url = $"https://query2.finance.yahoo.com/v10/finance/quoteSummary/{symbol}"
20+
.SetQueryParam("modules", "assetProfile,convert_dates")
21+
.SetQueryParam("crumb", YahooSession.Crumb);
22+
23+
// Invalid symbols as part of a request are ignored by Yahoo.
24+
// So the number of symbols returned may be less than requested.
25+
// If there are no valid symbols, an exception is thrown by Flurl.
26+
// This exception is caught (below) and an empty dictionary is returned.
27+
// There seems to be no easy way to reliably identify changed symbols.
28+
29+
dynamic data = null;
30+
31+
try
32+
{
33+
data = await url
34+
.WithCookie(YahooSession.Cookie.Name, YahooSession.Cookie.Value)
35+
.WithHeader(YahooSession.UserAgentKey, YahooSession.UserAgentValue)
36+
.GetAsync(token)
37+
.ReceiveJson()
38+
.ConfigureAwait(false);
39+
}
40+
catch (FlurlHttpException ex)
41+
{
42+
if (ex.Call.Response.StatusCode == (int)System.Net.HttpStatusCode.NotFound)
43+
{
44+
return null;
45+
}
46+
else
47+
{
48+
throw;
49+
}
50+
}
51+
52+
var response = data.quoteSummary;
53+
54+
var error = response.error;
55+
if (error != null)
56+
{
57+
throw new InvalidDataException($"An error was returned by Yahoo: {error}");
58+
}
59+
60+
var result = response.result[0].assetProfile;
61+
var pascalDictionary = ((IDictionary<string, dynamic>) result).ToDictionary(x => x.Key.ToPascal(), x => x.Value);
62+
63+
64+
return new SecurityProfile(pascalDictionary);
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)