Phase 0.3: ProfitTarget-Take-Profit implementiert (dormant bei 9999)

- SellLogic.IsProfitTargetReached (pure, getestet): currentPrice >= entry*(1+pct/100);
  pct<=0 oder Default 9999 = inaktiv.
- Ladder-Start-Logik konsolidiert: SellLadderService.StartLadderAsync ist jetzt die
  gemeinsame Quelle fuer Master-SELLs (Engine) UND eigene Exits (Profit-Target).
  SellLadderService als Singleton+Hosted registriert; Engine + TraderMonitor
  injizieren es. Engine-SELL-Block ruft nur noch StartLadderAsync (verhaltensgleich).
- TraderMonitorService.CheckProfitTargetsAsync im 30s-Live-Sync: erreicht eine
  Live-Position ihre Schwelle, Exit ueber die Leiter (Startlimit = aktueller Preis,
  ExitReason "Profit Target"). PreRedeemLimit hat Vorrang. Dormant, da ProfitTarget
  projektweit 9999.

169 Tests gruen. Build/Smoke gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-07 17:54:21 +02:00
co-authored by Claude Opus 4.8
parent b378bc3499
commit 395caad11a
6 changed files with 153 additions and 63 deletions
+17
View File
@@ -94,6 +94,23 @@ namespace PolyTrader.Tests
Assert.Equal(expected, LadderIntervalSeconds(isHf));
}
[Theory]
[InlineData(0.50, 0.55, 10, true)] // genau an der Schwelle (entry*1.10)
[InlineData(0.50, 0.60, 10, true)] // darüber
[InlineData(0.50, 0.54, 10, false)] // darunter
[InlineData(0.50, 0.99, 9999, false)] // Default 9999 -> nie erreicht (inaktiv)
[InlineData(0.50, 0.99, 0, false)] // 0 -> deaktiviert
public void IsProfitTargetReached_threshold(double entry, double current, double pct, bool expected)
{
Assert.Equal(expected, IsProfitTargetReached((decimal)current, (decimal)entry, (decimal)pct));
}
[Fact]
public void IsProfitTargetReached_zero_entry_is_false()
{
Assert.False(IsProfitTargetReached(0.9m, 0m, 10m));
}
[Fact]
public void Ladder_walks_down_in_steps_until_floor()
{