Phase 6 (Stufe 1): EF Core + MySQL Fundament (Core-Seite)

- Pomelo.EntityFrameworkCore.MySql 8.0.3 + EF Core Design im Core; DI.Abstractions
  auf 8.0.2 angehoben (Downgrade-Konflikt aufgeloest).
- DatabaseOptions: Provider (MySql|Mongo) + MySqlConnectionString (Connection liegt
  in gitignorierter appsettings.Local.json, NICHT im Repo).
- Position: AccountId + IsDemo ergaenzt (MySQL: eine positions-Tabelle statt
  Collection-per-Account).
- CoreDbContext (accounts/positions/markets/trade_log) mit Keys, Decimal-Praezision,
  NotMapped fuer Runtime-Felder, Text-Spalten fuer JSON. Design-Time-Factory (Env-Var).
- EF-Migration InitialCore erstellt UND auf die MySQL-DB angewandt (Tabellen live).

Naechste Stufen: Core-EF-Repos + DI-Umschaltung, Modul-Context (CopyTradingDbContext)
+ Repos, Config-Migration Mongo->MySQL, dann Mongo entfernen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-05 13:32:06 +02:00
co-authored by Claude Opus 4.8
parent 87dd9a750d
commit 97bff61fc5
9 changed files with 939 additions and 1 deletions
+2
View File
@@ -65,6 +65,8 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<!-- Angehoben, um Downgrade-Konflikt (EF Core zieht 8.0.2) aufzulösen. -->
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -8,6 +8,13 @@ namespace PolyTrader.Core.Configuration
{ {
public const string SectionName = "Database"; public const string SectionName = "Database";
/// <summary>"MySql" (Zielzustand) oder "Mongo" (Übergang/Config-Migration).</summary>
public string Provider { get; set; } = "MySql";
/// <summary>MySQL-Connection-String (aus gitignorierter appsettings.Local.json).</summary>
public string MySqlConnectionString { get; set; } = string.Empty;
// --- MongoDB (nur noch für die einmalige Config-Migration nach MySQL) ---
public string ConnectionString { get; set; } = "mongodb://localhost:27017"; public string ConnectionString { get; set; } = "mongodb://localhost:27017";
public string DatabaseName { get; set; } = "PolyTraderDB"; public string DatabaseName { get; set; } = "PolyTraderDB";
+5
View File
@@ -2,6 +2,11 @@ namespace PolyTraderSharp.Models
{ {
public class Position public class Position
{ {
// Für MySQL: eine positions-Tabelle mit account_id + is_demo (in Mongo lag das
// im Collection-Namen open_positions_{id} / demo_positions_{id}).
public int AccountId { get; set; }
public bool IsDemo { get; set; }
[MongoDB.Bson.Serialization.Attributes.BsonId] [MongoDB.Bson.Serialization.Attributes.BsonId]
public string TokenId { get; set; } = string.Empty; public string TokenId { get; set; } = string.Empty;
public string MarketSlug { get; set; } = string.Empty; public string MarketSlug { get; set; } = string.Empty;
@@ -0,0 +1,94 @@
using Microsoft.EntityFrameworkCore;
using PolyTraderSharp.Models;
namespace PolyTrader.Core.Persistence.Ef
{
/// <summary>
/// EF-Core-Kontext für die Core-Entitäten (eigene Trading-Accounts, Positionen,
/// Markt-Cache, generischer Trade-Log). Modul-Entitäten liegen im
/// CopyTradingDbContext des Moduls (gleiche MySQL-DB, andere Tabellen).
/// </summary>
public class CoreDbContext : DbContext
{
public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { }
public DbSet<AccountState> Accounts => Set<AccountState>();
public DbSet<Position> Positions => Set<Position>();
public DbSet<MarketData> Markets => Set<MarketData>();
public DbSet<TradeRecord> TradeLog => Set<TradeRecord>();
protected override void OnModelCreating(ModelBuilder b)
{
b.Entity<AccountState>(e =>
{
e.ToTable("accounts");
e.HasKey(x => x.AccountId);
e.Property(x => x.AccountId).ValueGeneratedNever();
e.Ignore(x => x.OpenPositions); // Runtime-Only (In-Memory Hot-Path)
e.Property(x => x.Name).HasMaxLength(200);
e.Property(x => x.WalletAddress).HasMaxLength(128);
e.Property(x => x.ApiKey).HasMaxLength(256);
e.Property(x => x.ApiSecret).HasMaxLength(256);
e.Property(x => x.ApiPassphrase).HasMaxLength(256);
e.Property(x => x.PrivateKey).HasMaxLength(256);
e.Property(x => x.PayoutAddress).HasMaxLength(128);
e.Property(x => x.TotalBalance).HasPrecision(18, 6);
e.Property(x => x.AvailableBalance).HasPrecision(18, 6);
e.Property(x => x.PayoutLimitUsd).HasPrecision(18, 6);
});
b.Entity<Position>(e =>
{
e.ToTable("positions");
e.HasKey(x => new { x.AccountId, x.IsDemo, x.TokenId });
e.Property(x => x.TokenId).HasMaxLength(120);
e.Property(x => x.MarketSlug).HasMaxLength(300);
e.Property(x => x.ConditionId).HasMaxLength(120);
e.Property(x => x.SourceTraderName).HasMaxLength(200);
e.Property(x => x.SourceTraderAddress).HasMaxLength(128);
e.Property(x => x.MarketQuestion).HasMaxLength(1000);
e.Property(x => x.Outcome).HasMaxLength(200);
e.Property(x => x.Side).HasMaxLength(10);
e.Property(x => x.EntryPrice).HasPrecision(18, 6);
e.Property(x => x.Size).HasPrecision(18, 6);
e.Property(x => x.AmountUsd).HasPrecision(18, 6);
e.Property(x => x.CurrentPrice).HasPrecision(18, 6);
e.Property(x => x.CurrentValueUsd).HasPrecision(18, 6);
});
b.Entity<MarketData>(e =>
{
e.ToTable("markets");
e.HasKey(x => x.Id);
e.Property(x => x.Id).HasMaxLength(120);
e.Property(x => x.ConditionId).HasMaxLength(120);
e.Property(x => x.Slug).HasMaxLength(300);
e.Property(x => x.Category).HasMaxLength(200);
e.Property(x => x.Question).HasMaxLength(1000);
e.Property(x => x.ClobTokenIds).HasColumnType("text");
e.Property(x => x.Outcomes).HasColumnType("text");
});
b.Entity<TradeRecord>(e =>
{
e.ToTable("trade_log");
e.HasKey(x => x.Id);
e.Property(x => x.Id).HasMaxLength(64);
e.Property(x => x.ModuleName).HasMaxLength(64);
e.Property(x => x.TokenId).HasMaxLength(120);
e.Property(x => x.MarketQuestion).HasMaxLength(1000);
e.Property(x => x.Outcome).HasMaxLength(200);
e.Property(x => x.Side).HasMaxLength(10);
e.Property(x => x.ExitReason).HasMaxLength(200);
e.Property(x => x.EntryPrice).HasPrecision(18, 6);
e.Property(x => x.ExitPrice).HasPrecision(18, 6);
e.Property(x => x.Size).HasPrecision(18, 6);
e.Property(x => x.RealizedPnl).HasPrecision(18, 6);
e.Property(x => x.PnlPercent).HasPrecision(18, 6);
e.HasIndex(x => x.ClosedAt);
e.HasIndex(x => x.ModuleName);
e.HasIndex(x => x.AccountId);
});
}
}
}
@@ -0,0 +1,26 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace PolyTrader.Core.Persistence.Ef
{
/// <summary>
/// Design-Time-Factory für EF-Tooling (dotnet ef migrations/database).
/// Liest den Connection-String aus der Umgebungsvariable POLYTRADER_MYSQL,
/// damit keine Zugangsdaten im Code/Repo landen.
/// </summary>
public class CoreDbContextFactory : IDesignTimeDbContextFactory<CoreDbContext>
{
public CoreDbContext CreateDbContext(string[] args)
{
var conn = Environment.GetEnvironmentVariable("POLYTRADER_MYSQL")
?? "Server=localhost;Port=3306;Database=polytrader;User ID=root;Password=;";
var options = new DbContextOptionsBuilder<CoreDbContext>()
.UseMySql(conn, ServerVersion.AutoDetect(conn))
.Options;
return new CoreDbContext(options);
}
}
}
@@ -0,0 +1,310 @@
// <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 PolyTrader.Core.Persistence.Ef;
#nullable disable
namespace PolyTrader.Core.Persistence.Ef.Migrations
{
[DbContext(typeof(CoreDbContext))]
[Migration("20260705112545_InitialCore")]
partial class InitialCore
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("PolyTraderSharp.Models.AccountState", b =>
{
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<string>("ApiKey")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("ApiPassphrase")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("ApiSecret")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("AvailableBalance")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<bool>("CloseOnlyMode")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasOpenLimitOrders")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("PayoutAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<decimal>("PayoutLimitUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("PrivateKey")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("TotalBalance")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("WalletAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.HasKey("AccountId");
b.ToTable("accounts", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.MarketData", b =>
{
b.Property<string>("Id")
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<bool>("Active")
.HasColumnType("tinyint(1)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("ClobTokenIds")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Closed")
.HasColumnType("tinyint(1)");
b.Property<string>("ConditionId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime(6)");
b.Property<bool>("NegRisk")
.HasColumnType("tinyint(1)");
b.Property<string>("Outcomes")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Question")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("varchar(300)");
b.HasKey("Id");
b.ToTable("markets", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.Position", b =>
{
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("TokenId")
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<decimal>("AmountUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("ConditionId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<decimal>("CurrentPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("CurrentValueUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("EntryPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<DateTime?>("ExpiryDate")
.HasColumnType("datetime(6)");
b.Property<string>("MarketQuestion")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("MarketSlug")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("varchar(300)");
b.Property<DateTime>("OpenedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("varchar(10)");
b.Property<decimal>("Size")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("SourceTraderAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("SourceTraderId")
.HasColumnType("int");
b.Property<string>("SourceTraderName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.HasKey("AccountId", "IsDemo", "TokenId");
b.ToTable("positions", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.TradeRecord", b =>
{
b.Property<string>("Id")
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<DateTime>("ClosedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("EntryPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("ExitPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("ExitReason")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("MarketQuestion")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("ModuleName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<DateTime>("OpenedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<decimal>("PnlPercent")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("RealizedPnl")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("varchar(10)");
b.Property<decimal>("Size")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ClosedAt");
b.HasIndex("ModuleName");
b.ToTable("trade_log", (string)null);
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,182 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PolyTrader.Core.Persistence.Ef.Migrations
{
/// <inheritdoc />
public partial class InitialCore : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "accounts",
columns: table => new
{
AccountId = table.Column<int>(type: "int", nullable: false),
Name = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
WalletAddress = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ApiKey = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ApiSecret = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ApiPassphrase = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
PrivateKey = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
IsDemo = table.Column<bool>(type: "tinyint(1)", nullable: false),
IsActive = table.Column<bool>(type: "tinyint(1)", nullable: false),
CloseOnlyMode = table.Column<bool>(type: "tinyint(1)", nullable: false),
PayoutAddress = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
PayoutLimitUsd = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
TotalBalance = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
AvailableBalance = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
HasOpenLimitOrders = table.Column<bool>(type: "tinyint(1)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_accounts", x => x.AccountId);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "markets",
columns: table => new
{
Id = table.Column<string>(type: "varchar(120)", maxLength: 120, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConditionId = table.Column<string>(type: "varchar(120)", maxLength: 120, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Question = table.Column<string>(type: "varchar(1000)", maxLength: 1000, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Slug = table.Column<string>(type: "varchar(300)", maxLength: 300, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
EndDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
Active = table.Column<bool>(type: "tinyint(1)", nullable: false),
Closed = table.Column<bool>(type: "tinyint(1)", nullable: false),
Category = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ClobTokenIds = table.Column<string>(type: "text", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Outcomes = table.Column<string>(type: "text", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
NegRisk = table.Column<bool>(type: "tinyint(1)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_markets", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "positions",
columns: table => new
{
AccountId = table.Column<int>(type: "int", nullable: false),
IsDemo = table.Column<bool>(type: "tinyint(1)", nullable: false),
TokenId = table.Column<string>(type: "varchar(120)", maxLength: 120, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
MarketSlug = table.Column<string>(type: "varchar(300)", maxLength: 300, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConditionId = table.Column<string>(type: "varchar(120)", maxLength: 120, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
SourceTraderId = table.Column<int>(type: "int", nullable: false),
SourceTraderName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
SourceTraderAddress = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
MarketQuestion = table.Column<string>(type: "varchar(1000)", maxLength: 1000, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Outcome = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Side = table.Column<string>(type: "varchar(10)", maxLength: 10, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
EntryPrice = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
Size = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
AmountUsd = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
CurrentPrice = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
CurrentValueUsd = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
ExpiryDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
OpenedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_positions", x => new { x.AccountId, x.IsDemo, x.TokenId });
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "trade_log",
columns: table => new
{
Id = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ModuleName = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
AccountId = table.Column<int>(type: "int", nullable: false),
IsDemo = table.Column<bool>(type: "tinyint(1)", nullable: false),
TokenId = table.Column<string>(type: "varchar(120)", maxLength: 120, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
MarketQuestion = table.Column<string>(type: "varchar(1000)", maxLength: 1000, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Outcome = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Side = table.Column<string>(type: "varchar(10)", maxLength: 10, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
EntryPrice = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
ExitPrice = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
Size = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
RealizedPnl = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
PnlPercent = table.Column<decimal>(type: "decimal(18,6)", precision: 18, scale: 6, nullable: false),
OpenedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
ClosedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
ExitReason = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_trade_log", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_trade_log_AccountId",
table: "trade_log",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_trade_log_ClosedAt",
table: "trade_log",
column: "ClosedAt");
migrationBuilder.CreateIndex(
name: "IX_trade_log_ModuleName",
table: "trade_log",
column: "ModuleName");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "accounts");
migrationBuilder.DropTable(
name: "markets");
migrationBuilder.DropTable(
name: "positions");
migrationBuilder.DropTable(
name: "trade_log");
}
}
}
@@ -0,0 +1,307 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PolyTrader.Core.Persistence.Ef;
#nullable disable
namespace PolyTrader.Core.Persistence.Ef.Migrations
{
[DbContext(typeof(CoreDbContext))]
partial class CoreDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("PolyTraderSharp.Models.AccountState", b =>
{
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<string>("ApiKey")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("ApiPassphrase")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("ApiSecret")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("AvailableBalance")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<bool>("CloseOnlyMode")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasOpenLimitOrders")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("PayoutAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<decimal>("PayoutLimitUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("PrivateKey")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<decimal>("TotalBalance")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("WalletAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.HasKey("AccountId");
b.ToTable("accounts", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.MarketData", b =>
{
b.Property<string>("Id")
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<bool>("Active")
.HasColumnType("tinyint(1)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("ClobTokenIds")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Closed")
.HasColumnType("tinyint(1)");
b.Property<string>("ConditionId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime(6)");
b.Property<bool>("NegRisk")
.HasColumnType("tinyint(1)");
b.Property<string>("Outcomes")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Question")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("varchar(300)");
b.HasKey("Id");
b.ToTable("markets", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.Position", b =>
{
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("TokenId")
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<decimal>("AmountUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("ConditionId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<decimal>("CurrentPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("CurrentValueUsd")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("EntryPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<DateTime?>("ExpiryDate")
.HasColumnType("datetime(6)");
b.Property<string>("MarketQuestion")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("MarketSlug")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("varchar(300)");
b.Property<DateTime>("OpenedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("varchar(10)");
b.Property<decimal>("Size")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("SourceTraderAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("SourceTraderId")
.HasColumnType("int");
b.Property<string>("SourceTraderName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.HasKey("AccountId", "IsDemo", "TokenId");
b.ToTable("positions", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.TradeRecord", b =>
{
b.Property<string>("Id")
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<DateTime>("ClosedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("EntryPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("ExitPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("ExitReason")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<bool>("IsDemo")
.HasColumnType("tinyint(1)");
b.Property<string>("MarketQuestion")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("ModuleName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<DateTime>("OpenedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Outcome")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<decimal>("PnlPercent")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("RealizedPnl")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("varchar(10)");
b.Property<decimal>("Size")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ClosedAt");
b.HasIndex("ModuleName");
b.ToTable("trade_log", (string)null);
});
#pragma warning restore 612, 618
}
}
}
+6 -1
View File
@@ -11,7 +11,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.24.0" /> <PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageReference Include="Nethereum.Web3" Version="6.1.0" /> <PackageReference Include="Nethereum.Web3" Version="6.1.0" />