示例#1
0
        /// <summary>
        /// Process submit order
        /// For crypto currencies: check if we have the correct amount of base currency, if not, create and additional order for getting the correct base currency amount
        /// </summary>
        /// <param name="ticket"></param>
        /// <returns></returns>
        protected override OrderTicketResponse SubmitOrder(SubmitOrderTicket ticket)
        {
            //Check for associated quant fund
            var quantfund = Portfolio.QuantFunds.FirstOrDefault(x => x.FundId == ticket.FundId);

            //Check if we can get the pending order
            var     cashposition = (quantfund == null ? CashManager.GetCashPositions() : CashManager.GetCashPositions(quantfund))[ticket.Security.BaseCurrency];
            decimal value        = Math.Abs(ticket.Security.ConvertValue(ticket.Quantity * ticket.Security.Price, cashposition.BaseCurrency));

            if (cashposition.TotalSettledCash < value)
            {
                //We need extra cash for this in currency X
                decimal valueneeded = value - cashposition.TotalSettledCash;

                //Create and send
                var security    = Portfolio.BrokerAccount.Securities[$"{cashposition.BaseCurrency}.BC"];
                var orderticket = SubmitOrderTicket.MarketOrder(ticket.FundId, security, valueneeded, $"Base currency conversion needed to execute order with id {ticket.OrderId}");
                var response    = SubmitOrder(orderticket);

                //Wait for this order
                if (!response.IsError)
                {
                    WaitForOrder(response.OrderId);
                }
                else
                {
                    _log.Error($"Could not process currency conversion for order with id {ticket.OrderId}, due to conversion order error {response.ErrorCode} : {response.ErrorMessage}");
                }
            }

            //Use base implementation
            return(base.SubmitOrder(ticket));
        }
示例#2
0
        /// <summary>
        /// Calculate order size for signal order
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="state"></param>
        /// <param name="weight"></param>
        /// <returns></returns>
        public override decimal OrderQuantity(SubmitOrderTicket ticket, SecurityState state, decimal weight)
        {
            //Get the needed weight (instead of the supplied weight we get from the universe, we change it to reflect our own weight)
            if (_adjustedweights.ContainsKey(ticket.Security))
            {
                var oldweight = weight;
                weight = _adjustedweights[ticket.Security];
                Info($"Adjusted weight from {oldweight}, to {weight}");
            }
            else
            {
                Warning($"Could not adjust weight, could not find security {ticket.Security}");
            }

            //Get target amount
            decimal target = TargetWeight(ticket.Security,
                                          (state == SecurityState.EntryShort ? -1 : state == SecurityState.EntryLong ? 1 : 0) * weight);

            //Check if target is valid
            if (target == 0)
            {
                ticket.Cancel();
                return(0);
            }
            else
            {
                return(target);
            }
        }
示例#3
0
        /// <summary>
        /// Processes the submit ticket.
        /// </summary>
        /// <param name="ticket">The ticket.</param>
        /// <param name="quantfund">Associated Quant Fund</param>
        /// <returns></returns>
        private OrderTicket ProcessSubmitTicket(SubmitOrderTicket ticket, IQuantFund quantfund)
        {
            if (quantfund != null && quantfund.IsBackfilling)
            {
                ticket.SetResponse(
                    OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.QuantFundBackfilling,
                                              $"Quant fund {ticket.FundId} is currently backfilling, cannot process orders."));
            }
            else
            {
                _orderTicketQueue.Add(ticket);
                ticket.SetResponse(OrderTicketResponse.Processed(ticket.OrderId), OrderTicketState.Processing);
            }

            return(ticket);
        }
示例#4
0
        /// <summary>
        /// Calculate order size for signal order
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="state"></param>
        /// <param name="weight"></param>
        /// <returns></returns>
        public override decimal OrderQuantity(SubmitOrderTicket ticket, SecurityState state, decimal weight)
        {
            //Get target amount
            decimal target = TargetWeight(ticket.Security,
                                          (state == SecurityState.EntryShort ? -1 : state == SecurityState.EntryLong ? 1 : 0) * weight);

            //Check if target is valid
            if (target == 0)
            {
                ticket.Cancel();
                return(0);
            }
            else
            {
                return(target);
            }
        }
示例#5
0
 /// <summary>
 /// Perform risk management checks and retrieve new orders to offset risks
 /// </summary>
 /// <param name="orderticket"></param>
 /// <param name="state"></param>
 /// <param name="weight"></param>
 /// <returns></returns>
 public virtual IEnumerable <OrderTicket> RiskManagement(SubmitOrderTicket orderticket, SecurityState state, decimal weight) =>
 throw new NotImplementedException("RiskManagement method should be implemented for a risk management module to function.");
示例#6
0
 /// <summary>
 /// Create a new stop limit order ticket
 /// </summary>
 /// <param name="security">The security.</param>
 /// <param name="quantity">The quantity.</param>
 /// <param name="stopprice">The stopprice.</param>
 /// <param name="limitprice">The limitprice.</param>
 /// <param name="comment">The comment.</param>
 /// <param name="exchange"></param>
 /// <returns></returns>
 public SubmitOrderTicket StopLimitOrder(Security security, decimal quantity, decimal stopprice, decimal limitprice, string comment = "", string exchange = "") =>
 SubmitOrderTicket.StopLimitOrder(QuantFund.FundId, security, quantity, limitprice, stopprice, comment, exchange);
示例#7
0
 /// <summary>
 /// Create a new market order ticket
 /// </summary>
 /// <param name="security">The security.</param>
 /// <param name="quantity">The quantity.</param>
 /// <param name="comment">The comment.</param>
 /// <param name="exchange"></param>
 /// <returns></returns>
 public SubmitOrderTicket MarketOrder(Security security, decimal quantity, string comment = "",
                                      string exchange = "") =>
 SubmitOrderTicket.MarketOrder(QuantFund.FundId, security, quantity, comment, exchange);
