/******************************************************** * CLASS PROPERTIES *********************************************************/ /******************************************************** * CLASS METHODS *********************************************************/ /// <summary> /// Perform neccessary check to see if the model has been filled, appoximate the best we can. /// </summary> /// <param name="vehicle">Asset we're working with</param> /// <param name="order">Order class to check if filled.</param> public virtual OrderEvent Fill(Security vehicle, Order order) { //Default order event to return. var fill = new OrderEvent(order); try { switch (order.Type) { case OrderType.Limit: fill = LimitFill(vehicle, order); break; case OrderType.StopMarket: fill = StopFill(vehicle, order); break; case OrderType.Market: fill = MarketFill(vehicle, order); break; } } catch (Exception err) { Log.Error("SecurityTransactionModel.TransOrderDirection.Fill(): " + err.Message); } return fill; }
/// <summary> /// Gets the order fee associated with the specified order. This returns the cost /// of the transaction in the account currency /// </summary> /// <param name="security">The security matching the order</param> /// <param name="order">The order to compute fees for</param> /// <returns>The cost of the order in units of the account currency</returns> public decimal GetOrderFee(Security security, Order order) { switch (security.Type) { case SecurityType.Forex: // get the total order value in the account currency var totalOrderValue = order.GetValue(security); var fee = Math.Abs(_forexCommissionRate*totalOrderValue); return Math.Max(_forexMinimumOrderFee, fee); case SecurityType.Equity: var tradeValue = Math.Abs(order.GetValue(security)); //Per share fees var tradeFee = 0.005m * order.AbsoluteQuantity; //Maximum Per Order: 0.5% //Minimum per order. $1.0 var maximumPerOrder = 0.005m * tradeValue; if (tradeFee < 1) { tradeFee = 1; } else if (tradeFee > maximumPerOrder) { tradeFee = maximumPerOrder; } //Always return a positive fee. return Math.Abs(tradeFee); } // all other types default to zero fees return 0m; }
/// <summary> /// Initializes a new instance of the <see cref="StreamStore"/> class /// </summary> /// <param name="config">The subscripton's configuration</param> /// <param name="security">The security object, used for exchange hours</param> public StreamStore(SubscriptionDataConfig config, Security security) { _security = security; _config = config; _increment = config.Increment; _queue = new ConcurrentQueue<BaseData>(); }
/// <summary> /// Returns true if the brokerage could accept this order. This takes into account /// order type, security type, and order size limits. /// </summary> /// <remarks> /// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit /// </remarks> /// <param name="security"></param> /// <param name="order">The order to be processed</param> /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param> /// <returns>True if the brokerage could process the order, false otherwise</returns> public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message) { message = null; // validate security type if (security.Type != SecurityType.Forex && security.Type != SecurityType.Cfd) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "This model does not support " + security.Type + " security type." ); return false; } // validate order type if (order.Type != OrderType.Limit && order.Type != OrderType.Market && order.Type != OrderType.StopMarket) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "This model does not support " + order.Type + " order type." ); return false; } return true; }
/// <summary> /// Slippage Model. Return a decimal cash slippage approximation on the order. /// </summary> public override decimal GetSlippageApproximation(Security asset, Order order) { var lastData = asset.GetLastData(); if (lastData == null) return 0; return lastData.Value*_slippagePercent; }
/// <summary> /// Get the slippage approximation for this order /// </summary> /// <returns>Decimal value of the slippage approximation</returns> /// <seealso cref="Order"/> public override decimal GetSlippageApproximation(Security security, Order order) { //Return 0 by default decimal slippage = 0; //For FOREX, the slippage is the Bid/Ask Spread for Tick, and an approximation for TradeBars switch (security.Resolution) { case Resolution.Minute: case Resolution.Second: //Get the last data packet: //Assume slippage is 1/10,000th of the price slippage = security.GetLastData().Value * 0.0001m; break; case Resolution.Tick: var lastTick = (Tick)security.GetLastData(); switch (order.Direction) { case OrderDirection.Buy: //We're buying, assume slip to Asking Price. slippage = Math.Abs(order.Price - lastTick.AskPrice); break; case OrderDirection.Sell: //We're selling, assume slip to the bid price. slippage = Math.Abs(order.Price - lastTick.BidPrice); break; } break; } return slippage; }
/// <summary> /// Initializes a new instance of the <see cref="LiveSubscription"/> class /// </summary> /// <param name="security">The security this subscription is for</param> /// <param name="enumerator">The subscription's data source</param> /// <param name="utcStartTime">The start time of the subscription</param> /// <param name="utcEndTime">The end time of the subscription</param> /// <param name="isUserDefined">True if the user explicitly defined this subscription, false otherwise</param> public LiveSubscription(Security security, IEnumerator<BaseData> enumerator, DateTime utcStartTime, DateTime utcEndTime, bool isUserDefined) : base(security, enumerator, utcStartTime, utcEndTime, isUserDefined) { NeedsMoveNext = true; IsCustomData = security.SubscriptionDataConfig.IsCustomData; StreamStore = new StreamStore(Configuration, security); }
/// <summary> /// Initializes a new instance of the <see cref="LiveSubscription"/> class /// </summary> /// <param name="universe">The universe of the subscription</param> /// <param name="security">The security this subscription is for</param> /// <param name="enumerator">The subscription's data source</param> /// <param name="utcStartTime">The start time of the subscription</param> /// <param name="utcEndTime">The end time of the subscription</param> public LiveSubscription(IUniverse universe, Security security, IEnumerator<BaseData> enumerator, DateTime utcStartTime, DateTime utcEndTime) : base(universe, security, enumerator, utcStartTime, utcEndTime) { NeedsMoveNext = true; IsCustomData = security.SubscriptionDataConfig.IsCustomData; StreamStore = new StreamStore(Configuration, security); }
public void UpdatesAfterCorrectPeriodElapses() { const int periods = 3; var periodSpan = Time.OneMinute; var reference = new DateTime(2016, 04, 06, 12, 0, 0); var referenceUtc = reference.ConvertToUtc(TimeZones.NewYork); var timeKeeper = new TimeKeeper(referenceUtc); var config = new SubscriptionDataConfig(typeof (TradeBar), Symbols.SPY, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, true, false, false); var security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), config, new Cash("USD", 0, 0), SymbolProperties.GetDefault("USD")); security.SetLocalTimeKeeper(timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); var model = new RelativeStandardDeviationVolatilityModel(periodSpan, periods); security.VolatilityModel = model; var first = new IndicatorDataPoint(reference, 1); security.SetMarketPrice(first); Assert.AreEqual(0m, model.Volatility); const decimal value = 0.471404520791032M; // std of 1,2 is ~0.707 over a mean of 1.5 var second = new IndicatorDataPoint(reference.AddMinutes(1), 2); security.SetMarketPrice(second); Assert.AreEqual(value, model.Volatility); // update should not be applied since not enough time has passed var third = new IndicatorDataPoint(reference.AddMinutes(1.01), 1000); security.SetMarketPrice(third); Assert.AreEqual(value, model.Volatility); var fourth = new IndicatorDataPoint(reference.AddMinutes(2), 3m); security.SetMarketPrice(fourth); Assert.AreEqual(0.5m, model.Volatility); }
public void PerformsLimitFillSell() { var model = new SecurityTransactionModel(); var order = new LimitOrder(Symbol, -100, 101.5m, 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, 101m)); var fill = model.LimitFill(security, order); Assert.AreEqual(0, fill.FillQuantity); Assert.AreEqual(0, fill.FillPrice); Assert.AreEqual(OrderStatus.None, fill.Status); Assert.AreEqual(OrderStatus.None, order.Status); security.SetMarketPrice(DateTime.Now, new TradeBar(DateTime.Now, Symbol, 102m, 103m, 101m, 102.3m, 100)); fill = model.LimitFill(security, order); // this fills worst case scenario, so it's at the limit price Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(Math.Max(order.LimitPrice, security.Low), fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); Assert.AreEqual(OrderStatus.Filled, order.Status); }
public void HoldingsTests() { var security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig()); // Long 100 stocks test security.Holdings.SetHoldings(100m, 100); Assert.AreEqual(100m, security.Holdings.AveragePrice); Assert.AreEqual(100, security.Holdings.Quantity); Assert.IsTrue(security.HoldStock); Assert.IsTrue(security.Invested); Assert.IsTrue(security.Holdings.IsLong); Assert.IsFalse(security.Holdings.IsShort); // Short 100 stocks test security.Holdings.SetHoldings(100m, -100); Assert.AreEqual(100m, security.Holdings.AveragePrice); Assert.AreEqual(-100, security.Holdings.Quantity); Assert.IsTrue(security.HoldStock); Assert.IsTrue(security.Invested); Assert.IsFalse(security.Holdings.IsLong); Assert.IsTrue(security.Holdings.IsShort); // Flat test security.Holdings.SetHoldings(100m, 0); Assert.AreEqual(100m, security.Holdings.AveragePrice); Assert.AreEqual(0, security.Holdings.Quantity); Assert.IsFalse(security.HoldStock); Assert.IsFalse(security.Invested); Assert.IsFalse(security.Holdings.IsLong); Assert.IsFalse(security.Holdings.IsShort); }
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; }
public void PerformsLimitFillSell() { var model = new SecurityTransactionModel(); var order = new LimitOrder(Symbol, -100, 101.5m, Noon, type: SecurityType.Equity); var config = CreateTradeBarConfig(Symbol); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, 1); security.SetMarketPrice(Noon, new IndicatorDataPoint(Symbol, Noon, 101m)); var fill = model.LimitFill(security, order); Assert.AreEqual(0, fill.FillQuantity); Assert.AreEqual(0, fill.FillPrice); Assert.AreEqual(OrderStatus.None, fill.Status); Assert.AreEqual(OrderStatus.None, order.Status); security.SetMarketPrice(Noon, new TradeBar(Noon, Symbol, 102m, 103m, 101m, 102.3m, 100)); fill = model.LimitFill(security, order); // this fills worst case scenario, so it's at the limit price Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(Math.Max(order.LimitPrice, security.Low), fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); Assert.AreEqual(OrderStatus.Filled, order.Status); }
public void FundsAreSettledImmediately() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); var model = new ImmediateSettlementModel(); var config = CreateTradeBarConfig(); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config); portfolio.SetCash(1000); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); var timeUtc = Noon.ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, "USD", 1000); Assert.AreEqual(2000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, "USD", -500); Assert.AreEqual(1500, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); model.ApplyFunds(portfolio, security, timeUtc, "USD", 1000); Assert.AreEqual(2500, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <summary> /// Create a new holding class instance setting the initial properties to $0. /// </summary> /// <param name="security">The security being held</param> public SecurityHolding(Security security) { _security = security; //Total Sales Volume for the day _totalSaleVolume = 0; _lastTradeProfit = 0; }
/// <summary> /// Initializes a new instance of the <see cref="LiveSubscription"/> class /// </summary> /// <param name="security">The security this subscription is for</param> /// <param name="enumerator">The subscription's data source</param> /// <param name="utcStartTime">The start time of the subscription</param> /// <param name="utcEndTime">The end time of the subscription</param> /// <param name="isUserDefined">True if the user explicitly defined this subscription, false otherwise</param> /// <param name="isFundamentalSubscription">True if this subscription is used to define the times to perform universe selection /// for a specific market, false for all other subscriptions</param> public LiveSubscription(Security security, IEnumerator<BaseData> enumerator, DateTime utcStartTime, DateTime utcEndTime, bool isUserDefined, bool isFundamentalSubscription) : base(security, enumerator, utcStartTime, utcEndTime, isUserDefined, isFundamentalSubscription) { NeedsMoveNext = true; IsCustomData = security.IsDynamicallyLoadedData; StreamStore = new StreamStore(Configuration, security); }
public void PerformsLimitFillSell() { var model = new ForexTransactionModel(); var order = new LimitOrder(Symbol, -100, 101.5m, 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, 101m)); var fill = model.LimitFill(security, order); Assert.AreEqual(0, fill.FillQuantity); Assert.AreEqual(0, fill.FillPrice); Assert.AreEqual(OrderStatus.None, fill.Status); Assert.AreEqual(OrderStatus.None, order.Status); security.SetMarketPrice(new TradeBar(DateTime.Now, Symbol, 102m, 103m, 101m, 102.3m, 100)); fill = model.LimitFill(security, order); // this fills worst case scenario, so it's at the limit price Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(Math.Max(order.LimitPrice, security.Low), fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); Assert.AreEqual(OrderStatus.Filled, order.Status); }
/// <summary> /// Applies cash settlement rules /// </summary> /// <param name="portfolio">The algorithm's portfolio</param> /// <param name="security">The fill's security</param> /// <param name="applicationTimeUtc">The fill time (in UTC)</param> /// <param name="currency">The currency symbol</param> /// <param name="amount">The amount of cash to apply</param> public void ApplyFunds(SecurityPortfolioManager portfolio, Security security, DateTime applicationTimeUtc, string currency, decimal amount) { if (amount > 0) { // positive amount: sell order filled portfolio.UnsettledCashBook[currency].AddAmount(amount); // find the correct settlement date (usually T+3 or T+1) var settlementDate = applicationTimeUtc.ConvertFromUtc(security.Exchange.TimeZone).Date; for (var i = 0; i < _numberOfDays; i++) { settlementDate = settlementDate.AddDays(1); // only count days when market is open if (!security.Exchange.Hours.IsDateOpen(settlementDate)) i--; } // use correct settlement time var settlementTimeUtc = settlementDate.Add(_timeOfDay).ConvertToUtc(security.Exchange.Hours.TimeZone); portfolio.AddUnsettledCashAmount(new UnsettledCashAmount(settlementTimeUtc, currency, amount)); } else { // negative amount: buy order filled portfolio.CashBook[currency].AddAmount(amount); } }
/// <summary> /// Returns true if the brokerage could accept this order. This takes into account /// order type, security type, and order size limits. /// </summary> /// <remarks> /// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit /// </remarks> /// <param name="security">The security of the order</param> /// <param name="order">The order to be processed</param> /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param> /// <returns>True if the brokerage could process the order, false otherwise</returns> public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message) { message = null; var securityType = order.SecurityType; if (securityType != SecurityType.Equity) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "This model only supports equities." ); return false; } if (order.Type == OrderType.MarketOnOpen || order.Type == OrderType.MarketOnClose) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "Tradier brokerage only supports Market orders. MarketOnOpen and MarketOnClose orders not supported." ); return false; } if (!CanExecuteOrder(security, order)) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "ExtendedMarket", "Tradier does not support extended market hours trading. Your order will be processed at market open." ); } // tradier order limits return true; }
/// <summary> /// Initializes the specified security by setting up the models /// </summary> /// <param name="security">The security to be initialized</param> public override void Initialize(Security security) { // first call the default implementation base.Initialize(security); // now apply our data normalization mode security.SetDataNormalizationMode(_dataNormalizationMode); }
/// <summary> /// Initializes the specified security by setting up the models /// </summary> /// <param name="security">The security to be initialized</param> public virtual void Initialize(Security security) { // set leverage and models security.SetLeverage(_brokerageModel.GetLeverage(security)); security.FillModel = _brokerageModel.GetFillModel(security); security.FeeModel = _brokerageModel.GetFeeModel(security); security.SlippageModel = _brokerageModel.GetSlippageModel(security); security.SettlementModel = _brokerageModel.GetSettlementModel(security, _brokerageModel.AccountType); }
public void SellOnThursdaySettleOnTuesday() { 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, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); portfolio.SetCash(3000); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Thursday var timeUtc = Noon.AddDays(3).ConvertToUtc(TimeZones.NewYork); model.ApplyFunds(portfolio, security, timeUtc, "USD", 1000); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Saturday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Sunday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Monday, still unsettled timeUtc = timeUtc.AddDays(1); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(3000, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Tuesday 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); // Tuesday at 8 AM, now settled timeUtc = timeUtc.AddMinutes(5); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(4000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <summary> /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// </summary> public override void Initialize() { SetStartDate(2013, 10, 07); //Set Start Date SetEndDate(2013, 10, 11); //Set End Date SetCash(100000); //Set Strategy Cash // Find more symbols here: http://quantconnect.com/data AddSecurity(SecurityType.Equity, "SPY", Resolution.Second, fillDataForward: true, extendedMarketHours: true); security = Securities["SPY"]; }
/// <summary> /// Returns true if the brokerage would be able to execute this order at this time assuming /// market prices are sufficient for the fill to take place. This is used to emulate the /// brokerage fills in backtesting and paper trading. For example some brokerages may not perform /// executions during extended market hours. This is not intended to be checking whether or not /// the exchange is open, that is handled in the Security.Exchange property. /// </summary> /// <param name="security">The security being ordered</param> /// <param name="order">The order to test for execution</param> /// <returns>True if the brokerage would be able to perform the execution, false otherwise</returns> public bool CanExecuteOrder(Security security, Order order) { // tradier doesn't support after hours trading var timeOfDay = security.Time.TimeOfDay; if (timeOfDay < EquityExchange.MarketOpen || timeOfDay > EquityExchange.MarketClose) { return false; } return true; }
/// <summary> /// Returns true if the brokerage could accept this order. This takes into account /// order type, security type, and order size limits. /// </summary> /// <remarks> /// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit /// </remarks> /// <param name="security"></param> /// <param name="order">The order to be processed</param> /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param> /// <returns>True if the brokerage could process the order, false otherwise</returns> public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message) { message = null; // validate security type if (security.Type != SecurityType.Forex && security.Type != SecurityType.Cfd) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "This model does not support " + security.Type + " security type." ); return false; } // validate order type if (order.Type != OrderType.Limit && order.Type != OrderType.Market && order.Type != OrderType.StopMarket) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "This model does not support " + order.Type + " order type." ); return false; } // validate order quantity if (order.Quantity % 1000 != 0) { message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", "The order quantity must be a multiple of 1000." ); return false; } // validate stop/limit orders= prices var limit = order as LimitOrder; if (limit != null) { return IsValidOrderPrices(security, OrderType.Limit, limit.Direction, security.Price, limit.LimitPrice, ref message); } var stopMarket = order as StopMarketOrder; if (stopMarket != null) { return IsValidOrderPrices(security, OrderType.StopMarket, stopMarket.Direction, stopMarket.StopPrice, security.Price, ref message); } var stopLimit = order as StopLimitOrder; if (stopLimit != null) { return IsValidOrderPrices(security, OrderType.StopLimit, stopLimit.Direction, stopLimit.StopPrice, stopLimit.LimitPrice, ref message); } return true; }
/// <summary> /// Sets the leverage for the applicable securities, i.e, equities /// </summary> /// <remarks> /// This is added to maintain backwards compatibility with the old margin/leverage system /// </remarks> /// <param name="security"></param> /// <param name="leverage">The new leverage</param> public virtual void SetLeverage(Security security, decimal leverage) { if (leverage < 1) { throw new ArgumentException("Leverage must be greater than or equal to 1."); } decimal margin = 1/leverage; _initialMarginRequirement = margin; _maintenanceMarginRequirement = margin; }
/// <summary> /// Updates the models for the specified security. If the <see cref="DefaultBrokerageModel"/> is specified, /// then no update is performed. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="model">The brokerage model</param> /// <param name="security">The security to be updated</param> public static void UpdateModel(this IAlgorithm algorithm, IBrokerageModel model, Security security) { if (model.GetType() == typeof(DefaultBrokerageModel)) { // if we're using the default don't do anything return; } security.TransactionModel = model.GetTransactionModel(security); security.SettlementModel = model.GetSettlementModel(security, algorithm.AccountType); }
/// <summary> /// Returns true if the brokerage would allow updating the order as specified by the request /// </summary> /// <param name="security">The security of the order</param> /// <param name="order">The order to be updated</param> /// <param name="request">The requested update to be made to the order</param> /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be updated</param> /// <returns>True if the brokerage would allow updating the order, false otherwise</returns> public override bool CanUpdateOrder(Security security, Order order, UpdateOrderRequest request, out BrokerageMessageEvent message) { message = null; if (order.SecurityType == SecurityType.Forex && request.Quantity != null) { return IsForexWithinOrderSizeLimits(order.Symbol.Value, request.Quantity.Value, out message); } return true; }
/// <summary> /// Default stop fill model implementation in base class security. (Stop Market Order Type) /// </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="MarketFill(Security, MarketOrder)"/> /// <seealso cref="SecurityTransactionModel.LimitFill"/> public virtual OrderEvent StopMarketFill(Security asset, StopMarketOrder order) { //Default order event to return. var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var fill = new OrderEvent(order, utcTime, 0); // make sure the exchange is open before filling if (!IsExchangeOpen(asset)) return fill; //If its cancelled don't need anymore checks: if (order.Status == OrderStatus.Canceled) return fill; //Get the range of prices in the last bar: decimal minimumPrice; decimal maximumPrice; DataMinMaxPrices(asset, out minimumPrice, out maximumPrice, order.Direction); //Calculate the model slippage: e.g. 0.01c var slip = asset.SlippageModel.GetSlippageApproximation(asset, order); //Check if the Stop Order was filled: opposite to a limit order switch (order.Direction) { case OrderDirection.Sell: //-> 1.1 Sell Stop: If Price below setpoint, Sell: if (minimumPrice < order.StopPrice) { fill.Status = OrderStatus.Filled; // Assuming worse case scenario fill - fill at lowest of the stop & asset price. fill.FillPrice = Math.Min(order.StopPrice, asset.Price - slip); } break; case OrderDirection.Buy: //-> 1.2 Buy Stop: If Price Above Setpoint, Buy: if (maximumPrice > order.StopPrice) { fill.Status = OrderStatus.Filled; // Assuming worse case scenario fill - fill at highest of the stop & asset price. fill.FillPrice = Math.Max(order.StopPrice, asset.Price + slip); } break; } // assume the order completely filled if (fill.Status == OrderStatus.Filled) { fill.FillQuantity = order.Quantity; fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order); } return fill; }
public override void Initialize() { SetStartDate(2012, 01, 01); SetEndDate(2012, 02, 01); AddSecurity(SecurityType.Equity, "SPY", Resolution.Hour); // set our models _security = Securities[_spy]; _security.FeeModel = new CustomFeeModel(this); _security.FillModel = new CustomFillModel(this); _security.SlippageModel = new CustomSlippageModel(this); }
/// <summary> /// Gets the amount of buying power reserved to maintain the specified position /// </summary> /// <param name="security">The security for the position</param> /// <returns>The reserved buying power in account currency</returns> public decimal GetReservedBuyingPowerForPosition(Security security) { // Always returns 0. Since we're purchasing currencies outright, the position doesn't consume buying power return(0); }
/// <summary> /// Gets the current leverage of the security /// </summary> /// <param name="security">The security to get leverage for</param> /// <returns>The current leverage in the security</returns> public decimal GetLeverage(Security security) { // Always returns 1. Cash accounts have no leverage. return(1m); }
/// <summary> /// Sets the leverage for the applicable securities, i.e, equities /// </summary> /// <remarks> /// This is added to maintain backwards compatibility with the old margin/leverage system /// </remarks> /// <param name="security">The security to set leverage for</param> /// <param name="leverage">The new leverage</param> public void SetLeverage(Security security, decimal leverage) { // No action performed. This model always uses a leverage = 1 }
/// <summary> /// Check if there is sufficient buying power to execute this order. /// </summary> /// <param name="portfolio">The algorithm's portfolio</param> /// <param name="security">The security to be traded</param> /// <param name="order">The order to be checked</param> /// <returns>Returns true if there is sufficient buying power to execute the order, false otherwise</returns> public bool HasSufficientBuyingPowerForOrder(SecurityPortfolioManager portfolio, Security security, Order order) { var baseCurrency = security as IBaseCurrencySymbol; if (baseCurrency == null) { return(false); } decimal totalQuantity; decimal orderQuantity; if (order.Direction == OrderDirection.Buy) { // quantity available for buying in quote currency totalQuantity = portfolio.CashBook[security.QuoteCurrency.Symbol].Amount; orderQuantity = order.AbsoluteQuantity * GetOrderPrice(security, order); } else { // quantity available for selling in base currency totalQuantity = portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount; orderQuantity = order.AbsoluteQuantity; } // calculate reserved quantity for open orders (in quote or base currency depending on direction) var openOrdersReservedQuantity = GetOpenOrdersReservedQuantity(portfolio, security, order); if (order.Direction == OrderDirection.Sell) { // can sell available and non-reserved quantities return(orderQuantity <= totalQuantity - openOrdersReservedQuantity); } if (order.Type == OrderType.Market) { // find a target value in account currency for buy market orders var targetValue = portfolio.CashBook.ConvertToAccountCurrency(totalQuantity - openOrdersReservedQuantity, security.QuoteCurrency.Symbol); var maximumQuantity = GetMaximumOrderQuantityForTargetValue(portfolio, security, targetValue) * GetOrderPrice(security, order); // include existing holdings var holdingsValue = portfolio.CashBook.ConvertToAccountCurrency( portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount, baseCurrency.BaseCurrencySymbol); return(orderQuantity <= Math.Abs(maximumQuantity) + holdingsValue); } // for limit orders, add fees to the order cost var orderFee = 0m; if (order.Type == OrderType.Limit) { orderFee = security.FeeModel.GetOrderFee(security, order); orderFee = portfolio.CashBook.Convert(orderFee, CashBook.AccountCurrency, security.QuoteCurrency.Symbol); } return(orderQuantity <= totalQuantity - openOrdersReservedQuantity - orderFee); }
/// <summary> /// Get the maximum market order quantity to obtain a position with a given value in account currency /// </summary> /// <param name="portfolio">The algorithm's portfolio</param> /// <param name="security">The security to be traded</param> /// <param name="targetPortfolioValue">The value in account currency that we want our holding to have</param> /// <returns>Returns the maximum allowed market order quantity</returns> public decimal GetMaximumOrderQuantityForTargetValue(SecurityPortfolioManager portfolio, Security security, decimal targetPortfolioValue) { // no shorting allowed if (targetPortfolioValue < 0) { return(0); } var baseCurrency = security as IBaseCurrencySymbol; if (baseCurrency == null) { return(0); } // if target value is zero, return amount of base currency available to sell if (targetPortfolioValue == 0) { return(-portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount); } // convert base currency cash to account currency var baseCurrencyPosition = portfolio.CashBook.ConvertToAccountCurrency( portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount, baseCurrency.BaseCurrencySymbol); // convert quote currency cash to account currency var quoteCurrencyPosition = portfolio.CashBook.ConvertToAccountCurrency( portfolio.CashBook[security.QuoteCurrency.Symbol].Amount, security.QuoteCurrency.Symbol); // determine the unit price in terms of the account currency var unitPrice = new MarketOrder(security.Symbol, 1, DateTime.UtcNow).GetValue(security); if (unitPrice == 0) { return(0); } // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - baseCurrencyPosition); var direction = targetPortfolioValue > baseCurrencyPosition ? OrderDirection.Buy : OrderDirection.Sell; // calculate the total cash available var cashRemaining = direction == OrderDirection.Buy ? quoteCurrencyPosition : baseCurrencyPosition; if (cashRemaining <= 0) { return(0); } // continue iterating while we do not have enough cash for the order decimal cashRequired; decimal orderValue; decimal orderFees; var feeToPriceRatio = 0m; // compute the initial order quantity var orderQuantity = targetOrderValue / unitPrice; // rounding off Order Quantity to the nearest multiple of Lot Size orderQuantity -= orderQuantity % security.SymbolProperties.LotSize; do { // reduce order quantity by feeToPriceRatio, since it is faster than by lot size // if it becomes nonpositive, return zero orderQuantity -= feeToPriceRatio; if (orderQuantity <= 0) { return(0); } // generate the order var order = new MarketOrder(security.Symbol, orderQuantity, DateTime.UtcNow); orderValue = order.GetValue(security); orderFees = security.FeeModel.GetOrderFee(security, order); // find an incremental delta value for the next iteration step feeToPriceRatio = orderFees / unitPrice; feeToPriceRatio -= feeToPriceRatio % security.SymbolProperties.LotSize; if (feeToPriceRatio < security.SymbolProperties.LotSize) { feeToPriceRatio = security.SymbolProperties.LotSize; } // calculate the cash required for the order cashRequired = orderValue; } while (cashRequired > cashRemaining || orderValue + orderFees > targetOrderValue); // add directionality back in return((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity); }
private static decimal GetOpenOrdersReservedQuantity(SecurityPortfolioManager portfolio, Security security, Order order) { var baseCurrency = security as IBaseCurrencySymbol; if (baseCurrency == null) { return(0); } // find the target currency for the requested direction and the securities potentially involved var targetCurrency = order.Direction == OrderDirection.Buy ? security.QuoteCurrency.Symbol : baseCurrency.BaseCurrencySymbol; var symbolDirectionPairs = new Dictionary <Symbol, OrderDirection>(); foreach (var portfolioSecurity in portfolio.Securities.Values) { var basePortfolioSecurity = portfolioSecurity as IBaseCurrencySymbol; if (basePortfolioSecurity == null) { continue; } if (basePortfolioSecurity.BaseCurrencySymbol == targetCurrency) { symbolDirectionPairs.Add(portfolioSecurity.Symbol, OrderDirection.Sell); } else if (portfolioSecurity.QuoteCurrency.Symbol == targetCurrency) { symbolDirectionPairs.Add(portfolioSecurity.Symbol, OrderDirection.Buy); } } // fetch open orders with matching symbol/side var openOrders = portfolio.Transactions.GetOpenOrders(x => { OrderDirection dir; return(symbolDirectionPairs.TryGetValue(x.Symbol, out dir) && // same direction of our order dir == x.Direction && // don't count our current order x.Id != order.Id && // only count working orders (x.Type == OrderType.Limit || x.Type == OrderType.StopMarket)); } ); // calculate reserved quantity for selected orders var openOrdersReservedQuantity = 0m; foreach (var openOrder in openOrders) { var orderSecurity = portfolio.Securities[openOrder.Symbol]; var orderBaseCurrency = orderSecurity as IBaseCurrencySymbol; if (orderBaseCurrency != null) { // convert order value to target currency var quantityInTargetCurrency = openOrder.AbsoluteQuantity; if (orderSecurity.QuoteCurrency.Symbol == targetCurrency) { quantityInTargetCurrency *= GetOrderPrice(security, openOrder); } openOrdersReservedQuantity += quantityInTargetCurrency; } } return(openOrdersReservedQuantity); }