public DatabaseGenerator(
     VersionControl versionControl,
     EventHistoryService eventHistoryService,
     TradingRepository tradingRepository,
     AccountRepository accountRepository,
     TradeEventProcessor tradeEventProcessor,
     ILogger <DatabaseGenerator> logger)
 {
     _versionControl      = versionControl;
     _eventHistoryService = eventHistoryService;
     _tradingRepository   = tradingRepository;
     _accountRepository   = accountRepository;
     _tradeEventProcessor = tradeEventProcessor;
     _logger = logger;
 }
Exemplo n.º 2
0
        private (List <MatchOrderEventEntry>, decimal) PlanMatchOrdersLocked(
            string user, string accountId, string instrument, OrderSide orderSide, decimal?limitPriceValue,
            decimal quantityRemaining, long lockedEventVersionNumber, string requestId,
            Func <string, Exception> reportInvalidMessage)
        {
            var plannedEvents = new List <MatchOrderEventEntry>();
            var baseCurrency  = instrument.Split("_")[0];
            var quoteCurrency = instrument.Split("_")[1];

            // Start the process of matching relevant offers
            var matchingOffers = orderSide == OrderSide.Buy
                ? TradingOrderService.MatchSellers(limitPriceValue, instrument).Result
                : TradingOrderService.MatchBuyers(limitPriceValue, instrument).Result;

            matchingOffers.MoveNext();
            var matchingOfferBatch = matchingOffers.Current.ToList();

            while (quantityRemaining > 0 && matchingOfferBatch.Count > 0)
            {
                _logger.LogInformation(
                    $"Request {requestId} matched a batch of {matchingOfferBatch.Count} {(orderSide == OrderSide.Buy ? "buyers" : "sellers")}");
                foreach (var other in matchingOfferBatch)
                {
                    var     otherRemaining = other.Qty - other.FilledQty;
                    decimal matchedQuantity;
                    if (otherRemaining >= quantityRemaining)
                    {
                        // Entire command order remainder is consumed by the seller offer
                        matchedQuantity = quantityRemaining;
                        _logger.LogInformation(
                            $"New {instrument} {(orderSide == OrderSide.Buy ? "buy" : "sell")} limit order planning entirely matched order id {other.Id}");
                    }
                    else
                    {
                        // Fraction of order will remain, but the seller offer will be consumed
                        matchedQuantity = otherRemaining;
                        _logger.LogInformation(
                            $"New {instrument} {(orderSide == OrderSide.Buy ? "buy" : "sell")} limit order planning partially matched order id {other.Id}");
                    }

                    quantityRemaining -= matchedQuantity;

                    var matchEvent = new MatchOrderEventEntry
                    {
                        VersionNumber              = lockedEventVersionNumber,
                        ActionUser                 = user,
                        ActionAccountId            = accountId,
                        TargetOrderOnVersionNumber = other.CreatedOnVersionId,
                        TargetUser                 = other.User,
                        TargetAccountId            = other.AccountId,
                        Instrument                 = instrument,
                        Qty        = matchedQuantity,
                        ActionSide = orderSide,
                        Price      = other.LimitPrice,
                        ActionOrderQtyRemaining = quantityRemaining,
                        TargetOrderQtyRemaining = other.Qty - other.FilledQty - matchedQuantity,
                    };

                    // Calculating new balances for double-check purposes
                    var(actionBaseMod, actionQuoteMod, targetBaseMod, targetQuoteMod) =
                        TradeEventProcessor.MatchOrderBalanceModifications(matchEvent);
                    try
                    {
                        matchEvent.ActionBaseNewBalance =
                            UserService.GetBalanceAndReservedBalance(
                                matchEvent.ActionUser, matchEvent.ActionAccountId, baseCurrency
                                ).Item1 + actionBaseMod;
                        matchEvent.ActionQuoteNewBalance =
                            UserService.GetBalanceAndReservedBalance(
                                matchEvent.ActionUser, matchEvent.ActionAccountId, quoteCurrency
                                ).Item1 + actionQuoteMod;
                        matchEvent.TargetBaseNewBalance =
                            UserService.GetBalanceAndReservedBalance(
                                matchEvent.TargetUser, matchEvent.TargetAccountId, baseCurrency
                                ).Item1 + targetBaseMod;
                        matchEvent.TargetQuoteNewBalance =
                            UserService.GetBalanceAndReservedBalance(
                                matchEvent.TargetUser, matchEvent.TargetAccountId, quoteCurrency
                                ).Item1 + targetQuoteMod;
                    }
                    catch (Exception e)
                    {
                        // This can happen if a user didn't generate his balances yet, so it's not a fatal error
                        throw reportInvalidMessage(
                                  $"There was a problem with your coin balances. {e.GetType().Name}: {e.Message}");
                    }

                    plannedEvents.Add(matchEvent);
                    if (quantityRemaining == 0)
                    {
                        break;
                    }
                }

                if (quantityRemaining == 0)
                {
                    break;
                }


                // Keep the iteration going in order to find further matching orders as long as remaining qty > 0
                if (!matchingOffers.MoveNext())
                {
                    break;
                }

                matchingOfferBatch = matchingOffers.Current.ToList();
            }

            return(plannedEvents, quantityRemaining);
        }