diff --git a/src/IBKRTrader.Core/Capital/CapitalService.cs b/src/IBKRTrader.Core/Capital/CapitalService.cs
index 135c764..ba2e5ac 100644
--- a/src/IBKRTrader.Core/Capital/CapitalService.cs
+++ b/src/IBKRTrader.Core/Capital/CapitalService.cs
@@ -214,8 +214,9 @@ public sealed class CapitalService : ICapitalService
///
public Task SettleReservationAsync(
- long reservationId, int filledQuantity, decimal actualAmount, CancellationToken ct = default) =>
- _reservations.SettleAsync(reservationId, filledQuantity, actualAmount, ct);
+ long reservationId, int filledQuantity, decimal actualAmount, string? brokerOrderId = null,
+ CancellationToken ct = default) =>
+ _reservations.SettleAsync(reservationId, filledQuantity, actualAmount, brokerOrderId, ct);
///
public Task CancelReservationAsync(long reservationId, string reason, CancellationToken ct = default) =>
diff --git a/src/IBKRTrader.Core/Capital/ICapitalService.cs b/src/IBKRTrader.Core/Capital/ICapitalService.cs
index 32d9604..fa043b6 100644
--- a/src/IBKRTrader.Core/Capital/ICapitalService.cs
+++ b/src/IBKRTrader.Core/Capital/ICapitalService.cs
@@ -34,7 +34,8 @@ public interface ICapitalService
/// (mit Puffer) und tatsächlichem Bedarf fließt zurück in den Pool.
///
Task SettleReservationAsync(
- long reservationId, int filledQuantity, decimal actualAmount, CancellationToken ct = default);
+ long reservationId, int filledQuantity, decimal actualAmount, string? brokerOrderId = null,
+ CancellationToken ct = default);
/// Gibt eine Bindung frei, ohne dass ausgeführt wurde.
Task CancelReservationAsync(long reservationId, string reason, CancellationToken ct = default);
diff --git a/src/IBKRTrader.Core/Capital/ReservationService.cs b/src/IBKRTrader.Core/Capital/ReservationService.cs
index 7dbc36e..b3e8840 100644
--- a/src/IBKRTrader.Core/Capital/ReservationService.cs
+++ b/src/IBKRTrader.Core/Capital/ReservationService.cs
@@ -189,7 +189,8 @@ public sealed class ReservationService
/// Tatsächlich ausgeführte Menge; 0 = nichts ausgeführt.
/// Tatsächlich benötigtes Kapital (bei Teilfüllung anteilig).
public async Task SettleAsync(
- long id, int filledQuantity, decimal actualAmount, CancellationToken ct = default)
+ long id, int filledQuantity, decimal actualAmount, string? brokerOrderId = null,
+ CancellationToken ct = default)
{
await using var db = await _dbf.CreateDbContextAsync(ct);
var row = await db.Reservations.FindAsync([id], ct);
@@ -197,6 +198,12 @@ public sealed class ReservationService
row.UpdatedAt = DateTime.UtcNow;
+ // Die Order-ID spaetestens hier festhalten. Im synchronen Pfad gibt es keinen beobachtbaren
+ // Zeitpunkt zwischen Absenden und Endstatus, an dem MarkSubmittedAsync greifen koennte -
+ // ohne diese Zeile bliebe BrokerOrderId leer, und der Abgleich beim Neustart haette nichts,
+ // woran er eine Bindung einer Order zuordnen koennte.
+ if (!string.IsNullOrWhiteSpace(brokerOrderId)) row.BrokerOrderId = brokerOrderId;
+
if (filledQuantity <= 0)
{
row.State = ReservationState.Cancelled;
diff --git a/src/IBKRTrader.Core/Persistence/Ef/CoreDbContext.cs b/src/IBKRTrader.Core/Persistence/Ef/CoreDbContext.cs
index bbce4c3..8ed19df 100644
--- a/src/IBKRTrader.Core/Persistence/Ef/CoreDbContext.cs
+++ b/src/IBKRTrader.Core/Persistence/Ef/CoreDbContext.cs
@@ -56,7 +56,12 @@ public class CoreDbContext : DbContext
e.ToTable("core_trade_history");
e.HasKey(x => x.Id);
e.Property(x => x.Module).HasMaxLength(50);
- e.Property(x => x.Symbol).HasMaxLength(20);
+ // 64 wie core_position.ContractKey: hier steht seit der Optionserweiterung der
+ // Instrumentenschluessel und nicht mehr das nackte Ticker-Symbol. Bei 20 Zeichen wuerde
+ // "MSFT|20260918|P|302.5" auf "MSFT|20260918|P|302." gekuerzt - und das laesst sich als
+ // Strike 302 lesen. Ein still verfaelschter Eintrag in der Handelshistorie ist
+ // schlimmer als gar keiner.
+ e.Property(x => x.Symbol).HasMaxLength(64);
e.Property(x => x.Action).HasMaxLength(10);
e.Property(x => x.SignalId).HasMaxLength(64);
e.Property(x => x.IbkrOrderId).HasMaxLength(100);
diff --git a/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.Designer.cs b/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.Designer.cs
new file mode 100644
index 0000000..b28f1b2
--- /dev/null
+++ b/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.Designer.cs
@@ -0,0 +1,598 @@
+//
+using System;
+using IBKRTrader.Core.Persistence.Ef;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace IBKRTrader.Core.Persistence.Ef.Migrations
+{
+ [DbContext(typeof(CoreDbContext))]
+ [Migration("20260904134622_WidenTradeHistorySymbol")]
+ partial class WidenTradeHistorySymbol
+ {
+ ///
+ 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("IBKRTrader.Core.IBKR.IBKRExternalIdentifier", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("InstrumentId")
+ .HasColumnType("bigint");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Ticker")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Source", "Ticker");
+
+ b.HasIndex("InstrumentId", "Source", "Ticker")
+ .IsUnique();
+
+ b.ToTable("core_ibkr_external_identifiers", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.IBKR.IBKRInstrument", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CompanyName")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Currency")
+ .IsRequired()
+ .HasMaxLength(5)
+ .HasColumnType("varchar(5)");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Exchange")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("IbkrConid")
+ .HasColumnType("bigint");
+
+ b.Property("Industry")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("Isin")
+ .HasMaxLength(12)
+ .HasColumnType("varchar(12)");
+
+ b.Property("LastFetched")
+ .HasColumnType("datetime(6)");
+
+ b.Property("PrimaryExchange")
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("SecType")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("Sector")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Active");
+
+ b.HasIndex("IbkrConid")
+ .IsUnique();
+
+ b.HasIndex("Symbol");
+
+ b.ToTable("core_ibkr_instruments", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.IBKR.IBKRMarketBar", b =>
+ {
+ b.Property("InstrumentId")
+ .HasColumnType("bigint");
+
+ b.Property("BarSize")
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime(6)");
+
+ b.Property("BarCount")
+ .HasColumnType("int");
+
+ b.Property("Close")
+ .HasPrecision(12, 6)
+ .HasColumnType("decimal(12,6)");
+
+ b.Property("High")
+ .HasPrecision(12, 6)
+ .HasColumnType("decimal(12,6)");
+
+ b.Property("Low")
+ .HasPrecision(12, 6)
+ .HasColumnType("decimal(12,6)");
+
+ b.Property("Open")
+ .HasPrecision(12, 6)
+ .HasColumnType("decimal(12,6)");
+
+ b.Property("Volume")
+ .HasColumnType("bigint");
+
+ b.Property("Wap")
+ .HasPrecision(12, 6)
+ .HasColumnType("decimal(12,6)");
+
+ b.HasKey("InstrumentId", "BarSize", "Timestamp");
+
+ b.HasIndex("Timestamp");
+
+ b.ToTable("core_ibkr_market_data", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreBudget", b =>
+ {
+ b.Property("Module")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("MaxPerTrade")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("TotalBudget")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("UsedBudget")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.HasKey("Module");
+
+ b.ToTable("core_budget", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreDecisionRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ContextJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Decision")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Module")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)");
+
+ b.Property("Side")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("SignalId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("SignalPrice")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SignalId");
+
+ b.HasIndex("Module", "Timestamp");
+
+ b.ToTable("core_decision_journal", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreOrderEvent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("DetailsJson")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EventType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Module")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OrderType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Price")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Quantity")
+ .HasColumnType("int");
+
+ b.Property("Response")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Side")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("SignalId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SignalId");
+
+ b.HasIndex("Symbol", "Timestamp");
+
+ b.ToTable("core_order_events", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CorePosition", b =>
+ {
+ b.Property("Module")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("ContractKey")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("AvgPrice")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Currency")
+ .IsRequired()
+ .HasMaxLength(5)
+ .HasColumnType("varchar(5)");
+
+ b.Property("Expiry")
+ .HasColumnType("date");
+
+ b.Property("Kind")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("Multiplier")
+ .HasColumnType("int");
+
+ b.Property("Quantity")
+ .HasColumnType("int");
+
+ b.Property("Right")
+ .HasMaxLength(1)
+ .HasColumnType("varchar(1)");
+
+ b.Property("Strike")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Module", "ContractKey");
+
+ b.HasIndex("Symbol");
+
+ b.ToTable("core_position", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreReservation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Amount")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Book")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BrokerOrderId")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("ContractKey")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Currency")
+ .IsRequired()
+ .HasMaxLength(5)
+ .HasColumnType("varchar(5)");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Note")
+ .HasColumnType("text");
+
+ b.Property("Quantity")
+ .HasColumnType("int");
+
+ b.Property("Shares")
+ .HasColumnType("int");
+
+ b.Property("Side")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("SignalId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("State")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BrokerOrderId");
+
+ b.HasIndex("ExpiresAt");
+
+ b.HasIndex("SignalId", "ContractKey")
+ .IsUnique();
+
+ b.HasIndex("State", "Book");
+
+ b.ToTable("core_reservation", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreSetting", b =>
+ {
+ b.Property("Key")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Value")
+ .HasColumnType("text");
+
+ b.HasKey("Key");
+
+ b.ToTable("core_settings", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreTrade", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("IbkrOrderId")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("Module")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Notes")
+ .HasColumnType("longtext");
+
+ b.Property("Price")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("Quantity")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("SignalId")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("Status")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("TotalValue")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("TradedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Module");
+
+ b.HasIndex("SignalId");
+
+ b.HasIndex("Symbol");
+
+ b.ToTable("core_trade_history", (string)null);
+ });
+
+ modelBuilder.Entity("IBKRTrader.Core.Persistence.Entities.CoreWorkerLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("FinishedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("Module")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("StartedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("WorkerName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkerName", "StartedAt");
+
+ b.ToTable("core_worker_log", (string)null);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.cs b/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.cs
new file mode 100644
index 0000000..41dbfa0
--- /dev/null
+++ b/src/IBKRTrader.Core/Persistence/Ef/Migrations/20260904134622_WidenTradeHistorySymbol.cs
@@ -0,0 +1,42 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace IBKRTrader.Core.Persistence.Ef.Migrations
+{
+ ///
+ public partial class WidenTradeHistorySymbol : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "Symbol",
+ table: "core_trade_history",
+ type: "varchar(64)",
+ maxLength: 64,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "varchar(20)",
+ oldMaxLength: 20)
+ .Annotation("MySql:CharSet", "utf8mb4")
+ .OldAnnotation("MySql:CharSet", "utf8mb4");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "Symbol",
+ table: "core_trade_history",
+ type: "varchar(20)",
+ maxLength: 20,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "varchar(64)",
+ oldMaxLength: 64)
+ .Annotation("MySql:CharSet", "utf8mb4")
+ .OldAnnotation("MySql:CharSet", "utf8mb4");
+ }
+ }
+}
diff --git a/src/IBKRTrader.Core/Persistence/Ef/Migrations/CoreDbContextModelSnapshot.cs b/src/IBKRTrader.Core/Persistence/Ef/Migrations/CoreDbContextModelSnapshot.cs
index f260434..25a4103 100644
--- a/src/IBKRTrader.Core/Persistence/Ef/Migrations/CoreDbContextModelSnapshot.cs
+++ b/src/IBKRTrader.Core/Persistence/Ef/Migrations/CoreDbContextModelSnapshot.cs
@@ -530,8 +530,8 @@ namespace IBKRTrader.Core.Persistence.Ef.Migrations
b.Property("Symbol")
.IsRequired()
- .HasMaxLength(20)
- .HasColumnType("varchar(20)");
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
b.Property("TotalValue")
.HasPrecision(18, 4)
diff --git a/src/IBKRTrader.Core/Trading/ExecutionService.cs b/src/IBKRTrader.Core/Trading/ExecutionService.cs
index 8aa498a..c64dda5 100644
--- a/src/IBKRTrader.Core/Trading/ExecutionService.cs
+++ b/src/IBKRTrader.Core/Trading/ExecutionService.cs
@@ -155,7 +155,8 @@ public sealed class ExecutionService : IExecutionService
// 9. Bindung abschließen. Reserviert wurde mit Puffer, ausgeführt zum echten Preis – die
// Differenz fließt zurück in den Pool.
var actualAmount = result.FilledQuantity * result.AvgFillPrice * signal.Instrument.Multiplier;
- await _capital.SettleReservationAsync(reservationId, result.FilledQuantity, actualAmount, ct);
+ await _capital.SettleReservationAsync(
+ reservationId, result.FilledQuantity, actualAmount, result.OrderId, ct);
Journal(signal, TradeDecision.Executed, DecisionReason.OrderPlaced,
$"Ausgeführt: {sideStr} {result.FilledQuantity}x {signal.Instrument.Key} @ {result.AvgFillPrice:F2}",
diff --git a/tests/IBKRTrader.Tests/Trading/ExecutionServiceTests.cs b/tests/IBKRTrader.Tests/Trading/ExecutionServiceTests.cs
index c0db0ea..1ad68b6 100644
--- a/tests/IBKRTrader.Tests/Trading/ExecutionServiceTests.cs
+++ b/tests/IBKRTrader.Tests/Trading/ExecutionServiceTests.cs
@@ -243,8 +243,9 @@ public class ExecutionServiceTests
await CreateSut().ExecuteAsync(BuySignal);
// Reserviert wurde mit Puffer, ausgefuehrt zum echten Preis: 5 x 100 = 500 fliessen als
- // tatsaechlicher Bedarf zurueck, der Rest wird freigegeben.
- await _capital.Received(1).SettleReservationAsync(1, 5, 500m, Arg.Any());
+ // tatsaechlicher Bedarf zurueck, der Rest wird freigegeben. Die Order-ID gehoert dazu -
+ // ohne sie kann der Abgleich beim Neustart keine Bindung einer Order zuordnen.
+ await _capital.Received(1).SettleReservationAsync(1, 5, 500m, "O1", Arg.Any());
}
[Fact]