feat(assets): update scanner background service, derivative entities, and dynamic settings
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using FinlyticAssets.Entities;
|
||||
using FinlyticCore.Entities.Assets;
|
||||
using FinlyticCore.Models.Assets;
|
||||
using FinlyticCore.Entities.Settings;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
@@ -12,6 +11,7 @@ public class AssetsDbContext : DbContext
|
||||
{
|
||||
}
|
||||
|
||||
public DbSet<SettingEntity> DynamicSettings => Set<SettingEntity>();
|
||||
public DbSet<Settings> Settings { get; set; }
|
||||
public DbSet<AssetEntity> TradeRepublicAssets { get; set; }
|
||||
public DbSet<TagEntity> TradeRepublicTags { get; set; }
|
||||
@@ -19,6 +19,13 @@ public class AssetsDbContext : DbContext
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<SettingEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.HasIndex(e => e.Key);
|
||||
});
|
||||
modelBuilder.Entity<AssetEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => new {e.Isin, e.InstrumentCategory});
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public abstract class AssetEntity
|
||||
{
|
||||
public string Isin { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string InstrumentCategory { get; set; } = string.Empty;
|
||||
public bool HasCfd { get; set; }
|
||||
public string? ImageId { get; set; }
|
||||
|
||||
public DateTime LastUpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public List<TagEntity> Tags { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using FinlyticAssets.Entities;
|
||||
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class BondEntity : AssetEntity
|
||||
{
|
||||
public string BondIssuerName { get; set; } = string.Empty;
|
||||
public string SearchSubtitle { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class CryptoEntity : AssetEntity
|
||||
{
|
||||
public string Subtitle { get; set; } = string.Empty;
|
||||
public string SearchSubtitle { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public enum OptionType
|
||||
{
|
||||
Long,
|
||||
Short
|
||||
}
|
||||
|
||||
public class DerivativeEntity : AssetEntity
|
||||
{
|
||||
// --- Verknüpfung zum Basiswert (Underlying) ---
|
||||
[StringLength(12, MinimumLength = 12)]
|
||||
public string? UnderlyingIsin { get; set; }
|
||||
|
||||
// --- Derivat-Spezifikationen ---
|
||||
public OptionType OptionType { get; set; } // Long / Short
|
||||
|
||||
[MaxLength(100)]
|
||||
public string ProductCategoryName { get; set; } = string.Empty; // Z.B. "Best Turbo"
|
||||
|
||||
[MaxLength(100)]
|
||||
public string NextGenProductCategoryName { get; set; } = string.Empty; // Z.B. "Turbo"
|
||||
|
||||
// --- Kennzahlen (Präzise decimals für Finanzwerte) ---
|
||||
[Column(TypeName = "numeric(18,6)")]
|
||||
public decimal Strike { get; set; } // Basispreis
|
||||
|
||||
[Column(TypeName = "numeric(18,6)")]
|
||||
public decimal Barrier { get; set; } // Knock-Out-Schwelle
|
||||
|
||||
[Column(TypeName = "numeric(10,4)")]
|
||||
public decimal Leverage { get; set; } // Hebel (z. B. 1.01)
|
||||
|
||||
public decimal? Size { get; set; }
|
||||
|
||||
public decimal? Factor { get; set; }
|
||||
|
||||
public decimal? Delta { get; set; }
|
||||
|
||||
[MaxLength(10)]
|
||||
public string Currency { get; set; } = "EUR";
|
||||
|
||||
public DateTime? Expiry { get; set; } // Verfallsdatum (null bei Open-End / Best Turbo)
|
||||
|
||||
// --- Emittent (Issuer) Daten ---
|
||||
[MaxLength(150)]
|
||||
public string Issuer { get; set; } = string.Empty; // Z.B. "Société Générale"
|
||||
|
||||
[MaxLength(150)]
|
||||
public string IssuerDisplayName { get; set; } = string.Empty;
|
||||
|
||||
public string? IssuerImageId { get; set; }
|
||||
|
||||
// PostgreSQL Mapped Array für TR-Kategorien
|
||||
public List<string> DerivativeProductCategories { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class EtfEntity : AssetEntity
|
||||
{
|
||||
public List<string> DerivativeProductCategories { get; set; } = new();
|
||||
public string EtfDescription { get; set; } = string.Empty;
|
||||
public string MappedEtfIndexName { get; set; } = string.Empty;
|
||||
public string Subtitle { get; set; } = string.Empty;
|
||||
public string SearchSubtitle { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class StockEntity : AssetEntity
|
||||
{
|
||||
public List<string> DerivativeProductCategories { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class SyntheticEntity : AssetEntity
|
||||
{
|
||||
public List<string> DerivativeProductCategories { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace FinlyticAssets.Entities;
|
||||
|
||||
public class TagEntity
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
public List<AssetEntity> Assets { get; set; } = new();
|
||||
}
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using FinlyticAssets.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FinlyticAssets.Migrations
|
||||
{
|
||||
[DbContext(typeof(AssetsDbContext))]
|
||||
[Migration("20260813202348_UpdateDerivativeAssets")]
|
||||
partial class UpdateDerivativeAssets
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("AssetEntityTagEntity", b =>
|
||||
{
|
||||
b.Property<string>("TagsId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetsIsin")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetsInstrumentCategory")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("TagsId", "AssetsIsin", "AssetsInstrumentCategory");
|
||||
|
||||
b.HasIndex("AssetsIsin", "AssetsInstrumentCategory");
|
||||
|
||||
b.ToTable("AssetEntityTagEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.AssetEntity", b =>
|
||||
{
|
||||
b.Property<string>("Isin")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("InstrumentCategory")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(13)
|
||||
.HasColumnType("character varying(13)");
|
||||
|
||||
b.Property<bool>("HasCfd")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ImageId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("LastUpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Isin", "InstrumentCategory");
|
||||
|
||||
b.HasIndex("LastUpdatedAt");
|
||||
|
||||
b.ToTable("TradeRepublicAssets");
|
||||
|
||||
b.HasDiscriminator<string>("AssetType").HasValue("AssetEntity");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.Settings", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("BatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CurrentScanningPage")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("CurrentScanningType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)");
|
||||
|
||||
b.Property<bool>("FinishedInitialScan")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("InitAssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("InitBatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("TradeRepublicMaxRequestPageSize")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.TagEntity", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TradeRepublicTags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.BondEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("BondIssuerName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue("Bond");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.CryptoEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Subtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("SearchSubtitle")
|
||||
.HasColumnName("CryptoEntity_SearchSubtitle");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Crypto");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.DerivativeEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<decimal>("Barrier")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("Currency")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<decimal?>("Delta")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime?>("Expiry")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("Factor")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Issuer")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerDisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerImageId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Leverage")
|
||||
.HasColumnType("numeric(10,4)");
|
||||
|
||||
b.Property<string>("NextGenProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<int>("OptionType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<decimal?>("Size")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal>("Strike")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("UnderlyingIsin")
|
||||
.HasMaxLength(12)
|
||||
.HasColumnType("character varying(12)");
|
||||
|
||||
b.HasDiscriminator().HasValue("Derivative");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.EtfEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EtfDescription")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MappedEtfIndexName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Subtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("EtfEntity_DerivativeProductCategories");
|
||||
|
||||
t.Property("SearchSubtitle")
|
||||
.HasColumnName("EtfEntity_SearchSubtitle");
|
||||
|
||||
t.Property("Subtitle")
|
||||
.HasColumnName("EtfEntity_Subtitle");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Etf");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.StockEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("StockEntity_DerivativeProductCategories");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Stock");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.SyntheticEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("SyntheticEntity_DerivativeProductCategories");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Synthetic");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AssetEntityTagEntity", b =>
|
||||
{
|
||||
b.HasOne("FinlyticAssets.Entities.TagEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FinlyticAssets.Entities.AssetEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AssetsIsin", "AssetsInstrumentCategory")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FinlyticAssets.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateDerivativeAssets : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UnderlyingIsin",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(12)",
|
||||
maxLength: 12,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Barrier",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric(18,6)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Currency",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(10)",
|
||||
maxLength: 10,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Delta",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "Expiry",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Factor",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Issuer",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(150)",
|
||||
maxLength: 150,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IssuerDisplayName",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(150)",
|
||||
maxLength: 150,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IssuerImageId",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Leverage",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric(10,4)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "NextGenProductCategoryName",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(100)",
|
||||
maxLength: 100,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "OptionType",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ProductCategoryName",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "character varying(100)",
|
||||
maxLength: 100,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Size",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "Strike",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "numeric(18,6)",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Barrier",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Currency",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Delta",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Expiry",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Factor",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Issuer",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IssuerDisplayName",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IssuerImageId",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Leverage",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "NextGenProductCategoryName",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "OptionType",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ProductCategoryName",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Size",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Strike",
|
||||
table: "TradeRepublicAssets");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UnderlyingIsin",
|
||||
table: "TradeRepublicAssets",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(12)",
|
||||
oldMaxLength: 12,
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using FinlyticAssets.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FinlyticAssets.Migrations
|
||||
{
|
||||
[DbContext(typeof(AssetsDbContext))]
|
||||
[Migration("20260813205059_AddDynamicSettings")]
|
||||
partial class AddDynamicSettings
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("AssetEntityTagEntity", b =>
|
||||
{
|
||||
b.Property<string>("TagsId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetsIsin")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetsInstrumentCategory")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("TagsId", "AssetsIsin", "AssetsInstrumentCategory");
|
||||
|
||||
b.HasIndex("AssetsIsin", "AssetsInstrumentCategory");
|
||||
|
||||
b.ToTable("AssetEntityTagEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.AssetEntity", b =>
|
||||
{
|
||||
b.Property<string>("Isin")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("InstrumentCategory")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("AssetType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(13)
|
||||
.HasColumnType("character varying(13)");
|
||||
|
||||
b.Property<bool>("HasCfd")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ImageId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("LastUpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Isin", "InstrumentCategory");
|
||||
|
||||
b.HasIndex("LastUpdatedAt");
|
||||
|
||||
b.ToTable("TradeRepublicAssets");
|
||||
|
||||
b.HasDiscriminator<string>("AssetType").HasValue("AssetEntity");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.Settings", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("BatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CurrentScanningPage")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("CurrentScanningType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)");
|
||||
|
||||
b.Property<bool>("FinishedInitialScan")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("InitAssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("InitBatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("TradeRepublicMaxRequestPageSize")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.TagEntity", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TradeRepublicTags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Settings.SettingEntity", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<DateTime>("LastUpdatedUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ServiceIdentifier")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<string>("ValueJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Key");
|
||||
|
||||
b.ToTable("DynamicSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.BondEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("BondIssuerName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue("Bond");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.CryptoEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Subtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("SearchSubtitle")
|
||||
.HasColumnName("CryptoEntity_SearchSubtitle");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Crypto");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.DerivativeEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<decimal>("Barrier")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("Currency")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<decimal?>("Delta")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime?>("Expiry")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("Factor")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Issuer")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerDisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerImageId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Leverage")
|
||||
.HasColumnType("numeric(10,4)");
|
||||
|
||||
b.Property<string>("NextGenProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<int>("OptionType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<decimal?>("Size")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal>("Strike")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("UnderlyingIsin")
|
||||
.HasMaxLength(12)
|
||||
.HasColumnType("character varying(12)");
|
||||
|
||||
b.HasDiscriminator().HasValue("Derivative");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.EtfEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EtfDescription")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MappedEtfIndexName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Subtitle")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("EtfEntity_DerivativeProductCategories");
|
||||
|
||||
t.Property("SearchSubtitle")
|
||||
.HasColumnName("EtfEntity_SearchSubtitle");
|
||||
|
||||
t.Property("Subtitle")
|
||||
.HasColumnName("EtfEntity_Subtitle");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Etf");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.StockEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("StockEntity_DerivativeProductCategories");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Stock");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.SyntheticEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("TradeRepublicAssets", t =>
|
||||
{
|
||||
t.Property("DerivativeProductCategories")
|
||||
.HasColumnName("SyntheticEntity_DerivativeProductCategories");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue("Synthetic");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AssetEntityTagEntity", b =>
|
||||
{
|
||||
b.HasOne("FinlyticAssets.Entities.TagEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FinlyticAssets.Entities.AssetEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AssetsIsin", "AssetsInstrumentCategory")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FinlyticAssets.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDynamicSettings : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DynamicSettings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Key = table.Column<string>(type: "character varying(150)", maxLength: 150, nullable: false),
|
||||
ValueJson = table.Column<string>(type: "text", nullable: false),
|
||||
ServiceIdentifier = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
LastUpdatedUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DynamicSettings", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DynamicSettings_Key",
|
||||
table: "DynamicSettings",
|
||||
column: "Key");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "DynamicSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// <auto-generated />
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using FinlyticAssets.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -40,44 +40,7 @@ namespace FinlyticAssets.Migrations
|
||||
b.ToTable("AssetEntityTagEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.Settings", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("BatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CurrentScanningPage")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("CurrentScanningType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)");
|
||||
|
||||
b.Property<bool>("FinishedInitialScan")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("InitAssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("InitBatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("TradeRepublicMaxRequestPageSize")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.AssetEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.AssetEntity", b =>
|
||||
{
|
||||
b.Property<string>("Isin")
|
||||
.HasColumnType("text");
|
||||
@@ -118,7 +81,44 @@ namespace FinlyticAssets.Migrations
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.TagEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.Settings", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("BatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CurrentScanningPage")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("CurrentScanningType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)");
|
||||
|
||||
b.Property<bool>("FinishedInitialScan")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("InitAssetUpdateTypeDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("InitBatchAssetUpdateDelay")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("TradeRepublicMaxRequestPageSize")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.TagEntity", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
@@ -136,9 +136,39 @@ namespace FinlyticAssets.Migrations
|
||||
b.ToTable("TradeRepublicTags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.BondEntity", b =>
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Settings.SettingEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<DateTime>("LastUpdatedUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ServiceIdentifier")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<string>("ValueJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Key");
|
||||
|
||||
b.ToTable("DynamicSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.BondEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("BondIssuerName")
|
||||
.IsRequired()
|
||||
@@ -151,9 +181,9 @@ namespace FinlyticAssets.Migrations
|
||||
b.HasDiscriminator().HasValue("Bond");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.CryptoEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.CryptoEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("SearchSubtitle")
|
||||
.IsRequired()
|
||||
@@ -172,23 +202,76 @@ namespace FinlyticAssets.Migrations
|
||||
b.HasDiscriminator().HasValue("Crypto");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.DerivativeEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.DerivativeEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<decimal>("Barrier")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("Currency")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<decimal?>("Delta")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UnderlyingIsin")
|
||||
b.Property<DateTime?>("Expiry")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("Factor")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Issuer")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerDisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("IssuerImageId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Leverage")
|
||||
.HasColumnType("numeric(10,4)");
|
||||
|
||||
b.Property<string>("NextGenProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<int>("OptionType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ProductCategoryName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<decimal?>("Size")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal>("Strike")
|
||||
.HasColumnType("numeric(18,6)");
|
||||
|
||||
b.Property<string>("UnderlyingIsin")
|
||||
.HasMaxLength(12)
|
||||
.HasColumnType("character varying(12)");
|
||||
|
||||
b.HasDiscriminator().HasValue("Derivative");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.EtfEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.EtfEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
@@ -225,9 +308,9 @@ namespace FinlyticAssets.Migrations
|
||||
b.HasDiscriminator().HasValue("Etf");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.StockEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.StockEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
@@ -242,9 +325,9 @@ namespace FinlyticAssets.Migrations
|
||||
b.HasDiscriminator().HasValue("Stock");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FinlyticCore.Entities.Assets.SyntheticEntity", b =>
|
||||
modelBuilder.Entity("FinlyticAssets.Entities.SyntheticEntity", b =>
|
||||
{
|
||||
b.HasBaseType("FinlyticCore.Entities.Assets.AssetEntity");
|
||||
b.HasBaseType("FinlyticAssets.Entities.AssetEntity");
|
||||
|
||||
b.Property<string>("DerivativeProductCategories")
|
||||
.IsRequired()
|
||||
@@ -261,13 +344,13 @@ namespace FinlyticAssets.Migrations
|
||||
|
||||
modelBuilder.Entity("AssetEntityTagEntity", b =>
|
||||
{
|
||||
b.HasOne("FinlyticCore.Entities.Assets.TagEntity", null)
|
||||
b.HasOne("FinlyticAssets.Entities.TagEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FinlyticCore.Entities.Assets.AssetEntity", null)
|
||||
b.HasOne("FinlyticAssets.Entities.AssetEntity", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AssetsIsin", "AssetsInstrumentCategory")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FinlyticAssets.Models;
|
||||
using FinlyticCore.Dtos.TradeRepublic;
|
||||
using FinlyticCore.Models.Assets;
|
||||
using FinlyticCore.Models.TradeRepublic;
|
||||
using FinlyticCore.Services.TradeRepublic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using FinlyticAssets.Database;
|
||||
using FinlyticAssets.Entities;
|
||||
using FinlyticCore.Entities.Assets;
|
||||
using FinlyticCore.Models.TradeRepublic;
|
||||
using FinlyticCore.Dtos.TradeRepublic;
|
||||
using FinlyticCore.Services.TradeRepublic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -21,6 +20,7 @@ public interface IAssetsDbService
|
||||
public Task UpdateAssetImageIdAsync(string isin, string imageId);
|
||||
public Task<bool> DeleteAssetAsync(string isin);
|
||||
public Task<List<AssetEntity>> GetDiscoveryAssetsAsync(int limit = 15);
|
||||
public Task<List<DerivativeEntity>> GetDerivativesByUnderlyingAsync(string underlyingIsin, string optionType = "long", bool forceRefresh = false, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -393,6 +393,82 @@ public class AssetsDbService : IAssetsDbService
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Inherits documentation from interface.</summary>
|
||||
public async Task<List<DerivativeEntity>> GetDerivativesByUnderlyingAsync(string underlyingIsin, string optionType = "long", bool forceRefresh = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var targetOptionType = optionType.Equals("short", StringComparison.OrdinalIgnoreCase) ? OptionType.Short : OptionType.Long;
|
||||
var cutoff = DateTime.UtcNow.AddDays(-7);
|
||||
|
||||
if (!forceRefresh)
|
||||
{
|
||||
var cached = await _context.TradeRepublicAssets
|
||||
.OfType<DerivativeEntity>()
|
||||
.AsNoTracking()
|
||||
.Include(a => a.Tags)
|
||||
.Where(d => d.UnderlyingIsin == underlyingIsin && d.OptionType == targetOptionType && d.LastUpdatedAt >= cutoff)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (cached.Count > 0)
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
var trReq = new TradeRepublicDerivativesRequest(Underlying: underlyingIsin, OptionType: optionType, ProductCategory: "knockOutProduct", PageSize: 50, After: "0");
|
||||
var trResponse = await _tradeRepublicService.GetDerivativesAsync(trReq, cancellationToken);
|
||||
if (trResponse?.Results != null && trResponse.Results.Count > 0)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var isins = trResponse.Results.Select(r => r.Isin).Distinct().ToList();
|
||||
var existingDerivatives = await _context.TradeRepublicAssets
|
||||
.OfType<DerivativeEntity>()
|
||||
.Where(d => isins.Contains(d.Isin))
|
||||
.ToDictionaryAsync(d => d.Isin, cancellationToken);
|
||||
|
||||
foreach (var item in trResponse.Results)
|
||||
{
|
||||
if (!existingDerivatives.TryGetValue(item.Isin, out var entity))
|
||||
{
|
||||
entity = new DerivativeEntity
|
||||
{
|
||||
Isin = item.Isin,
|
||||
InstrumentCategory = "derivative",
|
||||
Type = "derivative"
|
||||
};
|
||||
await _context.TradeRepublicAssets.AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
entity.UnderlyingIsin = underlyingIsin;
|
||||
entity.OptionType = item.OptionType.Equals("short", StringComparison.OrdinalIgnoreCase) ? OptionType.Short : OptionType.Long;
|
||||
entity.ProductCategoryName = item.ProductCategoryName;
|
||||
entity.NextGenProductCategoryName = item.NextGenProductCategoryName;
|
||||
entity.Strike = item.Strike ?? 0m;
|
||||
entity.Barrier = item.Barrier ?? 0m;
|
||||
entity.Leverage = item.Leverage ?? 0m;
|
||||
entity.Size = item.Size;
|
||||
entity.Factor = item.Factor;
|
||||
entity.Delta = item.Delta;
|
||||
entity.Currency = item.Currency ?? "EUR";
|
||||
entity.Expiry = DateTime.TryParse(item.Expiry, out var exp) ? exp : null;
|
||||
entity.Issuer = item.Issuer;
|
||||
entity.IssuerDisplayName = item.IssuerDisplayName;
|
||||
entity.IssuerImageId = item.IssuerImageId;
|
||||
entity.ImageId = item.ImageId;
|
||||
entity.Name = $"{item.IssuerDisplayName} {item.NextGenProductCategoryName} ({item.OptionType.ToUpper()})";
|
||||
entity.LastUpdatedAt = now;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
return await _context.TradeRepublicAssets
|
||||
.OfType<DerivativeEntity>()
|
||||
.AsNoTracking()
|
||||
.Include(a => a.Tags)
|
||||
.Where(d => d.UnderlyingIsin == underlyingIsin && d.OptionType == targetOptionType)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
#region Helper & Mapping Methods
|
||||
|
||||
private AssetEntity MapDtoToEntity(TradeRepublicAsset dto)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
|
||||
|
||||
using FinlyticAssets.Entities;
|
||||
using FinlyticCore.Dtos.Assets;
|
||||
|
||||
namespace FinlyticCore.Util;
|
||||
namespace FinlyticAssets.Util;
|
||||
|
||||
public static class AssetMapper
|
||||
{
|
||||
|
||||
public static AssetDto ToDto(this AssetEntity entity)
|
||||
{
|
||||
var dtoTags = entity.Tags.Select(t => new TagDto
|
||||
@@ -83,7 +81,21 @@ public static class AssetMapper
|
||||
LastUpdatedAt = deriv.LastUpdatedAt,
|
||||
Tags = dtoTags,
|
||||
DerivativeProductCategories = deriv.DerivativeProductCategories,
|
||||
UnderlyingIsin = deriv.UnderlyingIsin
|
||||
UnderlyingIsin = deriv.UnderlyingIsin,
|
||||
OptionType = deriv.OptionType.ToString(),
|
||||
ProductCategoryName = deriv.ProductCategoryName,
|
||||
NextGenProductCategoryName = deriv.NextGenProductCategoryName,
|
||||
Strike = deriv.Strike,
|
||||
Barrier = deriv.Barrier,
|
||||
Leverage = deriv.Leverage,
|
||||
Size = deriv.Size,
|
||||
Factor = deriv.Factor,
|
||||
Delta = deriv.Delta,
|
||||
Currency = deriv.Currency,
|
||||
Expiry = deriv.Expiry,
|
||||
Issuer = deriv.Issuer,
|
||||
IssuerDisplayName = deriv.IssuerDisplayName,
|
||||
IssuerImageId = deriv.IssuerImageId
|
||||
},
|
||||
SyntheticEntity synth => new SyntheticDto
|
||||
{
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
using System.Text.Json;
|
||||
using FinlyticAssets.Entities;
|
||||
using FinlyticAssets.Services;
|
||||
using FinlyticCore.Entities.Assets;
|
||||
using FinlyticCore.Models;
|
||||
using FinlyticCore.Models.Assets;
|
||||
using FinlyticCore.Util;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FinlyticAssets.Util;
|
||||
|
||||
@@ -61,6 +56,7 @@ public class AssetsMqttClient(
|
||||
await SubscribeAsync("services/request/assets_Get/#");
|
||||
await SubscribeAsync("services/request/assets_Search/#");
|
||||
await SubscribeAsync("services/request/assets_GetDiscovery/#");
|
||||
await SubscribeAsync("services/request/assets_GetDerivatives/#");
|
||||
await SubscribeAsync("services/request/assets_FetchLogo/#");
|
||||
await SubscribeAsync("services/request/health_Ping/#");
|
||||
await SubscribeAsync("services/config/updated/#");
|
||||
@@ -119,6 +115,9 @@ public class AssetsMqttClient(
|
||||
case "assets_GetDiscovery":
|
||||
responseData = await HandleAssetsGetDiscoveryAsync(payload, dbService);
|
||||
break;
|
||||
case "assets_GetDerivatives":
|
||||
responseData = (await HandleAssetsGetDerivativesAsync(payload, dbService)).Cast<AssetEntity>().ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
string defaultResponseTopic = $"services/response/{channel}/{correlationId}";
|
||||
@@ -216,4 +215,24 @@ public class AssetsMqttClient(
|
||||
}
|
||||
return await dbService.GetDiscoveryAssetsAsync(limit);
|
||||
}
|
||||
|
||||
private async Task<List<DerivativeEntity>> HandleAssetsGetDerivativesAsync(string payload, IAssetsDbService dbService)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(payload)) return [];
|
||||
|
||||
try
|
||||
{
|
||||
var req = JsonSerializer.Deserialize(payload, FinlyticJsonSerializerContext.Default.GetDerivativesRequest);
|
||||
if (req != null && !string.IsNullOrEmpty(req.UnderlyingIsin))
|
||||
{
|
||||
return await dbService.GetDerivativesByUnderlyingAsync(req.UnderlyingIsin, req.OptionType, req.ShouldForceRefresh);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "[{Channel}] Error parsing GetDerivativesRequest payload.", "AssetsChannel");
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user