From a0e367e645baf201208d655a4719325c5328ed27 Mon Sep 17 00:00:00 2001 From: bergm Date: Wed, 1 Jul 2026 16:39:28 +0200 Subject: [PATCH] Phase 3d (1/2): TraderMonitorService auf Repositories umgestellt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 Positions-Zugriffe (open_positions_{id}) -> IPositionRepository (FindLive/UpsertLive/DeleteLive). - 1 Market-Upsert -> IMarketRepository. - closed_trades bleibt auf _db (ClosedTrade-Repo folgt in Phase 5). - Verhalten unverändert (Repos bilden Shim-Semantik 1:1 nach); Build 0 Fehler. Co-Authored-By: Claude Opus 4.8 --- services/TraderMonitorService.cs | 35 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/services/TraderMonitorService.cs b/services/TraderMonitorService.cs index c809a13..9afc326 100644 --- a/services/TraderMonitorService.cs +++ b/services/TraderMonitorService.cs @@ -1,5 +1,6 @@ using System; using MongoDB.Driver; +using PolyTrader.Core.Persistence; using PolyTraderSharp.Extensions; using System.Collections.Concurrent; using System.Linq; @@ -21,7 +22,9 @@ namespace PolyTraderSharp.Services private readonly ChannelWriter _closedTradeWriter; private readonly TerminalLogger _logger; private readonly IMongoDatabase? _db; - + private readonly IPositionRepository _positionRepo; + private readonly IMarketRepository _marketRepo; + // Prevents duplicates. Fast O(1) lookup cache to prevent DB spam. private readonly ConcurrentDictionary _processedTxHashes = new(); private DateTime _lastHashCleanup = DateTime.UtcNow; @@ -42,6 +45,8 @@ namespace PolyTraderSharp.Services ChannelWriter signalWriter, ChannelWriter closedTradeWriter, TerminalLogger logger, + IPositionRepository positionRepo, + IMarketRepository marketRepo, IMongoDatabase? db = null) { _state = state; @@ -50,6 +55,8 @@ namespace PolyTraderSharp.Services _signalWriter = signalWriter; _closedTradeWriter = closedTradeWriter; _logger = logger; + _positionRepo = positionRepo; + _marketRepo = marketRepo; _db = db; } @@ -332,8 +339,7 @@ namespace PolyTraderSharp.Services { _ = Task.Run(() => { try { - var mdColl = _db.GetCollection("markets"); - mdColl.Upsert(coldItem); + _marketRepo.Upsert(coldItem); } catch { } // Failsafe }); } @@ -549,8 +555,7 @@ namespace PolyTraderSharp.Services { try { - var liveCol = _db.GetCollection($"open_positions_{acc.AccountId}"); - var dbPos = liveCol.LiteFindOne(x => x.TokenId == asset); + var dbPos = _positionRepo.FindLive(acc.AccountId, asset); if (dbPos != null && dbPos.SourceTraderId > 0) { resolvedSourceId = dbPos.SourceTraderId; @@ -705,7 +710,7 @@ namespace PolyTraderSharp.Services existing.CurrentValueUsd = curValue; if (expiry.HasValue) existing.ExpiryDate = expiry; - if (_db != null) { try { _db.GetCollection($"open_positions_{acc.AccountId}").Upsert(existing); } catch { } } + try { _positionRepo.UpsertLive(acc.AccountId, existing); } catch { } // Auto-Redeem Fallback via REST if (acc.PreRedeemLimit > 0 && curPrice >= acc.PreRedeemLimit && acc.IsActive) @@ -791,8 +796,7 @@ namespace PolyTraderSharp.Services { try { - var liveCol = _db.GetCollection($"open_positions_{acc.AccountId}"); - var dbPos = liveCol.LiteFindOne(x => x.TokenId == asset); + var dbPos = _positionRepo.FindLive(acc.AccountId, asset); if (dbPos != null) { if (dbPos.SourceTraderId > 0) @@ -829,7 +833,7 @@ namespace PolyTraderSharp.Services OpenedAt = resolvedOpenedAt }; acc.OpenPositions.TryAdd(asset, newPos); - if (_db != null) { try { _db.GetCollection($"open_positions_{acc.AccountId}").Upsert(newPos); } catch { } } + try { _positionRepo.UpsertLive(acc.AccountId, newPos); } catch { } if (resolvedTraderId > 0) _logger.Info($"🌐 Live Position erkannt: {title} ({newPos.Outcome}) - ${amountUsd} - Account: {acc.Name} [Zugeordnet: {resolvedTraderName}]"); @@ -857,8 +861,7 @@ namespace PolyTraderSharp.Services { try { - var liveCol = _db.GetCollection($"open_positions_{acc.AccountId}"); - var dbPos = liveCol.LiteFindOne(x => x.TokenId == k); + var dbPos = _positionRepo.FindLive(acc.AccountId, k); if (dbPos != null && dbPos.SourceTraderId > 0) { removedPos.SourceTraderId = dbPos.SourceTraderId; @@ -880,8 +883,8 @@ namespace PolyTraderSharp.Services if (matchedClose.HasValue) { acc.OpenPositions.TryRemove(k, out _); // Safe removal! - if (_db != null) { try { _db.GetCollection($"open_positions_{acc.AccountId}").Delete(k); } catch { } } - + try { _positionRepo.DeleteLive(acc.AccountId, k); } catch { } + decimal realizedPnl = 0m; DateTime resolvedClosedAt = DateTime.UtcNow; @@ -953,8 +956,8 @@ namespace PolyTraderSharp.Services if (isClosed) { acc.OpenPositions.TryRemove(k, out _); // Safe removal! - if (_db != null) { try { _db.GetCollection($"open_positions_{acc.AccountId}").Delete(k); } catch { } } - + try { _positionRepo.DeleteLive(acc.AccountId, k); } catch { } + decimal exitPrice = isWinner ? 1.0m : 0.0m; decimal exitUsd = removedPos.Size * exitPrice; decimal realizedPnl = exitUsd - removedPos.AmountUsd; @@ -1029,7 +1032,7 @@ namespace PolyTraderSharp.Services { if (acc.OpenPositions.TryRemove(k, out _)) { - if (_db != null) { try { _db.GetCollection($"open_positions_{acc.AccountId}").Delete(k); } catch { } } + try { _positionRepo.DeleteLive(acc.AccountId, k); } catch { } _logger.Info($"🌐 Live Position {removedPos.MarketQuestion} final entfernt (Ext. Verkauft/Wartend nach {ageMinutes:F0} Min.)"); } }