feat(core): update DTOs, Trade Republic client, Yahoo scrapers, and dynamic settings

This commit is contained in:
2026-08-14 23:55:02 +02:00
parent 3d8af3940b
commit 4f733bf8c3
511 changed files with 1990 additions and 1080548 deletions
@@ -5,277 +5,38 @@ using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// Data transfer object representing the complete fundamental analysis dataset of an asset.
/// Haupt-DTO für die aggregierte Anzeige der Stammdaten, Fundamentaldaten und Events eines Assets.
/// </summary>
[Serializable]
public record AssetFundamentalsDto
{
[JsonPropertyName("isin")]
public string Isin { get; init; } = string.Empty;
[JsonPropertyName("primaryTicker")]
public string PrimaryTicker { get; init; } = string.Empty;
[JsonPropertyName("ticker")]
public string Ticker { get; init; } = string.Empty;
[JsonPropertyName("companyName")]
public string CompanyName { get; init; } = string.Empty;
[JsonPropertyName("exchange")]
public string? Exchange { get; init; }
[JsonPropertyName("tradingCurrency")]
public string? TradingCurrency { get; init; }
[JsonPropertyName("businessSummary")]
public string? BusinessSummary { get; init; }
[JsonPropertyName("sector")]
public string? Sector { get; init; }
[JsonPropertyName("industry")]
public string? Industry { get; init; }
[JsonPropertyName("country")]
public string? Country { get; init; }
[JsonPropertyName("employees")]
public int? Employees { get; init; }
/// <summary>
/// Grundlegende Unternehmens- und Stammdaten (Aus AssetDataEntity).
/// </summary>
[JsonPropertyName("asset")]
public AssetHeaderDto Asset { get; init; } = new();
// Valuation Metrics (derived from Primary Ticker)
[JsonPropertyName("currentPrice")]
public decimal CurrentPrice { get; init; }
[JsonPropertyName("dayChangeAbsolute")]
public decimal DayChangeAbsolute { get; init; }
[JsonPropertyName("dayChangePercent")]
public decimal DayChangePercent { get; init; }
[JsonPropertyName("fiftyTwoWeekHigh")]
public decimal FiftyTwoWeekHigh { get; init; }
[JsonPropertyName("fiftyTwoWeekLow")]
public decimal FiftyTwoWeekLow { get; init; }
[JsonPropertyName("marketCapitalization")]
public decimal MarketCapitalization { get; init; }
[JsonPropertyName("enterpriseValue")]
public decimal EnterpriseValue { get; init; }
[JsonPropertyName("peRatioTrailing")]
public decimal? PeRatioTrailing { get; init; }
[JsonPropertyName("peRatioForward")]
public decimal? PeRatioForward { get; init; }
[JsonPropertyName("pegRatio")]
public decimal? PegRatio { get; init; }
[JsonPropertyName("pbRatio")]
public decimal? PbRatio { get; init; }
[JsonPropertyName("psRatio")]
public decimal? PsRatio { get; init; }
[JsonPropertyName("evToEbitda")]
public decimal? EvToEbitda { get; init; }
[JsonPropertyName("evToRevenue")]
public decimal? EvToRevenue { get; init; }
/// <summary>
/// Aktuellste Finanzeckdaten und Kennzahlen (Aus FundamentalDataEntity).
/// </summary>
[JsonPropertyName("fundamentals")]
public FundamentalDataDto? Fundamentals { get; init; }
// Financial Health & Leverage
[JsonPropertyName("grossMargin")]
public decimal? GrossMargin { get; init; }
[JsonPropertyName("operatingMargin")]
public decimal? OperatingMargin { get; init; }
[JsonPropertyName("netProfitMargin")]
public decimal? NetProfitMargin { get; init; }
[JsonPropertyName("returnOnEquity")]
public decimal? ReturnOnEquity { get; init; }
[JsonPropertyName("returnOnAssets")]
public decimal? ReturnOnAssets { get; init; }
[JsonPropertyName("returnOnInvestedCapital")]
public decimal? ReturnOnInvestedCapital { get; init; }
[JsonPropertyName("debtToEquity")]
public decimal? DebtToEquity { get; init; }
[JsonPropertyName("currentRatio")]
public decimal? CurrentRatio { get; init; }
[JsonPropertyName("quickRatio")]
public decimal? QuickRatio { get; init; }
[JsonPropertyName("interestCoverage")]
public decimal? InterestCoverage { get; init; }
// Dividends & Ownership
[JsonPropertyName("dividendYield")]
public decimal? DividendYield { get; init; }
[JsonPropertyName("payoutRatio")]
public decimal? PayoutRatio { get; init; }
[JsonPropertyName("exDividendDate")]
public DateTime? ExDividendDate { get; init; }
[JsonPropertyName("nextEarningsDate")]
public DateTime? NextEarningsDate { get; init; }
[JsonPropertyName("percentHeldByInstitutions")]
public decimal? PercentHeldByInstitutions { get; init; }
[JsonPropertyName("percentHeldByInsiders")]
public decimal? PercentHeldByInsiders { get; init; }
[JsonPropertyName("shortRatio")]
public decimal? ShortRatio { get; init; }
[JsonPropertyName("shortPercentOfFloat")]
public decimal? ShortPercentOfFloat { get; init; }
// Forecasts
[JsonPropertyName("consensusRating")]
public string? ConsensusRating { get; init; }
[JsonPropertyName("priceTargetLow")]
public decimal? PriceTargetLow { get; init; }
[JsonPropertyName("priceTargetHigh")]
public decimal? PriceTargetHigh { get; init; }
[JsonPropertyName("priceTargetMedian")]
public decimal? PriceTargetMedian { get; init; }
[JsonPropertyName("priceTargetMean")]
public decimal? PriceTargetMean { get; init; }
// Timestamps
[JsonPropertyName("lastUpdatedAt")]
public DateTime LastUpdatedAt { get; init; }
// Relational Collections
/// <summary>
/// Liste der Führungskräfte/Vorstände (Aus KeyExecutiveEntity).
/// </summary>
[JsonPropertyName("executives")]
public List<CompanyExecutiveDto> Executives { get; init; } = [];
[JsonPropertyName("financialStatements")]
public List<FinancialStatementDto> FinancialStatements { get; init; } = [];
[JsonPropertyName("estimates")]
public List<ForwardEstimateDto> Estimates { get; init; } = [];
[JsonPropertyName("availableTickers")]
public List<TickerDto> AvailableTickers { get; init; } = [];
}
public List<KeyExecutiveDto> Executives { get; init; } = [];
public record CompanyExecutiveDto
{
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("title")]
public string Title { get; init; } = string.Empty;
[JsonPropertyName("age")]
public int? Age { get; init; }
[JsonPropertyName("compensation")]
public decimal? Compensation { get; init; }
}
/// <summary>
/// Bevorstehende oder vergangene Termine wie Earnings oder Dividenden (Aus AssetEventEntity).
/// </summary>
[JsonPropertyName("events")]
public List<CorporateEventDto> Events { get; init; } = [];
public record FinancialStatementDto
{
[JsonPropertyName("periodType")]
public string PeriodType { get; init; } = string.Empty; // "Annual" or "Quarterly"
[JsonPropertyName("endDate")]
public DateTime EndDate { get; init; }
// Income Statement
[JsonPropertyName("totalRevenue")]
public decimal? TotalRevenue { get; init; }
[JsonPropertyName("costOfRevenue")]
public decimal? CostOfRevenue { get; init; }
[JsonPropertyName("grossProfit")]
public decimal? GrossProfit { get; init; }
[JsonPropertyName("operatingExpenses")]
public decimal? OperatingExpenses { get; init; }
[JsonPropertyName("operatingIncome")]
public decimal? OperatingIncome { get; init; }
[JsonPropertyName("ebitda")]
public decimal? Ebitda { get; init; }
[JsonPropertyName("netIncome")]
public decimal? NetIncome { get; init; }
[JsonPropertyName("epsBasic")]
public decimal? EpsBasic { get; init; }
[JsonPropertyName("epsDiluted")]
public decimal? EpsDiluted { get; init; }
// Balance Sheet
[JsonPropertyName("cashAndCashEquivalents")]
public decimal? CashAndCashEquivalents { get; init; }
[JsonPropertyName("accountsReceivable")]
public decimal? AccountsReceivable { get; init; }
[JsonPropertyName("inventory")]
public decimal? Inventory { get; init; }
[JsonPropertyName("totalCurrentAssets")]
public decimal? TotalCurrentAssets { get; init; }
[JsonPropertyName("totalNonCurrentAssets")]
public decimal? TotalNonCurrentAssets { get; init; }
[JsonPropertyName("currentLiabilities")]
public decimal? CurrentLiabilities { get; init; }
[JsonPropertyName("longTermDebt")]
public decimal? LongTermDebt { get; init; }
[JsonPropertyName("totalLiabilities")]
public decimal? TotalLiabilities { get; init; }
[JsonPropertyName("totalStockholdersEquity")]
public decimal? TotalStockholdersEquity { get; init; }
// Cash Flow Statement
[JsonPropertyName("operatingCashFlow")]
public decimal? OperatingCashFlow { get; init; }
[JsonPropertyName("investingCashFlow")]
public decimal? InvestingCashFlow { get; init; }
[JsonPropertyName("capitalExpenditures")]
public decimal? CapitalExpenditures { get; init; }
[JsonPropertyName("financingCashFlow")]
public decimal? FinancingCashFlow { get; init; }
[JsonPropertyName("freeCashFlow")]
public decimal? FreeCashFlow { get; init; } // OperatingCashFlow - CapEx
}
public record ForwardEstimateDto
{
[JsonPropertyName("period")]
public string Period { get; init; } = string.Empty; // "CurrentQuarter", "NextQuarter", "CurrentYear", "NextYear"
[JsonPropertyName("expectedRevenue")]
public decimal? ExpectedRevenue { get; init; }
[JsonPropertyName("expectedEps")]
public decimal? ExpectedEps { get; init; }
[JsonPropertyName("expectedGrowthRate")]
public decimal? ExpectedGrowthRate { get; init; }
}
public record TickerDto
{
[JsonPropertyName("ticker")]
public string Ticker { get; init; } = string.Empty;
[JsonPropertyName("exchange")]
public string? Exchange { get; init; }
[JsonPropertyName("tradingCurrency")]
public string? TradingCurrency { get; init; }
[JsonPropertyName("currentPrice")]
public decimal CurrentPrice { get; init; }
[JsonPropertyName("dayChangeAbsolute")]
public decimal DayChangeAbsolute { get; init; }
[JsonPropertyName("dayChangePercent")]
public decimal DayChangePercent { get; init; }
[JsonPropertyName("fiftyTwoWeekHigh")]
public decimal FiftyTwoWeekHigh { get; init; }
[JsonPropertyName("fiftyTwoWeekLow")]
public decimal FiftyTwoWeekLow { get; init; }
[JsonPropertyName("marketCapitalization")]
public decimal MarketCapitalization { get; init; }
[JsonPropertyName("enterpriseValue")]
public decimal EnterpriseValue { get; init; }
[JsonPropertyName("peRatioTrailing")]
public decimal? PeRatioTrailing { get; init; }
[JsonPropertyName("peRatioForward")]
public decimal? PeRatioForward { get; init; }
[JsonPropertyName("pegRatio")]
public decimal? PegRatio { get; init; }
[JsonPropertyName("pbRatio")]
public decimal? PbRatio { get; init; }
[JsonPropertyName("psRatio")]
public decimal? PsRatio { get; init; }
[JsonPropertyName("evToEbitda")]
public decimal? EvToEbitda { get; init; }
[JsonPropertyName("evToRevenue")]
public decimal? EvToRevenue { get; init; }
[JsonPropertyName("grossMargin")]
public decimal? GrossMargin { get; init; }
[JsonPropertyName("operatingMargin")]
public decimal? OperatingMargin { get; init; }
[JsonPropertyName("netProfitMargin")]
public decimal? NetProfitMargin { get; init; }
[JsonPropertyName("returnOnEquity")]
public decimal? ReturnOnEquity { get; init; }
[JsonPropertyName("returnOnAssets")]
public decimal? ReturnOnAssets { get; init; }
[JsonPropertyName("returnOnInvestedCapital")]
public decimal? ReturnOnInvestedCapital { get; init; }
[JsonPropertyName("debtToEquity")]
public decimal? DebtToEquity { get; init; }
[JsonPropertyName("currentRatio")]
public decimal? CurrentRatio { get; init; }
[JsonPropertyName("quickRatio")]
public decimal? QuickRatio { get; init; }
[JsonPropertyName("interestCoverage")]
public decimal? InterestCoverage { get; init; }
[JsonPropertyName("dividendYield")]
public decimal? DividendYield { get; init; }
[JsonPropertyName("payoutRatio")]
public decimal? PayoutRatio { get; init; }
[JsonPropertyName("exDividendDate")]
public DateTime? ExDividendDate { get; init; }
}
/// <summary>
/// Zeitstempel der letzten Gesamt-Aktualisierung.
/// </summary>
[JsonPropertyName("lastUpdatedAt")]
public DateTime LastUpdatedAt { get; init; } = DateTime.UtcNow;
}
@@ -0,0 +1,25 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// Enthält die Stammdaten eines Unternehmens/Assets.
/// </summary>
[Serializable]
public record AssetHeaderDto
{
[JsonPropertyName("isin")]
public string Isin { get; init; } = string.Empty;
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("description")]
public string Description { get; init; } = string.Empty;
[JsonPropertyName("primaryTicker")]
public TickerInfoDto PrimaryTicker { get; init; }
[JsonPropertyName("availableTickers")]
public List<TickerInfoDto> AvailableTickers { get; init; } = [];
}
@@ -4,22 +4,29 @@ using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// DTO representing a scheduled corporate event (e.g. Earnings, Ex-Dividend, Dividend Payout).
/// Repräsentiert ein Unternehmensereignis (z. B. Quartalszahlen, Dividendentag).
/// </summary>
[Serializable]
public record CorporateEventDto
{
[JsonPropertyName("id")]
public Guid Id { get; init; }
[JsonPropertyName("isin")]
public string Isin { get; init; } = string.Empty;
public string? Isin { get; init; }
[JsonPropertyName("ticker")]
public string Ticker { get; init; } = string.Empty;
public TickerInfoDto Ticker { get; init; }
[JsonPropertyName("companyName")]
public string CompanyName { get; init; } = string.Empty;
[JsonPropertyName("eventType")]
public string EventType { get; init; } = string.Empty; // "Quartalsergebnis", "Ex-Dividendentag", "Dividenden-Zahltag"
public string? CompanyName { get; init; }
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty; // z.B. "Earnings", "Ex-Dividend"
[JsonIgnore]
public string EventType => Type;
[JsonPropertyName("date")]
public DateTime Date { get; init; }
}
}
@@ -0,0 +1,128 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// Repräsentiert die finanziellen Kennzahlen und Valuation-Multiples eines Assets.
/// </summary>
[Serializable]
public record FundamentalDataDto
{
[JsonPropertyName("ticker")]
public TickerInfoDto Ticker { get; init; }
// --- Valuation & Multiples ---
[JsonPropertyName("marketCap")]
public decimal? MarketCap { get; init; }
[JsonPropertyName("enterpriseValue")]
public decimal? EnterpriseValue { get; init; }
[JsonPropertyName("trailingPe")]
public decimal? TrailingPe { get; init; }
[JsonPropertyName("forwardPe")]
public decimal? ForwardPe { get; init; }
[JsonPropertyName("pegRatio")]
public decimal? PegRatio { get; init; }
[JsonPropertyName("priceToSales")]
public decimal? PriceToSales { get; init; }
[JsonPropertyName("priceToBook")]
public decimal? PriceToBook { get; init; }
[JsonPropertyName("evToEbitda")]
public decimal? EvToEbitda { get; init; }
// --- Income Statement (TTM) ---
[JsonPropertyName("totalRevenue")]
public decimal? TotalRevenue { get; init; }
[JsonPropertyName("revenueGrowthYoY")]
public decimal? RevenueGrowthYoY { get; init; }
[JsonPropertyName("grossProfit")]
public decimal? GrossProfit { get; init; }
[JsonPropertyName("operatingIncome")]
public decimal? OperatingIncome { get; init; }
[JsonPropertyName("ebitda")]
public decimal? Ebitda { get; init; }
[JsonPropertyName("netIncome")]
public decimal? NetIncome { get; init; }
[JsonPropertyName("dilutedEps")]
public decimal? DilutedEps { get; init; }
// --- Balance Sheet & Cash Flow ---
[JsonPropertyName("totalCash")]
public decimal? TotalCash { get; init; }
[JsonPropertyName("totalDebt")]
public decimal? TotalDebt { get; init; }
[JsonPropertyName("debtToEquity")]
public decimal? DebtToEquity { get; init; }
[JsonPropertyName("currentRatio")]
public decimal? CurrentRatio { get; init; }
[JsonPropertyName("operatingCashFlow")]
public decimal? OperatingCashFlow { get; init; }
[JsonPropertyName("freeCashFlow")]
public decimal? FreeCashFlow { get; init; }
// --- Dividenden & Profitabilität ---
[JsonPropertyName("returnOnEquity")]
public decimal? ReturnOnEquity { get; init; }
[JsonPropertyName("returnOnAssets")]
public decimal? ReturnOnAssets { get; init; }
[JsonPropertyName("forwardDividendYield")]
public decimal? ForwardDividendYield { get; init; }
[JsonPropertyName("payoutRatio")]
public decimal? PayoutRatio { get; init; }
// --- 52-Wochen-Spannbreite ---
[JsonPropertyName("fiftyTwoWeekHigh")]
public decimal? FiftyTwoWeekHigh { get; init; }
[JsonPropertyName("fiftyTwoWeekLow")]
public decimal? FiftyTwoWeekLow { get; init; }
// --- Analysten-Ratings & Kursziele ---
[JsonPropertyName("consensusRating")]
public string? ConsensusRating { get; init; }
[JsonPropertyName("priceTargetLow")]
public decimal? PriceTargetLow { get; init; }
[JsonPropertyName("priceTargetMean")]
public decimal? PriceTargetMean { get; init; }
[JsonPropertyName("priceTargetHigh")]
public decimal? PriceTargetHigh { get; init; }
// --- Aktionärsstruktur & Short-Interesse ---
[JsonPropertyName("percentHeldByInstitutions")]
public decimal? PercentHeldByInstitutions { get; init; }
[JsonPropertyName("percentHeldByInsiders")]
public decimal? PercentHeldByInsiders { get; init; }
[JsonPropertyName("shortPercentOfFloat")]
public decimal? ShortPercentOfFloat { get; init; }
[JsonPropertyName("shortRatio")]
public decimal? ShortRatio { get; init; }
[JsonPropertyName("lastUpdatedUtc")]
public DateTime LastUpdatedUtc { get; init; }
}
@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// Repräsentiert eine Führungskraft/Vorstandsmitglied eines Unternehmens.
/// </summary>
[Serializable]
public record KeyExecutiveDto
{
[JsonPropertyName("id")]
public Guid Id { get; init; }
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("title")]
public string Title { get; init; } = string.Empty;
[JsonPropertyName("payment")]
public string Payment { get; init; } = string.Empty;
}
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.Fundamentals;
/// <summary>
/// Enthält einen Ticker mit zugehörigem Börsenplatz.
/// </summary>
[Serializable]
public record TickerInfoDto
{
[JsonPropertyName("ticker")]
public string Ticker { get; init; } = string.Empty;
[JsonPropertyName("exchange")]
public string? Exchange { get; init; }
}
@@ -0,0 +1,133 @@
namespace FinlyticCore.Dtos.TradeRepublic;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
// 1. Der Response-Wrapper
public record TradeRepublicAssetResponse(
[property: JsonPropertyName("correlationId")] string CorrelationId,
[property: JsonPropertyName("resultCount")] int ResultCount,
[property: JsonPropertyName("results")] IList<TradeRepublicAsset> Results
);
// 2. Das Tag-Objekt
public record TradeRepublicTag
{
[JsonPropertyName("id")] public string Id { get; init; } = "";
[JsonPropertyName("name")] public string Name { get; init; } = "";
[JsonPropertyName("type")] public string Type { get; init; } = "";
}
// 3. Die Basisklasse MIT UNSEREM CUSTOM CONVERTER
[JsonConverter(typeof(TradeRepublicAssetConverter))]
public record TradeRepublicAsset
{
[JsonPropertyName("isin")] public string Isin { get; init; } = "";
[JsonPropertyName("name")] public string Name { get; init; } = "";
[JsonPropertyName("type")] public string Type { get; init; } = "";
[JsonPropertyName("instrumentCategory")] public string InstrumentCategory { get; init; } = "";
[JsonPropertyName("hasCfd")] public bool HasCfd { get; init; }
[JsonPropertyName("imageId")] public string? ImageId { get; init; }
[JsonPropertyName("tags")]
public IReadOnlyList<TradeRepublicTag> Tags { get; init; } = Array.Empty<TradeRepublicTag>();
}
// 4. Die spezifischen Klassen
public record TradeRepublicStock : TradeRepublicAsset
{
[JsonPropertyName("derivativeProductCategories")]
public IReadOnlyList<string> DerivativeProductCategories { get; init; } = Array.Empty<string>();
}
public record TradeRepublicCrypto : TradeRepublicAsset
{
[JsonPropertyName("subtitle")] public string Subtitle { get; init; } = "";
[JsonPropertyName("searchSubtitle")] public string SearchSubtitle { get; init; } = "";
}
public record TradeRepublicEtf : TradeRepublicAsset
{
[JsonPropertyName("derivativeProductCategories")]
public IReadOnlyList<string> DerivativeProductCategories { get; init; } = Array.Empty<string>();
[JsonPropertyName("etfDescription")] public string EtfDescription { get; init; } = "";
[JsonPropertyName("mappedEtfIndexName")] public string MappedEtfIndexName { get; init; } = "";
[JsonPropertyName("subtitle")] public string Subtitle { get; init; } = "";
[JsonPropertyName("searchSubtitle")] public string SearchSubtitle { get; init; } = "";
}
public record TradeRepublicSynthetic : TradeRepublicAsset
{
[JsonPropertyName("derivativeProductCategories")]
public IReadOnlyList<string> DerivativeProductCategories { get; init; } = Array.Empty<string>();
}
// Anleihen
public record TradeRepublicBond : TradeRepublicAsset
{
[JsonPropertyName("bondIssuerName")] public string BondIssuerName { get; init; } = "";
[JsonPropertyName("searchSubtitle")] public string SearchSubtitle { get; init; } = "";
}
// Derivate (Hebeleffekte etc.)
public record TradeRepublicDerivative : TradeRepublicAsset
{
[JsonPropertyName("derivativeProductCategories")]
public IReadOnlyList<string> DerivativeProductCategories { get; init; } = Array.Empty<string>();
[JsonIgnore]
public string? UnderlyingIsin
{
get
{
if (!string.IsNullOrEmpty(ImageId) && ImageId.StartsWith("logos/"))
{
var parts = ImageId.Split('/');
if (parts.Length >= 2)
{
return parts[1];
}
}
return null;
}
}
}
// 5. Custom Converter
public class TradeRepublicAssetConverter : JsonConverter<TradeRepublicAsset>
{
public override TradeRepublicAsset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var doc = JsonDocument.ParseValue(ref reader);
var root = doc.RootElement;
string? instrumentType = null;
if (root.TryGetProperty("instrumentType", out var typeElement))
{
instrumentType = typeElement.GetString();
}
TradeRepublicAsset? result = instrumentType switch
{
"stock" => JsonSerializer.Deserialize<TradeRepublicStock>(root.GetRawText(), options),
"crypto" => JsonSerializer.Deserialize<TradeRepublicCrypto>(root.GetRawText(), options),
"fund" => JsonSerializer.Deserialize<TradeRepublicEtf>(root.GetRawText(), options),
"synthetic" => JsonSerializer.Deserialize<TradeRepublicSynthetic>(root.GetRawText(), options),
"bond" => JsonSerializer.Deserialize<TradeRepublicBond>(root.GetRawText(), options),
"derivative" => JsonSerializer.Deserialize<TradeRepublicDerivative>(root.GetRawText(), options),
_ => JsonSerializer.Deserialize<TradeRepublicAssetFallback>(root.GetRawText(), options)
};
return result ?? new TradeRepublicAssetFallback();
}
public override void Write(Utf8JsonWriter writer, TradeRepublicAsset value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
file record TradeRepublicAssetFallback : TradeRepublicAsset;
@@ -0,0 +1,20 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
/// <summary>
/// DTO für den Verbindungsaufbau / Connect-Request an die Trade Republic WebSocket / API.
/// </summary>
public record TradeRepublicConnectRequest(
[property: JsonPropertyName("locale")] string Locale = "de",
[property: JsonPropertyName("platformId")] string PlatformId = "webtrading",
[property: JsonPropertyName("platformVersion")] string PlatformVersion = "chrome - 151.0.0",
[property: JsonPropertyName("clientId")] string ClientId = "app.traderepublic.com",
[property: JsonPropertyName("clientVersion")] string ClientVersion = "1.2632.6",
TradeRepublicHeaders? Headers = null
)
{
[JsonPropertyName("__headers")]
public TradeRepublicHeaders Headers { get; init; } = Headers ?? new TradeRepublicHeaders();
}
@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicDerivativesRequest(
[property: JsonPropertyName("type")] string Type = "derivatives",
[property: JsonPropertyName("jurisdiction")] string Jurisdiction = "DE",
[property: JsonPropertyName("lang")] string Lang = "en",
[property: JsonPropertyName("underlying")] string Underlying = "",
[property: JsonPropertyName("productCategory")] string ProductCategory = "knockOutProduct",
[property: JsonPropertyName("leverage")] decimal Leverage = 0,
[property: JsonPropertyName("sortBy")] string SortBy = "leverage",
[property: JsonPropertyName("sortDirection")] string SortDirection = "asc",
[property: JsonPropertyName("optionType")] string OptionType = "long",
[property: JsonPropertyName("pageSize")] int PageSize = 50,
[property: JsonPropertyName("after")] string After = "0",
TradeRepublicHeaders? Headers = null
)
{
[JsonPropertyName("__headers")]
public TradeRepublicHeaders Headers { get; init; } = Headers ?? new TradeRepublicHeaders();
}
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicDerivativeItemDto(
[property: JsonPropertyName("isin")] string Isin = "",
[property: JsonPropertyName("optionType")] string OptionType = "",
[property: JsonPropertyName("productCategoryName")] string ProductCategoryName = "",
[property: JsonPropertyName("nextGenProductCategoryName")] string NextGenProductCategoryName = "",
[property: JsonPropertyName("barrier")] decimal? Barrier = null,
[property: JsonPropertyName("leverage")] decimal? Leverage = null,
[property: JsonPropertyName("strike")] decimal? Strike = null,
[property: JsonPropertyName("size")] decimal? Size = null,
[property: JsonPropertyName("factor")] decimal? Factor = null,
[property: JsonPropertyName("delta")] decimal? Delta = null,
[property: JsonPropertyName("currency")] string Currency = "EUR",
[property: JsonPropertyName("expiry")] string? Expiry = null,
[property: JsonPropertyName("issuerDisplayName")] string IssuerDisplayName = "",
[property: JsonPropertyName("issuer")] string Issuer = "",
[property: JsonPropertyName("issuerImageId")] string IssuerImageId = "",
[property: JsonPropertyName("imageId")] string ImageId = ""
);
public record TradeRepublicCursorsDto(
[property: JsonPropertyName("before")] string? Before = null,
[property: JsonPropertyName("after")] string? After = null
);
public record TradeRepublicDerivativesResponse(
[property: JsonPropertyName("results")] List<TradeRepublicDerivativeItemDto> Results,
[property: JsonPropertyName("resultCount")] int ResultCount = 0,
[property: JsonPropertyName("issuerCount")] Dictionary<string, int>? IssuerCount = null,
[property: JsonPropertyName("cursors")] TradeRepublicCursorsDto? Cursors = null
);
@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
using FinlyticCore.Util;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicHeaders(
[property: JsonPropertyName("traceparent")] string Traceparent
)
{
public TradeRepublicHeaders() : this(StringCodeGenerator.GenerateTraceparent())
{}
}
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicFilter(
[property: JsonPropertyName("key")] string Key,
[property: JsonPropertyName("value")] string Value
);
public record TradeRepublicSearchData(
[property: JsonPropertyName("q")] string Query = "",
[property: JsonPropertyName("page")] int Page = 1,
[property: JsonPropertyName("pageSize")] int PageSize = 50,
IReadOnlyList<TradeRepublicFilter>? Filter = null
)
{
[JsonPropertyName("filter")]
public IReadOnlyList<TradeRepublicFilter> Filter { get; init; } = Filter ?? Array.Empty<TradeRepublicFilter>();
}
public record TradeRepublicSearchRequest(
[property: JsonPropertyName("data")] TradeRepublicSearchData Data,
[property: JsonPropertyName("type")] string Type = "neonSearch",
TradeRepublicHeaders? Headers = null
)
{
[JsonPropertyName("__headers")]
public TradeRepublicHeaders Headers { get; init; } = Headers ?? new TradeRepublicHeaders();
}
@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicStockDetailsRequest(
[property: JsonPropertyName("id")] string Id,
[property: JsonPropertyName("type")] string Type = "stockDetails",
[property: JsonPropertyName("jurisdiction")] string Jurisdiction = "DE",
TradeRepublicHeaders? Headers = null
)
{
[JsonPropertyName("__headers")]
public TradeRepublicHeaders Headers { get; init; } = Headers ?? new TradeRepublicHeaders();
}
@@ -0,0 +1,109 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicCompanyDto(
[property: JsonPropertyName("name")] string Name = "",
[property: JsonPropertyName("description")] string? Description = null,
[property: JsonPropertyName("yearFounded")] int? YearFounded = null,
[property: JsonPropertyName("tickerSymbol")] string? TickerSymbol = null,
[property: JsonPropertyName("peRatioSnapshot")] decimal? PeRatioSnapshot = null,
[property: JsonPropertyName("pbRatioSnapshot")] decimal? PbRatioSnapshot = null,
[property: JsonPropertyName("dividendYieldSnapshot")] decimal? DividendYieldSnapshot = null,
[property: JsonPropertyName("earningsCall")] string? EarningsCall = null,
[property: JsonPropertyName("marketCapSnapshot")] decimal? MarketCapSnapshot = null,
[property: JsonPropertyName("marketCapCurrency")] string? MarketCapCurrency = null,
[property: JsonPropertyName("dailyCloseYearSD")] decimal? DailyCloseYearSd = null,
[property: JsonPropertyName("beta")] decimal? Beta = null,
[property: JsonPropertyName("countryCode")] string? CountryCode = null,
[property: JsonPropertyName("ceoName")] string? CeoName = null,
[property: JsonPropertyName("cfoName")] string? CfoName = null,
[property: JsonPropertyName("cooName")] string? CooName = null,
[property: JsonPropertyName("employeeCount")] long? EmployeeCount = null,
[property: JsonPropertyName("eps")] decimal? Eps = null,
[property: JsonPropertyName("epsCurrency")] string? EpsCurrency = null
);
public record TradeRepublicSimilarStockTagDto(
[property: JsonPropertyName("type")] string Type = "",
[property: JsonPropertyName("id")] string Id = "",
[property: JsonPropertyName("name")] string Name = "",
[property: JsonPropertyName("icon")] string? Icon = null
);
public record TradeRepublicSimilarStockDto(
[property: JsonPropertyName("isin")] string Isin = "",
[property: JsonPropertyName("name")] string Name = "",
[property: JsonPropertyName("tags")] List<TradeRepublicSimilarStockTagDto>? Tags = null
);
public record TradeRepublicDividendDto(
[property: JsonPropertyName("id")] string Id = "",
[property: JsonPropertyName("paymentDate")] string? PaymentDate = null,
[property: JsonPropertyName("recordDate")] string? RecordDate = null,
[property: JsonPropertyName("exDate")] string? ExDate = null,
[property: JsonPropertyName("amount")] decimal? Amount = null,
[property: JsonPropertyName("amountCurrency")] string? AmountCurrency = null,
[property: JsonPropertyName("yield")] decimal? Yield = null,
[property: JsonPropertyName("type")] string? Type = null
);
public record TradeRepublicEventDto(
[property: JsonPropertyName("id")] string Id = "",
[property: JsonPropertyName("title")] string? Title = null,
[property: JsonPropertyName("timestamp")] long? Timestamp = null,
[property: JsonPropertyName("description")] string? Description = null,
[property: JsonPropertyName("webcastUrl")] string? WebcastUrl = null,
[property: JsonPropertyName("dividend")] TradeRepublicDividendDto? Dividend = null,
[property: JsonPropertyName("type")] string? Type = null
);
public record TradeRepublicTargetPriceDto(
[property: JsonPropertyName("averageCurrency")] string? AverageCurrency = null,
[property: JsonPropertyName("average")] decimal? Average = null,
[property: JsonPropertyName("highCurrency")] string? HighCurrency = null,
[property: JsonPropertyName("high")] decimal? High = null,
[property: JsonPropertyName("lowCurrency")] string? LowCurrency = null,
[property: JsonPropertyName("low")] decimal? Low = null
);
public record TradeRepublicRecommendationsDto(
[property: JsonPropertyName("buy")] int? Buy = null,
[property: JsonPropertyName("outperform")] int? Outperform = null,
[property: JsonPropertyName("hold")] int? Hold = null,
[property: JsonPropertyName("underperform")] int? Underperform = null,
[property: JsonPropertyName("sell")] int? Sell = null
);
public record TradeRepublicAnalystRatingDto(
[property: JsonPropertyName("targetPrice")] TradeRepublicTargetPriceDto? TargetPrice = null,
[property: JsonPropertyName("recommendations")] TradeRepublicRecommendationsDto? Recommendations = null
);
public record TradeRepublicAggregatedDividendDto(
[property: JsonPropertyName("periodStartDate")] string? PeriodStartDate = null,
[property: JsonPropertyName("projected")] bool? Projected = null,
[property: JsonPropertyName("yieldValue")] decimal? YieldValue = null,
[property: JsonPropertyName("amount")] decimal? Amount = null,
[property: JsonPropertyName("amountCurrency")] string? AmountCurrency = null,
[property: JsonPropertyName("count")] int? Count = null,
[property: JsonPropertyName("projectedCount")] int? ProjectedCount = null,
[property: JsonPropertyName("price")] decimal? Price = null,
[property: JsonPropertyName("priceCurrency")] string? PriceCurrency = null
);
public record TradeRepublicStockDetailsResponse(
[property: JsonPropertyName("isin")] string Isin = "",
[property: JsonPropertyName("company")] TradeRepublicCompanyDto? Company = null,
[property: JsonPropertyName("similarStocks")] List<TradeRepublicSimilarStockDto>? SimilarStocks = null,
[property: JsonPropertyName("expectedDividend")] TradeRepublicDividendDto? ExpectedDividend = null,
[property: JsonPropertyName("dividends")] List<TradeRepublicDividendDto>? Dividends = null,
[property: JsonPropertyName("totalDivendendCount")] int? TotalDivendendCount = null,
[property: JsonPropertyName("events")] List<TradeRepublicEventDto>? Events = null,
[property: JsonPropertyName("pastEvents")] List<TradeRepublicEventDto>? PastEvents = null,
[property: JsonPropertyName("analystRating")] TradeRepublicAnalystRatingDto? AnalystRating = null,
[property: JsonPropertyName("hasKpis")] bool? HasKpis = null,
[property: JsonPropertyName("aggregatedDividends")] List<TradeRepublicAggregatedDividendDto>? AggregatedDividends = null,
[property: JsonPropertyName("dividendFrequency")] string? DividendFrequency = null
);
@@ -0,0 +1,13 @@
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicTickerRequest(
[property: JsonPropertyName("id")] string Id, // e.g. "US5398301094.TIB"
[property: JsonPropertyName("type")] string Type = "ticker",
TradeRepublicHeaders? Headers = null
)
{
[JsonPropertyName("__headers")]
public TradeRepublicHeaders Headers { get; init; } = Headers ?? new TradeRepublicHeaders();
}
@@ -0,0 +1,26 @@
using System;
using System.Globalization;
using System.Text.Json.Serialization;
namespace FinlyticCore.Dtos.TradeRepublic;
public record TradeRepublicPriceTick(
[property: JsonPropertyName("time")] long Time,
[property: JsonPropertyName("price")] string Price,
[property: JsonPropertyName("size")] decimal Size
)
{
public decimal PriceValue => decimal.TryParse(Price, NumberStyles.Any, CultureInfo.InvariantCulture, out var v) ? v : 0m;
public DateTime DateTimeUtc => DateTimeOffset.FromUnixTimeMilliseconds(Time).UtcDateTime;
}
public record TradeRepublicTickerResponse(
[property: JsonPropertyName("bid")] TradeRepublicPriceTick? Bid,
[property: JsonPropertyName("ask")] TradeRepublicPriceTick? Ask,
[property: JsonPropertyName("last")] TradeRepublicPriceTick? Last,
[property: JsonPropertyName("pre")] TradeRepublicPriceTick? Pre,
[property: JsonPropertyName("open")] TradeRepublicPriceTick? Open,
[property: JsonPropertyName("qualityId")] string? QualityId,
[property: JsonPropertyName("leverage")] decimal? Leverage,
[property: JsonPropertyName("delta")] decimal? Delta
);
@@ -19,6 +19,7 @@ public record YahooQuoteSummaryResultDto(
/// Contains module blocks requested via the modules query parameter.
/// </summary>
public record YahooQuoteSummaryModulesDto(
[property: JsonPropertyName("quoteType")] YahooQuoteTypeDto? QuoteType, // <--- HIER HINZUGEFÜGT
[property: JsonPropertyName("assetProfile")] YahooAssetProfileDto? AssetProfile,
[property: JsonPropertyName("financialData")] YahooFinancialDataDto? FinancialData,
[property: JsonPropertyName("defaultKeyStatistics")] YahooDefaultKeyStatisticsDto? DefaultKeyStatistics,
@@ -34,6 +35,12 @@ public record YahooQuoteSummaryModulesDto(
#region Module DTOs
public record YahooQuoteTypeDto(
[property: JsonPropertyName("shortName")] string? ShortName,
[property: JsonPropertyName("longName")] string? LongName,
[property: JsonPropertyName("symbol")] string? Symbol
);
/// <summary>
/// Asset profile details including address, industry, sector, officers, and corporate governance risks.
/// </summary>