internal List <HiddenOrderEntry> GetStopOrders(
     string user, string accountId, string instrument, OrderSide orderSide)
 {
     return(HiddenOrders.Find(order =>
                              order.User.Equals(user) &&
                              order.AccountId.Equals(accountId) &&
                              order.Instrument.Equals(instrument) &&
                              order.Side == orderSide
                              ).ToList());
 }
        public object FindOpenOrderCreatedByVersionNumber(long cancelOrderCreatedOnVersionNumber)
        {
            var targetOrder = OrderBook.Find(
                Builders <OrderBookEntry> .Filter.Eq(e => e.CreatedOnVersionId, cancelOrderCreatedOnVersionNumber)
                ).SingleOrDefault();

            if (targetOrder != null)
            {
                return(targetOrder);
            }
            else
            {
                // There has to be one or the other
                var hiddenOrder = HiddenOrders.Find(
                    Builders <HiddenOrderEntry> .Filter.Eq(e => e.CreatedOnVersionId, cancelOrderCreatedOnVersionNumber)
                    ).Single();
                return(hiddenOrder);
            }
        }
        /// <summary>
        /// Cancels an active order, inserting a relevant order history entry.
        /// </summary>
        /// <param name="cancelOrderCreatedOnVersionNumber">Version number of creation of the order to be canceled</param>
        /// <param name="orderHistoryTime">Time of the cancellation event</param>
        /// <param name="openOrder">Found open order</param>
        /// <returns>Remaining unmatched order amount of paid coin depending on side</returns>
        internal decimal CancelOrderByCreatedOnVersionNumber(
            long cancelOrderCreatedOnVersionNumber,
            DateTime orderHistoryTime,
            out object openOrder)
        {
            decimal remainingUnmatchedAmount;

            openOrder = FindOpenOrderCreatedByVersionNumber(cancelOrderCreatedOnVersionNumber);
            if (openOrder is OrderBookEntry limitOrder)
            {
                InsertOrderHistoryEntry(limitOrder.FilledQty, limitOrder, OrderStatus.Cancelled, orderHistoryTime);
                remainingUnmatchedAmount = limitOrder.Qty - limitOrder.FilledQty;
                if (limitOrder.Side == OrderSide.Buy)
                {
                    remainingUnmatchedAmount *= limitOrder.LimitPrice;
                }

                OrderBook.DeleteOne(
                    Builders <OrderBookEntry> .Filter.Eq(e => e.Id, limitOrder.Id)
                    );
            }
            else if (openOrder is HiddenOrderEntry stopOrder)
            {
                InsertOrderHistoryEntry(stopOrder, OrderStatus.Cancelled, orderHistoryTime);
                remainingUnmatchedAmount = stopOrder.Qty;
                if (stopOrder.Side == OrderSide.Buy)
                {
                    remainingUnmatchedAmount *= stopOrder.StopPrice;
                }

                HiddenOrders.DeleteOne(
                    Builders <HiddenOrderEntry> .Filter.Eq(e => e.Id, stopOrder.Id)
                    );
            }
            else
            {
                throw new Exception(
                          $"Couldn't cancel order created on version number {cancelOrderCreatedOnVersionNumber}, as there was no such order open");
            }

            return(remainingUnmatchedAmount);
        }
        internal void CreateOrder(CreateOrderEventEntry createOrder)
        {
            _logger.LogDebug("Called create order @ version number " + createOrder.VersionNumber);
            switch (createOrder.Type)
            {
            case OrderType.Limit:
                var limitOrder = new OrderBookEntry
                {
                    EntryTime          = createOrder.EntryTime,
                    CreatedOnVersionId = createOrder.VersionNumber,
                    User       = createOrder.User,
                    AccountId  = createOrder.AccountId,
                    Instrument = createOrder.Instrument,
                    Qty        = createOrder.Qty,
                    Side       = createOrder.Side,
                    FilledQty  = 0m,
                    LimitPrice = createOrder.LimitPrice.Value,
                    // TODO from stop loss and take profit
                    //ChildrenIds
                    DurationType = createOrder.DurationType,
                    Duration     = createOrder.Duration,
                };
                OrderBook.InsertOne(limitOrder);
                break;

            case OrderType.Stop:
                var stopOrder = new HiddenOrderEntry
                {
                    EntryTime          = createOrder.EntryTime,
                    CreatedOnVersionId = createOrder.VersionNumber,
                    User       = createOrder.User,
                    AccountId  = createOrder.AccountId,
                    Instrument = createOrder.Instrument,
                    Qty        = createOrder.Qty,
                    Side       = createOrder.Side,
                    StopPrice  = createOrder.StopPrice.Value,
                    // TODO from stop loss and take profit
                    //ChildrenIds
                    DurationType = createOrder.DurationType,
                    Duration     = createOrder.Duration,
                };
                HiddenOrders.InsertOne(stopOrder);
                break;

            case OrderType.Market:
                OrderHistory.InsertOne(
                    new OrderHistoryEntry
                {
                    CreateTime = createOrder.EntryTime,
                    CloseTime  = createOrder.EntryTime,
                    User       = createOrder.User,
                    AccountId  = createOrder.AccountId,
                    Instrument = createOrder.Instrument,
                    Qty        = createOrder.Qty,
                    Side       = createOrder.Side,
                    // Closed market order
                    Type = OrderType.Market,
                    // The market order will be filled by the following match orders
                    FilledQty = createOrder.FilledMarketOrderQty,
                    // The most expensive accepted limit price will be shown to the user
                    LimitPrice = createOrder.LimitPrice.Value,
                    StopPrice  = null,
                    // TODO from stop loss and take profit
                    //ChildrenIds
                    DurationType = createOrder.DurationType,
                    Duration     = createOrder.Duration,
                    Status       = OrderStatus.Filled,
                }
                    );
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(createOrder.Type));
            }

            _logger.LogDebug("Persisted create order @ version number " + createOrder.VersionNumber);
        }