namespace Backend.MarketDataRequest { public enum HistoricalBarSize { OneMin, FiveMins, FifteenMins, OneHour, OneDay, FiveDays, OneMonth } public enum HistoricalWhatToShow { Trades, Bid, Ask, Midpoint } public sealed class HistoricalLinePoint { public string Timestamp { get; init; } = string.Empty; public double Price { get; init; } } public sealed class HistoricalEquityRequest { public int RequestId { get; init; } public string Symbol { get; init; } = string.Empty; // Example: "" or "20260311 11:00:00 US/Eastern" public string EndDateTime { get; init; } = string.Empty; // Examples: "1 H", "1 D", "5 D", "1 M" public string Duration { get; init; } = "1 D"; public HistoricalBarSize BarSize { get; init; } = HistoricalBarSize.OneMin; public HistoricalWhatToShow WhatToShow { get; init; } = HistoricalWhatToShow.Trades; public bool UseRth { get; init; } = true; public bool KeepUpToDate { get; init; } = false; // IBKR formatDate=1 returns human-readable dates for intraday bars. public int FormatDate { get; init; } = 1; public void Validate() { if (RequestId <= 0) throw new ArgumentException("RequestId must be greater than 0."); if (string.IsNullOrWhiteSpace(Symbol)) throw new ArgumentException("Symbol is required."); if (string.IsNullOrWhiteSpace(Duration)) throw new ArgumentException("Duration is required."); if (string.IsNullOrWhiteSpace(EndDateTime)) throw new ArgumentException("EndDateTime is required for this example."); } } public static class HistoricalRequestMappings { public static string ToIbString(this HistoricalBarSize BarSize) => BarSize switch { HistoricalBarSize.OneMin => "1 min", HistoricalBarSize.FiveMins => "5 mins", HistoricalBarSize.FifteenMins => "15 mins", HistoricalBarSize.OneHour => "1 hour", HistoricalBarSize.OneDay => "1 day", HistoricalBarSize.FiveDays => "5 days", HistoricalBarSize.OneMonth => "1 month", _ => throw new ArgumentOutOfRangeException(nameof(BarSize)) }; public static string ToIbString(this HistoricalWhatToShow whatToShow) => whatToShow switch { HistoricalWhatToShow.Trades => "TRADES", HistoricalWhatToShow.Bid => "BID", HistoricalWhatToShow.Ask => "ASK", HistoricalWhatToShow.Midpoint => "MIDPOINT", _ => throw new ArgumentOutOfRangeException(nameof(whatToShow)) }; } }