Ejemplo n.º 1
0
        /// <summary>
        /// Check if there is sufficient buying power to execute this order.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio, the security and the order</param>
        /// <returns>Returns buying power information for an order</returns>
        public virtual HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters)
        {
            // short circuit the div 0 case
            if (parameters.Order.Quantity == 0)
            {
                return(parameters.Sufficient());
            }

            var ticket = parameters.Portfolio.Transactions.GetOrderTicket(parameters.Order.Id);

            if (ticket == null)
            {
                return(parameters.Insufficient(
                           $"Null order ticket for id: {parameters.Order.Id}"
                           ));
            }

            if (parameters.Order.Type == OrderType.OptionExercise)
            {
                // for option assignment and exercise orders we look into the requirements to process the underlying security transaction
                var option     = (Option.Option)parameters.Security;
                var underlying = option.Underlying;

                if (option.IsAutoExercised(underlying.Close) && underlying.IsTradable)
                {
                    var quantity = option.GetExerciseQuantity(parameters.Order.Quantity);

                    var newOrder = new LimitOrder
                    {
                        Id         = parameters.Order.Id,
                        Time       = parameters.Order.Time,
                        LimitPrice = option.StrikePrice,
                        Symbol     = underlying.Symbol,
                        Quantity   = quantity
                    };

                    // we continue with this call for underlying
                    var parametersForUnderlying = parameters.ForUnderlying(newOrder);

                    var freeMargin = underlying.BuyingPowerModel.GetBuyingPower(parametersForUnderlying.Portfolio, parametersForUnderlying.Security, parametersForUnderlying.Order.Direction);
                    // we add the margin used by the option itself
                    freeMargin += GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(option, -parameters.Order.Quantity));

                    var initialMarginRequired = underlying.BuyingPowerModel.GetInitialMarginRequiredForOrder(
                        new InitialMarginRequiredForOrderParameters(parameters.Portfolio.CashBook, underlying, newOrder));

                    return(HasSufficientBuyingPowerForOrder(parametersForUnderlying, ticket, freeMargin, initialMarginRequired));
                }

                return(parameters.Sufficient());
            }

            return(HasSufficientBuyingPowerForOrder(parameters, ticket));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Check if there is sufficient buying power to execute this order.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio, the security and the order</param>
        /// <returns>Returns buying power information for an order</returns>
        public virtual HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters)
        {
            // short circuit the div 0 case
            if (parameters.Order.Quantity == 0)
            {
                return(parameters.Sufficient());
            }

            var ticket = parameters.Portfolio.Transactions.GetOrderTicket(parameters.Order.Id);

            if (ticket == null)
            {
                return(parameters.Insufficient(
                           $"Null order ticket for id: {parameters.Order.Id}"
                           ));
            }

            if (parameters.Order.Type == OrderType.OptionExercise)
            {
                // for option assignment and exercise orders we look into the requirements to process the underlying security transaction
                var option     = (Option.Option)parameters.Security;
                var underlying = option.Underlying;

                if (option.IsAutoExercised(underlying.Close) && underlying.IsTradable)
                {
                    var quantity = option.GetExerciseQuantity(parameters.Order.Quantity);

                    var newOrder = new LimitOrder
                    {
                        Id         = parameters.Order.Id,
                        Time       = parameters.Order.Time,
                        LimitPrice = option.StrikePrice,
                        Symbol     = underlying.Symbol,
                        Quantity   = option.Symbol.ID.OptionRight == OptionRight.Call ? quantity : -quantity
                    };

                    // we continue with this call for underlying
                    return(underlying.BuyingPowerModel.HasSufficientBuyingPowerForOrder(
                               parameters.ForUnderlying(newOrder)
                               ));
                }

                return(parameters.Sufficient());
            }

            // When order only reduces or closes a security position, capital is always sufficient
            if (parameters.Security.Holdings.Quantity * parameters.Order.Quantity < 0 && Math.Abs(parameters.Security.Holdings.Quantity) >= Math.Abs(parameters.Order.Quantity))
            {
                return(parameters.Sufficient());
            }

            var freeMargin = GetMarginRemaining(parameters.Portfolio, parameters.Security, parameters.Order.Direction);
            var initialMarginRequiredForOrder = GetInitialMarginRequiredForOrder(
                new InitialMarginRequiredForOrderParameters(
                    parameters.Portfolio.CashBook, parameters.Security, parameters.Order
                    ));

            // pro-rate the initial margin required for order based on how much has already been filled
            var percentUnfilled = (Math.Abs(parameters.Order.Quantity) - Math.Abs(ticket.QuantityFilled)) / Math.Abs(parameters.Order.Quantity);
            var initialMarginRequiredForRemainderOfOrder = percentUnfilled * initialMarginRequiredForOrder;

            if (Math.Abs(initialMarginRequiredForRemainderOfOrder) > freeMargin)
            {
                return(parameters.Insufficient(Invariant($"Id: {parameters.Order.Id}, ") +
                                               Invariant($"Initial Margin: {initialMarginRequiredForRemainderOfOrder.Normalize()}, ") +
                                               Invariant($"Free Margin: {freeMargin.Normalize()}")
                                               ));
            }

            return(parameters.Sufficient());
        }