Engine-Testabdeckung (Guards) + K3-Korrektur am echten Bug-Ort
Testabdeckung fuer den geldkritischen Engine-Pfad (bisher 0 Tests), da die Fable-Guards zwischen Services entstehen und Unit-Tests sie nicht fangen: - Engine._clob -> IClobClient (verhaltensneutral, DI registriert IClobClient bereits); ProcessAccountOrderAsync internal. FakeMarketRepository/FakeAccountRepository ergaenzt. - 7 Integrationstests (CopyTradingEngineTests) ueber gemockten CLOB: H3 BUY-Skip bei ExitPending, Doppel-SELL-Guard, K3 System-Close (TraderId==0) schliesst Fremd-Position, Fremd-Trader-SELL bleibt abgewiesen, H2 Cleanup schont Leiter (+ Kontrast ohne Leiter). DABEI ECHTEN BUG GEFANGEN: Der K3-Fix aus Slice 3 sass an der falschen Stelle (IsAuthorizedSell nach dem Position-Remove, Zeile ~643) – der eigentliche Ownership-Check ist der fruehe inPortfolio-Lookup (Zeile 437, p.SourceTraderId == signal.TraderId), der System-Signale schon vorher mit early return abwies. Fix jetzt am richtigen Ort; der downstream-Check bleibt als Defense-in-depth. Ohne den Engine-Test waere das unentdeckt geblieben. Build 0 Fehler, 242 Tests gruen, --smoke-ui ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
782c08a860
commit
f4045f08e1
@@ -19,7 +19,7 @@ namespace PolyTraderSharp.Services
|
||||
private readonly ChannelReader<CopySignal> _signalReader;
|
||||
private readonly ChannelWriter<ClosedTrade> _closedTradeWriter;
|
||||
private readonly TerminalLogger _logger;
|
||||
private readonly PolymarketClobClient _clob;
|
||||
private readonly IClobClient _clob;
|
||||
private readonly PolymarketApiService _api;
|
||||
private readonly IPositionRepository _positionRepo;
|
||||
private readonly IMarketRepository _marketRepo;
|
||||
@@ -34,7 +34,7 @@ namespace PolyTraderSharp.Services
|
||||
ChannelReader<CopySignal> signalReader,
|
||||
ChannelWriter<ClosedTrade> closedTradeWriter,
|
||||
TerminalLogger logger,
|
||||
PolymarketClobClient clob,
|
||||
IClobClient clob,
|
||||
PolymarketApiService api,
|
||||
IPositionRepository positionRepo,
|
||||
IMarketRepository marketRepo,
|
||||
@@ -219,7 +219,7 @@ namespace PolyTraderSharp.Services
|
||||
await Task.WhenAll(accountTasks);
|
||||
}
|
||||
|
||||
private async Task ProcessAccountOrderAsync(AccountState account, TrackedTrader? trader, CopySignal signal, bool isNegRisk)
|
||||
internal async Task ProcessAccountOrderAsync(AccountState account, TrackedTrader? trader, CopySignal signal, bool isNegRisk)
|
||||
{
|
||||
// Copytrading-Detail-Einstellungen (Limits) dieses Accounts.
|
||||
var settings = _copyState.GetAccountSettings(account.AccountId);
|
||||
@@ -434,9 +434,12 @@ namespace PolyTraderSharp.Services
|
||||
{
|
||||
// PRE-FLIGHT SELL Check: Exists in portfolio AND opened by the SAME master trader?
|
||||
// CRITICAL: We must NOT sell a position opened by Trader A based on a SELL signal from Trader B.
|
||||
var inPortfolio = account.OpenPositions.Values.FirstOrDefault(p =>
|
||||
// K3: System-Signale (TraderId == 0, Demo-Auto-Close bei Marktauflösung) sind vom
|
||||
// Ownership-Check ausgenommen (CopyTradingRisk.IsAuthorizedSell) – sonst wird die Position
|
||||
// hier als "gehört anderem Trader" abgewiesen und schließt bei Resolution nie.
|
||||
var inPortfolio = account.OpenPositions.Values.FirstOrDefault(p =>
|
||||
(p.TokenId == signal.TokenId || (p.MarketSlug == signal.MarketSlug && p.Outcome == signal.Outcome))
|
||||
&& p.SourceTraderId == signal.TraderId);
|
||||
&& CopyTradingRisk.IsAuthorizedSell(signal.TraderId, p.SourceTraderId));
|
||||
if (inPortfolio == null)
|
||||
{
|
||||
// Check if position exists but belongs to a different trader (for clearer logging)
|
||||
|
||||
Reference in New Issue
Block a user