示例#8
0
 /// <summary>
 /// Perform risk management checks and retrieve new orders to offset risks
 /// </summary>
 /// <param name="orderticket"></param>
 /// <param name="state"></param>
 /// <param name="weight"></param>
 /// <returns></returns>
 public override IEnumerable <OrderTicket> RiskManagement(SubmitOrderTicket orderticket, SecurityState state, decimal weight) =>
 Nothing;
示例#9
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));
        }
示例#10
0
        /// <summary>
        /// Process any simulated orders
        /// </summary>
        /// <param name="datapoints"></param>
        protected virtual void ProcessSimulatedOrders(IEnumerable <DataPoint> datapoints)
        {
            //Check if we need to check this
            if (OrderCount == 0)
            {
                return;
            }

            //Only check on tick data and bars
            var datapointsused = datapoints.Where(x => x.DataType == DataType.QuoteBar || x.DataType == DataType.TradeBar || x.DataType == DataType.Tick);

            //Triggered orders
            List <PendingOrder> triggered = new List <PendingOrder>();

            //Get all orders that need to be simulated internally
            foreach (var item in OrderTracker.PendingOrders
                     .Where(x => !x.OrderState.IsDone())
                     .Where(x => x.IsSimulated)
                     .Join(datapointsused, x => x.Security.Ticker, x => x.Ticker, (po, dp) => new { PendingOrder = po, DataPoint = dp })
                     .ToArray())
            {
                //Check if already triggered
                if (triggered.Select(x => x.OrderId).Contains(item.PendingOrder.OrderId))
                {
                    continue;
                }

                //Get Data
                var currentprices = item.DataPoint.OrderPrice(item.PendingOrder.Security, item.PendingOrder.Order.Direction);
                var order         = item.PendingOrder.Order;

                //Create function for converting to a market order
                SubmitOrderTicket CreateSubmitTicket() =>
                SubmitOrderTicket.MarketOrder(item.PendingOrder.FundId, order.Security, order.Quantity);

                //logging function
                void Log(decimal price) => _log.Debug($"Simulated order of type {order.Type} with id {order.InternalId} was triggered at price {price} for processing");
                string CreateComment() =>
                $"Sending market order for simulated order {item.PendingOrder.OrderId} and order type {OrderType.Limit}. OldComment: {item.PendingOrder.Comment}";

                //Check order type and logic
                switch (order)
                {
                case LimitOrder limitorder:
                {
                    //Check if limit order price is triggered
                    if (limitorder.IsTriggered(currentprices, out decimal price))
                    {
                        //create a new order from this order, as it will be converted to a market order
                        Log(price);
                        var norder = CreateSubmitTicket();
                        norder.Comment = CreateComment();
                        SubmitOrder(norder);

                        //Add to triggered
                        triggered.Add(item.PendingOrder);
                    }
                    break;
                }

                case StopLimitOrder stoplimitorder:
                {
                    //Check if stop limit order price is triggered
                    if (stoplimitorder.IsTriggered(currentprices, out decimal price))
                    {
                        //create a new order from this order, as it will be converted to a market order
                        Log(price);
                        var norder = CreateSubmitTicket();
                        norder.Comment = CreateComment();
                        SubmitOrder(norder);

                        //Add to triggered
                        triggered.Add(item.PendingOrder);
                    }
                    break;
                }

                case StopMarketOrder stoporder:
                {
                    //Check if stop order price is triggered
                    if (stoporder.IsTriggered(currentprices, out decimal price))
                    {
                        //create a new order from this order, as it will be converted to a market order
                        Log(price);
                        var norder = CreateSubmitTicket();
                        norder.Comment = CreateComment();
                        SubmitOrder(norder);

                        //Add to triggered
                        triggered.Add(item.PendingOrder);
                    }
                    break;
                }

                case MarketOnCloseOrder marketOnCloseOrder:
                {
                    //Check if stop order price is triggered
                    if (marketOnCloseOrder.IsTriggered())
                    {
                        //create a new order from this order, as it will be converted to a market order
                        var norder = CreateSubmitTicket();
                        norder.Comment = CreateComment();
                        SubmitOrder(norder);

                        //Add to triggered
                        triggered.Add(item.PendingOrder);
                    }
                    break;
                }

                case MarketOnOpenOrder marketOnOpenOrder:
                {
                    //Check if stop order price is triggered
                    if (marketOnOpenOrder.IsTriggered())
                    {
                        //create a new order from this order, as it will be converted to a market order
                        var norder = CreateSubmitTicket();
                        norder.Comment = CreateComment();
                        SubmitOrder(norder);

                        //Add to triggered
                        triggered.Add(item.PendingOrder);
                    }
                    break;
                }

                default:
                    _log.Error($"Simulated order of type {item.PendingOrder.Order.Type} is not supported, removing order!");
                    triggered.Add(item.PendingOrder);
                    break;
                }
            }

            //Remove all triggered orders
            triggered.ForEach(x => OrderTracker.TryRemoveOrder(x.OrderId));
        }
示例#11
0
 /// <summary>
 /// Calculate order size for signal order
 /// </summary>
 /// <param name="ticket"></param>
 /// <param name="state"></param>
 /// <param name="weight"></param>
 /// <returns></returns>
 public virtual decimal OrderQuantity(SubmitOrderTicket ticket, SecurityState state, decimal weight) =>
 throw new NotImplementedException("OrderQuantity should be implemented for a money management module to function.");