public void ProcessEvent(WalletConsolidationTransferEventEntry eventEntry) { if (eventEntry.Valid != null) { // Consolidation was either invalid anyway, or it's already validated return; } // Validate the consolidation's withdrawal - Wallet Server actively waits for this! var currentVersionNumberEvents = _eventHistoryService.FindByVersionNumber(eventEntry.VersionNumber) .ToList(); var consolidationList = currentVersionNumberEvents.FindAll(e => e is WalletConsolidationTransferEventEntry); var withdrawalList = currentVersionNumberEvents.FindAll(e => e is WalletWithdrawalEventEntry); if (withdrawalList.Count == 0) { throw new Exception("Standalone consolidation not implemented yet"); } var withdrawal = (WalletWithdrawalEventEntry)withdrawalList.Single(); bool valid; if (withdrawal.Validated.HasValue) { valid = withdrawal.Validated.Value; } else { var(balance, reservedBalance) = _userService .GetBalanceAndReservedBalance(withdrawal.User, withdrawal.AccountId, withdrawal.CoinSymbol); if (!IsValidWithdrawal(withdrawal, balance)) { valid = false; // Withdrawal is invalid _eventHistoryService.ReportWithdrawalValidation(withdrawal, valid); } else { valid = true; _eventHistoryService.ReportWithdrawalValidation(withdrawal, valid); } } foreach (var consolidationEntry in consolidationList) { var consolidation = (WalletConsolidationTransferEventEntry)consolidationEntry; _eventHistoryService.ReportConsolidationValidated(consolidation, valid); } }
internal void MatchOrder(MatchOrderEventEntry matchOrder) { _logger.LogDebug("Called match order @ version number " + matchOrder.VersionNumber); // Old incorrect way: // In order to find actionOrderId, we must go a little roundabout way // var matchOrderRelatedCreateOrder = _eventHistoryRepository.Events<CreateOrderEventEntry>().Find( // Builders<CreateOrderEventEntry>.Filter.Eq(e => e.VersionNumber, matchOrder.VersionNumber) // ).First(); // var actionOrderId = matchOrderRelatedCreateOrder.Id; var now = matchOrder.EntryTime; // Action order is not used in case it's a market order var actionOrder = OrderBook.Find( Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, matchOrder.VersionNumber) ).SingleOrDefault(); var targetOrder = OrderBook.Find( Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, matchOrder.TargetOrderOnVersionNumber) ).Single(); AssertMatchOrderQty(matchOrder, actionOrder, targetOrder); if (actionOrder != null) { if (matchOrder.ActionOrderQtyRemaining == 0) { OrderBook.DeleteOne( Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, matchOrder.VersionNumber) ); // The entire order quantity was filled InsertOrderHistoryEntry(actionOrder.Qty, actionOrder, OrderStatus.Filled, now); } else { OrderBook.UpdateOne( Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, matchOrder.VersionNumber), Builders <OrderBookEntry> .Update.Set( e => e.FilledQty, actionOrder.Qty - matchOrder.ActionOrderQtyRemaining) ); } } else if ( // This condition can be completely deleted without a worry, it's just a double-check ((CreateOrderEventEntry)_eventHistoryService .FindByVersionNumber(matchOrder.VersionNumber) .First() ).Type != OrderType.Market ) { // We don't have to update the OrderHistoryEntry, because it already contains the matched quantity throw new Exception( $"Match order id {matchOrder.Id} did not have action being a limit order, and it was not a market order"); } if (matchOrder.TargetOrderQtyRemaining == 0) { OrderBook.DeleteOne( Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, matchOrder.TargetOrderOnVersionNumber) ); // The entire order quantity was filled InsertOrderHistoryEntry(targetOrder.Qty, targetOrder, OrderStatus.Filled, now); } else { OrderBook.UpdateOne( Builders <OrderBookEntry> .Filter.Eq( e => e.CreatedOnVersionId, matchOrder.TargetOrderOnVersionNumber), Builders <OrderBookEntry> .Update.Set( e => e.FilledQty, targetOrder.Qty - matchOrder.TargetOrderQtyRemaining) ); } TransactionHistory.InsertMany( new[] { new TransactionHistoryEntry { ExecutionTime = now, User = matchOrder.ActionUser, AccountId = matchOrder.ActionAccountId, Instrument = matchOrder.Instrument, Side = targetOrder.Side == OrderSide.Buy ? OrderSide.Sell : OrderSide.Buy, OrderId = actionOrder?.Id, // The entire quantity was filled FilledQty = matchOrder.Qty, Price = targetOrder.LimitPrice, }, new TransactionHistoryEntry { ExecutionTime = now, User = targetOrder.User, AccountId = targetOrder.AccountId, Instrument = targetOrder.Instrument, Side = targetOrder.Side, OrderId = targetOrder.Id, // The entire quantity was filled FilledQty = matchOrder.Qty, Price = targetOrder.LimitPrice, } } ); _logger.LogDebug("Persisted match order @ version number " + matchOrder.VersionNumber); }