Files
PolyTraderSharp/tests/PolyTrader.Tests/SellLogicTests.cs
T
RichardandClaude Opus 4.8 581755029a Testnetz: Micro-Order-Minimum + SELL-Proportionalität extrahiert; SELL-Leiter (Phase 0.1) vorbereitet
Weiter im Muster extrahieren->testen (verhaltensneutral, clob.md):
- CopyTradingRisk.IsBelowPolymarketMinimum (Shares < 5.5 || USDC < 0.10) –
  BUY-Micro-Order-Filter verdrahtet + Tests.
- SellLogic.SellProportion (signalSize/(remaining+signalSize), Denominator<=0 -> 0)
  + Konstante MinSignificantSellRatio (0.30); SELL-Proportionalitätscheck der
  Engine ruft sie jetzt (Charakterisierung, sichert Phase-2-Umbau ab).
- SellLogic-Eskalationsleiter (Phase 0.1, NOCH NICHT verdrahtet): FirstLimit
  (HF-fest/prozentual), Floor (SellFloorPct), NextPrice (relative Stufe, auf Floor
  geclamped), IsAtFloor. Reine Grundlage fuer das spaetere SELL-Wiring.
- Tests: CopyTradingRisk-Minimum (5 Faelle) + SellLogicTests (Proportion +
  Leiter). Gesamt 154 gruen.

Build/Smoke gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:03:44 +02:00

90 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using PolyTrader.Modules.CopyTrading.Logic;
using Xunit;
using static PolyTrader.Modules.CopyTrading.Logic.SellLogic;
namespace PolyTrader.Tests
{
/// <summary>
/// Sicherheitsnetz für die SELL-Logik: Proportionalität (aktuelles Verhalten, Phase-2-Umbau)
/// und die Eskalationsleiter (Phase 0.1 Preis-Stufen, Floor-Clamping).
/// </summary>
public class SellLogicTests
{
// ---------------- SellProportion ----------------
[Fact]
public void SellProportion_is_share_over_total_before_sell()
{
// Master hält noch 300, verkauft 200 -> 200/500 = 0.40
Assert.Equal(0.40m, SellProportion(masterSharesRemaining: 300m, signalSize: 200m));
}
[Fact]
public void SellProportion_small_partial_is_below_threshold()
{
// 498 Rest, 2 verkauft -> 0.004 < 0.30
var ratio = SellProportion(498m, 2m);
Assert.True(ratio < MinSignificantSellRatio);
}
[Fact]
public void SellProportion_full_exit_is_one()
{
Assert.Equal(1.0m, SellProportion(0m, 10m));
}
[Theory]
[InlineData(0, 0)] // gar nichts
[InlineData(-5, 5)] // Denominator 0
[InlineData(-10, 5)] // Denominator negativ
public void SellProportion_guards_non_positive_denominator(double remaining, double signal)
{
Assert.Equal(0m, SellProportion((decimal)remaining, (decimal)signal));
}
// ---------------- Eskalationsleiter ----------------
[Fact]
public void FirstLimit_normal_trader_applies_percentage_discount()
{
// 0.99 * (1 - 2%) = 0.9702
Assert.Equal(0.9702m, FirstLimit(0.99m, isHf: false, maxPriceDifferencePct: 2m));
}
[Fact]
public void FirstLimit_hf_trader_applies_fixed_half_cent_discount()
{
Assert.Equal(0.985m, FirstLimit(0.99m, isHf: true, maxPriceDifferencePct: 99m));
}
[Fact]
public void Floor_is_reference_minus_floor_pct()
{
// 0.99 * (1 - 15%) = 0.8415
Assert.Equal(0.8415m, Floor(0.99m, 15m));
}
[Fact]
public void NextPrice_steps_down_relative_when_above_floor()
{
// 0.90 * (1 - 3%) = 0.873, über Floor 0.80
Assert.Equal(0.873m, NextPrice(0.90m, stepPct: 3m, floor: 0.80m));
}
[Fact]
public void NextPrice_clamps_to_floor()
{
// 0.82 * 0.97 = 0.7954 -> unter Floor -> 0.80
Assert.Equal(0.80m, NextPrice(0.82m, 3m, 0.80m));
}
[Fact]
public void IsAtFloor_is_inclusive()
{
Assert.True(IsAtFloor(0.80m, 0.80m));
Assert.True(IsAtFloor(0.79m, 0.80m));
Assert.False(IsAtFloor(0.81m, 0.80m));
}
}
}