public void ReducesPositionWhenMarginAboveTargetBasedOnSetting(decimal holdings, decimal minimumOrderMarginPortfolioPercentage)
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);
            var model     = new SecurityMarginModel();

            security.Holdings.SetHoldings(security.Price, holdings);

            var currentSignedUsedMargin = model.GetInitialMarginRequirement(security, security.Holdings.Quantity);
            var totalPortfolioValue     = algorithm.Portfolio.TotalPortfolioValue;
            var sign = Math.Sign(security.Holdings.Quantity) == 0 ? 1 : Math.Sign(security.Holdings.Quantity);
            // we inverse the sign here so that new target is less than current, we expect a reduction
            var newTarget = currentSignedUsedMargin / (totalPortfolioValue) + 0.00001m * sign * -1;

            var result = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, newTarget, minimumOrderMarginPortfolioPercentage);

            if (minimumOrderMarginPortfolioPercentage == 0)
            {
                // Reproduces GH issue #5763 a small Reduction in the target should reduce the position
                Assert.AreEqual(1m * sign * -1, result.Quantity);
                Assert.IsFalse(result.IsError);
            }
            else
            {
                Assert.AreEqual(0, result.Quantity);
                Assert.IsFalse(result.IsError);
            }
        }
        /// <summary>
        /// Gets a new buying power model for the security, returning the default model with the security's configured leverage.
        /// For cash accounts, leverage = 1 is used.
        /// </summary>
        /// <param name="security">The security to get a buying power model for</param>
        /// <returns>The buying power model for this brokerage/security</returns>
        public virtual IBuyingPowerModel GetBuyingPowerModel(Security security)
        {
            var leverage = GetLeverage(security);
            IBuyingPowerModel model;

            switch (security.Type)
            {
            case SecurityType.Crypto:
                model = new CashBuyingPowerModel();
                break;

            case SecurityType.Forex:
            case SecurityType.Cfd:
                model = new SecurityMarginModel(leverage, RequiredFreeBuyingPowerPercent);
                break;

            case SecurityType.Option:
                model = new OptionMarginModel(RequiredFreeBuyingPowerPercent);
                break;

            case SecurityType.FutureOption:
                model = new FuturesOptionsMarginModel(RequiredFreeBuyingPowerPercent, (Option)security);
                break;

            case SecurityType.Future:
                model = new FutureMarginModel(RequiredFreeBuyingPowerPercent, security);
                break;

            default:
                model = new SecurityMarginModel(leverage, RequiredFreeBuyingPowerPercent);
                break;
            }
            return(model);
        }
        public void ReducesPositionWhenMarginAboveTargetWhenNegativeFreeMargin(decimal holdings)
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);
            var model     = new SecurityMarginModel();

            security.Holdings.SetHoldings(security.Price, holdings);

            var security2 = InitAndGetSecurity(algorithm, 0, symbol: "AAPL");

            // eat up all our TPV
            security2.Holdings.SetHoldings(security.Price, (algorithm.Portfolio.TotalPortfolioValue / security.Price) * 2);

            var currentSignedUsedMargin = model.GetInitialMarginRequirement(security, security.Holdings.Quantity);
            var totalPortfolioValue     = algorithm.Portfolio.TotalPortfolioValue;
            var sign = Math.Sign(security.Holdings.Quantity) == 0 ? 1 : Math.Sign(security.Holdings.Quantity);
            // we inverse the sign here so that new target is less than current, we expect a reduction
            var newTarget = currentSignedUsedMargin / (totalPortfolioValue) + 0.00001m * sign * -1;

            Assert.IsTrue(0 > algorithm.Portfolio.MarginRemaining);
            var result = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, newTarget, 0);

            // Reproduces GH issue #5763 a small Reduction in the target should reduce the position
            Assert.AreEqual(1m * sign * -1, result.Quantity);
            Assert.IsFalse(result.IsError);
        }
示例#4
0
        public void ReturnsMinimumOrderValueReason()
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);
            var model     = new SecurityMarginModel();
            var result    = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, 0.00000001m);

            Assert.AreEqual(0m, result.Quantity);
            Assert.IsFalse(result.IsError);
            Assert.IsTrue(result.Reason.Contains("is less than the minimum"));
        }
        public void ZeroTargetWithZeroHoldingsIsNotAnError()
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);

            var model  = new SecurityMarginModel();
            var result = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, 0, 0);

            Assert.AreEqual(0, result.Quantity);
            Assert.IsTrue(result.Reason.IsNullOrEmpty());
            Assert.IsFalse(result.IsError);
        }
        public void ZeroTargetWithZeroHoldingsIsNotAnError()
        {
            var algorithm = new QCAlgorithm();
            var security  = algorithm.AddEquity("SPY");

            var model  = new SecurityMarginModel();
            var result = model.GetMaximumOrderQuantityForTargetValue(algorithm.Portfolio, security, 0);

            Assert.AreEqual(0, result.Quantity);
            Assert.AreEqual(string.Empty, result.Reason);
            Assert.AreEqual(false, result.IsError);
        }
        public void ZeroTargetWithNonZeroHoldingsReturnsNegativeOfQuantity()
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);

            security.Holdings.SetHoldings(200, 10);

            var model  = new SecurityMarginModel();
            var result = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, 0, 0);

            Assert.AreEqual(-10, result.Quantity);
            Assert.IsTrue(result.Reason.IsNullOrEmpty());
            Assert.IsFalse(result.IsError);
        }
        public void ZeroTargetWithNonZeroHoldingsReturnsNegativeOfQuantity()
        {
            var algorithm = new QCAlgorithm();
            var security  = algorithm.AddEquity("SPY");

            security.Holdings.SetHoldings(200, 10);

            var model  = new SecurityMarginModel();
            var result = model.GetMaximumOrderQuantityForTargetValue(algorithm.Portfolio, security, 0);

            Assert.AreEqual(-10, result.Quantity);
            Assert.AreEqual(string.Empty, result.Reason);
            Assert.AreEqual(false, result.IsError);
        }
        public void ReturnsMinimumOrderValueReason(decimal holdings)
        {
            var algorithm = GetAlgorithm();
            var security  = InitAndGetSecurity(algorithm, 0);
            var model     = new SecurityMarginModel();

            security.Holdings.SetHoldings(security.Price, holdings);
            var currentSignedUsedMargin = model.GetInitialMarginRequirement(security, security.Holdings.Quantity);
            var totalPortfolioValue     = algorithm.Portfolio.TotalPortfolioValue;
            var sign = Math.Sign(security.Holdings.Quantity) == 0 ? 1 : Math.Sign(security.Holdings.Quantity);
            // we increase it slightly, should not trigger a new order because it's increasing final margin usage, rounds down
            var newTarget = currentSignedUsedMargin / (totalPortfolioValue) + 0.00001m * sign;

            var result = model.GetMaximumOrderQuantityForTargetBuyingPower(algorithm.Portfolio, security, newTarget, 0);

            Assert.AreEqual(0m, result.Quantity);
            Assert.IsFalse(result.IsError);
            Assert.IsTrue(result.Reason.Contains("The order quantity is less than the lot size of", StringComparison.InvariantCultureIgnoreCase));
        }