/// <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)); }
/// <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); } } } }