예제 #1
0
        /// <summary>
        /// Check if there is sufficient buying power for the position group to execute this order.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio, the position group and the order</param>
        /// <returns>Returns buying power information for an order against a position group</returns>
        public virtual HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(
            HasSufficientPositionGroupBuyingPowerForOrderParameters parameters
            )
        {
            // The addition of position groups requires that we not only check initial margin requirements, but also
            // that we confirm that after the changes have been applied and the new groups resolved our maintenance
            // margin is still in a valid range (less than TPV). For this model, we use the security's sufficient buying
            // power impl to confirm initial margin requirements and lean heavily on GetReservedBuyingPowerImpact for
            // help with confirming that our expected maintenance margin is still less than TPV.
            //   1. Confirm we have sufficient buying power to execute the trade using security's BP model
            //   2. Confirm we pass position group specific checks
            //   3. Confirm we haven't exceeded maintenance margin limits via GetReservedBuyingPowerImpact's delta

            // 1. Confirm we meet initial margin requirements, accounting for buffer
            var availableBuyingPower = this.GetPositionGroupBuyingPower(
                parameters.Portfolio, parameters.PositionGroup, parameters.Order.Direction
                );

            // 2. Confirm we pass position group specific checks
            var result = PassesPositionGroupSpecificBuyingPowerForOrderChecks(parameters, availableBuyingPower);

            if (result?.IsSufficient == false)
            {
                return(result);
            }

            // 3. Confirm that the new groupings arising from the change doesn't make maintenance margin exceed TPV
            var args             = new ReservedBuyingPowerImpactParameters(parameters.Portfolio, parameters.PositionGroup, parameters.Order);
            var deltaBuyingPower = GetReservedBuyingPowerImpact(args).Delta;

            if (deltaBuyingPower <= availableBuyingPower)
            {
                return(parameters.Sufficient());
            }

            return(parameters.Insufficient(Invariant(
                                               $"Id: {parameters.Order.Id}, Maintenance Margin Delta: {deltaBuyingPower.Normalize()}, Free Margin: {availableBuyingPower.Value.Normalize()}"
                                               )));
        }
예제 #2
0
        /// <summary>
        /// Computes the impact on the portfolio's buying power from adding the position group to the portfolio. This is
        /// a 'what if' analysis to determine what the state of the portfolio would be if these changes were applied. The
        /// delta (before - after) is the margin requirement for adding the positions and if the margin used after the changes
        /// are applied is less than the total portfolio value, this indicates sufficient capital.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio and a position group containing the contemplated
        /// changes to the portfolio</param>
        /// <returns>Returns the portfolio's total portfolio value and margin used before and after the position changes are applied</returns>
        public virtual ReservedBuyingPowerImpact GetReservedBuyingPowerImpact(ReservedBuyingPowerImpactParameters parameters)
        {
            // This process aims to avoid having to compute buying power on the entire portfolio and instead determines
            // the set of groups that can be impacted by the changes being contemplated. The only real way to determine
            // the change in maintenance margin is to determine what groups we'll have after the changes and compute the
            // margin based on that.
            //   1. Determine impacted groups (depends on IPositionGroupResolver.GetImpactedGroups)
            //   2. Compute the currently reserved buying power of impacted groups
            //   3. Create position collection using impacted groups and apply contemplated changes
            //   4. Resolve new position groups using position collection with applied contemplated changes
            //   5. Compute the contemplated reserved buying power on these newly resolved groups

            // 1. Determine impacted groups
            var positionManager = parameters.Portfolio.Positions;

            // 2. Compute current reserved buying power
            var current        = 0m;
            var impactedGroups = new List <IPositionGroup>();

            // 3. Determine set of impacted positions to be grouped
            var positions = parameters.Order.CreatePositions(parameters.Portfolio.Securities).ToList();

            var impactedPositions = positions.ToDictionary(p => p.Symbol);

            foreach (var impactedGroup in positionManager.GetImpactedGroups(positions))
            {
                impactedGroups.Add(impactedGroup);
                current += impactedGroup.BuyingPowerModel.GetReservedBuyingPowerForPositionGroup(
                    parameters.Portfolio, impactedGroup
                    );

                foreach (var position in impactedGroup)
                {
                    IPosition existing;
                    if (impactedPositions.TryGetValue(position.Symbol, out existing))
                    {
                        // if it already exists then combine it with the existing
                        impactedPositions[position.Symbol] = existing.Combine(position);
                    }
                    else
                    {
                        impactedPositions[position.Symbol] = position;
                    }
                }
            }

            // 4. Resolve new position groups
            var contemplatedGroups = positionManager.ResolvePositionGroups(new PositionCollection(impactedPositions.Values));

            // 5. Compute contemplated reserved buying power
            var contemplated = 0m;

            foreach (var contemplatedGroup in contemplatedGroups)
            {
                contemplated += contemplatedGroup.BuyingPowerModel.GetMaintenanceMargin(
                    parameters.Portfolio, contemplatedGroup
                    );
            }

            return(new ReservedBuyingPowerImpact(
                       current, contemplated, impactedGroups, parameters.ContemplatedChanges, contemplatedGroups
                       ));
        }