refactor(bot): update paper trading models, broker integration, background services, and test project

This commit is contained in:
2026-08-24 21:37:10 +02:00
parent 5c95dd182c
commit 7060f0f7b1
32 changed files with 1904 additions and 1477 deletions
@@ -1,153 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace FinlyticBot.Migrations
{
/// <inheritdoc />
public partial class InitBotDatabase : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "BotAuditLogs",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TradeId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Symbol = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: false),
Action = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
IsAccepted = table.Column<bool>(type: "boolean", nullable: false),
Reason = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
CalculatedSize = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
AccountEquity = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
Timestamp = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_BotAuditLogs", x => x.Id);
});
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.CreateTable(
name: "ExecutedPaperTrades",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TradeId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Symbol = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: false),
Isin = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: false),
CompanyName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
AlpacaOrderId = table.Column<Guid>(type: "uuid", nullable: true),
Side = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Quantity = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
SignalEntryPrice = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
ActualFillPrice = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
StopLossPrice = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TakeProfitPrice1 = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TakeProfitPrice2 = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
CalculatedCrv = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
WinRate = table.Column<double>(type: "double precision", nullable: false),
SlippagePercent = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
RealizedPnl = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
RealizedPnlPercent = table.Column<decimal>(type: "numeric(18,4)", nullable: true),
Status = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: false),
RejectReason = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
PlacedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
FilledAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
ClosedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ExecutedPaperTrades", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_BotAuditLogs_Action",
table: "BotAuditLogs",
column: "Action");
migrationBuilder.CreateIndex(
name: "IX_BotAuditLogs_Symbol",
table: "BotAuditLogs",
column: "Symbol");
migrationBuilder.CreateIndex(
name: "IX_BotAuditLogs_Timestamp",
table: "BotAuditLogs",
column: "Timestamp");
migrationBuilder.CreateIndex(
name: "IX_BotAuditLogs_TradeId",
table: "BotAuditLogs",
column: "TradeId");
migrationBuilder.CreateIndex(
name: "IX_DynamicSettings_Key",
table: "DynamicSettings",
column: "Key",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_AlpacaOrderId",
table: "ExecutedPaperTrades",
column: "AlpacaOrderId");
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_Isin",
table: "ExecutedPaperTrades",
column: "Isin");
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_PlacedAt",
table: "ExecutedPaperTrades",
column: "PlacedAt");
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_Status",
table: "ExecutedPaperTrades",
column: "Status");
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_Symbol",
table: "ExecutedPaperTrades",
column: "Symbol");
migrationBuilder.CreateIndex(
name: "IX_ExecutedPaperTrades_TradeId",
table: "ExecutedPaperTrades",
column: "TradeId",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "BotAuditLogs");
migrationBuilder.DropTable(
name: "DynamicSettings");
migrationBuilder.DropTable(
name: "ExecutedPaperTrades");
}
}
}
@@ -12,8 +12,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace FinlyticBot.Migrations
{
[DbContext(typeof(BotDbContext))]
[Migration("20260817142432_InitBotDatabase")]
partial class InitBotDatabase
[Migration("20260819191434_InitialBotMigration")]
partial class InitialBotMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -25,160 +25,131 @@ namespace FinlyticBot.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("FinlyticBot.Entities.BotAuditLogEntity", b =>
modelBuilder.Entity("FinlyticBot.Database.Entities.BotPortfolioSnapshotEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<decimal?>("AccountEquity")
b.Property<decimal>("CashEur")
.HasColumnType("decimal(18,4)");
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<decimal?>("CalculatedSize")
.HasColumnType("decimal(18,4)");
b.Property<bool>("IsAccepted")
.HasColumnType("boolean");
b.Property<string>("Reason")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("Symbol")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<DateTime>("Timestamp")
b.Property<DateTime>("CreatedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<string>("TradeId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<decimal>("DailyRealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<int>("OpenPositionsCount")
.HasColumnType("integer");
b.Property<DateTime>("SnapshotDateUtc")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("TotalEquityEur")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("TotalUnrealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("WinRatePercent")
.HasColumnType("decimal(6,2)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("SnapshotDateUtc");
b.HasIndex("Symbol");
b.HasIndex("Timestamp");
b.HasIndex("TradeId");
b.ToTable("BotAuditLogs");
b.ToTable("bot_portfolio_snapshots");
});
modelBuilder.Entity("FinlyticBot.Entities.ExecutedPaperTradeEntity", b =>
modelBuilder.Entity("FinlyticBot.Database.Entities.BotPositionEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<decimal?>("ActualFillPrice")
b.Property<string>("AlpacaOrderId")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<decimal>("AverageBuyIn")
.HasColumnType("decimal(18,4)");
b.Property<Guid?>("AlpacaOrderId")
.HasColumnType("uuid");
b.Property<string>("ClientOrderId")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<decimal>("CalculatedCrv")
.HasColumnType("decimal(18,4)");
b.Property<DateTime?>("ClosedAt")
b.Property<DateTime?>("ClosedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<string>("CompanyName")
b.Property<decimal>("CurrentPrice")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("CurrentStopLoss")
.HasColumnType("decimal(18,4)");
b.Property<int>("Direction")
.HasColumnType("integer");
b.Property<decimal>("EntryPrice")
.HasColumnType("decimal(18,4)");
b.Property<string>("ExitPlan")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
.HasColumnType("jsonb");
b.Property<DateTime?>("FilledAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("InitialStopLoss")
.HasColumnType("decimal(18,4)");
b.Property<string>("Isin")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<DateTime>("PlacedAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("Quantity")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("RealizedPnl")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("RealizedPnlPercent")
.HasColumnType("decimal(18,4)");
b.Property<string>("RejectReason")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<decimal>("SignalEntryPrice")
b.Property<DateTime>("LastSyncAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("OpenedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("ProposalId")
.HasColumnType("uuid");
b.Property<decimal>("Quantity")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("SlippagePercent")
b.Property<decimal>("RealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<decimal>("StopLossPrice")
.HasColumnType("decimal(18,4)");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("Symbol")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<decimal>("TakeProfitPrice1")
b.Property<decimal>("TakeProfit1")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("TakeProfitPrice2")
b.Property<decimal>("TakeProfit2")
.HasColumnType("decimal(18,4)");
b.Property<string>("TradeId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<decimal>("TotalFeesEur")
.HasColumnType("decimal(18,4)");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<double>("WinRate")
.HasColumnType("double precision");
b.Property<int>("Venue")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("AlpacaOrderId");
b.HasIndex("OpenedAtUtc");
b.HasIndex("Isin");
b.HasIndex("ProposalId");
b.HasIndex("PlacedAt");
b.HasIndex("Status", "Venue");
b.HasIndex("Status");
b.HasIndex("Symbol");
b.HasIndex("TradeId")
.IsUnique();
b.ToTable("ExecutedPaperTrades");
b.ToTable("bot_positions");
});
modelBuilder.Entity("FinlyticCore.Entities.Settings.SettingEntity", b =>
@@ -0,0 +1,121 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace FinlyticBot.Migrations
{
/// <inheritdoc />
public partial class InitialBotMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "bot_portfolio_snapshots",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
SnapshotDateUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
TotalEquityEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
CashEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
OpenPositionsCount = table.Column<int>(type: "integer", nullable: false),
DailyRealizedPnlEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TotalUnrealizedPnlEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
WinRatePercent = table.Column<decimal>(type: "numeric(6,2)", nullable: true),
CreatedAtUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_bot_portfolio_snapshots", x => x.Id);
});
migrationBuilder.CreateTable(
name: "bot_positions",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ProposalId = table.Column<Guid>(type: "uuid", nullable: false),
Isin = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Symbol = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: false),
Venue = table.Column<int>(type: "integer", nullable: false),
AlpacaOrderId = table.Column<string>(type: "character varying(60)", maxLength: 60, nullable: true),
ClientOrderId = table.Column<string>(type: "character varying(60)", maxLength: 60, nullable: true),
Direction = table.Column<int>(type: "integer", nullable: false),
Quantity = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
EntryPrice = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
AverageBuyIn = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
InitialStopLoss = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
CurrentStopLoss = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
CurrentPrice = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TakeProfit1 = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TakeProfit2 = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
RealizedPnlEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
TotalFeesEur = table.Column<decimal>(type: "numeric(18,4)", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
ExitPlan = table.Column<string>(type: "jsonb", nullable: false),
OpenedAtUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ClosedAtUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastSyncAtUtc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_bot_positions", x => x.Id);
});
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_bot_portfolio_snapshots_SnapshotDateUtc",
table: "bot_portfolio_snapshots",
column: "SnapshotDateUtc");
migrationBuilder.CreateIndex(
name: "IX_bot_positions_OpenedAtUtc",
table: "bot_positions",
column: "OpenedAtUtc");
migrationBuilder.CreateIndex(
name: "IX_bot_positions_ProposalId",
table: "bot_positions",
column: "ProposalId");
migrationBuilder.CreateIndex(
name: "IX_bot_positions_Status_Venue",
table: "bot_positions",
columns: new[] { "Status", "Venue" });
migrationBuilder.CreateIndex(
name: "IX_DynamicSettings_Key",
table: "DynamicSettings",
column: "Key",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "bot_portfolio_snapshots");
migrationBuilder.DropTable(
name: "bot_positions");
migrationBuilder.DropTable(
name: "DynamicSettings");
}
}
}
@@ -22,160 +22,131 @@ namespace FinlyticBot.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("FinlyticBot.Entities.BotAuditLogEntity", b =>
modelBuilder.Entity("FinlyticBot.Database.Entities.BotPortfolioSnapshotEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<decimal?>("AccountEquity")
b.Property<decimal>("CashEur")
.HasColumnType("decimal(18,4)");
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<decimal?>("CalculatedSize")
.HasColumnType("decimal(18,4)");
b.Property<bool>("IsAccepted")
.HasColumnType("boolean");
b.Property<string>("Reason")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("Symbol")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<DateTime>("Timestamp")
b.Property<DateTime>("CreatedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<string>("TradeId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<decimal>("DailyRealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<int>("OpenPositionsCount")
.HasColumnType("integer");
b.Property<DateTime>("SnapshotDateUtc")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("TotalEquityEur")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("TotalUnrealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("WinRatePercent")
.HasColumnType("decimal(6,2)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("SnapshotDateUtc");
b.HasIndex("Symbol");
b.HasIndex("Timestamp");
b.HasIndex("TradeId");
b.ToTable("BotAuditLogs");
b.ToTable("bot_portfolio_snapshots");
});
modelBuilder.Entity("FinlyticBot.Entities.ExecutedPaperTradeEntity", b =>
modelBuilder.Entity("FinlyticBot.Database.Entities.BotPositionEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<decimal?>("ActualFillPrice")
b.Property<string>("AlpacaOrderId")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<decimal>("AverageBuyIn")
.HasColumnType("decimal(18,4)");
b.Property<Guid?>("AlpacaOrderId")
.HasColumnType("uuid");
b.Property<string>("ClientOrderId")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<decimal>("CalculatedCrv")
.HasColumnType("decimal(18,4)");
b.Property<DateTime?>("ClosedAt")
b.Property<DateTime?>("ClosedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<string>("CompanyName")
b.Property<decimal>("CurrentPrice")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("CurrentStopLoss")
.HasColumnType("decimal(18,4)");
b.Property<int>("Direction")
.HasColumnType("integer");
b.Property<decimal>("EntryPrice")
.HasColumnType("decimal(18,4)");
b.Property<string>("ExitPlan")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
.HasColumnType("jsonb");
b.Property<DateTime?>("FilledAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("InitialStopLoss")
.HasColumnType("decimal(18,4)");
b.Property<string>("Isin")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<DateTime>("PlacedAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("Quantity")
.HasColumnType("decimal(18,4)");
b.Property<decimal>("RealizedPnl")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("RealizedPnlPercent")
.HasColumnType("decimal(18,4)");
b.Property<string>("RejectReason")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("Side")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<decimal>("SignalEntryPrice")
b.Property<DateTime>("LastSyncAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("OpenedAtUtc")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("ProposalId")
.HasColumnType("uuid");
b.Property<decimal>("Quantity")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("SlippagePercent")
b.Property<decimal>("RealizedPnlEur")
.HasColumnType("decimal(18,4)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<decimal>("StopLossPrice")
.HasColumnType("decimal(18,4)");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("Symbol")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<decimal>("TakeProfitPrice1")
b.Property<decimal>("TakeProfit1")
.HasColumnType("decimal(18,4)");
b.Property<decimal?>("TakeProfitPrice2")
b.Property<decimal>("TakeProfit2")
.HasColumnType("decimal(18,4)");
b.Property<string>("TradeId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<decimal>("TotalFeesEur")
.HasColumnType("decimal(18,4)");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<double>("WinRate")
.HasColumnType("double precision");
b.Property<int>("Venue")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("AlpacaOrderId");
b.HasIndex("OpenedAtUtc");
b.HasIndex("Isin");
b.HasIndex("ProposalId");
b.HasIndex("PlacedAt");
b.HasIndex("Status", "Venue");
b.HasIndex("Status");
b.HasIndex("Symbol");
b.HasIndex("TradeId")
.IsUnique();
b.ToTable("ExecutedPaperTrades");
b.ToTable("bot_positions");
});
modelBuilder.Entity("FinlyticCore.Entities.Settings.SettingEntity", b =>