feat(core): update DTOs, Trade Republic client, Yahoo scrapers, and dynamic settings
This commit is contained in:
@@ -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
|
||||
);
|
||||
Reference in New Issue
Block a user