Implement A3, A4, A5, B3: Add MarketOutcomePriceSnapshot, implement Polymarket CLOB prices-history endpoint, improve strategy classification, introduce CopytradingScore, and decouple/optimize scoring pipeline into a separate worker

This commit is contained in:
Richard
2026-07-03 11:20:28 +02:00
parent e994e1ce72
commit f8c8230d99
21 changed files with 2035 additions and 22 deletions
@@ -0,0 +1,737 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Predictalytics.Infrastructure.Data;
#nullable disable
namespace Predictalytics.Infrastructure.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20260703091721_AddMarketOutcomePriceSnapshot")]
partial class AddMarketOutcomePriceSnapshot
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Predictalytics.Domain.Entities.Alert", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("IsRead")
.HasColumnType("tinyint(1)");
b.Property<string>("Message")
.IsRequired()
.HasMaxLength(4096)
.HasColumnType("varchar(4096)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<int>("Severity")
.HasColumnType("int");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<int?>("TraderId")
.HasColumnType("int");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("CreatedAt");
b.HasIndex("TraderId");
b.ToTable("Alerts");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Market", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime>("DbCreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasMaxLength(4096)
.HasColumnType("varchar(4096)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime(6)");
b.Property<string>("EventSlug")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<string>("ImageUrl")
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<bool>("IsResolved")
.HasColumnType("tinyint(1)");
b.Property<DateTime?>("LastTradesUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("Liquidity")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("MarketSlug")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformMarketId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("Question")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<string>("ResolutionOutcome")
.HasColumnType("longtext");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime(6)");
b.Property<decimal>("Volume")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.HasKey("Id");
b.HasIndex("Platform", "PlatformMarketId")
.IsUnique();
b.ToTable("Markets");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketAnalytics", b =>
{
b.Property<int>("MarketId")
.HasColumnType("int");
b.Property<decimal>("AverageTradeSize")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("BotActivityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<DateTime>("LastCalculatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("UniqueTradersCount")
.HasColumnType("int");
b.HasKey("MarketId");
b.ToTable("MarketAnalytics");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcome", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("CurrentPrice")
.HasPrecision(18, 8)
.HasColumnType("decimal(18,8)");
b.Property<string>("Label")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<int>("MarketId")
.HasColumnType("int");
b.Property<int>("OutcomeIndex")
.HasColumnType("int");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("TokenId");
b.HasIndex("MarketId", "OutcomeIndex")
.IsUnique();
b.ToTable("MarketOutcomes");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("MarketOutcomeId")
.HasColumnType("int");
b.Property<decimal>("Price")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<DateTime>("Timestamp")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("MarketOutcomeId", "Timestamp");
b.ToTable("MarketOutcomePriceSnapshots");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.PlatformConfig", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("BaseUrl")
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("SettingsJson")
.HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("PlatformConfigs");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trade", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
b.Property<decimal>("Amount")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("AssetId")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("varchar(80)");
b.Property<int?>("DbMarketId")
.HasColumnType("int");
b.Property<DateTime>("ExecutedAt")
.HasColumnType("datetime(6)");
b.Property<string>("MarketId")
.IsRequired()
.HasMaxLength(66)
.HasColumnType("varchar(66)");
b.Property<int?>("MarketOutcomeId")
.HasColumnType("int");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformTradeId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("Price")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<int>("Side")
.HasColumnType("int");
b.Property<decimal>("Size")
.HasPrecision(14, 6)
.HasColumnType("decimal(14,6)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<string>("TransactionHash")
.HasMaxLength(66)
.HasColumnType("varchar(66)");
b.HasKey("Id");
b.HasIndex("AssetId");
b.HasIndex("DbMarketId");
b.HasIndex("ExecutedAt");
b.HasIndex("MarketOutcomeId");
b.HasIndex("TraderId");
b.HasIndex("Platform", "PlatformTradeId")
.IsUnique();
b.ToTable("Trades");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trader", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("IsAutoDiscovered")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsInitialImportComplete")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSuspectedBot")
.HasColumnType("tinyint(1)");
b.Property<DateTime?>("LastApiErrorAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastPolledAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastTradesUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<int?>("ManualPriorityOverride")
.HasColumnType("int");
b.Property<string>("Notes")
.HasColumnType("longtext");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformUserId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("Strategy")
.HasColumnType("int");
b.Property<int>("Tier")
.HasColumnType("int");
b.Property<decimal>("TotalPnl")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<int>("TotalTrades")
.HasColumnType("int");
b.Property<decimal>("WinRate")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("Id");
b.HasIndex("Platform", "PlatformUserId")
.IsUnique();
b.ToTable("Traders");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderAnalytics", b =>
{
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<DateTime>("LastCalculatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("OverallPnL")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("OverallWinRate")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("PnL24h")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("PnL30d")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("PnL7d")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("WinRate24h")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("WinRate30d")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("WinRate7d")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("TraderId");
b.ToTable("TraderAnalytics");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderPosition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("AvgCost")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<DateTime>("LastUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("MarketOutcomeId")
.HasColumnType("int");
b.Property<decimal>("RealizedPnl")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("SharesHeld")
.HasPrecision(14, 6)
.HasColumnType("decimal(14,6)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("MarketOutcomeId");
b.HasIndex("TraderId", "MarketOutcomeId")
.IsUnique();
b.ToTable("TraderPositions");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderScore", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("ActivityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<DateTime>("CalculatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("CombinedScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("QualityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<int>("Rank")
.HasColumnType("int");
b.Property<decimal>("TimingScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<decimal>("VolumeScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("Id");
b.HasIndex("TraderId")
.IsUnique();
b.ToTable("TraderScores");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.WatchlistEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("AlertsEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("Label")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("Notes")
.HasColumnType("longtext");
b.Property<int>("TraderId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("TraderId")
.IsUnique();
b.ToTable("WatchlistEntries");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Alert", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany()
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketAnalytics", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "Market")
.WithOne("Analytics")
.HasForeignKey("Predictalytics.Domain.Entities.MarketAnalytics", "MarketId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Market");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcome", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "Market")
.WithMany("Outcomes")
.HasForeignKey("MarketId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Market");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MarketOutcome");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trade", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "DbMarket")
.WithMany()
.HasForeignKey("DbMarketId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("Trades")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("DbMarket");
b.Navigation("MarketOutcome");
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderAnalytics", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithOne("Analytics")
.HasForeignKey("Predictalytics.Domain.Entities.TraderAnalytics", "TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderPosition", b =>
{
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("Positions")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MarketOutcome");
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderScore", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithOne("CurrentScore")
.HasForeignKey("Predictalytics.Domain.Entities.TraderScore", "TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.WatchlistEntry", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("WatchlistEntries")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Market", b =>
{
b.Navigation("Analytics");
b.Navigation("Outcomes");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trader", b =>
{
b.Navigation("Analytics");
b.Navigation("CurrentScore");
b.Navigation("Positions");
b.Navigation("Trades");
b.Navigation("WatchlistEntries");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,50 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Predictalytics.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddMarketOutcomePriceSnapshot : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MarketOutcomePriceSnapshots",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
MarketOutcomeId = table.Column<int>(type: "int", nullable: false),
Timestamp = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Price = table.Column<decimal>(type: "decimal(10,6)", precision: 10, scale: 6, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MarketOutcomePriceSnapshots", x => x.Id);
table.ForeignKey(
name: "FK_MarketOutcomePriceSnapshots_MarketOutcomes_MarketOutcomeId",
column: x => x.MarketOutcomeId,
principalTable: "MarketOutcomes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_MarketOutcomePriceSnapshots_MarketOutcomeId_Timestamp",
table: "MarketOutcomePriceSnapshots",
columns: new[] { "MarketOutcomeId", "Timestamp" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "MarketOutcomePriceSnapshots");
}
}
}
@@ -0,0 +1,741 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Predictalytics.Infrastructure.Data;
#nullable disable
namespace Predictalytics.Infrastructure.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20260703091905_AddCopytradingScore")]
partial class AddCopytradingScore
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Predictalytics.Domain.Entities.Alert", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("IsRead")
.HasColumnType("tinyint(1)");
b.Property<string>("Message")
.IsRequired()
.HasMaxLength(4096)
.HasColumnType("varchar(4096)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<int>("Severity")
.HasColumnType("int");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<int?>("TraderId")
.HasColumnType("int");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("CreatedAt");
b.HasIndex("TraderId");
b.ToTable("Alerts");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Market", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime>("DbCreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasMaxLength(4096)
.HasColumnType("varchar(4096)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime(6)");
b.Property<string>("EventSlug")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<string>("ImageUrl")
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<bool>("IsResolved")
.HasColumnType("tinyint(1)");
b.Property<DateTime?>("LastTradesUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("Liquidity")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("MarketSlug")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("varchar(512)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformMarketId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("Question")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<string>("ResolutionOutcome")
.HasColumnType("longtext");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime(6)");
b.Property<decimal>("Volume")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.HasKey("Id");
b.HasIndex("Platform", "PlatformMarketId")
.IsUnique();
b.ToTable("Markets");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketAnalytics", b =>
{
b.Property<int>("MarketId")
.HasColumnType("int");
b.Property<decimal>("AverageTradeSize")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("BotActivityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<DateTime>("LastCalculatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("UniqueTradersCount")
.HasColumnType("int");
b.HasKey("MarketId");
b.ToTable("MarketAnalytics");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcome", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("CurrentPrice")
.HasPrecision(18, 8)
.HasColumnType("decimal(18,8)");
b.Property<string>("Label")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<int>("MarketId")
.HasColumnType("int");
b.Property<int>("OutcomeIndex")
.HasColumnType("int");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("TokenId");
b.HasIndex("MarketId", "OutcomeIndex")
.IsUnique();
b.ToTable("MarketOutcomes");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("MarketOutcomeId")
.HasColumnType("int");
b.Property<decimal>("Price")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<DateTime>("Timestamp")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("MarketOutcomeId", "Timestamp");
b.ToTable("MarketOutcomePriceSnapshots");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.PlatformConfig", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("BaseUrl")
.HasMaxLength(1024)
.HasColumnType("varchar(1024)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("SettingsJson")
.HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("PlatformConfigs");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trade", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
b.Property<decimal>("Amount")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("AssetId")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("varchar(80)");
b.Property<int?>("DbMarketId")
.HasColumnType("int");
b.Property<DateTime>("ExecutedAt")
.HasColumnType("datetime(6)");
b.Property<string>("MarketId")
.IsRequired()
.HasMaxLength(66)
.HasColumnType("varchar(66)");
b.Property<int?>("MarketOutcomeId")
.HasColumnType("int");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformTradeId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("Price")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<int>("Side")
.HasColumnType("int");
b.Property<decimal>("Size")
.HasPrecision(14, 6)
.HasColumnType("decimal(14,6)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<string>("TransactionHash")
.HasMaxLength(66)
.HasColumnType("varchar(66)");
b.HasKey("Id");
b.HasIndex("AssetId");
b.HasIndex("DbMarketId");
b.HasIndex("ExecutedAt");
b.HasIndex("MarketOutcomeId");
b.HasIndex("TraderId");
b.HasIndex("Platform", "PlatformTradeId")
.IsUnique();
b.ToTable("Trades");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trader", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("IsAutoDiscovered")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsInitialImportComplete")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSuspectedBot")
.HasColumnType("tinyint(1)");
b.Property<DateTime?>("LastApiErrorAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastPolledAt")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("LastTradesUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<int?>("ManualPriorityOverride")
.HasColumnType("int");
b.Property<string>("Notes")
.HasColumnType("longtext");
b.Property<int>("Platform")
.HasColumnType("int");
b.Property<string>("PlatformUserId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("Strategy")
.HasColumnType("int");
b.Property<int>("Tier")
.HasColumnType("int");
b.Property<decimal>("TotalPnl")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<int>("TotalTrades")
.HasColumnType("int");
b.Property<decimal>("WinRate")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("Id");
b.HasIndex("Platform", "PlatformUserId")
.IsUnique();
b.ToTable("Traders");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderAnalytics", b =>
{
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<DateTime>("LastCalculatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("OverallPnL")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("OverallWinRate")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("PnL24h")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("PnL30d")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("PnL7d")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("WinRate24h")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("WinRate30d")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("WinRate7d")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("TraderId");
b.ToTable("TraderAnalytics");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderPosition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("AvgCost")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<DateTime>("LastUpdatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("MarketOutcomeId")
.HasColumnType("int");
b.Property<decimal>("RealizedPnl")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<decimal>("SharesHeld")
.HasPrecision(14, 6)
.HasColumnType("decimal(14,6)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("MarketOutcomeId");
b.HasIndex("TraderId", "MarketOutcomeId")
.IsUnique();
b.ToTable("TraderPositions");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderScore", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("ActivityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<DateTime>("CalculatedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("CombinedScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("CopytradingScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("QualityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<int>("Rank")
.HasColumnType("int");
b.Property<decimal>("TimingScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.Property<decimal>("VolumeScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.HasKey("Id");
b.HasIndex("TraderId")
.IsUnique();
b.ToTable("TraderScores");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.WatchlistEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("AlertsEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("Label")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("Notes")
.HasColumnType("longtext");
b.Property<int>("TraderId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("TraderId")
.IsUnique();
b.ToTable("WatchlistEntries");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Alert", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany()
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketAnalytics", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "Market")
.WithOne("Analytics")
.HasForeignKey("Predictalytics.Domain.Entities.MarketAnalytics", "MarketId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Market");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcome", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "Market")
.WithMany("Outcomes")
.HasForeignKey("MarketId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Market");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MarketOutcome");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trade", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "DbMarket")
.WithMany()
.HasForeignKey("DbMarketId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("Trades")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("DbMarket");
b.Navigation("MarketOutcome");
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderAnalytics", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithOne("Analytics")
.HasForeignKey("Predictalytics.Domain.Entities.TraderAnalytics", "TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderPosition", b =>
{
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("Positions")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MarketOutcome");
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.TraderScore", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithOne("CurrentScore")
.HasForeignKey("Predictalytics.Domain.Entities.TraderScore", "TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.WatchlistEntry", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Trader", "Trader")
.WithMany("WatchlistEntries")
.HasForeignKey("TraderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Trader");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Market", b =>
{
b.Navigation("Analytics");
b.Navigation("Outcomes");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trader", b =>
{
b.Navigation("Analytics");
b.Navigation("CurrentScore");
b.Navigation("Positions");
b.Navigation("Trades");
b.Navigation("WatchlistEntries");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Predictalytics.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddCopytradingScore : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<decimal>(
name: "CopytradingScore",
table: "TraderScores",
type: "decimal(8,4)",
precision: 8,
scale: 4,
nullable: false,
defaultValue: 0m);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CopytradingScore",
table: "TraderScores");
}
}
}
@@ -213,6 +213,31 @@ namespace Predictalytics.Infrastructure.Migrations
b.ToTable("MarketOutcomes");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("MarketOutcomeId")
.HasColumnType("int");
b.Property<decimal>("Price")
.HasPrecision(10, 6)
.HasColumnType("decimal(10,6)");
b.Property<DateTime>("Timestamp")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("MarketOutcomeId", "Timestamp");
b.ToTable("MarketOutcomePriceSnapshots");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.PlatformConfig", b =>
{
b.Property<int>("Id")
@@ -505,6 +530,10 @@ namespace Predictalytics.Infrastructure.Migrations
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("CopytradingScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
b.Property<decimal>("QualityScore")
.HasPrecision(8, 4)
.HasColumnType("decimal(8,4)");
@@ -596,6 +625,17 @@ namespace Predictalytics.Infrastructure.Migrations
b.Navigation("Market");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.MarketOutcomePriceSnapshot", b =>
{
b.HasOne("Predictalytics.Domain.Entities.MarketOutcome", "MarketOutcome")
.WithMany()
.HasForeignKey("MarketOutcomeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MarketOutcome");
});
modelBuilder.Entity("Predictalytics.Domain.Entities.Trade", b =>
{
b.HasOne("Predictalytics.Domain.Entities.Market", "DbMarket")