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); }
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)); }