Neues Strategiemodul PolyTrader.Modules.ResolutionFarming (IPolyTraderModule, Name=ResolutionFarming, DbPrefix=rf_), in Solution/App/Tests + beide Modul-Listen in Program.cs eingebunden. Skelett laedt (RegisterServices/UI noch no-op). Geldkritische Entscheidungslogik pur und vollstaendig unit-getestet: - FarmingRiskEngine: Netto-Edge nach Fees (NetEdge/NetEdgePct/HasEdge), Positionsgroesse unter Markt-/Cluster-/Gesamt-Exposure-Limits (AllowedPositionUsd), Kill-Switch, Tages-Drossel. - FarmingScanner: Preisband, Kategorie-Whitelist, Blacklist, Cluster-Key (korrelierte Favoriten teilen einen Cluster), Kandidaten-Score. - FarmingFillModel: Shares fuer Budget (2-Dezimal-Floor), Resolve-PnL (Auszahlung - Kosten - Entry-Fee, Maker/Taker), Einstiegskosten inkl. Fee. Nutzt Core.FeeModel. - RfSettings (rf_settings) mit konservativen Defaults + PropertyGrid-Attributen. 39 neue Tests. Build 0 Fehler, 283 Tests gruen, --smoke-ui ok. Persistenz (DbContext/Migration/Repos), Scanner-/Monitor-Jobs, Execution und UI folgen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
1.7 KiB
C#
50 lines
1.7 KiB
C#
using PolyTrader.Modules.ResolutionFarming.Logic;
|
|
using Xunit;
|
|
using static PolyTrader.Modules.ResolutionFarming.Logic.FarmingFillModel;
|
|
|
|
namespace PolyTrader.Tests
|
|
{
|
|
/// <summary>Sicherheitsnetz für das Fill-/PnL-Modell (Demo-Realismus: Fee beim Einstieg, Auszahlung bei Auflösung).</summary>
|
|
public class FarmingFillModelTests
|
|
{
|
|
[Fact]
|
|
public void SharesForBudget_floors_to_two_decimals()
|
|
{
|
|
// 25 / 0.95 = 26.315... -> 26.31
|
|
Assert.Equal(26.31m, SharesForBudget(25m, 0.95m));
|
|
Assert.Equal(0m, SharesForBudget(0m, 0.95m));
|
|
Assert.Equal(0m, SharesForBudget(25m, 0m));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvePnl_winner_maker_pays_no_fee()
|
|
{
|
|
// 100 Shares @ 0.95, Maker (0 Fee), Gewinner: 100 - 95 - 0 = 5
|
|
Assert.Equal(5m, ResolvePnl(100m, 0.95m, 0, isWinner: true));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvePnl_winner_taker_subtracts_fee()
|
|
{
|
|
// 100 @ 0.95, Taker 100 bps: cost 95, fee 0.95, payout 100 -> 100 - 95 - 0.95 = 4.05
|
|
Assert.Equal(4.05m, ResolvePnl(100m, 0.95m, 100, isWinner: true));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvePnl_loser_loses_cost_and_fee()
|
|
{
|
|
// Verlierer: payout 0 -> -(cost) - fee = -95 - 0.95 = -95.95
|
|
Assert.Equal(-95.95m, ResolvePnl(100m, 0.95m, 100, isWinner: false));
|
|
}
|
|
|
|
[Fact]
|
|
public void EntryCostWithFee_adds_taker_fee()
|
|
{
|
|
// 100 @ 0.95, 100 bps: 95 + 0.95 = 95.95
|
|
Assert.Equal(95.95m, EntryCostWithFee(100m, 0.95m, 100));
|
|
// Maker: nur cost
|
|
Assert.Equal(95m, EntryCostWithFee(100m, 0.95m, 0));
|
|
}
|
|
}
|
|
}
|