Phase 3d (2/2): CopyTradingEngine auf Repositories umgestellt

- MarketCache-Preload + Market-Hydration -> IMarketRepository
  (GetActive/FindByTokenId/Upsert).
- Demo-/Live-Positionen -> IPositionRepository (UpsertDemo/UpsertLive/DeleteDemo).
- Account-Persistenz -> IAccountRepository.
- _db (IMongoDatabase) vollständig aus CopyTradingEngine entfernt.
- Verhalten unverändert; Build 0 Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
bergm
2026-07-01 16:42:18 +02:00
co-authored by Claude Opus 4.8
parent a0e367e645
commit 0c6fc6a2af
+21 -22
View File
@@ -1,5 +1,6 @@
using System;
using MongoDB.Driver;
using PolyTrader.Core.Persistence;
using PolyTraderSharp.Extensions;
using System.Threading;
using System.Threading.Channels;
@@ -20,7 +21,9 @@ namespace PolyTraderSharp.Services
private readonly TerminalLogger _logger;
private readonly PolymarketClobClient _clob;
private readonly PolymarketApiService _api;
private readonly IMongoDatabase? _db;
private readonly IPositionRepository _positionRepo;
private readonly IMarketRepository _marketRepo;
private readonly IAccountRepository _accountRepo;
private readonly ConcurrentDictionary<int, SemaphoreSlim> _accountSemaphores = new();
private readonly ConcurrentDictionary<int, DateTime> _lastInactiveLogPerTrader = new();
@@ -31,7 +34,9 @@ namespace PolyTraderSharp.Services
TerminalLogger logger,
PolymarketClobClient clob,
PolymarketApiService api,
IMongoDatabase? db = null)
IPositionRepository positionRepo,
IMarketRepository marketRepo,
IAccountRepository accountRepo)
{
_state = state;
_signalReader = signalReader;
@@ -39,18 +44,17 @@ namespace PolyTraderSharp.Services
_logger = logger;
_clob = clob;
_api = api;
_db = db;
_positionRepo = positionRepo;
_marketRepo = marketRepo;
_accountRepo = accountRepo;
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info("Starte Preload des MarketCache aus MongoDB um Flaschenhälse zu vermeiden...");
if (_db != null)
{
var coll = _db.GetCollection<MarketData>("markets");
// Initialize cache for EVERYTHING in DB that is not closed!
var activeMarkets = coll.LiteFind(x => !x.Closed);
var activeMarkets = _marketRepo.GetActive();
int loaded = 0;
foreach (var md in activeMarkets)
@@ -126,24 +130,23 @@ namespace PolyTraderSharp.Services
if (cachedData.EndDate.HasValue) signal.EndDate = cachedData.EndDate;
isNegRisk = cachedData.NegRisk;
}
else if (_db != null)
else
{
try
{
var marketColl = _db.GetCollection<MarketData>("markets");
var marketData = marketColl.LiteFind(x => x.ClobTokenIds != null && x.ClobTokenIds.Contains(signal.TokenId)).FirstOrDefault();
var marketData = _marketRepo.FindByTokenId(signal.TokenId);
if (marketData == null)
{
var fetchedMarket = await _api.GetMarketByTokenIdAsync(signal.TokenId);
if (fetchedMarket != null) { marketColl.Upsert(fetchedMarket); marketData = fetchedMarket; }
if (fetchedMarket != null) { _marketRepo.Upsert(fetchedMarket); marketData = fetchedMarket; }
}
if (marketData == null && !string.IsNullOrEmpty(signal.MarketSlug) && !signal.MarketSlug.StartsWith("0x"))
{
var fetchedMarkets = await _api.GetMarketsByEventSlugAsync(signal.MarketSlug);
foreach (var fetched in fetchedMarkets) {
marketColl.Upsert(fetched);
_marketRepo.Upsert(fetched);
if (fetched.ClobTokenIds != null && fetched.ClobTokenIds.Contains(signal.TokenId)) marketData = fetched;
}
}
@@ -531,10 +534,10 @@ namespace PolyTraderSharp.Services
return old;
});
if (_db != null) _db.GetCollection<Position>($"demo_positions_{account.AccountId}").Upsert(finalPos);
_positionRepo.UpsertDemo(account.AccountId, finalPos);
account.UpdateBalance(account.AvailableBalance - exactUsdc);
if (_db != null) _db.GetCollection<AccountState>("accounts").Upsert(account);
_accountRepo.Upsert(account);
_logger.Trade($"✅ [DEMO AUSGEFÜHRT]\n" +
$" Konto: {account.Name}\n" +
$" Markt: {signal.MarketQuestion}\n" +
@@ -576,15 +579,11 @@ namespace PolyTraderSharp.Services
});
account.UpdateBalance(account.AvailableBalance - exactUsdc);
if (_db != null) _db.GetCollection<AccountState>("accounts").Upsert(account);
_accountRepo.Upsert(account);
if (_db != null)
{
var liveCol = _db.GetCollection<Position>($"open_positions_{account.AccountId}");
if (account.OpenPositions.TryGetValue(signal.TokenId, out var savedPos))
{
liveCol.Upsert(savedPos);
}
_positionRepo.UpsertLive(account.AccountId, savedPos);
}
// Track order placement time for stale order cleanup
@@ -644,14 +643,14 @@ namespace PolyTraderSharp.Services
{
if (account.IsDemo)
{
if (_db != null) _db.GetCollection<Position>($"demo_positions_{account.AccountId}").Delete(signal.TokenId);
_positionRepo.DeleteDemo(account.AccountId, signal.TokenId);
decimal exitUsd = openPos.Size * signal.Price;
decimal realizedPnl = exitUsd - openPos.AmountUsd;
_state.GlobalPnl += realizedPnl;
account.UpdateBalance(account.AvailableBalance + exitUsd);
if (_db != null) _db.GetCollection<AccountState>("accounts").Upsert(account);
_accountRepo.Upsert(account);
var ct = new ClosedTrade
{