public void TestMethod2() { var portfolio = testPortfolio(2000.0m); var trade = new Trade(testSecurity("ABC"), TradeActionBuySell.Buy, 100, TradeType.Market); var rule = new TradeApprovalRule_2("Rule2"); // Should pass Assert.IsTrue(rule.Run(trade, portfolio, testDate, TimeOfDay.MarketOpen)); trade = new Trade(testSecurity("ABC"), TradeActionBuySell.Buy, 250, TradeType.Market); // Should fail Assert.IsFalse(rule.Run(trade, portfolio, testDate, TimeOfDay.MarketOpen)); }
public void RegTTest() { // Test scenario outlined at IBKR https://www.interactivebrokers.com/en/index.php?f=24862 PortfolioSetup testSetupParams = new PortfolioSetup(PortfolioDirection.LongShort, PortfolioMarginType.RegTMargin, 10000, new DateTime(2019, 11, 18)); Portfolio testPortfolio = new Portfolio(testSetupParams); TradingEnvironment.Instance.NegateCommissionForTesting = true; var testSecXYZ = new Security("XYZ", SecurityType.USCommonEquity); var testSecABC = new Security("ABC", SecurityType.USCommonEquity); DateTime[] day = new DateTime[] { new DateTime(2019, 11, 15), new DateTime(2019, 11, 18), // Day 1 new DateTime(2019, 11, 19), new DateTime(2019, 11, 20), new DateTime(2019, 11, 21), new DateTime(2019, 11, 22) // Day 5 }; // Setup stock as described testSecXYZ.GetPriceBar(day[1], true).SetPriceValues(40m, 40m, 40m, 40m); testSecXYZ.GetPriceBar(day[2], true).SetPriceValues(40m, 40m, 40m, 40m); testSecXYZ.GetPriceBar(day[3], true).SetPriceValues(40m, 45m, 35m, 40m); testSecXYZ.GetPriceBar(day[4], true).SetPriceValues(45m, 45m, 45m, 45m); testSecXYZ.GetPriceBar(day[5], true).SetPriceValues(40m, 40m, 40m, 40m); testSecABC.GetPriceBar(day[1], true).SetPriceValues(101m, 101m, 101m, 101m); testSecABC.GetPriceBar(day[2], true).SetPriceValues(101m, 101m, 101m, 101m); testSecABC.GetPriceBar(day[3], true).SetPriceValues(101m, 101m, 101m, 101m); testSecABC.GetPriceBar(day[4], true).SetPriceValues(101m, 101m, 101m, 101m); testSecABC.GetPriceBar(day[5], true).SetPriceValues(101m, 101m, 75m, 100m); // Day 1 /* * Deposit $10,000.00 Cash in Margin Account. * After the deposit, account values look like this: * Cash $10,000.00 (Initial deposit) * Securities Market Value $0.00 (No positions held) * Equity with Loan Value (ELV1) $10,000.00 * Initial Margin $0.00 IM = 25% * Stock Value * Maintenance Margin (MM) $0.00 MM = 25% * Stock Value * Available Funds $10,000.00 ELV - IM * Excess Liquidity $10,000.00 ELV - MM * * Reg T Margin $0.00 Reg T Margin = 50% * Stock Value * SMA2 $10,000.00 SMA >= 0 * SMA Requirement Satisfied, NO liquidation */ Assert.AreEqual(10000.00m, testPortfolio.TotalCashValue(day[1])); Assert.AreEqual(0.0m, testPortfolio.SecuritiesMarketValue(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(10000.00m, testPortfolio.EquityWithLoanValue(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.BrokerInitialMarginRequirement(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(10000.0m, testPortfolio.AvailableFunds(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(10000.0m, testPortfolio.ExcessLiquidity(day[1], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(10000.0m, testPortfolio.SpecialMemorandumAccountBalance(day[1], TimeOfDay.MarketEndOfDay)); // Day 2 /* * Customer BUYS 500 shares of XYZ stock at $40.00/share. * Total Amount = $20,000.00. After the trade, account values look like this: * Cash ($10,000.00) * Securities Market Value $20,000.00 * Equity with Loan Value (ELV1) $10,000.00 * Initial Margin $5,000.00 IM = 25% * Stock Value * Maintenance Margin (MM) $5,000.00 MM = 25% * Stock Value * Available Funds $5,000.00 ELV-IM * Available Funds were >=0 at the time of the trade, so the trade was submitted. * Excess Liquidity $5,000.00 ELV - MM */ var trade1 = new Trade(testSecXYZ, TradeActionBuySell.Buy, 500, TradeType.Limit, 40.0m) { TradeStatus = TradeStatus.Pending }; trade1.MarkExecuted(day[2], 40.0m); testPortfolio.AddExecutedTrade(trade1); Assert.AreEqual(-10000.00m, testPortfolio.TotalCashValue(day[2])); Assert.AreEqual(20000.0m, testPortfolio.SecuritiesMarketValue(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(10000.00m, testPortfolio.EquityWithLoanValue(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.BrokerInitialMarginRequirement(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.AvailableFunds(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.ExcessLiquidity(day[2], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.SpecialMemorandumAccountBalance(day[2], TimeOfDay.MarketEndOfDay)); // Day 3 - 1 /* * First, the price of XYZ rises to 45.00/share. * Account values now look like this: * Cash ($10,000.00) * Securities Market Value $22,500.00 * Equity with Loan Value (ELV1) $12,500.00 * Initial Margin $5,625.00 IM = 25% * Stock Value * Maintenance Margin (MM) $5,625.00 MM = 25% * Stock Value * Available Funds $6,875.00 ELVIM * Excess Liquidity $6,875.00 ELV - MM * Excess Liquidity >=0, so NO LIQUIDATION occurs. */ // Our methods calculate EOD, so set price bar accordingly for this intraday scenario testSecXYZ.GetPriceBar(day[3]).SetPriceValues(45m, 45m, 45m, 45m); Assert.AreEqual(-10000.00m, testPortfolio.TotalCashValue(day[3])); Assert.AreEqual(22500, testPortfolio.SecuritiesMarketValue(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.EquityWithLoanValue(day[3], TimeOfDay.MarketEndOfDay)); // IBKR initial and maintenance margin is the same; our methods calculate initial based on the execution price for use in trade approval // Assert.AreEqual(5625.0m, testPortfolio.BrokerInitialMarginRequirement(day[3])); Assert.AreEqual(5625.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(6875.0m, testPortfolio.AvailableFunds(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(6875.0m, testPortfolio.ExcessLiquidity(day[3], TimeOfDay.MarketEndOfDay)); //var log = testPortfolio.ToStringAllAccounting(day[3]); //log.AddRange(testPortfolio.ToStringAllActivity(day[3])); //OutputToTextFile(log); // Day 3 - 2 /* * Then the price of XYZ falls to $35.00/share. * Account values now look like this: * Cash ($10,000.00) * Securities Market Value $17,500.00 * Equity with Loan Value (ELV1) $7,500.00 * Initial Margin $4,375.00 IM = 25% * Stock Value * Maintenance Margin (MM) $4,375.00 MM = 25% * Stock Value * Available Funds $3,125.00 ELVIM * Excess Liquidity $3,125.00 ELV - MM * Reg T Margin $8,750.00 Reg T Margin = 50% * Stock Value * SMA2 $0.00 */ testSecXYZ.GetPriceBar(day[3]).SetPriceValues(35m, 35m, 35m, 35m); Assert.AreEqual(-10000.00m, testPortfolio.TotalCashValue(day[3])); Assert.AreEqual(17500.0m, testPortfolio.SecuritiesMarketValue(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(7500.0m, testPortfolio.EquityWithLoanValue(day[3], TimeOfDay.MarketEndOfDay)); // Assert.AreEqual(5625.0m, testPortfolio.BrokerInitialMarginRequirement(day[3])); Assert.AreEqual(4375.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(3125.0m, testPortfolio.AvailableFunds(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(3125.0m, testPortfolio.ExcessLiquidity(day[3], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.SpecialMemorandumAccountBalance(day[3], TimeOfDay.MarketEndOfDay)); // Day 4 /* * Customer SELLS 500 shares of XYZ at $45.00/share. * Total Amount = $22,500.00. After the trade, account values look like this: * Cash $12,500.00 * Securities Market Value $0.00 Positions no longer held. * Equity with Loan Value (ELV1) $12,500.00 * Initial Margin $0.00 IM = 25% * Stock Value * Maintenance Margin (MM) $0.00 MM = 25% * Stock Value * Available Funds $12,500.00 ELV-IM * Excess Liquidity $12,500.00 ELV - MM * Reg T Margin $0.00 Reg T Margin = 50% * Stock Value * SMA2 $12,500.00 */ var trade2 = new Trade(testSecXYZ, TradeActionBuySell.Sell, 500, TradeType.Limit, 45.00m) { TradeStatus = TradeStatus.Pending }; trade2.MarkExecuted(day[4], 45.0m); testPortfolio.AddExecutedTrade(trade2); Assert.AreEqual(12500.0m, testPortfolio.TotalCashValue(day[4])); Assert.AreEqual(0.0m, testPortfolio.SecuritiesMarketValue(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.EquityWithLoanValue(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.BrokerInitialMarginRequirement(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(0.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.AvailableFunds(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.ExcessLiquidity(day[4], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.SpecialMemorandumAccountBalance(day[4], TimeOfDay.MarketEndOfDay)); // Day 5 - 1 /* * Customer attempts to BUY 500 shares of ABC stock at $101.00/share. * Total Amount = $50,500.00. Account values at the time of the attempted trade would look like this: * Cash $12,500.00 * Securities Market Value $0.00 * Equity with Loan Value (ELV1) $12,500.00 * Initial Margin $12,625.00 IM = 25% * Stock Value * Maintenance Margin (MM) $12,625.00 MM = 25% * Stock Value * Available Funds ($125.00) ELV-IM * Available Funds <=0 so the trade is Rejected. * Excess Liquidity ($125.00) ELV - MM */ var trade3 = new Trade(testSecABC, TradeActionBuySell.Buy, 500, TradeType.Limit, 101.00m) { TradeStatus = TradeStatus.Pending }; var copyPort = testPortfolio.Copy(); var copyTrade = trade3.Copy(); copyTrade.MarkExecuted(day[5], 101.00m); copyPort.AddExecutedTrade(copyTrade); // Post-trade available funds are negative, so this trade would be rejected Assert.AreEqual(-125.0m, copyPort.AvailableFunds(day[5], TimeOfDay.MarketOpen)); // Test rule implementation var rule = new TradeApprovalRule_2("Rule2"); Assert.IsFalse(rule.Run(trade3, testPortfolio, day[5], TimeOfDay.MarketOpen)); copyTrade = null; copyPort = null; // Day 5 - 2 /* * Later on Day 5, the customer buys some stock. * Customer BUYS 300 shares of ABC stock at $100.00/share. * Total Amount = $30,000.00. After the trade, account values look like this: * Cash ($17,500.00) * Securities Market Value $30,000.00 * Equity with Loan Value (ELV1) $12,500.00 * Initial Margin $7,500.00 IM = 25% * Stock Value * Maintenance Margin (MM) $7,500.00 MM = 25% * Stock Value * Available Funds $5,000.00 ELVIM * Excess Liquidity $5,000.00 ELV - MM * Reg T Margin $15,000.00 Reg T Margin = 50% * Stock Value * SMA2 -$2,500.00 */ testSecABC.GetPriceBar(day[5]).SetPriceValues(100m, 100m, 100m, 100m); var trade4 = new Trade(testSecABC, TradeActionBuySell.Buy, 300, TradeType.Limit, 100.00m) { TradeStatus = TradeStatus.Pending }; trade4.MarkExecuted(day[5], 100.0m); testPortfolio.AddExecutedTrade(trade4); Assert.AreEqual(-17500.0m, testPortfolio.TotalCashValue(day[5])); Assert.AreEqual(30000.0m, testPortfolio.SecuritiesMarketValue(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(12500.0m, testPortfolio.EquityWithLoanValue(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(7500.0m, testPortfolio.BrokerInitialMarginRequirement(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(7500.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.AvailableFunds(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.ExcessLiquidity(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(-2500.0m, testPortfolio.SpecialMemorandumAccountBalance(day[5], TimeOfDay.MarketEndOfDay)); // Day 5 - 2 alternate /* * Consider an alternate Day 5 scenario in which the price of ABC stock drops. * Price of ABC stock drops to $75.00/share. * Account values would now look like this: * Cash ($17,500.00) * Securities Market Value $22,500.00 * Equity with Loan Value (ELV1) $5,000.00 * Initial Margin $5,625.00 IM = 25% * Stock Value * Maintenance Margin (MM) $5,625.00 MM = 25% * Stock Value * Available Funds ($625.00) ELVIM * Excess Liquidity ($625.00) */ testSecABC.GetPriceBar(day[5]).SetPriceValues(75m, 75m, 75m, 75m); Assert.AreEqual(-17500.0m, testPortfolio.TotalCashValue(day[5])); Assert.AreEqual(22500.0m, testPortfolio.SecuritiesMarketValue(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5000.0m, testPortfolio.EquityWithLoanValue(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5625.0m, testPortfolio.BrokerInitialMarginRequirement(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(5625.0m, testPortfolio.BrokerMaintenanceMarginRequirement(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(-625.0m, testPortfolio.AvailableFunds(day[5], TimeOfDay.MarketEndOfDay)); Assert.AreEqual(-625.0m, testPortfolio.ExcessLiquidity(day[5], TimeOfDay.MarketEndOfDay)); TradingEnvironment.Instance.NegateCommissionForTesting = false; }