public void OldBaseFillModel_MarketOnCloseFill(bool isMarketAlwaysOpen)
        {
            var model        = new TestFillModelInheritBaseClass();
            var security     = SecurityTests.GetSecurity(isMarketAlwaysOpen);
            var reference    = new DateTime(2022, 4, 5, 10, 0, 0);
            var referenceUtc = reference.ConvertToUtc(TimeZones.NewYork);
            var timeKeeper   = new TimeKeeper(referenceUtc);

            security.SetLocalTimeKeeper(timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));

            var args = new FillModelParameters(security, new MarketOnCloseOrder(security.Symbol, 1, orderDateTime),
                                               new MockSubscriptionDataConfigProvider(_config), Time.OneHour);

            if (isMarketAlwaysOpen)
            {
                Assert.Throws <InvalidOperationException>(() => model.Fill(args));
            }
            else
            {
                var result = model.Fill(args);

                Assert.True(model.MarketOnCloseFillWasCalled);
                Assert.IsNotNull(result);
                Assert.True(model.GetPricesWasCalled);
                Assert.AreEqual(12345, result.OrderEvent.FillPrice);
            }
        }
Esempio n. 2
0
 /// <summary>
 /// Return an order event with the fill details
 /// </summary>
 /// <param name="parameters">A parameters object containing the security and order</param>
 /// <returns>Order fill information detailing the average price and quantity filled.</returns>
 public override Fill Fill(FillModelParameters parameters)
 {
     Parameters = parameters;
     using (Py.GIL())
     {
         return((_model.Fill(parameters) as PyObject).GetAndDispose <Fill>());
     }
 }
Esempio n. 3
0
 /// <summary>
 /// Return an order event with the fill details
 /// </summary>
 /// <param name="parameters">A parameters object containing the security and order</param>
 /// <returns>Order fill information detailing the average price and quantity filled.</returns>
 public override Fill Fill(FillModelParameters parameters)
 {
     Parameters = parameters;
     using (Py.GIL())
     {
         return(_model.Fill(parameters));
     }
 }
Esempio n. 4
0
            public Fill Fill(FillModelParameters parameters)
            {
                var order  = parameters.Order;
                var status = OrderStatus.PartiallyFilled;

                if (FilledOrders.ContainsKey(order.Id))
                {
                    status = OrderStatus.Filled;
                }
                FilledOrders[order.Id] = order;
                return(new Fill(new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero)
                {
                    FillPrice = parameters.Security.Price,
                    FillQuantity = order.Quantity / 2,
                    Status = status
                }));
            }
