Пример #1
0
 /// <summary>
 /// Called when an order ticket event has occurred.
 /// TODO: not implemented in the flow => so this needs to be implemented in the flow
 /// </summary>
 /// <param name="orderticketevent">The order ticket event.</param>
 public void OnOrderTicketEvent(OrderTicketEvent orderticketevent)
 {
     if (IsRunning)
     {
         Modules.ForEach(x => x.OnOrderTicketEvent(orderticketevent));
     }
 }
Пример #2
0
        /// <summary>
        /// Submits the order.
        /// </summary>
        /// <param name="pendingorder">The order.</param>
        /// <returns></returns>
        public bool SubmitOrder(PendingOrder pendingorder)
        {
            //get the underlying order
            var order = pendingorder.Order;

            //Check current order state
            if (order.State == OrderState.New)
            {
                //Set order
                lock (_locker)
                {
                    _activeOrders[pendingorder.OrderId] = pendingorder;
                }

                //Check order id
                if (order.BrokerId.Contains(order.InternalId.ToString()))
                {
                    order.BrokerId.Add(order.InternalId.ToString());
                }

                //Order event
                OrderStateChange?.Invoke(this, OrderTicketEvent.Submitted(order.InternalId));
                return(true);
            }

            return(false);
        }
Пример #3
0
        /// <summary>
        /// Called when [order ticket event].
        /// TODO: send to ordertickethandler for processing fills and updating
        /// TODO: send to quant fund for notification
        /// </summary>
        /// <param name="pendingorder"></param>
        /// <param name="orderticketevent">The orderticketevent.</param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnOrderTicketEvent(PendingOrder pendingorder, OrderTicketEvent orderticketevent)
        {
            throw new NotImplementedException();

            //Send updates (so if the order is completed, the receiving party will know this)
            //EventRunner.Enqueue(PendingOrderInfoMessage.Generate(pendingorder), true);
            //EventRunner.Enqueue(OrderInfoMessage.Create(pendingorder), true);
        }
Пример #4
0
 /// <summary>
 /// Cancels the order.
 /// </summary>
 /// <param name="order">The order.</param>
 /// <returns></returns>
 public bool CancelOrder(PendingOrder order)
 {
     //Check if we can remove this order
     if (!_activeOrders.TryRemove(order.OrderId, out PendingOrder active))
     {
         return(false); //Cannot find order
     }
     //Send cancelled order notification
     OrderStateChange?.Invoke(this, OrderTicketEvent.Cancelled(order.OrderId, "Order was cancelled"));
     return(true);
 }
Пример #5
0
        /// <summary>
        /// Updates the order.
        /// </summary>
        /// <param name="pendingorder">The order.</param>
        /// <returns></returns>
        public bool UpdateOrder(PendingOrder pendingorder)
        {
            //Check if we can find this order
            if (!_activeOrders.TryGetValue(pendingorder.OrderId, out PendingOrder active))
            {
                return(false); //Cannot find order
            }
            lock (_locker)
            {
                //Update order instance
                pendingorder.UpdateOrder(active.Order);
            }

            //Send updated order notification
            OrderStateChange?.Invoke(this, OrderTicketEvent.Updated(active.OrderId, "Order was updated"));
            return(true);
        }
Пример #6
0
        /// <summary>
        /// Process submit order
        /// </summary>
        /// <param name="ticket"></param>
        protected virtual OrderTicketResponse CancelOrder(CancelOrderTicket ticket)
        {
            //Check if we can get the order
            if (!OrderTracker.TryGetOrder(ticket.OrderId, out PendingOrder pendingorder))
            {
                _log.Error($"Unable to cancel order with ID {ticket.OrderId}, order id unkown.");
                return(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.UnableToFindOrder));
            }

            //Check if order is closed
            if (pendingorder.Order.State.IsDone())
            {
                return(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.InvalidOrderStatus));
            }

            //try and cancel the order
            bool ordercancelled = false;

            try
            {
                ordercancelled = BrokerConnection.CancelOrder(pendingorder);
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not cancel order with id {ticket.OrderId} broker connection refused to do so");
            }

            //If not managed to cancel
            if (!ordercancelled)
            {
                var message = $"Brokerconnection failed to cancel order with id {ticket.OrderId}";
                Portfolio.Log(LogLevel.Error, message);
                HandleOrderTicketEvent(OrderTicketEvent.Error(ticket.OrderId));
                return(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.BrokerageFailedToCancelOrder));
            }

            //Order was cancelled
            var order = pendingorder.Order as OrderImpl;

            order.State = OrderState.Cancelled;
            pendingorder.UpdateOrder(order);

            //Return result for order ticket
            return(OrderTicketResponse.Processed(ticket.OrderId));
        }
