Skip to content

CalvinPangch/YFinance.NET

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

61 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

YFinance.NET - C# Port

CI .NET License

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.

Features

  • βœ… 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

Installation

Prerequisites

  • .NET SDK 10.0 or later
  • Internet connectivity for accessing Yahoo Finance API

From Source

  1. Clone the repository:
git clone https://github.com/CalvinPangch/yfinance.git
cd yfinance
  1. Build the solution:
dotnet build
  1. 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"

Add to Your Project

Option 1: Project Reference (if YFinance.NET is in your solution)

dotnet add reference path/to/YFinance.NET.Implementation/YFinance.NET.Implementation.csproj

Option 2: NuGet Package (once published)

dotnet add package YFinance.NET

Install from GitHub Packages

  1. Authenticate to GitHub Packages.
  2. Add the source: https://nuget.pkg.github.com/CalvinPangch/index.json
  3. Install: dotnet add package YFinance.NET --version <version>

Quick Start

Console Application

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}");
}

ASP.NET Core Integration

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);
    }
}

Usage Examples

Historical Data with Date Range

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]}");
}

Using Period Enums

// 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");
}

Different Time Intervals

// 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
});

Error Handling

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}");
}

Fast Info - Quick Access to Key Metrics

// 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}");

Corporate Actions - Combined Dividends and Splits

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}");
}

Batch Operations - Multiple Tickers in Parallel

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);

Tickers Class - Convenient Multi-Ticker Management

// 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");

Major Holders and Insider Roster

// 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");
}

Additional APIs

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 });

Project Structure

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/

Configuration

Dependency Injection

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)

Service Registration

services.AddYFinance(); // Registers all required services

This extension method registers:

  • HTTP client with proper factory pattern
  • All scraper implementations
  • Cache and cookie services
  • Utility classes

Testing

Run All Tests

dotnet test

Run Specific Test Categories

# 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"

Test Coverage

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

Dependencies

Core Dependencies

  • Microsoft.Extensions.DependencyInjection - Dependency injection
  • Microsoft.Extensions.Http - HTTP client factory
  • Microsoft.Extensions.Caching.Memory - Response caching
  • System.Text.Json - JSON serialization

Planned Dependencies

  • NodaTime - Timezone handling (for complex DST scenarios)
  • HtmlAgilityPack - HTML parsing (for consent page handling)

Test Dependencies

  • xUnit - Testing framework
  • Moq - Mocking framework
  • FluentAssertions - Assertion library

API Reference

ITickerService

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);
}

HistoryRequest

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)
}

Period Enum

Pre-defined time periods:

  • OneDay, FiveDays
  • OneMonth, ThreeMonths, SixMonths
  • OneYear, TwoYears, FiveYears, TenYears
  • YearToDate, Max

Interval Enum

Data granularity:

  • OneMinute, TwoMinutes, FiveMinutes, FifteenMinutes, ThirtyMinutes
  • OneHour, NinetyMinutes
  • OneDay, FiveDays, OneWeek, OneMonth, ThreeMonths

Roadmap

Implemented βœ…

  • 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

In Progress 🚧

  • Price repair algorithms
  • Timezone DST edge-case handling
  • Complete screener/query implementation

Planned πŸ“‹

  • NuGet package publication

Python yfinance Parity: ~85% βœ…

The C# implementation now has excellent coverage of core Python yfinance features including batch operations, fast info, and multi-ticker management.

Contributing

Contributions are welcome! Please ensure:

  1. All tests pass (dotnet test)
  2. Code follows existing patterns (DI, async/await)
  3. New features include unit tests
  4. Integration tests for API interactions

Legal Notice

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

License

Apache Software License 2.0 (same as original yfinance Python library)

Credits

  • Original Library: yfinance by Ran Aroussi
  • C# Port: This project

References

Support


Disclaimer: This software is provided "as is", without warranty of any kind. Use at your own risk.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages