/// <summary> /// Provides a mechanism for derived types to add their own buying power for order checks without needing to /// recompute the available buying power. Implementations should return null if all checks pass and should /// return an instance of <see cref="HasSufficientBuyingPowerForOrderResult"/> with IsSufficient=false if it /// fails. /// </summary> protected virtual HasSufficientBuyingPowerForOrderResult PassesPositionGroupSpecificBuyingPowerForOrderChecks( HasSufficientPositionGroupBuyingPowerForOrderParameters parameters, decimal availableBuyingPower ) { return(null); }
/// <summary> /// Additionally check initial margin requirements if the algorithm only has default position groups /// </summary> protected override HasSufficientBuyingPowerForOrderResult PassesPositionGroupSpecificBuyingPowerForOrderChecks( HasSufficientPositionGroupBuyingPowerForOrderParameters parameters, decimal availableBuyingPower ) { // only check initial margin requirements when the algorithm is only using default position groups if (!parameters.Portfolio.Positions.IsOnlyDefaultGroups) { return(null); } var symbol = parameters.PositionGroup.Single().Symbol; var security = parameters.Portfolio.Securities[symbol]; return(security.BuyingPowerModel.HasSufficientBuyingPowerForOrder( parameters.Portfolio, security, parameters.Order )); }
/// <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 override HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder( HasSufficientPositionGroupBuyingPowerForOrderParameters parameters ) { if (parameters.PositionGroup.Count != 1) { return(parameters.Error( $"{nameof(SecurityPositionGroupBuyingPowerModel)} only supports position groups containing exactly one position." )); } var position = parameters.PositionGroup.Single(); var security = parameters.Portfolio.Securities[position.Symbol]; return(security.BuyingPowerModel.HasSufficientBuyingPowerForOrder( parameters.Portfolio, security, parameters.Order )); }
/// <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()}" ))); }