Пример #7
0
        /// <summary>
        /// Cancels the order ticket.
        /// </summary>
        /// <param name="ticket">The ticket.</param>
        /// <param name="quantfund">Ticket associated quant fund</param>
        /// <returns></returns>
        private OrderTicket ProcessCancelTicket(CancelOrderTicket ticket, IQuantFund quantfund)
        {
            //Try and get current order ticket
            if (!OrderTracker.TryGetOrder(ticket.OrderId, out PendingOrder pendingorder))
            {
                ticket.SetResponse(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.UnableToFindOrder));
                return(ticket);
            }

            try
            {
                //Try and process cancel ticket
                if (pendingorder.OrderState.IsDone())
                {
                    _log.Error($"Order is already of state {pendingorder.OrderState} while trying to cancel this order");
                    ticket.SetResponse(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.InvalidOrderStatus));
                }
                else if (quantfund != null && quantfund.IsBackfilling)
                {
                    ticket.SetResponse(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.QuantFundBackfilling));
                }
                else
                {
                    // update the order status
                    var order = pendingorder.Order as OrderImpl;
                    order.State = OrderState.CancelPending;
                    pendingorder.UpdateOrder(order);

                    // notify the portfolio with an order event
                    HandleOrderTicketEvent(OrderTicketEvent.Cancelled(pendingorder.OrderId));

                    // send the request to be processed
                    ticket.SetResponse(OrderTicketResponse.Processed(ticket.OrderId), OrderTicketState.Processing);
                    _orderTicketQueue.Add(ticket);
                }
            }
            catch (Exception exc)
            {
                _log.Error(exc);
                ticket.SetResponse(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.ProcessingError, exc.Message));
            }

            //return result
            return(ticket);
        }
Пример #8
0
        /// <summary>
        /// Handles the order ticket event.
        /// </summary>
        /// <param name="orderticketevent">The orderticketevent.</param>
        private void HandleOrderTicketEvent(OrderTicketEvent orderticketevent)
        {
            //Retrieve the order
            if (!(GetOrderById(orderticketevent.OrderId) is OrderImpl order))
            {
                _log.Error($"Unable to retrieve order with id {orderticketevent.OrderId} could not proceed");
                return;
            }

            //Set new order status
            order.State = orderticketevent.OrderState;

            //Get pending order instance
            if (!OrderTracker.TryGetOrder(orderticketevent.OrderId, out PendingOrder pendingorder))
            {
                _log.Error($"Unable to retrieve pending order with id {orderticketevent.OrderId} could not proceed");
                return;
            }

            //Check if we need to apply fill
            if ((order.State == OrderState.Filled || order.State == OrderState.PartialFilled))
            {
                pendingorder.AddFill(orderticketevent.Fill);
            }

            //Check if we need to fire an event
            if (orderticketevent.OrderState != OrderState.None)
            {
                //Create new event
                try
                {
                    Portfolio.OnOrderTicketEvent(pendingorder, orderticketevent);
                }
                catch (Exception exc)
                {
                    Portfolio.Log(LogLevel.Error, $"Could not process orderticket event: {exc.Message}");
                    _log.Error(exc);
                }
            }
        }
Пример #9
0
 /// <summary>
 /// Called when an order ticket event has occured.
 /// </summary>
 /// <param name="orderticketevent">The orderticketevent.</param>
 public virtual void OnOrderTicketEvent(OrderTicketEvent orderticketevent)
 {
 }
