CopyTrading Slice 1: Settings-Fundament + detaillierte Erklärungen

Umsetzung des Fable-Plans, Start mit dem risikoarmen Settings-Fundament
(kein Hot-Path/CLOB-Verhalten geändert):

- Alle Copytrading-Settings (alt + neu) haben jetzt [Description]/[DisplayName] ->
  im PropertyGrid als Erklärung sichtbar (Richards Vorgabe). Test erzwingt, dass
  jede einstellbare Option eine Beschreibung trägt.
- ProfitTarget-Default -> 9999 (praktisch deaktiviert); Migration setzt zusätzlich
  bestehende Zeilen per SQL auf 9999 (Entscheidung 2). Take-Profit-LOGIK folgt.
- Neue Account-Settings (noch nicht verdrahtet, für Phase 0.1/1.3/2):
  SellFloorPct (15), MaxSpreadPct (5), MinSellRatioPct (10).
- Neue Master-Trader-Settings: AutoPauseEnabled (Default AN, per Master abschaltbar,
  Entscheidung 3) + MakerEntry (Default aus, Entscheidung 4).
- EF-Migration AddCopytradingBehaviorSettings (neue Spalten + sinnvolle Defaults
  fuer Bestandszeilen) erstellt und auf MySQL angewendet.
- Erklärung dokumentiert einen gefundenen Skalen-Verdacht: PreRedeemLimit wird
  gegen den 0-1-Preis verglichen; Alt-Werte 99.5 triggern nie (-> ggf. 0.995).

Tests: 86 gruen. Build/Smoke gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-07 09:44:50 +02:00
co-authored by Claude Opus 4.8
parent 92a88e8be8
commit 38f609ed31
8 changed files with 546 additions and 13 deletions
@@ -86,6 +86,9 @@ namespace PolyTrader.Modules.CopyTrading.Persistence.Ef
e.Property(x => x.perMaxTime24h).HasPrecision(18, 6);
e.Property(x => x.perMaxTime72h).HasPrecision(18, 6);
e.Property(x => x.perMaxTimeNone).HasPrecision(18, 6);
e.Property(x => x.SellFloorPct).HasPrecision(18, 6);
e.Property(x => x.MaxSpreadPct).HasPrecision(18, 6);
e.Property(x => x.MinSellRatioPct).HasPrecision(18, 6);
});
b.Entity<MasterTraderHistoryRecord>(e =>
@@ -0,0 +1,270 @@
// <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.Modules.CopyTrading.Persistence.Ef;
#nullable disable
namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
{
[DbContext(typeof(CopyTradingDbContext))]
[Migration("20260707073736_AddCopytradingBehaviorSettings")]
partial class AddCopytradingBehaviorSettings
{
/// <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.ClosedTrade", b =>
{
b.Property<int>("TradeId")
.HasColumnType("int");
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>("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<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<int>("SourceTraderId")
.HasColumnType("int");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<decimal>("TotalFees")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.HasKey("TradeId");
b.HasIndex("AccountId");
b.HasIndex("SourceTraderId");
b.HasIndex("TokenId");
b.ToTable("mod_copytrading_closed_trades", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.CopyTradingAccountSettings", b =>
{
b.Property<int>("AccountId")
.HasColumnType("int");
b.Property<decimal>("MaxBuyPrice")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("MaxPriceDifference")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("MaxSpreadPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("MinSellRatioPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("PerMarketLimit")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("PerMasterLimit")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("PreRedeemLimit")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("ProfitTarget")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("SellFloorPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("perMaxTime24h")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("perMaxTime6h")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("perMaxTime72h")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("perMaxTimeNone")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.HasKey("AccountId");
b.ToTable("mod_copytrading_account_settings", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.MasterTraderHistoryRecord", b =>
{
b.Property<string>("Id")
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<DateTime>("ClosedAt")
.HasColumnType("datetime(6)");
b.Property<decimal>("RealizedPnl")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<string>("TokenId")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("varchar(120)");
b.Property<int>("TraderId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ClosedAt");
b.HasIndex("TraderId");
b.ToTable("mod_copytrading_mt_history", (string)null);
});
modelBuilder.Entity("PolyTraderSharp.Models.TrackedTrader", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("AssignedAccountIds")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("AutoPauseEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsHidden")
.HasColumnType("tinyint(1)");
b.Property<bool>("MakerEntry")
.HasColumnType("tinyint(1)");
b.Property<string>("Reasoning")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<double>("TotalPnl")
.HasColumnType("double");
b.Property<int>("TotalTrades")
.HasColumnType("int");
b.Property<string>("WalletAddress")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<int>("WinningTrades")
.HasColumnType("int");
b.Property<double>("Winrate30t")
.HasColumnType("double");
b.HasKey("Id");
b.ToTable("mod_copytrading_traders", (string)null);
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,83 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
{
/// <inheritdoc />
public partial class AddCopytradingBehaviorSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "AutoPauseEnabled",
table: "mod_copytrading_traders",
type: "tinyint(1)",
nullable: false,
defaultValue: true);
migrationBuilder.AddColumn<bool>(
name: "MakerEntry",
table: "mod_copytrading_traders",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<decimal>(
name: "MaxSpreadPct",
table: "mod_copytrading_account_settings",
type: "decimal(18,6)",
precision: 18,
scale: 6,
nullable: false,
defaultValue: 5m);
migrationBuilder.AddColumn<decimal>(
name: "MinSellRatioPct",
table: "mod_copytrading_account_settings",
type: "decimal(18,6)",
precision: 18,
scale: 6,
nullable: false,
defaultValue: 10m);
migrationBuilder.AddColumn<decimal>(
name: "SellFloorPct",
table: "mod_copytrading_account_settings",
type: "decimal(18,6)",
precision: 18,
scale: 6,
nullable: false,
defaultValue: 15m);
// Entscheidung Richard: ProfitTarget zunächst überall auf 9999 (praktisch deaktiviert),
// bis die Take-Profit-Logik (Phase 0.3) scharf geschaltet wird.
migrationBuilder.Sql("UPDATE mod_copytrading_account_settings SET ProfitTarget = 9999;");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AutoPauseEnabled",
table: "mod_copytrading_traders");
migrationBuilder.DropColumn(
name: "MakerEntry",
table: "mod_copytrading_traders");
migrationBuilder.DropColumn(
name: "MaxSpreadPct",
table: "mod_copytrading_account_settings");
migrationBuilder.DropColumn(
name: "MinSellRatioPct",
table: "mod_copytrading_account_settings");
migrationBuilder.DropColumn(
name: "SellFloorPct",
table: "mod_copytrading_account_settings");
}
}
}
@@ -120,6 +120,14 @@ namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("MaxSpreadPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("MinSellRatioPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("PerMarketLimit")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
@@ -136,6 +144,10 @@ namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("SellFloorPct")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
b.Property<decimal>("perMaxTime24h")
.HasPrecision(18, 6)
.HasColumnType("decimal(18,6)");
@@ -196,6 +208,9 @@ namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<bool>("AutoPauseEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(64)
@@ -217,6 +232,9 @@ namespace PolyTrader.Modules.CopyTrading.Persistence.Ef.Migrations
b.Property<bool>("IsHidden")
.HasColumnType("tinyint(1)");
b.Property<bool>("MakerEntry")
.HasColumnType("tinyint(1)");
b.Property<string>("Reasoning")
.IsRequired()
.HasMaxLength(1000)