public void TestWithSnapshot() { var snapshot = new SnapshotEntity() { Balance = 1, AvgOpenPrice = 40000 }; var ops = new List <AvgPriceUpdate>(); // ops.Add(new OperationUpdate() // { // Amount = 1, // Balance = 1, // AssetPriceInUsd = 40000 // }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = 2, AssetPriceInUsd = 50000 }); ops.Add(new AvgPriceUpdate() { Amount = (decimal) - 1.5, Balance = (decimal)0.5, AssetPriceInUsd = 45000 }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = (decimal)1.5, AssetPriceInUsd = 53000 }); ops.Add(new AvgPriceUpdate() { Amount = (decimal) - 0.5, Balance = 1, AssetPriceInUsd = 55000 }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = 2, AssetPriceInUsd = 50000 }); var t = AvgPriceCalculator.CalculateAvgPrice(ops, snapshot); Assert.AreEqual(45000, t[0].AvgOpenPrice); Assert.AreEqual(45000, t[1].AvgOpenPrice); Assert.AreEqual((decimal)50333.33, t[2].AvgOpenPrice); Assert.AreEqual((decimal)50333.33, t[3].AvgOpenPrice); Assert.AreEqual((decimal)50166.66, t[4].AvgOpenPrice); }
public void TestWithoutSnapshot() { var ops = new List <AvgPriceUpdate>(); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = 1, AssetPriceInUsd = 40000 }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = 2, AssetPriceInUsd = 50000 }); ops.Add(new AvgPriceUpdate() { Amount = (decimal) - 1.5, Balance = (decimal)0.5, AssetPriceInUsd = 45000 }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = (decimal)1.5, AssetPriceInUsd = 53000 }); ops.Add(new AvgPriceUpdate() { Amount = (decimal) - 0.5, Balance = 1, AssetPriceInUsd = 55000 }); ops.Add(new AvgPriceUpdate() { Amount = 1, Balance = 2, AssetPriceInUsd = 50000 }); var t = AvgPriceCalculator.CalculateAvgPrice(ops, null); Assert.AreEqual(40000, t[0].AvgOpenPrice); Assert.AreEqual(45000, t[1].AvgOpenPrice); Assert.AreEqual(45000, t[2].AvgOpenPrice); Assert.AreEqual((decimal)50333.33, t[3].AvgOpenPrice); Assert.AreEqual((decimal)50333.33, t[4].AvgOpenPrice); Assert.AreEqual((decimal)50166.66, t[5].AvgOpenPrice); }
private async ValueTask HandleEvents(IReadOnlyList <ExBalanceUpdateMessage> messages) { using var activity = MyTelemetry.StartActivity("Handle ExBalanceUpdateMessage's") ?.AddTag("count-events", messages.Count); try { var sw = new Stopwatch(); sw.Start(); var list = new List <AvgPriceUpdate>(); var calculatedList = new List <AvgPriceUpdate>(); if (!messages.Any()) { return; } list.AddRange(GetOperationUpdates(messages)); if (!list.Any()) { return; } await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder); var groups = list.GroupBy(t => new { t.AssetId, t.WalletId }); foreach (var group in groups) { var semaphore = SemaphoreManager.GetOrCreate(group.Key.WalletId, group.Key.AssetId); await semaphore.WaitAsync(); try { var groupedList = group.OrderBy(t => t.TimeStamp).ToList(); var snapshot = await _snapshotManager.GetSnapshot(group.Key.WalletId, group.Key.AssetId); if (snapshot != null) { groupedList = groupedList.Where(t => t.TimeStamp > snapshot.LastTimestamp).ToList(); } if (!groupedList.Any()) { continue; } groupedList = AvgPriceCalculator.CalculateAvgPrice(groupedList, snapshot); calculatedList.AddRange(groupedList); var openTimestamp = groupedList.LastOrDefault(t => t.Balance == 0)?.TimeStamp ?? snapshot?.OpenTimestamp ?? default; var lastUpdate = groupedList.Last(); var newSnapshot = new SnapshotEntity { WalletId = lastUpdate.WalletId, AssetId = lastUpdate.AssetId, Balance = lastUpdate.Balance, AvgOpenPrice = lastUpdate.AvgOpenPrice, OpenTimestamp = openTimestamp, LastTimestamp = lastUpdate.TimeStamp }; await _snapshotManager.UpsertSnapshots(new() { newSnapshot }); } finally { semaphore.Release(); } } await ctx.UpsertAvgPriceAsync(calculatedList.Where(t => t.EventType != "Refund Blockchain Withdrawal").Select(update => new OperationHistoryEntity(update))); await ctx.SaveChangesAsync(); sw.Stop(); _logger.LogDebug( "Write {countUpdates} avg price updates in database from {countEvents} ME events. Time: {elapsedText} [{elapsedMilliseconds} ms]", list.Count, messages.Count, sw.Elapsed.ToString(), sw.ElapsedMilliseconds); } catch (Exception ex) { ex.FailActivity(); messages.AddToActivityAsJsonTag("me events"); throw; } }