Пример #10
0
        /// <summary>
        /// Processes the market data.
        /// </summary>
        /// <param name="dataupdates">The data updates.</param>
        public void ProcessMarketData(DataUpdates dataupdates)
        {
            //Only accept market data
            if (_activeOrders.Count == 0)
            {
                return;
            }

            //Check if we have any data
            if (!dataupdates.HasUpdates)
            {
                return;
            }

            lock (_locker)
            {
                foreach (var pkv in _activeOrders.OrderBy(x => x.Key))
                {
                    //get the order
                    var pendingorder = pkv.Value;
                    var order        = pendingorder.Order;

                    //Get datapoint
                    if (!dataupdates[order.Security].HasUpdates)
                    {
                        continue;
                    }

                    var datapoint = dataupdates[order.Security].Ticks.Count > 0
                        ? dataupdates[order.Security].Ticks.First().Value.First() as DataPoint
                        : dataupdates[order.Security].QuoteBars.Count > 0
                            ? dataupdates[order.Security].QuoteBars.First().Value as DataPoint
                            : dataupdates[order.Security].TradeBars.Count > 0
                                ? dataupdates[order.Security].TradeBars.First().Value as DataPoint
                                : null;

                    if (datapoint == null)
                    {
                        continue;
                    }

                    //Check if order is already done
                    if (order.State.IsDone())
                    {
                        _activeOrders.TryRemove(pkv.Key, out pendingorder);
                        continue;
                    }

                    //Check if we have enough buying power
                    if (!_portfolio.OrderTicketHandler.GetSufficientCapitalForOrder(pendingorder))
                    {
                        //Remove order from active orders, as it is cancelled by the broker instance
                        _activeOrders.TryRemove(pkv.Key, out pendingorder);
                        _portfolio.Log(LogLevel.Error, $"Insufficient funds to process order by sim broker");
                        OrderStateChange?.Invoke(this, OrderTicketEvent.Cancelled(pendingorder.OrderId, "Insufficient funds to process order by sim broker"));
                    }

                    //Check if we need to fill this order
                    var  fillmodel    = BrokerModel.GetFillModel(order);
                    Fill filledresult = Fill.NoFill();

                    try
                    {
                        filledresult = fillmodel.FillOrder(BrokerModel, datapoint, pendingorder, _usehighlyliquidfills);
                    }
                    catch (Exception exc)
                    {
                        _log.Error(exc);
                        _portfolio.Log(LogLevel.Error, string.Format("Order Error: id: {0}, Transaction model failed to fill for order type: {1} with error: {2}", order.InternalId, order.Type, exc.Message));
                        OrderStateChange?.Invoke(this, OrderTicketEvent.Cancelled(pendingorder.OrderId, "Exception during processing fill for this order, please check logs"));
                    }

                    //Check for any full or partial fills
                    if (filledresult.FillQuantity > 0)
                    {
                        if (filledresult.Status == OrderState.Filled)
                        {
                            OrderStateChange?.Invoke(this, OrderTicketEvent.Filled(order.InternalId, filledresult));
                        }
                        else if (filledresult.Status == OrderState.PartialFilled)
                        {
                            OrderStateChange?.Invoke(this, OrderTicketEvent.PartiallyFilled(order.InternalId, filledresult));
                        }
                    }

                    //Check if order is done
                    if (filledresult.Status.IsDone())
                    {
                        _activeOrders.TryRemove(pkv.Key, out pendingorder);
                    }
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Submit update order
        /// </summary>
        /// <param name="ticket"></param>
        protected virtual OrderTicketResponse UpdateOrder(UpdateOrderTicket ticket)
        {
            //Get current pending order
            if (!OrderTracker.TryGetOrder(ticket.OrderId, out PendingOrder pendingorder))
            {
                _log.Error($"Unable to retrieve order with id {ticket.OrderId} could not proceed");
                return(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.UnableToFindOrder, $"Current order with id {pendingorder.OrderId} cannot be found"));
            }

            //Get the order
            var order = pendingorder.Order as OrderImpl;

            //Check if we can update this order
            if (!CanUpdateOrder(order))
            {
                return(OrderTicketResponse.Error(order.InternalId, OrderTicketResponseErrorCode.InvalidOrderStatus,
                                                 $"Unable to update order with id {order.InternalId} and current state {order.State}"));
            }

            //Check if we can process this order
            try
            {
                if (!Portfolio.BrokerModel.CanUpdateOrder(order, out string message))
                {
                    //Notify we cannot update this order
                    order.State = OrderState.Invalid;
                    var response = OrderTicketResponse.Error(order.InternalId,
                                                             OrderTicketResponseErrorCode.BrokerageModelRefusedToUpdateOrder, $"Cannot update order {order.InternalId}: {message}");
                    Portfolio.Log(LogLevel.Error, response.ErrorMessage);
                    HandleOrderTicketEvent(OrderTicketEvent.Error(order.InternalId, response.ErrorMessage));
                    return(response);
                }
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not run CanUpdateOrder on order with id {order.InternalId}, please check the implemented logic");
                order.State = OrderState.Invalid;
                return(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.ProcessingError, $"Current order with id {pendingorder.OrderId} cannot be processed due to error"));
            }

            //Check order quantity and pricing in case this is out of range
            RoundLotSize(order);
            RoundOrderPrices(order);

            //Try and update this order
            bool orderupdatesucceeded = false;

            try
            {
                orderupdatesucceeded = BrokerConnection.UpdateOrder(pendingorder);
            }
            catch (Exception exc)
            {
                _log.Error(exc);
            }

            //Process a failed order update event
            if (!orderupdatesucceeded)
            {
                var errormessage =
                    $"Broker connection failed to update order with id {order.InternalId} with connection type {BrokerConnection.BrokerType}";
                Portfolio.Log(LogLevel.Error, errormessage);
                HandleOrderTicketEvent(OrderTicketEvent.Error(order.InternalId, "Failed to update order"));
                return(OrderTicketResponse.Error(order.InternalId,
                                                 OrderTicketResponseErrorCode.BrokerageFailedToUpdateOrder, errormessage));
            }
            else
            {
                //Apply updates to order
                order.Update(ticket);
                pendingorder.UpdateOrder(order);
            }

            return(OrderTicketResponse.Processed(order.InternalId));
        }
Пример #12
0
        /// <summary>
        /// Process submit order
        /// </summary>
        /// <param name="ticket"></param>
        protected virtual OrderTicketResponse SubmitOrder(SubmitOrderTicket ticket)
        {
            //Get order from factory
            PendingOrder pendingorder = OrderFactory.CreateOrder(ticket);
            OrderImpl    order        = pendingorder.Order as OrderImpl;

            //Round off order quantity for correct amounts
            RoundLotSize(order);

            //try and get the order from the order tracker
            if (!OrderTracker.TryAddOrder(pendingorder))
            {
                _log.Error($"Unable to add new order, order with id {pendingorder.OrderId} was already submitted");
                return(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.OrderAlreadyExists, $"Current order with id {pendingorder.OrderId} was already submitted"));
            }
            if (!OrderTracker.TryGetOrder(pendingorder.OrderId, out pendingorder))
            {
                _log.Error($"Unable to retrieve newly added order, order with id {pendingorder.OrderId} was cannot be processed properly");
                return(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.UnableToFindOrder, $"Current order with id {pendingorder.OrderId} cannot be found"));
            }

            //Round of prices
            RoundOrderPrices(order);

            //Set our new order
            pendingorder.UpdateOrder(order);

            //Check for correct size
            if (order.Quantity == 0)
            {
                order.State = OrderState.Invalid;
                var ticketresponse = OrderTicketResponse.Error(order.InternalId, OrderTicketResponseErrorCode.OrderQuantityZero);
                Portfolio.Log(LogLevel.Error, ticketresponse.ErrorMessage);
                return(ticketresponse);
            }

            //Check if we have enough capital for an order
            bool sufficientcapital = GetSufficientCapitalForOrder(pendingorder);

            if (!sufficientcapital)
            {
                //Not enough capital to execute this order
                order.State = OrderState.Invalid;
                var response = OrderTicketResponse.Error(order.InternalId,
                                                         OrderTicketResponseErrorCode.InsufficientBuyingPower, $"Cannot execute order with id {order.InternalId}, insufficient funds to execute order.");
                Portfolio.Log(LogLevel.Error, response.ErrorMessage);
                HandleOrderTicketEvent(OrderTicketEvent.Error(order.InternalId, $"Insufficent capital to execute order"));
                return(response);
            }

            //Check if broker accepts order at this moment
            try
            {
                if (!Portfolio.BrokerModel.CanSubmitOrder(order, out var message))
                {
                    //Broker model did not accept this order
                    order.State = OrderState.Invalid;
                    var response = OrderTicketResponse.Error(order.InternalId,
                                                             OrderTicketResponseErrorCode.BrokerageModelRefusedToSubmitOrder, $"Order with id {order.InternalId}: {message}");
                    Portfolio.Log(LogLevel.Error, "");
                    HandleOrderTicketEvent(OrderTicketEvent.Error(order.InternalId, $"Broker model of type {Portfolio.BrokerModel.BrokerType} declared order cannot be submitted, message: {message}"));
                    return(response);
                }
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not run CanSubmitOrder on order with id {order.InternalId}, please check the implemented logic");
                order.State = OrderState.Invalid;
                return(OrderTicketResponse.Error(pendingorder.OrderId, OrderTicketResponseErrorCode.ProcessingError, $"Current order with id {pendingorder.OrderId} cannot be processed due to error"));
            }

            //Try to execute this order to the broker connection attached
            bool ordersuccess = false;

            try
            {
                ordersuccess = BrokerConnection.SubmitOrder(pendingorder);
            }
            catch (Exception exc)
            {
                _log.Error(exc);
            }

            //Check if placing the order was a success
            if (!ordersuccess)
            {
                order.State = OrderState.Invalid;
                var submitmessage = "BrokerConnection failed to place order";
                var response      = OrderTicketResponse.Error(order.InternalId,
                                                              OrderTicketResponseErrorCode.BrokerageFailedToSubmitOrder, submitmessage);
                Portfolio.Log(LogLevel.Error, submitmessage);
                HandleOrderTicketEvent(OrderTicketEvent.Error(order.InternalId, submitmessage));
                return(response);
            }

            order.State = OrderState.Submitted;
            return(OrderTicketResponse.Processed(order.InternalId));
        }