/// <summary> /// Initializes a new instance of the <see cref="OrderTicket"/> class /// </summary> /// <param name="transactionManager">The transaction manager used for submitting updates and cancels for this ticket</param> /// <param name="submitRequest">The order request that initiated this order ticket</param> public OrderTicket(SecurityTransactionManager transactionManager, SubmitOrderRequest submitRequest) { _submitRequest = submitRequest; _orderId = submitRequest.OrderId; _transactionManager = transactionManager; _orderEvents = new List <OrderEvent>(); _updateRequests = new List <UpdateOrderRequest>(); _orderStatusClosedEvent = new ManualResetEvent(false); }
public void SellOnMondaySettleOnThursday() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(null, securities); var portfolio = new SecurityPortfolioManager(securities, transactions); // settlement at T+3, 8:00 AM var model = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security( SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); portfolio.SetCash(3000); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Monday var timeUtc = Noon.ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, Currencies.USD, 1000); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Tuesday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Wednesday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday at 7:55 AM, still unsettled timeUtc = timeUtc.AddDays(1).AddHours(-4).AddMinutes(-5); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday at 8 AM, now settled timeUtc = timeUtc.AddMinutes(5); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(4000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <summary> /// Creates a new <see cref="OrderTicket"/> tht represents trying to update an order for which no ticket exists /// </summary> public static OrderTicket InvalidUpdateOrderId(SecurityTransactionManager transactionManager, UpdateOrderRequest request) { var submit = new SubmitOrderRequest(OrderType.Market, SecurityType.Base, string.Empty, 0, 0, 0, DateTime.MaxValue, string.Empty); submit.SetResponse(OrderResponse.UnableToFindOrder(request)); var ticket = new OrderTicket(transactionManager, submit); request.SetResponse(OrderResponse.UnableToFindOrder(request)); ticket.AddUpdateRequest(request); ticket._orderStatusOverride = OrderStatus.Invalid; return(ticket); }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get <int>("OrderId"), SymbolMap[x.Get <string>("Symbol")], DateTime.MinValue, x.Get <OrderStatus>("Status"), x.Get <int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get <int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get <decimal>("FillPrice"), x.Get <int>("FillQuantity"), 0m) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var security = new Security(SecurityExchangeHours, subscriptions.Add(CASH, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLeverage(10m); securities.Add(CASH, security); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork)); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though security.SetMarketPrice(new IndicatorDataPoint(CASH, time, i + 1)); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
public void Setup() { var timeKeeper = new TimeKeeper(new DateTime(2015, 12, 07)); _securityManager = new SecurityManager(timeKeeper); _securityTransactionManager = new SecurityTransactionManager(_securityManager); _securityPortfolioManager = new SecurityPortfolioManager(_securityManager, _securityTransactionManager); _subscriptionManager = new SubscriptionManager(new AlgorithmSettings(), timeKeeper); _marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder(); _securityInitializer = SecurityInitializer.Null; }
public void OptimizerResultHandlerTest() { var shadow = new Wrapper(); Type shadowType = shadow.GetType(); var unit = new OptimizerResultHandler(shadow); var flags = BindingFlags.Instance | BindingFlags.NonPublic; var algorithmMock = new Mock <IAlgorithm>(); var securityManager = new SecurityManager(Mock.Of <ITimeKeeper>()); var securityTransactionManager = new SecurityTransactionManager(algorithmMock.Object, securityManager); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(o => o.GetOpenOrders(It.IsAny <Func <Order, bool> >())).Returns(new List <Order>()); securityTransactionManager.SetOrderProcessor(orderProcessor.Object); algorithmMock.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securityManager, securityTransactionManager)); var tradeBuilder = new Mock <ITradeBuilder>(); tradeBuilder.Setup(t => t.ClosedTrades).Returns(new List <QuantConnect.Statistics.Trade>()); algorithmMock.Setup(a => a.TradeBuilder).Returns(tradeBuilder.Object); unit.SetAlgorithm(algorithmMock.Object, 100); shadowType.GetProperty("Algorithm", flags).SetValue(shadow, algorithmMock.Object); securityTransactionManager.TransactionRecord.Add(DateTime.Now, 100); algorithmMock.Setup(s => s.Transactions).Returns(securityTransactionManager); var transactionHandler = new Mock <ITransactionHandler>(); transactionHandler.Setup(v => v.Orders).Returns(new ConcurrentDictionary <int, Order>()); shadowType.GetField("TransactionHandler", flags).SetValue(shadow, transactionHandler.Object); var startTime = shadowType.BaseType.BaseType.GetRuntimeFields().Single(s => s.Name.Contains("StartTime")); startTime.SetValue(shadow, DateTime.Now); var messagingHandler = new MessagingWrapper(); shadowType.GetField("MessagingHandler", flags).SetValue(shadow, messagingHandler); unit.SendFinalResult(); Assert.True((bool)shadowType.BaseType.GetField("ExitTriggered", flags).GetValue(shadow)); transactionHandler.Verify(v => v.Orders); Assert.True(messagingHandler.SendWasCalled); Assert.AreEqual(20, unit.FullResults.Count()); }
private SecurityPortfolioManager GetPortfolio(IOrderProcessor orderProcessor, int quantity) { var securities = new SecurityManager(new TimeKeeper(DateTime.Now, new[] { TimeZones.NewYork })); var transactions = new SecurityTransactionManager(null, securities); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(quantity); return(portfolio); }
/// <summary> /// Creates a new <see cref="OrderTicket"/> that represents trying to cancel an order for which no ticket exists /// </summary> public static OrderTicket InvalidCancelOrderId(SecurityTransactionManager transactionManager, CancelOrderRequest request) { var submit = new SubmitOrderRequest(OrderType.Market, SecurityType.Base, Symbol.Empty, 0, 0, 0, DateTime.MaxValue, request.Tag); submit.SetResponse(OrderResponse.UnableToFindOrder(request)); submit.SetOrderId(request.OrderId); var ticket = new OrderTicket(transactionManager, submit); request.SetResponse(OrderResponse.UnableToFindOrder(request)); ticket.TrySetCancelRequest(request); ticket._orderStatusOverride = OrderStatus.Invalid; return(ticket); }
public void Setup() { SymbolCache.Clear(); var timeKeeper = new TimeKeeper(new DateTime(2015, 12, 07)); _securityManager = new SecurityManager(timeKeeper); _securityTransactionManager = new SecurityTransactionManager(null, _securityManager); _securityPortfolioManager = new SecurityPortfolioManager(_securityManager, _securityTransactionManager); _subscriptionManager = new SubscriptionManager(timeKeeper, new DataManagerStub()); _marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder(); _securityInitializer = SecurityInitializer.Null; }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get <int>("OrderId"), x.Get <string>("Symbol"), x.Get <OrderStatus>("Status"), x.Get <decimal>("FillPrice"), x.Get <int>("FillQuantity")) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("CASH", new Security(SecurityExchangeHours.AlwaysOpen, subscriptions.Add(SecurityType.Base, "CASH", Resolution.Daily, "usa", TimeZones.NewYork), leverage: 10)); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though var updateData = new Dictionary <int, List <BaseData> >(); updateData.Add(0, new List <BaseData> { new IndicatorDataPoint("CASH", time, i + 1) }); securities.Update(time, updateData); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
private SecurityPortfolioManager GetPortfolio(IOrderProcessor orderProcessor, int quantity, DateTime time) { var securities = new SecurityManager(new TimeKeeper(time.ConvertToUtc(TimeZones.NewYork), TimeZones.NewYork)); var transactions = new SecurityTransactionManager(null, securities); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(quantity); portfolio.MarginCallModel = new TestDefaultMarginCallModel(portfolio, new OrderProperties()); return(portfolio); }
public void EquitySellAppliesSettlementCorrectly() { var securityExchangeHours = SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); securities.Add(Symbols.AAPL, new QuantConnect.Securities.Equity.Equity(securityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SettlementModel = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Buy on Monday var timeUtc = new DateTime(2015, 10, 26, 15, 30, 0); var orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); var fill = new OrderEvent(1, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Buy, 100, 10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(10, security.Holdings.Quantity); Assert.AreEqual(-1, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Tuesday, cash unsettled timeUtc = timeUtc.AddDays(1); orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); fill = new OrderEvent(2, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Sell, 100, -10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday, still cash unsettled timeUtc = timeUtc.AddDays(2); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday at open, cash settled var marketOpen = securityExchangeHours.MarketHours[timeUtc.DayOfWeek].GetMarketOpen(TimeSpan.Zero, false); Assert.IsTrue(marketOpen.HasValue); timeUtc = timeUtc.AddDays(1).Date.Add(marketOpen.Value).ConvertToUtc(securityExchangeHours.TimeZone); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <summary> /// Turn order into an order ticket /// </summary> /// <param name="order">The <see cref="Order"/> being converted</param> /// <param name="transactionManager">The transaction manager, <see cref="SecurityTransactionManager"/></param> /// <returns></returns> public static OrderTicket ToOrderTicket(this Order order, SecurityTransactionManager transactionManager) { var limitPrice = 0m; var stopPrice = 0m; switch (order.Type) { case OrderType.Limit: var limitOrder = order as LimitOrder; limitPrice = limitOrder.LimitPrice; break; case OrderType.StopMarket: var stopMarketOrder = order as StopMarketOrder; stopPrice = stopMarketOrder.StopPrice; break; case OrderType.StopLimit: var stopLimitOrder = order as StopLimitOrder; stopPrice = stopLimitOrder.StopPrice; limitPrice = stopLimitOrder.LimitPrice; break; case OrderType.OptionExercise: case OrderType.Market: case OrderType.MarketOnOpen: case OrderType.MarketOnClose: limitPrice = order.Price; stopPrice = order.Price; break; default: throw new ArgumentOutOfRangeException(); } var submitOrderRequest = new SubmitOrderRequest(order.Type, order.SecurityType, order.Symbol, order.Quantity, stopPrice, limitPrice, order.Time, order.Tag, order.Properties); submitOrderRequest.SetOrderId(order.Id); return(new OrderTicket(transactionManager, submitOrderRequest)); }
public void SellingShortFromZeroAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add(Symbols.AAPL, new Security(SecurityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var fill = new OrderEvent(1, Symbols.AAPL, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Sell, 100, -100, 0); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-100, securities[Symbols.AAPL].Holdings.Quantity); }
public void SellingShortFromZeroAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add("AAPL", new Security(SecurityExchangeHours.AlwaysOpen, CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"), 1)); var fill = new OrderEvent(1, "AAPL", OrderStatus.Filled, 100, -100); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-100, securities["AAPL"].Holdings.Quantity); }
public void SellOnMondaySettleOnThursday() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); // settlement at T+3, 8:00 AM var model = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config); portfolio.SetCash(3000); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Monday var timeUtc = Noon.ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, "USD", 1000); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Tuesday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Wednesday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday at 7:55 AM, still unsettled timeUtc = timeUtc.AddDays(1).AddHours(-4).AddMinutes(-5); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday at 8 AM, now settled timeUtc = timeUtc.AddMinutes(5); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(4000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
public void FundsAreSettledInAccountCurrency() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(null, securities); var portfolio = new SecurityPortfolioManager(securities, transactions); var model = new AccountCurrencyImmediateSettlementModel(); portfolio.SetCash(1000); portfolio.SetCash("EUR", 0, 1.1m); var config = CreateTradeBarConfig(Symbols.DE30EUR); var security = new Security( SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, portfolio.CashBook["EUR"], SymbolProperties.GetDefault("EUR"), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); var timeUtc = Noon.ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, "EUR", 1000); // 1000 + 1000 * 1.1 = 2100 Assert.AreEqual(2100, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, "EUR", -500); // 2100 - 500 * 1.1 = 1550 Assert.AreEqual(1550, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, "EUR", 1000); // 1550 + 1000 * 1.1 = 2650 Assert.AreEqual(2650, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <summary> /// QCAlgorithm Base Class Constructor - Initialize the underlying QCAlgorithm components. /// QCAlgorithm manages the transactions, portfolio, charting and security subscriptions for the users algorithms. /// </summary> public QCAlgorithm() { // AlgorithmManager will flip this when we're caught up with realtime IsWarmingUp = true; //Initialise the Algorithm Helper Classes: //- Note - ideally these wouldn't be here, but because of the DLL we need to make the classes shared across // the Worker & Algorithm, limiting ability to do anything else. //Initialise Start and End Dates: _startDate = new DateTime(1998, 01, 01); _endDate = DateTime.Now.AddDays(-1); // intialize our time keeper with only new york _timeKeeper = new TimeKeeper(_startDate, new[] { TimeZones.NewYork }); // set our local time zone _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork); //Initialise Data Manager SubscriptionManager = new SubscriptionManager(_timeKeeper); Securities = new SecurityManager(_timeKeeper); Transactions = new SecurityTransactionManager(Securities); Portfolio = new SecurityPortfolioManager(Securities, Transactions); BrokerageModel = new DefaultBrokerageModel(); Notify = new NotificationManager(false); // Notification manager defaults to disabled. //Initialise Algorithm RunMode to Series - Parallel Mode deprecated: _runMode = RunMode.Series; //Initialise to unlocked: _locked = false; // get exchange hours loaded from the market-hours-database.csv in /Data/market-hours _exchangeHoursProvider = SecurityExchangeHoursProvider.FromDataFolder(); UniverseSettings = new SubscriptionSettings(Resolution.Minute, 2m, true, false); // initialize our scheduler, this acts as a liason to the real time handler Schedule = new ScheduleManager(Securities, TimeZone); // initialize the trade builder TradeBuilder = new TradeBuilder(FillGroupingMethod.FillToFill, FillMatchingMethod.FIFO); }
private Security InitializeTest(DateTime reference, out SecurityPortfolioManager portfolio) { var security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetMarketPrice(new Tick { Value = 100 }); var timeKeeper = new TimeKeeper(reference); var securityManager = new SecurityManager(timeKeeper); securityManager.Add(security); var transactionManager = new SecurityTransactionManager(null, securityManager); portfolio = new SecurityPortfolioManager(securityManager, transactionManager); portfolio.SetCash("USD", 100 * 1000m, 1m); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(100 * 1000m, portfolio.CashBook[CashBook.AccountCurrency].Amount); return(security); }
public void EquitySellAppliesSettlementCorrectly() { var securityExchangeHours = SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); securities.Add("AAPL", new QuantConnect.Securities.Equity.Equity(securityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"), 1)); securities["AAPL"].SettlementModel = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); Assert.AreEqual(0, securities["AAPL"].Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Buy on Monday var timeUtc = new DateTime(2015, 10, 26, 15, 30, 0); var fill = new OrderEvent(1, "AAPL", timeUtc, OrderStatus.Filled, OrderDirection.Buy, 100, 10, 0); portfolio.ProcessFill(fill); Assert.AreEqual(10, securities["AAPL"].Holdings.Quantity); Assert.AreEqual(-1, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Tuesday, cash unsettled timeUtc = timeUtc.AddDays(1); fill = new OrderEvent(2, "AAPL", timeUtc, OrderStatus.Filled, OrderDirection.Sell, 100, -10, 0); portfolio.ProcessFill(fill); Assert.AreEqual(0, securities["AAPL"].Holdings.Quantity); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday, still cash unsettled timeUtc = timeUtc.AddDays(2); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday at open, cash settled timeUtc = timeUtc.AddDays(1).Date.Add(securityExchangeHours.MarketHours[timeUtc.DayOfWeek].MarketOpen).ConvertToUtc(securityExchangeHours.TimeZone); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
public void ForexFillUpdatesCashCorrectly() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); portfolio.CashBook.Add("EUR", 0, 1.1000m); securities.Add(Symbols.EURUSD, new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, portfolio.CashBook["USD"], CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.EURUSD]; Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); var orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.EURUSD, 100, DateTime.MinValue)); var fill = new OrderEvent(1, Symbols.EURUSD, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Buy, 1.1000m, 100, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(100, security.Holdings.Quantity); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(100, portfolio.CashBook["EUR"].Amount); Assert.AreEqual(888, portfolio.CashBook["USD"].Amount); }
public void ForexFillUpdatesCashCorrectly() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); portfolio.CashBook.Add("EUR", 0, 1.1000m); securities.Add("EURUSD", new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, portfolio.CashBook["USD"], CreateTradeBarDataConfig(SecurityType.Forex, "EURUSD"), 1)); Assert.AreEqual(0, securities["EURUSD"].Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); var fill = new OrderEvent(1, "EURUSD", DateTime.MinValue, OrderStatus.Filled, OrderDirection.Buy, 1.1000m, 100, 0); portfolio.ProcessFill(fill); Assert.AreEqual(100, securities["EURUSD"].Holdings.Quantity); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(100, portfolio.CashBook["EUR"].Quantity); Assert.AreEqual(888, portfolio.CashBook["USD"].Quantity); }
/// <summary> /// Creates the brokerage under test and connects it /// </summary> /// <param name="orderProvider"></param> /// <param name="securityProvider"></param> /// <returns></returns> protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) { var securities = new SecurityManager(new TimeKeeper(DateTime.UtcNow, TimeZones.NewYork)) { { Symbol, CreateSecurity(Symbol) } }; var transactions = new SecurityTransactionManager(null, securities); transactions.SetOrderProcessor(new FakeOrderProcessor()); var algorithm = new Mock <IAlgorithm>(); algorithm.Setup(a => a.Transactions).Returns(transactions); algorithm.Setup(a => a.Securities).Returns(securities); algorithm.Setup(a => a.BrokerageModel).Returns(new BinanceBrokerageModel()); algorithm.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securities, transactions)); var apiKey = Config.Get("binance-api-key"); var apiSecret = Config.Get("binance-api-secret"); var apiUrl = Config.Get("binance-api-url", "https://api.binance.com"); var websocketUrl = Config.Get("binance-websocket-url", "wss://stream.binance.com:9443/ws"); _binanceApi = new BinanceSpotRestApiClient( new SymbolPropertiesDatabaseSymbolMapper(Market.Binance), algorithm.Object?.Portfolio, apiKey, apiSecret, apiUrl); return(new BinanceBrokerage( apiKey, apiSecret, apiUrl, websocketUrl, algorithm.Object, new AggregationManager(), null )); }
public void FundsAreSettledImmediately() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(null, securities); var portfolio = new SecurityPortfolioManager(securities, transactions); var model = new ImmediateSettlementModel(); var config = CreateTradeBarConfig(); var security = new Security( SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); portfolio.SetCash(1000); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); var timeUtc = Noon.ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, Currencies.USD, 1000); Assert.AreEqual(2000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, Currencies.USD, -500); Assert.AreEqual(1500, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, Currencies.USD, 1000); Assert.AreEqual(2500, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/******************************************************** * CLASS CONSTRUCTOR *********************************************************/ /// <summary> /// QCAlgorithm Base Class Constructor - Initialize the underlying QCAlgorithm components. /// QCAlgorithm manages the transactions, portfolio, charting and security subscriptions for the users algorithms. /// </summary> public QCAlgorithm() { //Initialise the Algorithm Helper Classes: //- Note - ideally these wouldn't be here, but because of the DLL we need to make the classes shared across // the Worker & Algorithm, limiting ability to do anything else. //Initialise Data Manager SubscriptionManager = new SubscriptionManager(); Securities = new SecurityManager(); Transactions = new SecurityTransactionManager(Securities); Portfolio = new SecurityPortfolioManager(Securities, Transactions); Notify = new NotificationManager(false); // Notification manager defaults to disabled. //Initialise Algorithm RunMode to Series - Parallel Mode deprecated: _runMode = RunMode.Series; //Initialise to unlocked: _locked = false; //Initialise Start and End Dates: _startDate = new DateTime(1998, 01, 01); _endDate = DateTime.Now.AddDays(-1); }
public void ForexCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, but for a Forex security, // see TestData\CashTestingStrategy.csv; also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_forex_fills.xml"; const string equityFile = "TestData\\test_forex_equity.xml"; const string mchQuantityFile = "TestData\\test_forex_fills_mch_quantity.xml"; const string jwbQuantityFile = "TestData\\test_forex_fills_jwb_quantity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get <int>("OrderId"), x.Get <string>("Symbol"), x.Get <OrderStatus>("Status"), x.Get <decimal>("FillPrice"), x.Get <int>("FillQuantity")) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var mchQuantity = XDocument.Load(mchQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var jwbQuantity = XDocument.Load(jwbQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); portfolio.CashBook.Add("MCH", mchQuantity[0], 0); portfolio.CashBook.Add("JWB", jwbQuantity[0], 0); var jwbCash = portfolio.CashBook["JWB"]; var mchCash = portfolio.CashBook["MCH"]; var usdCash = portfolio.CashBook["USD"]; var mchJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen, jwbCash, subscriptions.Add(SecurityType.Forex, "MCHJWB", Resolution.Minute, "fxcm", TimeZones.NewYork), leverage: 10); var mchUsdSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen, usdCash, subscriptions.Add(SecurityType.Forex, "MCHUSD", Resolution.Minute, "fxcm", TimeZones.NewYork), leverage: 10); var usdJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen, mchCash, subscriptions.Add(SecurityType.Forex, "USDJWB", Resolution.Minute, "fxcm", TimeZones.NewYork), leverage: 10); // no fee model mchJwbSecurity.TransactionModel = new SecurityTransactionModel(); mchUsdSecurity.TransactionModel = new SecurityTransactionModel(); usdJwbSecurity.TransactionModel = new SecurityTransactionModel(); securities.Add(mchJwbSecurity); securities.Add(usdJwbSecurity); securities.Add(mchUsdSecurity); portfolio.CashBook.EnsureCurrencyDataFeeds(securities, subscriptions, SecurityExchangeHoursProvider.FromDataFolder()); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); // the value of 'MCJWB' increments for each fill, the original test algo did this monthly // the time doesn't really matter though decimal mchJwb = i + 1; decimal mchUsd = (i + 1) / (i + 2m); decimal usdJwb = i + 2; Assert.AreEqual((double)mchJwb, (double)(mchUsd * usdJwb), 1e-10); //Console.WriteLine("Step: " + i + " -- MCHJWB: " + mchJwb); var updateData = new Dictionary <int, List <BaseData> >(); updateData.Add(0, new List <BaseData> { new IndicatorDataPoint("MCHJWB", time, mchJwb) }); updateData.Add(1, new List <BaseData> { new IndicatorDataPoint("MCHUSD", time, mchUsd) }); updateData.Add(2, new List <BaseData> { new IndicatorDataPoint("JWBUSD", time, usdJwb) }); securities.Update(time, updateData); portfolio.CashBook.Update(updateData); portfolio.ProcessFill(fill); //Console.WriteLine("-----------------------"); //Console.WriteLine(fill); //Console.WriteLine("Post step: " + i); //foreach (var cash in portfolio.CashBook) //{ // Console.WriteLine(cash.Value); //} //Console.WriteLine("CashValue: " + portfolio.CashBook.TotalValueInAccountCurrency); Console.WriteLine(i + 1 + " " + portfolio.TotalPortfolioValue.ToString("C")); //Assert.AreEqual((double) equity[i + 1], (double)portfolio.TotalPortfolioValue, 2e-2); Assert.AreEqual((double)mchQuantity[i + 1], (double)portfolio.CashBook["MCH"].Quantity); Assert.AreEqual((double)jwbQuantity[i + 1], (double)portfolio.CashBook["JWB"].Quantity); //Console.WriteLine(); //Console.WriteLine(); } }
public void OptionExercise_NonAccountCurrency() { var algorithm = new QCAlgorithm(); var securities = new SecurityManager(new TimeKeeper(DateTime.Now, TimeZones.NewYork)); var transactions = new SecurityTransactionManager(null, securities); var transactionHandler = new BacktestingTransactionHandler(); var portfolio = new SecurityPortfolioManager(securities, transactions); var EUR = new Cash("EUR", 100 * 192, 10); portfolio.CashBook.Add("EUR", EUR); portfolio.SetCash("USD", 0, 1); algorithm.Securities = securities; transactionHandler.Initialize(algorithm, new BacktestingBrokerage(algorithm), _resultHandler); transactions.SetOrderProcessor(transactionHandler); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(Symbols.SPY), EUR, SymbolProperties.GetDefault(EUR.Symbol), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); securities.Add( Symbols.SPY_C_192_Feb19_2016, new Option( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(Symbols.SPY_C_192_Feb19_2016), EUR, new OptionSymbolProperties(new SymbolProperties("EUR", "EUR", 100, 0.01m, 1)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ) ); securities[Symbols.SPY_C_192_Feb19_2016].Holdings.SetHoldings(1, 1); securities[Symbols.SPY].SetMarketPrice(new Tick { Value = 200 }); transactions.AddOrder(new SubmitOrderRequest(OrderType.OptionExercise, SecurityType.Option, Symbols.SPY_C_192_Feb19_2016, -1, 0, 0, securities.UtcTime, "")); var option = (Option)securities[Symbols.SPY_C_192_Feb19_2016]; var order = (OptionExerciseOrder)transactions.GetOrders(x => true).First(); option.Underlying = securities[Symbols.SPY]; var fills = option.OptionExerciseModel.OptionExercise(option, order).ToList(); Assert.AreEqual(2, fills.Count); Assert.IsFalse(fills[0].IsAssignment); Assert.AreEqual("Automatic Exercise", fills[0].Message); Assert.AreEqual("Option Exercise", fills[1].Message); foreach (var fill in fills) { portfolio.ProcessFill(fill); } // now we have long position in SPY with average price equal to strike var newUnderlyingHoldings = securities[Symbols.SPY].Holdings; // we added 100*192 EUR (strike price) at beginning, all consumed by exercise Assert.AreEqual(0, EUR.Amount); Assert.AreEqual(0, portfolio.CashBook["USD"].Amount); Assert.AreEqual(100, newUnderlyingHoldings.Quantity); Assert.AreEqual(192.0, newUnderlyingHoldings.AveragePrice); // and long call option position has disappeared Assert.AreEqual(0, securities[Symbols.SPY_C_192_Feb19_2016].Holdings.Quantity); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = 1000; portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"); securities.Add(new Security(SecurityExchangeHours.AlwaysOpen, config1, 2, false)); securities["AAPL"].Holdings.SetHoldings(100, 100); securities["AAPL"].SetMarketPrice(new TradeBar { Time = time, Value = 100 }); //Console.WriteLine("AAPL TMU: " + securities["AAPL"].MarginModel.GetMaintenanceMargin(securities["AAPL"])); //Console.WriteLine("AAPL Value: " + securities["AAPL"].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, "EURUSD"); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen, usdCash, config2, 100, false)); securities["EURUSD"].Holdings.SetHoldings(1.1m, 1000); securities["EURUSD"].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities["EURUSD"].MarginModel.GetMaintenanceMargin(securities["EURUSD"])); //Console.WriteLine("EURUSD Value: " + securities["EURUSD"].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, "EURGBP"); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen, gbpCash, config3, 100, false)); securities["EURGBP"].Holdings.SetHoldings(1m, 1000); securities["EURGBP"].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities["EURGBP"].MarginModel.GetMaintenanceMargin(securities["EURGBP"])); //Console.WriteLine("EURGBP Value: " + securities["EURGBP"].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder("AAPL", 101, DateTime.Now) { Price = 100 }; var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder("AAPL", 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int)(1000 * leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = quantity; var config = CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"); securities.Add(new Security(SecurityExchangeHours.AlwaysOpen, config, leverage, false)); var time = DateTime.Now; const decimal buyPrice = 1m; var security = securities["AAPL"]; security.SetMarketPrice(new TradeBar(time, "AAPL", buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder("AAPL", quantity, time) { Price = buyPrice }; var fill = new OrderEvent(order) { FillPrice = buyPrice, FillQuantity = quantity }; Assert.AreEqual(portfolio.CashBook["USD"].Quantity, fill.FillPrice * fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = buyPrice }; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new TradeBar(time, "AAPL", highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; security.SetMarketPrice(new TradeBar(time, "AAPL", lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage and buy more and we'll get a margin call security.SetLeverage(leverage * 2); order = new MarketOrder("AAPL", quantity, time) { Price = buyPrice }; fill = new OrderEvent(order) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const int quantity = 1000; var securities = new SecurityManager(); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = quantity; var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "AAPL", Resolution.Minute, true, true, true, true, true, 0); securities.Add(new Security(config, 1, false)); var time = DateTime.Now; const decimal buyPrice = 1m; securities["AAPL"].Update(time, new TradeBar(time, "AAPL", buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder("AAPL", quantity, time) { Price = buyPrice }; var fill = new OrderEvent(order) { FillPrice = buyPrice, FillQuantity = quantity }; Assert.AreEqual(portfolio.CashBook["USD"].Quantity, fill.FillPrice * fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = buyPrice }; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; securities["AAPL"].Update(time, new TradeBar(time, "AAPL", highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; securities["AAPL"].Update(time, new TradeBar(time, "AAPL", lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue); // this would cause a margin call var marginCallOrders = portfolio.ScanForMarginCall(); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-quantity, marginCallOrders[0].Quantity); Assert.GreaterOrEqual(-portfolio.MarginRemaining, marginCallOrders[0].Price * marginCallOrders[0].Quantity); }