Пример #1
0
        private async Task <IList <EventEntry> > PlanStopOrderEvents(
            string user, string accountId, string instrument, decimal quantity, OrderSide orderSide,
            decimal stopPriceValue, string durationType, decimal?duration, decimal?stopLoss, decimal?takeProfit,
            string requestId, Func <string, Exception> reportInvalidMessage)
        {
            if (quantity <= 0)
            {
                throw reportInvalidMessage("You cannot create an order with a quantity of 0 or less");
            }

            if (stopPriceValue <= 0 ||
                stopLoss.HasValue && stopLoss.Value <= 0 ||
                takeProfit.HasValue && takeProfit.Value <= 0)
            {
                throw reportInvalidMessage("You cannot create a stop order with a price of 0 or less");
            }

            var stopOrderEvent = new CreateOrderEventEntry
            {
                User         = user,
                AccountId    = accountId,
                Instrument   = instrument,
                Qty          = quantity,
                Side         = orderSide,
                Type         = OrderType.Stop,
                LimitPrice   = null,
                StopPrice    = stopPriceValue,
                DurationType = durationType,
                Duration     = duration,
                StopLoss     = stopLoss,
                TakeProfit   = takeProfit,
            };
            var plannedEvents = new List <EventEntry>
            {
                stopOrderEvent
            };

            VersionControl.ExecuteUsingFixedVersion(currentVersionNumber =>
            {
                var eventVersionNumber       = currentVersionNumber + 1;
                stopOrderEvent.VersionNumber = eventVersionNumber;

                AssertUnreservedBalance(
                    user, accountId, instrument, quantity, orderSide, stopPriceValue, reportInvalidMessage);
            });
            return(plannedEvents);
        }
Пример #2
0
 public void ProcessEvent(CreateOrderEventEntry eventEntry)
 {
     _tradingOrderService.CreateOrder(eventEntry);
     if (eventEntry.Type == OrderType.Limit || eventEntry.Type == OrderType.Stop)
     {
         var price = eventEntry.Type == OrderType.Limit
             ? eventEntry.LimitPrice.Value
             : eventEntry.StopPrice.Value;
         _userService.ModifyReservedBalance(
             eventEntry.User,
             eventEntry.AccountId,
             eventEntry.Instrument.Split("_")[
                 eventEntry.Side == OrderSide.Buy ? 1 : 0
             ],
             eventEntry.Side == OrderSide.Buy
                 ? eventEntry.Qty * price
                 : eventEntry.Qty
             ).Wait();
     }
 }
Пример #3
0
        private async Task <IList <EventEntry> > PlanMarketOrderEvents(
            string user, string accountId, string instrument, decimal quantity, OrderSide orderSide,
            string durationType, decimal?duration, decimal?stopLoss, decimal?takeProfit,
            string requestId, Func <string, Exception> reportInvalidMessage)
        {
            if (quantity <= 0)
            {
                throw reportInvalidMessage("You cannot create an order with a quantity of 0 or less");
            }

            if (stopLoss.HasValue && stopLoss.Value <= 0 ||
                takeProfit.HasValue && takeProfit.Value <= 0)
            {
                throw reportInvalidMessage("You cannot create a market order with a price of 0 or less");
            }

            var marketOrderEvent = new CreateOrderEventEntry
            {
                User       = user,
                AccountId  = accountId,
                Instrument = instrument,
                Qty        = quantity,
                //FilledMarketOrderQty
                Side = orderSide,
                Type = OrderType.Market,
                //LimitPrice,
                StopPrice    = null,
                DurationType = durationType,
                Duration     = duration,
                StopLoss     = stopLoss,
                TakeProfit   = takeProfit,
            };
            var plannedEvents = new List <EventEntry>
            {
                marketOrderEvent
            };

            VersionControl.ExecuteUsingFixedVersion(currentVersionNumber =>
            {
                var eventVersionNumber         = currentVersionNumber + 1;
                marketOrderEvent.VersionNumber = eventVersionNumber;

                // In the case of buying we cannot be sure that the entire quantity will get matched
                if (orderSide == OrderSide.Sell)
                {
                    AssertUnreservedBalance(
                        user, accountId, instrument, quantity, orderSide, null, reportInvalidMessage);
                }

                var matchedOrders = PlanMatchOrdersLocked(
                    user, accountId, instrument, orderSide, null, quantity, eventVersionNumber,
                    requestId, reportInvalidMessage
                    );
                if (matchedOrders.Item1.Count == 0)
                {
                    throw reportInvalidMessage("Cannot execute a market order, as there are no other orders");
                }

                matchedOrders.Item1.ForEach(plannedEvents.Add);
                marketOrderEvent.FilledMarketOrderQty = quantity - matchedOrders.Item2;
                marketOrderEvent.LimitPrice           = matchedOrders.Item1.Last().Price;
            });
            return(plannedEvents);
        }
Пример #4
0
        private async Task <IList <EventEntry> > PlanLimitOrderEvents(
            string user, string accountId, string instrument, decimal quantity, OrderSide orderSide,
            decimal limitPriceValue, string durationType, decimal?duration, decimal?stopLoss, decimal?takeProfit,
            string requestId, Func <string, Exception> reportInvalidMessage)
        {
            if (quantity <= 0)
            {
                throw reportInvalidMessage("You cannot create an order with a quantity of 0 or less");
            }

            if (limitPriceValue <= 0 ||
                stopLoss.HasValue && stopLoss.Value <= 0 ||
                takeProfit.HasValue && takeProfit.Value <= 0)
            {
                throw reportInvalidMessage("You cannot create a limit order with a price of 0 or less");
            }

            var limitOrderEvent = new CreateOrderEventEntry
            {
                User         = user,
                AccountId    = accountId,
                Instrument   = instrument,
                Qty          = quantity,
                Side         = orderSide,
                Type         = OrderType.Limit,
                LimitPrice   = limitPriceValue,
                StopPrice    = null,
                DurationType = durationType,
                Duration     = duration,
                StopLoss     = stopLoss,
                TakeProfit   = takeProfit,
            };
            var plannedEvents = new List <EventEntry>
            {
                limitOrderEvent
            };
            var finished = false;

            // Note: using async prefix on the lambda caused it to never finish!
            VersionControl.ExecuteUsingFixedVersion(currentVersionNumber =>
            {
                var eventVersionNumber = currentVersionNumber + 1;
                // We are now locked to a specific version number
                limitOrderEvent.VersionNumber = eventVersionNumber;

                AssertUnreservedBalance(
                    user, accountId, instrument, quantity, orderSide, limitPriceValue, reportInvalidMessage);

                PlanMatchOrdersLocked(
                    user, accountId, instrument, orderSide, limitPriceValue, quantity, eventVersionNumber,
                    requestId, reportInvalidMessage
                    ).Item1.ForEach(plannedEvents.Add);

                finished = true;
            });

            if (finished == false)
            {
                throw new Exception($"{nameof(VersionControl.ExecuteUsingFixedVersion)} didn't finish");
            }

            return(plannedEvents);
        }
        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);
        }