Esempio n. 5
0
            public Fill Fill(FillModelParameters parameters)
            {
                var        order = parameters.Order;
                OrderEvent orderEvent;

                switch (order.Type)
                {
                case OrderType.Market:
                    orderEvent =
                        MarketFill(parameters.Security, parameters.Order as MarketOrder);
                    break;

                case OrderType.Limit:
                    orderEvent =
                        LimitFill(parameters.Security, parameters.Order as LimitOrder);
                    break;

                case OrderType.StopMarket:
                    orderEvent =
                        StopMarketFill(parameters.Security, parameters.Order as StopMarketOrder);
                    break;

                case OrderType.StopLimit:
                    orderEvent =
                        StopLimitFill(parameters.Security, parameters.Order as StopLimitOrder);
                    break;

                case OrderType.MarketOnOpen:
                    orderEvent =
                        MarketOnOpenFill(parameters.Security, parameters.Order as MarketOnOpenOrder);
                    break;

                case OrderType.MarketOnClose:
                    orderEvent =
                        MarketOnCloseFill(parameters.Security, parameters.Order as MarketOnCloseOrder);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                return(new Fill(orderEvent));
            }
Esempio n. 6
0
        public void PerformsMarketFillSell()
        {
            var model    = new EquityFillModel();
            var order    = new MarketOrder(Symbols.SPY, -100, Noon);
            var config   = CreateQuoteBarConfig(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()
                );

            security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
            security.SetMarketPrice(new IndicatorDataPoint(Symbols.SPY, Noon, 101.123m));

            var parameters = new FillModelParameters(
                security,
                order,
                new MockSubscriptionDataConfigProvider(config),
                Time.OneHour);

            // IndicatorDataPoint is not market data
            Assert.Throws <InvalidOperationException>(() => model.Fill(parameters),
                                                      $"Cannot get bid price to perform fill for {security.Symbol} because no market data subscription were found.");

            var bidBar = new Bar(101.123m, 101.123m, 101.123m, 101.123m);
            var askBar = new Bar(101.234m, 101.234m, 101.234m, 101.234m);

            security.SetMarketPrice(new QuoteBar(Noon, Symbols.SPY, bidBar, 0, askBar, 0));

            var fill = model.Fill(parameters).OrderEvent;

            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(bidBar.Close, fill.FillPrice);
            Assert.AreEqual(OrderStatus.Filled, fill.Status);
        }
Esempio n. 7
0
 public void SetParameters(FillModelParameters parameters)
 {
     Parameters = parameters;
 }
Esempio n. 8
0
        /// <summary>
        /// Scans all the outstanding orders and applies the algorithm model fills to generate the order events
        /// </summary>
        public virtual void Scan()
        {
            lock (_needsScanLock)
            {
                // there's usually nothing in here
                if (!_needsScan)
                {
                    return;
                }

                var stillNeedsScan = false;

                // process each pending order to produce fills/fire events
                foreach (var kvp in _pending.OrderBy(x => x.Key))
                {
                    var order = kvp.Value;
                    if (order == null)
                    {
                        Log.Error("BacktestingBrokerage.Scan(): Null pending order found: " + kvp.Key);
                        _pending.TryRemove(kvp.Key, out order);
                        continue;
                    }

                    if (order.Status.IsClosed())
                    {
                        // this should never actually happen as we always remove closed orders as they happen
                        _pending.TryRemove(order.Id, out order);
                        continue;
                    }

                    // all order fills are processed on the next bar (except for market orders)
                    if (order.Time == Algorithm.UtcTime && order.Type != OrderType.Market)
                    {
                        stillNeedsScan = true;
                        continue;
                    }

                    var fills = new[] { new OrderEvent(order,
                                                       Algorithm.UtcTime,
                                                       OrderFee.Zero) };

                    Security security;
                    if (!Algorithm.Securities.TryGetValue(order.Symbol, out security))
                    {
                        Log.Error("BacktestingBrokerage.Scan(): Unable to process order: " + order.Id + ". The security no longer exists.");
                        // invalidate the order in the algorithm before removing
                        OnOrderEvent(new OrderEvent(order,
                                                    Algorithm.UtcTime,
                                                    OrderFee.Zero)
                        {
                            Status = OrderStatus.Invalid
                        });
                        _pending.TryRemove(order.Id, out order);
                        continue;
                    }

                    // check if the time in force handler allows fills
                    if (order.TimeInForce.IsOrderExpired(security, order))
                    {
                        OnOrderEvent(new OrderEvent(order,
                                                    Algorithm.UtcTime,
                                                    OrderFee.Zero)
                        {
                            Status  = OrderStatus.Canceled,
                            Message = "The order has expired."
                        });
                        _pending.TryRemove(order.Id, out order);
                        continue;
                    }

                    // check if we would actually be able to fill this
                    if (!Algorithm.BrokerageModel.CanExecuteOrder(security, order))
                    {
                        continue;
                    }

                    // verify sure we have enough cash to perform the fill
                    HasSufficientBuyingPowerForOrderResult hasSufficientBuyingPowerResult;
                    try
                    {
                        hasSufficientBuyingPowerResult = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(Algorithm.Portfolio, security, order);
                    }
                    catch (Exception err)
                    {
                        // if we threw an error just mark it as invalid and remove the order from our pending list
                        OnOrderEvent(new OrderEvent(order,
                                                    Algorithm.UtcTime,
                                                    OrderFee.Zero,
                                                    err.Message)
                        {
                            Status = OrderStatus.Invalid
                        });
                        Order pending;
                        _pending.TryRemove(order.Id, out pending);

                        Log.Error(err);
                        Algorithm.Error($"Order Error: id: {order.Id}, Error executing margin models: {err.Message}");
                        continue;
                    }

                    //Before we check this queued order make sure we have buying power:
                    if (hasSufficientBuyingPowerResult.IsSufficient)
                    {
                        //Model:
                        var model = security.FillModel;

                        //Based on the order type: refresh its model to get fill price and quantity
                        try
                        {
                            if (order.Type == OrderType.OptionExercise)
                            {
                                var option = (Option)security;
                                fills = option.OptionExerciseModel.OptionExercise(option, order as OptionExerciseOrder).ToArray();
                            }
                            else
                            {
                                var context = new FillModelParameters(
                                    security,
                                    order,
                                    Algorithm.SubscriptionManager.SubscriptionDataConfigService);
                                fills = new[] { model.Fill(context).OrderEvent };
                            }

                            // invoke fee models for completely filled order events
                            foreach (var fill in fills)
                            {
                                if (fill.Status == OrderStatus.Filled)
                                {
                                    // this check is provided for backwards compatibility of older user-defined fill models
                                    // that may be performing fee computation inside the fill model w/out invoking the fee model
                                    // TODO : This check can be removed in April, 2019 -- a 6-month window to upgrade (also, suspect small % of users, if any are impacted)
                                    if (fill.OrderFee.Value.Amount == 0m)
                                    {
                                        fill.OrderFee = security.FeeModel.GetOrderFee(
                                            new OrderFeeParameters(security,
                                                                   order,
                                                                   Algorithm.Portfolio.CashBook.AccountCurrency));
                                    }
                                }
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error(err);
                            Algorithm.Error($"Order Error: id: {order.Id}, Transaction model failed to fill for order type: {order.Type} with error: {err.Message}");
                        }
                    }
                    else
                    {
                        // invalidate the order in the algorithm before removing
                        var message = $"Insufficient buying power to complete order (Value:{order.GetValue(security).SmartRounding()}), Reason: {hasSufficientBuyingPowerResult.Reason}.";
                        OnOrderEvent(new OrderEvent(order,
                                                    Algorithm.UtcTime,
                                                    OrderFee.Zero,
                                                    message)
                        {
                            Status = OrderStatus.Invalid
                        });
                        Order pending;
                        _pending.TryRemove(order.Id, out pending);

                        Algorithm.Error($"Order Error: id: {order.Id}, {message}");
                        continue;
                    }

                    foreach (var fill in fills)
                    {
                        // check if the fill should be emitted
                        if (!order.TimeInForce.IsFillValid(security, order, fill))
                        {
                            break;
                        }

                        // change in status or a new fill
                        if (order.Status != fill.Status || fill.FillQuantity != 0)
                        {
                            //If the fill models come back suggesting filled, process the affects on portfolio
                            OnOrderEvent(fill);
                        }

                        if (order.Type == OrderType.OptionExercise)
                        {
                            fill.Message = order.Tag;
                            OnOptionPositionAssigned(fill);
                        }
                    }

                    if (fills.All(x => x.Status.IsClosed()))
                    {
                        _pending.TryRemove(order.Id, out order);
                    }
                    else
                    {
                        stillNeedsScan = true;
                    }
                }

                // if we didn't fill then we need to continue to scan
                _needsScan = stillNeedsScan;
            }
        }
 public TestableLatestFillModel()
 {
     // NOTE. GetPrices will no be called before SubscriptionDataConfigProvider is set by the system
     Parameters = new FillModelParameters(null, null, new MockSubscriptionDataConfigProvider());
 }