Exemplo n.º 1
0
        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);
        }