public void MarketOrderFillsAtBidAsk(OrderDirection direction) { var symbol = Symbol.Create("EURUSD", SecurityType.Forex, "fxcm"); var exchangeHours = SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork); var quoteCash = new Cash("USD", 1000, 1); var symbolProperties = SymbolProperties.GetDefault("USD"); var security = new Forex(symbol, exchangeHours, quoteCash, symbolProperties); var reference = DateTime.Now; var referenceUtc = reference.ConvertToUtc(TimeZones.NewYork); var timeKeeper = new TimeKeeper(referenceUtc); security.SetLocalTimeKeeper(timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); var brokerageModel = new FxcmBrokerageModel(); var fillModel = brokerageModel.GetFillModel(security); const decimal bidPrice = 1.13739m; const decimal askPrice = 1.13746m; security.SetMarketPrice(new Tick(DateTime.Now, symbol, bidPrice, askPrice)); var quantity = direction == OrderDirection.Buy ? 1 : -1; var order = new MarketOrder(symbol, quantity, DateTime.Now); var fill = fillModel.MarketFill(security, order); var expected = direction == OrderDirection.Buy ? askPrice : bidPrice; Assert.AreEqual(expected, fill.FillPrice); }
public override OrderEvent MarketFill(Security asset, MarketOrder order) { // this model randomly fills market orders decimal absoluteRemaining; if (!_absoluteRemainingByOrderId.TryGetValue(order.Id, out absoluteRemaining)) { absoluteRemaining = order.AbsoluteQuantity; _absoluteRemainingByOrderId.Add(order.Id, order.AbsoluteQuantity); } var fill = base.MarketFill(asset, order); var absoluteFillQuantity = (int) (Math.Min(absoluteRemaining, _random.Next(0, 2*(int)order.AbsoluteQuantity))); fill.FillQuantity = Math.Sign(order.Quantity) * absoluteFillQuantity; if (absoluteRemaining == absoluteFillQuantity) { fill.Status = OrderStatus.Filled; _absoluteRemainingByOrderId.Remove(order.Id); } else { absoluteRemaining = absoluteRemaining - absoluteFillQuantity; _absoluteRemainingByOrderId[order.Id] = absoluteRemaining; fill.Status = OrderStatus.PartiallyFilled; } _algorithm.Log("CustomFillModel: " + fill); return fill; }
/// <summary> /// Converts an Oanda order into a LEAN order. /// </summary> private Order ConvertOrder(JToken order) { var type = order["type"].ToString(); Order qcOrder; var instrument = order["instrument"].ToString(); var id = order["id"].ToString(); var units = order["units"].ConvertInvariant <decimal>(); var createTime = order["createTime"].ToString(); var securityType = SymbolMapper.GetBrokerageSecurityType(instrument); var symbol = SymbolMapper.GetLeanSymbol(instrument, securityType, Market.Oanda); var time = GetTickDateTimeFromString(createTime); var quantity = units; switch (type) { case "MARKET_IF_TOUCHED": var stopOrder = order.ToObject <MarketIfTouchedOrder>(); qcOrder = new StopMarketOrder { StopPrice = stopOrder.Price.ToDecimal() }; break; case "LIMIT": var limitOrder = order.ToObject <OandaLimitOrder>(); qcOrder = new LimitOrder(symbol, quantity, limitOrder.Price.ToDecimal(), time); break; case "STOP": var stopLimitOrder = order.ToObject <StopOrder>(); var price = stopLimitOrder.Price.ConvertInvariant <decimal>(); var limitPrice = stopLimitOrder.PriceBound.ConvertInvariant <decimal>(); qcOrder = new StopLimitOrder(symbol, quantity, price, limitPrice, time); break; case "MARKET": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException( "An existing " + type + " working order was found and is currently unsupported. Please manually cancel the order before restarting the algorithm."); } qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(id); var gtdTime = order["gtdTime"]; if (gtdTime != null) { var expiry = GetTickDateTimeFromString(gtdTime.ToString()); qcOrder.Properties.TimeInForce = TimeInForce.GoodTilDate(expiry); } return(qcOrder); }
public void GetInitialMarginRequiredForOrderTest() { var security = GetSecurity(Symbols.AAPL); security.MarginModel = new NoMarginCallMarginModel(2); var order = new MarketOrder(security.Symbol, 100, DateTime.Now); var actual = security.MarginModel.GetInitialMarginRequiredForOrder(security, order); Assert.AreEqual(0, actual); }
public void PerformsMarketFillSell() { var model = new SecurityTransactionModel(); var order = new MarketOrder(Symbols.SPY, -100, Noon); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbols.SPY, Noon, 101.123m)); var fill = model.MarketFill(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); }
public void VerifyOpenMarketLeverage() { // Market is Open on Tuesday, Feb, 16th 2016 at Noon var leverage = 4m; var expected = 100 * 100m / leverage + 1; var model = new PatternDayTradingMarginModel(); var security = CreateSecurity(Noon); var order = new MarketOrder(security.Symbol, 100, security.LocalTime); Assert.AreEqual((double)leverage, (double)model.GetLeverage(security), 1e-3); Assert.AreEqual((double)expected, (double)model.GetInitialMarginRequiredForOrder(security, order), 1e-3); }
public void PerformsMarketFillBuy() { var model = new SecurityTransactionModel(); var order = new MarketOrder(Symbols.SPY, 100, Noon, type: SecurityType.Equity); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, 1); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbols.SPY, Noon, 101.123m)); var fill = model.MarketFill(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); }
public void PerformsMarketFillSell() { var model = new ForexTransactionModel(); var security = CreateSecurity(); var order = new MarketOrder(Symbols.USDJPY, -100, DateTime.Now, type: SecurityType.Forex); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbols.USDJPY, DateTime.Now, 101.123m)); var fill = model.MarketFill(security, order); var slip = model.GetSlippageApproximation(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price - slip, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); }
/// <summary> /// Profit if we closed the holdings right now including the approximate fees. /// </summary> /// <remarks>Does not use the transaction model for market fills but should.</remarks> public override decimal TotalCloseProfit() { if (AbsoluteQuantity == 0) { return 0; } decimal orderFee = 0; if (AbsoluteQuantity > 0) { // this is in the account currency var marketOrder = new MarketOrder(_forex.Symbol, -Quantity, _forex.LocalTime.ConvertToUtc(_forex.Exchange.TimeZone), type:_forex.Type); orderFee = _forex.TransactionModel.GetOrderFee(_forex, marketOrder); } // we need to add a conversion since the data is in terms of the quote currency return (Price - AveragePrice)*Quantity*_forex.QuoteCurrency.ConversionRate - orderFee; }
/// <summary> /// Profit if we closed the holdings right now including the approximate fees. /// </summary> /// <remarks>Does not use the transaction model for market fills but should.</remarks> public override decimal TotalCloseProfit() { if (AbsoluteQuantity == 0) { return 0; } decimal orderFee = 0; if (AbsoluteQuantity > 0) { // this is in the account currency var marketOrder = new MarketOrder(_cfd.Symbol, -Quantity, _cfd.LocalTime.ConvertToUtc(_cfd.Exchange.TimeZone)); orderFee = _cfd.FeeModel.GetOrderFee(_cfd, marketOrder); } // we need to add a conversion since the data is in terms of the quote currency return (Price - AveragePrice) * Quantity * _cfd.ContractMultiplier * _cfd.QuoteCurrency.ConversionRate - orderFee; }
/// <summary> /// Default market fill model for the base security class. Fills at the last traded price. /// </summary> /// <param name="asset">Security asset we're filling</param> /// <param name="order">Order packet to model</param> /// <returns>Order fill information detailing the average price and quantity filled.</returns> /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/> /// <seealso cref="LimitFill(Security, LimitOrder)"/> public virtual OrderEvent MarketFill(Security asset, MarketOrder order) { //Default order event to return. var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var orderFee = GetOrderFee(asset, order); var fill = new OrderEvent(order, utcTime, orderFee); if (order.Status == OrderStatus.Canceled) return fill; // make sure the exchange is open before filling if (!IsExchangeOpen(asset)) return fill; try { //Order [fill]price for a market order model is the current security price fill.FillPrice = asset.Price; fill.Status = OrderStatus.Filled; //Calculate the model slippage: e.g. 0.01c var slip = GetSlippageApproximation(asset, order); //Apply slippage switch (order.Direction) { case OrderDirection.Buy: fill.FillPrice += slip; break; case OrderDirection.Sell: fill.FillPrice -= slip; break; } // assume the order completely filled if (fill.Status == OrderStatus.Filled) fill.FillQuantity = order.Quantity; } catch (Exception err) { Log.Error("SecurityTransactionModel.MarketFill(): " + err.Message); } return fill; }
/// <summary> /// Converts an FXCM order to a QuantConnect order. /// </summary> /// <param name="fxcmOrder">The FXCM order</param> private Order ConvertOrder(ExecutionReport fxcmOrder) { Order order; if (fxcmOrder.getOrdType() == OrdTypeFactory.LIMIT) { order = new LimitOrder { LimitPrice = Convert.ToDecimal(fxcmOrder.getPrice()) }; } else if (fxcmOrder.getOrdType() == OrdTypeFactory.MARKET) { order = new MarketOrder(); } else if (fxcmOrder.getOrdType() == OrdTypeFactory.STOP) { order = new StopMarketOrder { StopPrice = Convert.ToDecimal(fxcmOrder.getPrice()) }; } else { throw new NotSupportedException("FxcmBrokerage.ConvertOrder(): The FXCM order type " + fxcmOrder.getOrdType() + " is not supported."); } var securityType = _symbolMapper.GetBrokerageSecurityType(fxcmOrder.getInstrument().getSymbol()); order.Symbol = _symbolMapper.GetLeanSymbol(fxcmOrder.getInstrument().getSymbol(), securityType, Market.FXCM); order.Quantity = Convert.ToInt32(fxcmOrder.getOrderQty() * (fxcmOrder.getSide() == SideFactory.BUY ? +1 : -1)); order.Status = ConvertOrderStatus(fxcmOrder.getFXCMOrdStatus()); order.BrokerId.Add(fxcmOrder.getOrderID()); order.Duration = ConvertDuration(fxcmOrder.getTimeInForce()); order.Time = FromJavaDate(fxcmOrder.getTransactTime().toDate()); return order; }
public QuantConnect.Orders.Order ConvertToOrder(Teb.FIX.Model.Order tebOrder) { QuantConnect.Orders.Order o = null; if (tebOrder.OrdType == CashDefinition.ORDTYPE_MARKET) { o = new QuantConnect.Orders.MarketOrder(); } else { o = new QuantConnect.Orders.LimitOrder(); (o as LimitOrder).LimitPrice = tebOrder.Price.HasValue ? tebOrder.Price.Value : 0; } o.Duration = ConvertToTimeInForce(tebOrder.Core.TimeInForce);; o.Id = int.Parse(tebOrder.ClOrdID.Replace("CS", "")); o.Price = tebOrder.Price.HasValue ? tebOrder.Price.Value : 0; o.Quantity = ConvertToQuantity(tebOrder); o.Status = ConvertToStatus(tebOrder); o.Time = tebOrder.TransactTime.HasValue ? tebOrder.TransactTime.Value : DateTime.Now; o.Symbol = tebOrder.Symbol; o.BrokerId.Add(tebOrder.ConnectionClOrdID); return(o); }
/// <summary> /// Creates an order of the correct type /// </summary> private static Order CreateOrder(OrderType orderType, JObject jObject) { Order order; switch (orderType) { case OrderType.Market: order = new MarketOrder(); break; case OrderType.Limit: order = new LimitOrder {LimitPrice = jObject["LimitPrice"].Value<decimal>()}; break; case OrderType.StopMarket: order = new StopMarketOrder { StopPrice = jObject["StopPrice"].Value<decimal>() }; break; case OrderType.StopLimit: order = new StopLimitOrder { LimitPrice = jObject["LimitPrice"].Value<decimal>(), StopPrice = jObject["StopPrice"].Value<decimal>() }; break; case OrderType.MarketOnOpen: order = new MarketOnOpenOrder(); break; case OrderType.MarketOnClose: order = new MarketOnCloseOrder(); break; default: throw new ArgumentOutOfRangeException(); } return order; }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(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, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config1, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.AAPL].SetLeverage(2m); securities[Symbols.AAPL].Holdings.SetHoldings(100, 100); securities[Symbols.AAPL].SetMarketPrice(new TradeBar{Time = time, Value = 100}); //Console.WriteLine("AAPL TMU: " + securities[Symbols.AAPL].MarginModel.GetMaintenanceMargin(securities[Symbols.AAPL])); //Console.WriteLine("AAPL Value: " + securities[Symbols.AAPL].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2, SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.EURUSD].SetLeverage(100m); securities[Symbols.EURUSD].Holdings.SetHoldings(1.1m, 1000); securities[Symbols.EURUSD].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities[Symbols.EURUSD].MarginModel.GetMaintenanceMargin(securities[Symbols.EURUSD])); //Console.WriteLine("EURUSD Value: " + securities[Symbols.EURUSD].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURGBP); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3, SymbolProperties.GetDefault(gbpCash.Symbol))); securities[Symbols.EURGBP].SetLeverage(100m); securities[Symbols.EURGBP].Holdings.SetHoldings(1m, 1000); securities[Symbols.EURGBP].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities[Symbols.EURGBP].MarginModel.GetMaintenanceMargin(securities[Symbols.EURGBP])); //Console.WriteLine("EURGBP Value: " + securities[Symbols.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(Symbols.AAPL, 101, DateTime.Now) { Price = 100 }; orderProcessor.AddOrder(acceptedOrder); var request = new SubmitOrderRequest(OrderType.Market, acceptedOrder.SecurityType, acceptedOrder.Symbol, acceptedOrder.Quantity, 0, 0, acceptedOrder.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder(Symbols.AAPL, 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
public void ComputeMarginProperlyShortCoverZeroLong() { const decimal leverage = 2m; const int amount = 1000; const int quantity = (int)(amount * leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(amount); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal sellPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, sellPrice, sellPrice, sellPrice, sellPrice, 1)); var order = new MarketOrder(Symbols.AAPL, -quantity, time) { Price = sellPrice }; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = sellPrice, FillQuantity = -quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); portfolio.ProcessFill(fill); // we shouldn't be able to place a new short order var newOrder = new MarketOrder(Symbols.AAPL, -1, time.AddSeconds(1)) { Price = sellPrice }; var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // we should be able to place cover to zero newOrder = new MarketOrder(Symbols.AAPL, quantity, time.AddSeconds(1)) { Price = sellPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsTrue(sufficientCapital); // now the stock doubles, so we should have negative margin remaining time = time.AddDays(1); const decimal highPrice = sellPrice * 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1)); // we still shouldn be able to place cover to zero newOrder = new MarketOrder(Symbols.AAPL, quantity, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsTrue(sufficientCapital); // we shouldn't be able to place cover to long newOrder = new MarketOrder(Symbols.AAPL, quantity + 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); }
/// <summary> /// Converts an Oanda order into a LEAN order. /// </summary> private Order ConvertOrder(JToken order) { var type = order["type"].ToString(); Order qcOrder; switch (type) { case "MARKET_IF_TOUCHED": var stopOrder = order.ToObject <MarketIfTouchedOrder>(); qcOrder = new StopMarketOrder { StopPrice = stopOrder.Price.ToDecimal() }; break; case "LIMIT": var limitOrder = order.ToObject <OandaLimitOrder>(); qcOrder = new LimitOrder { LimitPrice = limitOrder.Price.ToDecimal() }; break; case "STOP": var stopLimitOrder = order.ToObject <StopOrder>(); qcOrder = new StopLimitOrder { Price = Convert.ToDecimal(stopLimitOrder.Price), LimitPrice = Convert.ToDecimal(stopLimitOrder.PriceBound) }; break; case "MARKET": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException( "An existing " + type + " working order was found and is currently unsupported. Please manually cancel the order before restarting the algorithm."); } var instrument = order["instrument"].ToString(); var id = order["id"].ToString(); var units = Convert.ToInt32(order["units"]); var createTime = order["createTime"].ToString(); var securityType = SymbolMapper.GetBrokerageSecurityType(instrument); qcOrder.Symbol = SymbolMapper.GetLeanSymbol(instrument, securityType, Market.Oanda); qcOrder.Time = GetTickDateTimeFromString(createTime); qcOrder.Quantity = units; qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(id); var orderByBrokerageId = OrderProvider.GetOrderByBrokerageId(id); if (orderByBrokerageId != null) { qcOrder.Id = orderByBrokerageId.Id; } var gtdTime = order["gtdTime"]; if (gtdTime != null) { qcOrder.Duration = OrderDuration.Custom; qcOrder.DurationValue = GetTickDateTimeFromString(gtdTime.ToString()); } return(qcOrder); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int) (1000*leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(quantity); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder(Symbols.AAPL, quantity, time) {Price = buyPrice}; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); Assert.AreEqual(portfolio.CashBook["USD"].Amount, 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(Symbols.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, Symbols.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(Symbols.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, Symbols.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(Symbols.AAPL, quantity, time) { Price = buyPrice }; fill = new OrderEvent(order, DateTime.UtcNow, 0) { 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 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, 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 PerformsMarketFillBuy() { var model = new SecurityTransactionModel(); var order = new MarketOrder(Symbol, 100, DateTime.Now, type: SecurityType.Equity); var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, Symbol, Resolution.Minute, true, true, true, true, false, 0); var security = new Security(config, 1); security.SetMarketPrice(DateTime.Now, new IndicatorDataPoint(Symbol, DateTime.Now, 101.123m)); var fill = model.MarketFill(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); Assert.AreEqual(OrderStatus.Filled, order.Status); }
private static DateTime InitializeTest(out BasicTemplateAlgorithm algorithm, out Security security, out PartialMarketFillModel model, out MarketOrder order, out OrderTicket ticket) { var referenceTimeNY = new DateTime(2015, 12, 21, 13, 0, 0); var referenceTimeUtc = referenceTimeNY.ConvertToUtc(TimeZones.NewYork); algorithm = new BasicTemplateAlgorithm(); algorithm.SetDateTime(referenceTimeUtc); var transactionHandler = new BacktestingTransactionHandler(); transactionHandler.Initialize(algorithm, new BacktestingBrokerage(algorithm), new TestResultHandler(Console.WriteLine)); Task.Run(() => transactionHandler.Run()); algorithm.Transactions.SetOrderProcessor(transactionHandler); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false); security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), config); model = new PartialMarketFillModel(algorithm.Transactions, 2); algorithm.Securities.Add(security); algorithm.Securities[Symbols.SPY].FillModel = model; security.SetMarketPrice(new Tick { Symbol = Symbols.SPY, Value = 100 }); algorithm.SetFinishedWarmingUp(); order = new MarketOrder(Symbols.SPY, 100, referenceTimeUtc) { Id = 1 }; var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, algorithm.UtcTime, null); ticket = algorithm.Transactions.ProcessRequest(request); return referenceTimeUtc; }
public void PerformsMarketFillSell() { var model = new ForexTransactionModel(); var order = new MarketOrder(Symbol, -100, DateTime.Now, type: SecurityType.Forex); var config = CreateTradeBarDataConfig(SecurityType.Forex, Symbol); var security = new Security(SecurityExchangeHours.AlwaysOpen, config, 1); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbol, DateTime.Now, 101.123m)); var fill = model.MarketFill(security, order); var slip = model.GetSlippageApproximation(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price - slip, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); Assert.AreEqual(OrderStatus.Filled, order.Status); }
/// <summary> /// Calculate the order quantity to achieve target-percent holdings. /// </summary> /// <param name="symbol">Security object we're asking for</param> /// <param name="target">Target percentag holdings, this is an unlevered value, so /// if you have 2x leverage and request 100% holdings, it will utilize half of the /// available margin</param> /// <returns>Order quantity to achieve this percentage</returns> public int CalculateOrderQuantity(Symbol symbol, decimal target) { var security = Securities[symbol]; var price = security.Price; // can't order it if we don't have data if (price == 0) return 0; // this is the value in dollars that we want our holdings to have var targetPortfolioValue = target*Portfolio.TotalPortfolioValue; var quantity = security.Holdings.Quantity; var currentHoldingsValue = price*quantity; // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue); var direction = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell; // define lower and upper thresholds for the iteration var lowerThreshold = targetOrderValue - price/2; var upperThreshold = targetOrderValue + price/2; // continue iterating while we're still not within the specified thresholds var iterations = 0; var orderQuantity = 0; decimal orderValue = 0; while ((orderValue < lowerThreshold || orderValue > upperThreshold) && iterations < 10) { // find delta from where we are to where we want to be var delta = targetOrderValue - orderValue; // use delta value to compute a change in quantity required var deltaQuantity = (int)(delta / price); orderQuantity += deltaQuantity; // recompute order fees var order = new MarketOrder(security.Symbol, orderQuantity, UtcTime, type: security.Type); var fee = security.TransactionModel.GetOrderFee(security, order); orderValue = Math.Abs(order.GetValue(price)) + fee; // we need to add the fee in as well, even though it's not value, it's still a cost for the transaction // and we need to account for it to be sure we can make the trade produced by this method, imagine // set holdings 100% with 1x leverage, but a high fee structure, it quickly becomes necessary to include // otherwise the result of this function will be inactionable. iterations++; } // add directionality back in return (direction == OrderDirection.Sell ? -1 : 1) * orderQuantity; }
/// <summary> /// Performs partial market fills once per time step /// </summary> /// <param name="asset">The security being ordered</param> /// <param name="order">The order</param> /// <returns>The order fill</returns> public override OrderEvent MarketFill(Security asset, MarketOrder order) { var currentUtcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var ticket = _orderProvider.GetOrderTickets(x => x.OrderId == order.Id).FirstOrDefault(); if (ticket == null) { // if we can't find the ticket issue empty fills return new OrderEvent(order, currentUtcTime, 0); } // make sure some time has passed var lastOrderEvent = ticket.OrderEvents.LastOrDefault(); var increment = TimeSpan.FromTicks(Math.Max(asset.SubscriptionDataConfig.Increment.Ticks, 1)); if (lastOrderEvent != null && currentUtcTime - lastOrderEvent.UtcTime < increment) { // wait a minute between fills return new OrderEvent(order, currentUtcTime, 0); } var remaining = (int)(ticket.Quantity - ticket.QuantityFilled); var fill = base.MarketFill(asset, order); var filledThisTime = Math.Min(remaining, (int)(_percent * order.Quantity)); fill.FillQuantity = filledThisTime; // only mark it as filled if there is zero quantity remaining fill.Status = remaining == filledThisTime ? OrderStatus.Filled : OrderStatus.PartiallyFilled; return fill; }
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, config1, 2)); 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, usdCash, config2, 100)); 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, gbpCash, config3, 100)); 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 PartialFills() { bool orderFilled = false; var manualResetEvent = new ManualResetEvent(false); var qty = 1000000; var remaining = qty; var sync = new object(); Brokerage.OrderStatusChanged += (sender, orderEvent) => { lock (sync) { remaining -= orderEvent.FillQuantity; Console.WriteLine("Remaining: " + remaining + " FillQuantity: " + orderEvent.FillQuantity); if (orderEvent.Status == OrderStatus.Filled) { orderFilled = true; manualResetEvent.Set(); } } }; // pick a security with low, but some, volume var symbol = Symbols.EURUSD; var order = new MarketOrder(symbol, qty, DateTime.UtcNow, type: symbol.ID.SecurityType) { Id = 1 }; Brokerage.PlaceOrder(order); // pause for a while to wait for fills to come in manualResetEvent.WaitOne(2500); manualResetEvent.WaitOne(2500); manualResetEvent.WaitOne(2500); Console.WriteLine("Remaining: " + remaining); Assert.AreEqual(0, remaining); }
/// <summary> /// Performs application of an OrderEvent to the portfolio /// </summary> /// <param name="portfolio">The algorithm's portfolio</param> /// <param name="security">The fill's security</param> /// <param name="fill">The order event fill object to be applied</param> public virtual void ProcessFill(SecurityPortfolioManager portfolio, Security security, OrderEvent fill) { //Get the required information from the vehicle this order will affect var isLong = security.Holdings.IsLong; var isShort = security.Holdings.IsShort; var closedPosition = false; //Make local decimals to avoid any rounding errors from int multiplication var quantityHoldings = (decimal)security.Holdings.Quantity; var absoluteHoldingsQuantity = security.Holdings.AbsoluteQuantity; var averageHoldingsPrice = security.Holdings.AveragePrice; var lastTradeProfit = 0m; try { //Update the Vehicle approximate total sales volume. security.Holdings.AddNewSale(fill.FillPrice * Convert.ToDecimal(fill.AbsoluteFillQuantity)); //Get the Fee for this Order - Update the Portfolio Cash Balance: Remove Transacion Fees. var order = new MarketOrder(security.Symbol, fill.FillQuantity, security.LocalTime.ConvertToUtc(security.Exchange.TimeZone), type: security.Type) {Price = fill.FillPrice, Status = OrderStatus.Filled}; var feeThisOrder = Math.Abs(security.TransactionModel.GetOrderFee(security, order)); security.Holdings.AddNewFee(feeThisOrder); portfolio.CashBook[CashBook.AccountCurrency].AddAmount(-feeThisOrder); //Calculate & Update the Last Trade Profit if (isLong && fill.Direction == OrderDirection.Sell) { //Closing up a long position if (quantityHoldings >= fill.AbsoluteFillQuantity) { //Closing up towards Zero. lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * fill.AbsoluteFillQuantity; } else { //Closing up to Neg/Short Position (selling more than we have) - Only calc profit on the stock we have to sell. lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * quantityHoldings; } closedPosition = true; } else if (isShort && fill.Direction == OrderDirection.Buy) { //Closing up a short position. if (absoluteHoldingsQuantity >= fill.FillQuantity) { //Reducing the stock we have, and enough stock on hand to process order. lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * fill.AbsoluteFillQuantity; } else { //Increasing stock holdings, short to positive through zero, but only calc profit on stock we Buy. lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * absoluteHoldingsQuantity; } closedPosition = true; } if (closedPosition) { //Update Vehicle Profit Tracking: security.Holdings.AddNewProfit(lastTradeProfit); security.Holdings.SetLastTradeProfit(lastTradeProfit); portfolio.AddTransactionRecord(security.LocalTime.ConvertToUtc(security.Exchange.TimeZone), lastTradeProfit - 2 * feeThisOrder); } // Apply the funds using the current settlement model var amount = fill.FillPrice * Convert.ToDecimal(fill.FillQuantity); security.SettlementModel.ApplyFunds(portfolio, security, fill.UtcTime, CashBook.AccountCurrency, -amount); //UPDATE HOLDINGS QUANTITY, AVG PRICE: //Currently NO holdings. The order is ALL our holdings. if (quantityHoldings == 0) { //First transaction just subtract order from cash and set our holdings: averageHoldingsPrice = fill.FillPrice; quantityHoldings = fill.FillQuantity; } else if (isLong) { //If we're currently LONG on the stock. switch (fill.Direction) { case OrderDirection.Buy: //Update the Holding Average Price: Total Value / Total Quantity: averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + (decimal)fill.FillQuantity); //Add the new quantity: quantityHoldings += fill.FillQuantity; //Subtract this order from cash: break; case OrderDirection.Sell: quantityHoldings += fill.FillQuantity; //+ a short = a subtraction if (quantityHoldings < 0) { //If we've now passed through zero from selling stock: new avg price: averageHoldingsPrice = fill.FillPrice; } else if (quantityHoldings == 0) { averageHoldingsPrice = 0; } break; } } else if (isShort) { //We're currently SHORTING the stock: What is the new position now? switch (fill.Direction) { case OrderDirection.Buy: //Buying when we're shorting moves to close position: quantityHoldings += fill.FillQuantity; if (quantityHoldings > 0) { //If we were short but passed through zero, new average price is what we paid. The short position was closed. averageHoldingsPrice = fill.FillPrice; } else if (quantityHoldings == 0) { averageHoldingsPrice = 0; } break; case OrderDirection.Sell: //We are increasing a Short position: //E.g. -100 @ $5, adding -100 @ $10: Avg: $7.5 // dAvg = (-500 + -1000) / -200 = 7.5 averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (Convert.ToDecimal(fill.FillQuantity) * fill.FillPrice)) / (quantityHoldings + (decimal)fill.FillQuantity); quantityHoldings += fill.FillQuantity; break; } } } catch (Exception err) { Log.Error(err); } //Set the results back to the vehicle. security.Holdings.SetHoldings(averageHoldingsPrice, Convert.ToInt32(quantityHoldings)); }
/// <summary> /// Creates an <see cref="Order"/> to match the specified <paramref name="request"/> /// </summary> /// <param name="request">The <see cref="SubmitOrderRequest"/> to create an order for</param> /// <returns>The <see cref="Order"/> that matches the request</returns> public static Order CreateOrder(SubmitOrderRequest request) { Order order; switch (request.OrderType) { case OrderType.Market: order = new MarketOrder(request.Symbol, request.Quantity, request.Time, request.Tag, request.SecurityType); break; case OrderType.Limit: order = new LimitOrder(request.Symbol, request.Quantity, request.LimitPrice, request.Time, request.Tag, request.SecurityType); break; case OrderType.StopMarket: order = new StopMarketOrder(request.Symbol, request.Quantity, request.StopPrice, request.Time, request.Tag, request.SecurityType); break; case OrderType.StopLimit: order = new StopLimitOrder(request.Symbol, request.Quantity, request.StopPrice, request.LimitPrice, request.Time, request.Tag, request.SecurityType); break; case OrderType.MarketOnOpen: order = new MarketOnOpenOrder(request.Symbol, request.SecurityType, request.Quantity, request.Time, request.Tag); break; case OrderType.MarketOnClose: order = new MarketOnCloseOrder(request.Symbol, request.SecurityType, request.Quantity, request.Time, request.Tag); break; default: throw new ArgumentOutOfRangeException(); } order.Status = OrderStatus.New; order.Id = request.OrderId; if (request.Tag != null) { order.Tag = request.Tag; } return order; }
/// <summary> /// This is used to ensure each test starts with a clean, known state. /// </summary> protected void LiquidateHoldings() { Log.Trace(""); Log.Trace("LIQUIDATE HOLDINGS"); Log.Trace(""); var holdings = Brokerage.GetAccountHoldings(); foreach (var holding in holdings) { if (holding.Quantity == 0) continue; Log.Trace("Liquidating: " + holding); var order = new MarketOrder(holding.Symbol, (int)-holding.Quantity, DateTime.Now, type: holding.Type); _orderProvider.Add(order); PlaceOrderWaitForStatus(order, OrderStatus.Filled); } }
/// <summary> /// Profit if we closed the holdings right now including the approximate fees. /// </summary> /// <remarks>Does not use the transaction model for market fills but should.</remarks> public virtual decimal TotalCloseProfit() { if (AbsoluteQuantity == 0) { return 0; } // this is in the account currency var marketOrder = new MarketOrder(_security.Symbol, -Quantity, _security.LocalTime.ConvertToUtc(_security.Exchange.TimeZone), type: _security.Type); var orderFee = _security.TransactionModel.GetOrderFee(_security, marketOrder); return (Price - AveragePrice) * Quantity - orderFee; }
/// <summary> /// Market order implementation: Send a market order and wait for it to be filled. /// </summary> /// <param name="symbol">Symbol of the MarketType Required.</param> /// <param name="quantity">Number of shares to request.</param> /// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param> /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param> /// <returns>int Order id</returns> public int MarketOrder(string symbol, int quantity, bool asynchronous = false, string tag = "") { //Initalize the Market order parameters: var error = PreOrderChecks(symbol, quantity, OrderType.Market); if (error < 0) { return error; } var order = new MarketOrder(symbol, quantity, Time, tag, Securities[symbol].Type); //Set the rough price of the order for buying power calculations order.Price = Securities[symbol].Price; //Add the order and create a new order Id. var orderId = Transactions.AddOrder(order); //Wait for the order event to process: //Enqueue means send to order queue but don't wait for response: if (!asynchronous) { //Wait for the market order to fill. //This is processed in a parallel thread. while (!Transactions.Orders.ContainsKey(orderId) || (Transactions.Orders[orderId].Status != OrderStatus.Filled && Transactions.Orders[orderId].Status != OrderStatus.Invalid && Transactions.Orders[orderId].Status != OrderStatus.Canceled) || _processingOrder) { Thread.Sleep(1); } } return orderId; }
private Order ConvertOrder(IB.Order ibOrder, IB.Contract contract) { // this function is called by GetOpenOrders which is mainly used by the setup handler to // initialize algorithm state. So the only time we'll be executing this code is when the account // has orders sitting and waiting from before algo initialization... // because of this we can't get the time accurately Order order; var mappedSymbol = MapSymbol(contract); var orderType = ConvertOrderType(ibOrder); switch (orderType) { case OrderType.Market: order = new MarketOrder(mappedSymbol, ibOrder.TotalQuantity, new DateTime() // not sure how to get this data ); break; case OrderType.MarketOnOpen: order = new MarketOnOpenOrder(mappedSymbol, ibOrder.TotalQuantity, new DateTime()); break; case OrderType.MarketOnClose: order = new MarketOnCloseOrder(mappedSymbol, ibOrder.TotalQuantity, new DateTime() ); break; case OrderType.Limit: order = new LimitOrder(mappedSymbol, ibOrder.TotalQuantity, ibOrder.LimitPrice, new DateTime() ); break; case OrderType.StopMarket: order = new StopMarketOrder(mappedSymbol, ibOrder.TotalQuantity, ibOrder.AuxPrice, new DateTime() ); break; case OrderType.StopLimit: order = new StopLimitOrder(mappedSymbol, ibOrder.TotalQuantity, ibOrder.AuxPrice, ibOrder.LimitPrice, new DateTime() ); break; default: throw new InvalidEnumArgumentException("orderType", (int) orderType, typeof (OrderType)); } order.BrokerId.Add(ibOrder.OrderId.ToString()); return order; }
/// <summary> /// Automatically place an order which will set the holdings to between 100% or -100% of *Buying Power*. /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM /// </summary> /// <param name="symbol"> string Symbol indexer</param> /// <param name="percentage">decimal fraction of portfolio to set stock</param> /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param> /// <param name="tag">Tag the order with a short string.</param> /// <seealso cref="MarketOrder"/> public void SetHoldings(string symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "") { //Error checks: if (!Portfolio.ContainsKey(symbol)) { Error(symbol.ToUpper() + " not found in portfolio. Request this data when initializing the algorithm."); return; } //Range check values: if (percentage > 1) percentage = 1; if (percentage < -1) percentage = -1; //If they triggered a liquidate if (liquidateExistingHoldings) { foreach (var holdingSymbol in Portfolio.Keys) { if (holdingSymbol != symbol && Portfolio[holdingSymbol].AbsoluteQuantity > 0) { //Go through all existing holdings [synchronously], market order the inverse quantity: Order(holdingSymbol, -Portfolio[holdingSymbol].Quantity); } } } var security = Securities[symbol]; // compute the remaining margin for this security var direction = percentage > 0 ? OrderDirection.Buy : OrderDirection.Sell; // we need to account for the margin gained if crossing the zero line decimal extraMarginForClosing = 0m; if (security.Holdings.IsLong && direction == OrderDirection.Sell) { extraMarginForClosing = security.MarginModel.GetMaintenanceMargin(security); } else if (security.Holdings.IsShort && direction == OrderDirection.Buy) { extraMarginForClosing = security.MarginModel.GetMaintenanceMargin(security); } // compute an estimate of the buying power for this security incorporating the implied leverage // we don't want to apply the percentag to the required margin to bring us to zero, so we back out the 'extraMaginForClosing' var marginRemaining = Math.Abs(percentage)*(security.MarginModel.GetMarginRemaining(Portfolio, security, direction) - extraMarginForClosing); marginRemaining += extraMarginForClosing; // // Since we can't assume anything about the fee structure and the relative size of fees in // relation to the order size we need to perform some root finding. In general we'll only need // a two loops to compute a correct value. Some exotic fee structures may require more searching. // // compute the margin required for a single share int quantity = 1; var marketOrder = new MarketOrder(symbol, quantity, Time, type: security.Type) { Price = security.Price }; var marginRequiredForSingleShare = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder); // we can't do anything if we don't have data yet if (security.Price == 0) return; // we can't even afford one more share if (marginRemaining < marginRequiredForSingleShare) return; // we want marginRequired to end up between this and marginRemaining var marginRequiredLowerThreshold = marginRemaining - marginRequiredForSingleShare; // iterate until we get a decent estimate, max out at 10 loops. int loops = 0; var marginRequired = marginRequiredForSingleShare; while (marginRequired > marginRemaining || marginRequired < marginRequiredLowerThreshold) { var marginPerShare = marginRequired/quantity; quantity = (int) Math.Truncate(marginRemaining/marginPerShare); marketOrder.Quantity = quantity; if (quantity == 0) { // can't order anything return; } marginRequired = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder); // no need to iterate longer than 10 if (++loops > 10) break; } // nothing to change if (quantity == 0) { return; } // adjust for going short if (direction == OrderDirection.Sell) { quantity *= -1; } MarketOrder(symbol, quantity, false, tag); }