A C# port of the popular yfinance Python library for accessing Yahoo! Finance market and financial data. This library provides a clean, dependency-injection-based API for retrieving stock quotes, historical prices, financial statements, and other market data.
Note: This library is intended for research and educational purposes only. It is not affiliated with, endorsed, or vetted by Yahoo, Inc.
- β Historical Price Data - OHLC prices, volume, dividends, splits, capital gains
- β Real-time Quotes - Current prices and market data
- β Info & Fast Info - Full quote summary plus fast snapshot fields
- β Financial Statements - Income statements, balance sheets, cash flow
- β Analyst Data - Recommendations, upgrades/downgrades, earnings estimates
- β Holder Information - Institutional holdings, insider transactions, fund holders
- β Major Holders - Quick summary of insider and institutional ownership
- β Insider Roster - Current insider holder positions
- β Options Data - Option chains and expirations
- β ESG Scores - Environmental, social, and governance data
- β Calendar Events - Earnings dates, dividends, capital gains
- β Shares History - Shares outstanding and float history
- β Corporate Actions - Combined dividends and splits timeline
- β News - Latest ticker news items
- β Funds Data - Fund profile and holdings
- β Search/Lookup/Screener - Market-wide discovery and filters
- β Domain Data - Sector, industry, and market overviews
- β ISIN Lookup - Map tickers to ISIN identifiers
- β Live Market Streaming - Websocket updates for price data
- β Dependency Injection - Full DI support for ASP.NET Core and console apps
- β Async/Await - Fully asynchronous API
- β Timezone Support - Proper handling of market timezones
- β Clean Architecture - Separated interfaces, models, and implementations
- .NET SDK 10.0 or later
- Internet connectivity for accessing Yahoo Finance API
- Clone the repository:
git clone https://github.com/CalvinPangch/yfinance.git
cd yfinance- Build the solution:
dotnet build- Run tests (optional):
# Run all tests
dotnet test
# Run only unit tests
dotnet test --filter "FullyQualifiedName~YFinance.NET.Tests.Unit"
# Run only integration tests (requires internet)
dotnet test --filter "FullyQualifiedName~YFinance.NET.Tests.Integration"Option 1: Project Reference (if YFinance.NET is in your solution)
dotnet add reference path/to/YFinance.NET.Implementation/YFinance.NET.Implementation.csprojOption 2: NuGet Package (once published)
dotnet add package YFinance.NET- Authenticate to GitHub Packages.
- Add the source:
https://nuget.pkg.github.com/CalvinPangch/index.json - Install:
dotnet add package YFinance.NET --version <version>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using YFinance.NET.Interfaces;
using YFinance.NET.Implementation.DependencyInjection;
using YFinance.NET.Models.Enums;
using YFinance.NET.Models.Requests;
// Setup dependency injection
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddYFinance();
})
.Build();
// Get the ticker service
var tickerService = host.Services.GetRequiredService<ITickerService>();
// Fetch 1 month of Apple stock history
var history = await tickerService.GetHistoryAsync("AAPL", new HistoryRequest
{
Period = Period.OneMonth,
Interval = Interval.OneDay,
AutoAdjust = true
});
// Display results
Console.WriteLine($"Symbol: {history.Symbol}");
Console.WriteLine($"Timezone: {history.TimeZone}");
Console.WriteLine($"Data points: {history.Timestamps.Length}");
Console.WriteLine("\nRecent prices:");
for (int i = Math.Max(0, history.Timestamps.Length - 5); i < history.Timestamps.Length; i++)
{
Console.WriteLine($"{history.Timestamps[i]:yyyy-MM-dd} - " +
$"Open: ${history.Open[i]:F2}, " +
$"Close: ${history.Close[i]:F2}, " +
$"Volume: {history.Volume[i]:N0}");
}Program.cs:
using YFinance.NET.Implementation.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Add YFinance services
builder.Services.AddYFinance();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();StockController.cs:
using Microsoft.AspNetCore.Mvc;
using YFinance.NET.Interfaces;
using YFinance.NET.Models;
using YFinance.NET.Models.Enums;
using YFinance.NET.Models.Requests;
[ApiController]
[Route("api/[controller]")]
public class StockController : ControllerBase
{
private readonly ITickerService _tickerService;
public StockController(ITickerService tickerService)
{
_tickerService = tickerService;
}
[HttpGet("{symbol}/history")]
public async Task<ActionResult<HistoricalData>> GetHistory(
string symbol,
[FromQuery] int days = 30)
{
var endDate = DateTime.UtcNow.Date;
var startDate = endDate.AddDays(-days);
var history = await _tickerService.GetHistoryAsync(symbol, new HistoryRequest
{
Start = startDate,
End = endDate,
Interval = Interval.OneDay,
AutoAdjust = true
});
return Ok(history);
}
}var request = new HistoryRequest
{
Start = new DateTime(2024, 1, 1),
End = new DateTime(2024, 12, 31),
Interval = Interval.OneDay,
AutoAdjust = true,
Repair = false
};
var history = await tickerService.GetHistoryAsync("MSFT", request);
// Access OHLC data
for (int i = 0; i < history.Timestamps.Length; i++)
{
Console.WriteLine($"Date: {history.Timestamps[i]:yyyy-MM-dd}");
Console.WriteLine($" Open: ${history.Open[i]:F2}");
Console.WriteLine($" High: ${history.High[i]:F2}");
Console.WriteLine($" Low: ${history.Low[i]:F2}");
Console.WriteLine($" Close: ${history.Close[i]:F2}");
Console.WriteLine($" Adjusted Close: ${history.AdjustedClose[i]:F2}");
Console.WriteLine($" Volume: {history.Volume[i]:N0}");
if (history.Dividends != null && history.Dividends[i] > 0)
Console.WriteLine($" Dividend: ${history.Dividends[i]:F2}");
if (history.StockSplits != null && history.StockSplits[i] > 0)
Console.WriteLine($" Stock Split: {history.StockSplits[i]}");
}// Pre-defined time periods
var periods = new[]
{
Period.OneDay,
Period.FiveDays,
Period.OneMonth,
Period.ThreeMonths,
Period.SixMonths,
Period.OneYear,
Period.TwoYears,
Period.FiveYears,
Period.TenYears,
Period.YearToDate,
Period.Max
};
foreach (var period in periods)
{
var history = await tickerService.GetHistoryAsync("GOOGL", new HistoryRequest
{
Period = period,
Interval = Interval.OneDay
});
Console.WriteLine($"{period}: {history.Timestamps.Length} data points");
}// Intraday data (1-minute intervals)
var intraday = await tickerService.GetHistoryAsync("TSLA", new HistoryRequest
{
Period = Period.OneDay,
Interval = Interval.OneMinute
});
// Hourly data
var hourly = await tickerService.GetHistoryAsync("TSLA", new HistoryRequest
{
Period = Period.FiveDays,
Interval = Interval.OneHour
});
// Weekly data
var weekly = await tickerService.GetHistoryAsync("TSLA", new HistoryRequest
{
Period = Period.OneYear,
Interval = Interval.OneWeek
});
// Monthly data
var monthly = await tickerService.GetHistoryAsync("TSLA", new HistoryRequest
{
Period = Period.FiveYears,
Interval = Interval.OneMonth
});using YFinance.NET.Models.Exceptions;
try
{
var history = await tickerService.GetHistoryAsync("INVALID_SYMBOL", new HistoryRequest
{
Period = Period.OneMonth,
Interval = Interval.OneDay
});
}
catch (InvalidTickerException ex)
{
Console.WriteLine($"Invalid ticker: {ex.Message}");
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited: {ex.Message}");
// Implement exponential backoff or retry logic
}
catch (YahooFinanceException ex)
{
Console.WriteLine($"Yahoo Finance error: {ex.Message}");
}// Get lightweight essential data - faster than full quote
var fastInfo = await tickerService.GetFastInfoAsync("AAPL");
Console.WriteLine($"Last Price: ${fastInfo.LastPrice}");
Console.WriteLine($"Market Cap: ${fastInfo.MarketCap:N0}");
Console.WriteLine($"Volume: {fastInfo.Volume:N0}");
Console.WriteLine($"52-Week High: ${fastInfo.YearHigh}");
Console.WriteLine($"P/E Ratio: {fastInfo.PeRatio}");var actions = await tickerService.GetActionsAsync("AAPL", new HistoryRequest
{
Period = Period.FiveYears,
Interval = Interval.OneDay
});
foreach (var action in actions.Actions)
{
var actionType = action.Type == ActionType.Dividend ? "Dividend" : "Split";
Console.WriteLine($"{action.Date:yyyy-MM-dd} - {actionType}: {action.Value}");
}var multiTickerService = host.Services.GetRequiredService<IMultiTickerService>();
// Download historical data for multiple tickers
var symbols = new[] { "AAPL", "MSFT", "GOOGL", "AMZN" };
var histories = await multiTickerService.GetHistoryAsync(
symbols,
new HistoryRequest { Period = Period.OneMonth, Interval = Interval.OneDay },
maxConcurrency: 4
);
foreach (var (symbol, history) in histories)
{
Console.WriteLine($"{symbol}: {history.Close.Last()} ({history.Timestamps.Length} data points)");
}
// Batch quote downloads
var quotes = await multiTickerService.GetQuotesAsync(symbols);
// Batch fast info
var fastInfos = await multiTickerService.GetFastInfoAsync(symbols);
// Batch financial statements
var financials = await multiTickerService.GetFinancialStatementsAsync(symbols);// Create Tickers instance with space-separated symbols
var tickers = new Tickers(
"AAPL MSFT GOOGL",
tickerService,
multiTickerService
);
// Download all at once
var allHistories = await tickers.DownloadAsync(new HistoryRequest
{
Period = Period.OneYear,
Interval = Interval.OneDay
});
// Get quotes for all tickers
var allQuotes = await tickers.GetQuotesAsync();
// Get fast info for all
var allFastInfo = await tickers.GetFastInfoAsync();
Console.WriteLine($"Managing {tickers.Symbols.Count} symbols");// Get major holders summary
var majorHolders = await tickerService.GetMajorHoldersAsync("AAPL");
Console.WriteLine($"Insiders: {majorHolders.InsidersPercentHeld:P2}");
Console.WriteLine($"Institutions: {majorHolders.InstitutionsPercentHeld:P2}");
// Get detailed insider roster
var insiderRoster = await tickerService.GetInsiderRosterHoldersAsync("AAPL");
foreach (var insider in insiderRoster)
{
Console.WriteLine($"{insider.Name} ({insider.Relation}): {insider.PositionDirect} shares");
}var quote = await tickerService.GetQuoteAsync("AAPL");
var holders = await tickerService.GetHoldersAsync("AAPL");
var options = await tickerService.GetOptionChainAsync(new OptionChainRequest { Symbol = "AAPL" });
var expirations = await tickerService.GetOptionsExpirationsAsync("AAPL");
var esg = await tickerService.GetEsgAsync("AAPL");
var calendar = await tickerService.GetCalendarAsync("AAPL");
var shares = await tickerService.GetSharesHistoryAsync(new SharesHistoryRequest { Symbol = "AAPL" });
var news = await tickerService.GetNewsAsync(new NewsRequest { Symbol = "AAPL", Count = 10 });YFinance.NET/
βββ YFinance.NET.Interfaces/ # Service contracts and abstractions
β βββ IYahooFinanceClient.cs
β βββ ITickerService.cs
β βββ Scrapers/
β βββ IHistoryScraper.cs
β βββ ...
βββ YFinance.NET.Models/ # Data models and DTOs
β βββ HistoricalData.cs
β βββ QuoteData.cs
β βββ Enums/
β β βββ Period.cs
β β βββ Interval.cs
β βββ Requests/
β β βββ HistoryRequest.cs
β βββ Exceptions/
β βββ YahooFinanceException.cs
βββ YFinance.NET.Implementation/ # Concrete implementations
β βββ YahooFinanceClient.cs
β βββ TickerService.cs
β βββ Scrapers/
β β βββ HistoryScraper.cs
β βββ DependencyInjection/
β βββ ServiceCollectionExtensions.cs
βββ YFinance.NET.Tests/ # Unit and integration tests
βββ Unit/
βββ Integration/
The library uses Microsoft.Extensions.DependencyInjection with the following service lifetimes:
- Singleton:
IYahooFinanceClient, scrapers, stateless services - Transient: Lightweight utilities (parsers, helpers)
- Scoped: Not used (all operations are stateless)
services.AddYFinance(); // Registers all required servicesThis extension method registers:
- HTTP client with proper factory pattern
- All scraper implementations
- Cache and cookie services
- Utility classes
dotnet test# Unit tests only (fast, no external dependencies)
dotnet test --filter "FullyQualifiedName~Unit"
# Integration tests only (requires internet)
dotnet test --filter "FullyQualifiedName~Integration"
# Specific test class
dotnet test --filter "FullyQualifiedName~HistoryScraperTests"dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover- Microsoft.Extensions.DependencyInjection - Dependency injection
- Microsoft.Extensions.Http - HTTP client factory
- Microsoft.Extensions.Caching.Memory - Response caching
- System.Text.Json - JSON serialization
- NodaTime - Timezone handling (for complex DST scenarios)
- HtmlAgilityPack - HTML parsing (for consent page handling)
- xUnit - Testing framework
- Moq - Mocking framework
- FluentAssertions - Assertion library
Main entry point for all ticker operations.
public interface ITickerService
{
Task<QuoteData> GetQuoteAsync(string symbol, CancellationToken cancellationToken = default);
Task<HistoricalData> GetHistoryAsync(string symbol, HistoryRequest request, CancellationToken cancellationToken = default);
Task<FinancialStatement> GetFinancialStatementsAsync(string symbol, CancellationToken cancellationToken = default);
Task<AnalystData> GetAnalystDataAsync(string symbol, CancellationToken cancellationToken = default);
Task<HolderData> GetHoldersAsync(string symbol, CancellationToken cancellationToken = default);
Task<FundsData> GetFundsDataAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NewsItem>> GetNewsAsync(NewsRequest request, CancellationToken cancellationToken = default);
Task<IReadOnlyList<PeriodicEstimate>> GetEarningsEstimateAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<PeriodicEstimate>> GetRevenueEstimateAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<EarningsHistoryEntry>> GetEarningsHistoryAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<PeriodicEstimate>> GetEpsTrendAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<PeriodicEstimate>> GetEpsRevisionsAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<GrowthEstimateEntry>> GetGrowthEstimatesAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<EarningsDateEntry>> GetEarningsDatesAsync(EarningsDatesRequest request, CancellationToken cancellationToken = default);
Task<OptionChain> GetOptionChainAsync(OptionChainRequest request, CancellationToken cancellationToken = default);
Task<IReadOnlyList<DateTime>> GetOptionsExpirationsAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<RecommendationTrendEntry>> GetRecommendationsAsync(string symbol, CancellationToken cancellationToken = default);
Task<IReadOnlyList<UpgradeDowngradeEntry>> GetUpgradesDowngradesAsync(string symbol, CancellationToken cancellationToken = default);
Task<EsgData> GetEsgAsync(string symbol, CancellationToken cancellationToken = default);
Task<CalendarData> GetCalendarAsync(string symbol, CancellationToken cancellationToken = default);
Task<SharesHistoryData> GetSharesHistoryAsync(SharesHistoryRequest request, CancellationToken cancellationToken = default);
}Request model for historical data.
public class HistoryRequest
{
public DateTime? Start { get; set; } // Start date (exclusive with Period)
public DateTime? End { get; set; } // End date (exclusive with Period)
public Period? Period { get; set; } // Pre-defined period (exclusive with Start/End)
public Interval Interval { get; set; } // Data interval (default: OneDay)
public bool AutoAdjust { get; set; } // Adjust for splits/dividends (default: true)
public bool Repair { get; set; } // Repair bad data (default: false)
}Pre-defined time periods:
OneDay,FiveDaysOneMonth,ThreeMonths,SixMonthsOneYear,TwoYears,FiveYears,TenYearsYearToDate,Max
Data granularity:
OneMinute,TwoMinutes,FiveMinutes,FifteenMinutes,ThirtyMinutesOneHour,NinetyMinutesOneDay,FiveDays,OneWeek,OneMonth,ThreeMonths
- Historical price data (OHLC, volume, dividends, splits, capital gains)
- Quote data (real-time prices)
- Info + fast info endpoints
- Financial statements (income, balance sheet, cash flow)
- Analyst data (recommendations, upgrades/downgrades, earnings estimates)
- Holder information (institutional, insider, fund holders)
- Major holders summary (ownership percentages)
- Insider roster holders (current insider positions)
- Options chain data and expirations
- ESG scores
- Calendar events (earnings, dividends, capital gains)
- Shares outstanding and float history
- Corporate actions (combined dividends and splits timeline)
- News endpoints
- Funds data (profile, holdings)
- Search, lookup, and screener endpoints
- Sector, industry, and market domain summaries
- ISIN lookup
- Live market streaming
- Dependency injection setup
- Async/await pattern
- Integration tests
- Basic error handling
- Cookie and authentication management
- Response caching
- Rate limiting
- Price repair algorithms
- Timezone DST edge-case handling
- Complete screener/query implementation
- NuGet package publication
The C# implementation now has excellent coverage of core Python yfinance features including batch operations, fast info, and multi-ticker management.
Contributions are welcome! Please ensure:
- All tests pass (
dotnet test) - Code follows existing patterns (DI, async/await)
- New features include unit tests
- Integration tests for API interactions
This library is not affiliated with, endorsed, or vetted by Yahoo, Inc. It is an open-source tool that uses Yahoo's publicly available APIs and is intended for research and educational purposes only.
Important:
- Respect Yahoo's Terms of Service
- Do not use for commercial purposes without proper authorization
- Be mindful of rate limits and server load
- Data provided is for informational purposes only
Apache Software License 2.0 (same as original yfinance Python library)
- Original Library: yfinance by Ran Aroussi
- C# Port: This project
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Disclaimer: This software is provided "as is", without warranty of any kind. Use at your own risk.