Example #1
0
        /// <summary>
        /// Default option exercise model for the basic equity/index option security class.
        /// </summary>
        /// <param name="option">Option we're trading this order</param>
        /// <param name="order">Order to update</param>
        public IEnumerable <OrderEvent> OptionExercise(Option option, OptionExerciseOrder order)
        {
            var utcTime = option.LocalTime.ConvertToUtc(option.Exchange.TimeZone);

            var optionQuantity   = order.Quantity;
            var assignment       = order.Quantity < 0;
            var underlying       = option.Underlying;
            var exercisePrice    = order.Price;
            var fillQuantity     = option.GetExerciseQuantity(order.Quantity);
            var exerciseQuantity =
                option.Symbol.ID.OptionRight == OptionRight.Call ? fillQuantity : -fillQuantity;
            var exerciseDirection = assignment?
                                    (option.Symbol.ID.OptionRight == OptionRight.Call ? OrderDirection.Sell : OrderDirection.Buy):
                                    (option.Symbol.ID.OptionRight == OptionRight.Call ? OrderDirection.Buy : OrderDirection.Sell);

            var orderFee = option.FeeModel.GetOrderFee(option, order);

            var cashQuote = option.QuoteCurrency;

            var addUnderlyingEvent = new OrderEvent(order.Id,
                                                    underlying.Symbol,
                                                    utcTime,
                                                    OrderStatus.Filled,
                                                    exerciseDirection,
                                                    exercisePrice,
                                                    exerciseQuantity,
                                                    0.0m,
                                                    "Option Exercise/Assignment");

            var optionRemoveEvent = new OrderEvent(order.Id,
                                                   option.Symbol,
                                                   utcTime,
                                                   OrderStatus.Filled,
                                                   assignment ? OrderDirection.Buy : OrderDirection.Sell,
                                                   0.0m,
                                                   -optionQuantity,
                                                   orderFee,
                                                   "Adjusting(or removing) the exercised/assigned option");

            if (optionRemoveEvent.FillQuantity > 0)
            {
                optionRemoveEvent.IsAssignment = true;
            }

            if (option.ExerciseSettlement == SettlementType.PhysicalDelivery &&
                option.IsAutoExercised(underlying.Close))
            {
                return(new[] { optionRemoveEvent, addUnderlyingEvent });
            }

            return(new[] { optionRemoveEvent });
        }
        private decimal EstimateArbitragePnL(Option option,
                                             OptionHolding holding,
                                             Security underlying,
                                             ICurrencyConverter currencyConverter)
        {
            // no-arb argument:
            // if our long deep ITM position has a large B/A spread and almost no time value, it may be interesting for us
            // to exercise the option and close the resulting position in underlying instrument, if we want to exit now.

            // User's short option position is our long one.
            // In order to sell ITM position we take option bid price as an input
            var optionPrice = option.BidPrice;

            // we are interested in underlying bid price if we exercise calls and want to sell the underlying immediately.
            // we are interested in underlying ask price if we exercise puts
            var underlyingPrice = option.Symbol.ID.OptionRight == OptionRight.Call
                ? underlying.BidPrice
                : underlying.AskPrice;

            // quantity is normally negative algo's holdings, but since we're modeling the contract holder (counter-party)
            // it's negative THEIR holdings. holding.Quantity is negative, so if counter-party exercises, they would reduce holdings
            var underlyingQuantity = option.GetExerciseQuantity(holding.Quantity);

            // Scenario 1 (base): we just close option position
            var marketOrder1 = new MarketOrder(option.Symbol, -holding.Quantity, option.LocalTime.ConvertToUtc(option.Exchange.TimeZone));
            var orderFee1    = currencyConverter.ConvertToAccountCurrency(option.FeeModel.GetOrderFee(
                                                                              new OrderFeeParameters(option, marketOrder1)).Value);

            var basePnL = (optionPrice - holding.AveragePrice) * -holding.Quantity
                          * option.QuoteCurrency.ConversionRate
                          * option.SymbolProperties.ContractMultiplier
                          - orderFee1.Amount;

            // Scenario 2 (alternative): we exercise option and then close underlying position
            var optionExerciseOrder2 = new OptionExerciseOrder(option.Symbol, (int)holding.AbsoluteQuantity, option.LocalTime.ConvertToUtc(option.Exchange.TimeZone));
            var optionOrderFee2      = currencyConverter.ConvertToAccountCurrency(option.FeeModel.GetOrderFee(
                                                                                      new OrderFeeParameters(option, optionExerciseOrder2)).Value);

            var undelyingMarketOrder2 = new MarketOrder(underlying.Symbol, -underlyingQuantity, underlying.LocalTime.ConvertToUtc(underlying.Exchange.TimeZone));
            var undelyingOrderFee2    = currencyConverter.ConvertToAccountCurrency(underlying.FeeModel.GetOrderFee(
                                                                                       new OrderFeeParameters(underlying, undelyingMarketOrder2)).Value);

            // calculating P/L of the two transactions (exercise option and then close underlying position)
            var altPnL = (underlyingPrice - option.StrikePrice) * underlyingQuantity * underlying.QuoteCurrency.ConversionRate * option.ContractUnitOfTrade
                         - undelyingOrderFee2.Amount
                         - holding.AveragePrice * holding.AbsoluteQuantity * option.SymbolProperties.ContractMultiplier * option.QuoteCurrency.ConversionRate
                         - optionOrderFee2.Amount;

            return(altPnL - basePnL);
        }
Example #3
0
        /// <summary>
        /// Default option exercise model for the basic equity/index option security class.
        /// </summary>
        /// <param name="option">Option we're trading this order</param>
        /// <param name="order">Order to update</param>
        public IEnumerable <OrderEvent> OptionExercise(Option option, OptionExerciseOrder order)
        {
            var underlying = option.Underlying;

            var isShort = order.Quantity < 0;
            var utcTime = option.LocalTime.ConvertToUtc(option.Exchange.TimeZone);

            var inTheMoney = option.IsAutoExercised(underlying.Close);

            // we're assigned only if we get exercised against, meaning we wrote the option and it was exercised by the buyer
            var isAssignment = inTheMoney && isShort;

            yield return(new OrderEvent(
                             order.Id,
                             option.Symbol,
                             utcTime,
                             OrderStatus.Filled,
                             isShort ? OrderDirection.Buy : OrderDirection.Sell,
                             0.0m,
                             -order.Quantity,
                             OrderFee.Zero,
                             // note whether or not we expired OTM/ITM and whether we were assigned or exercised
                             inTheMoney ? isAssignment ? "Automatic Assignment" : "Automatic Exercise" : "OTM"
                             )
            {
                IsAssignment = isAssignment
            });

            if (inTheMoney && option.ExerciseSettlement == SettlementType.PhysicalDelivery)
            {
                var right = option.Symbol.ID.OptionRight;

                // TODO : Why doesn't this method take into account the directionality of the quantity like other quantity properties/methods
                var fillQuantity     = option.GetExerciseQuantity(order.Quantity);
                var exerciseQuantity = right == OptionRight.Call ? fillQuantity : -fillQuantity;

                yield return(new OrderEvent(
                                 order.Id,
                                 underlying.Symbol,
                                 utcTime,
                                 OrderStatus.Filled,
                                 right.GetExerciseDirection(isShort),
                                 order.Price,
                                 exerciseQuantity,
                                 OrderFee.Zero,
                                 isAssignment ? "Option Assignment" : "Option Exercise"
                                 ));
            }
        }
Example #4
0
        public void NonAccountCurrencyOption_Exercise()
        {
            var reference = new DateTime(2016, 02, 16, 11, 53, 30);
            SecurityPortfolioManager portfolio;
            var security = InitializeTest(reference, out portfolio);

            var cash = new Cash("EUR", 0, 10);

            portfolio.CashBook.Add("EUR", cash);
            var option = new Option(
                Symbols.SPY_C_192_Feb19_2016,
                SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
                cash,
                new OptionSymbolProperties(SymbolProperties.GetDefault("EUR")),
                portfolio.CashBook,
                RegisteredSecurityDataTypesProvider.Null,
                new SecurityCache()
                );

            option.Underlying = security;
            security.SetMarketPrice(new Tick {
                Value = 1000
            });
            portfolio.Securities.Add(option);
            var fakeOrderProcessor = new FakeOrderProcessor();

            portfolio.Transactions.SetOrderProcessor(fakeOrderProcessor);

            var fillPrice    = 1000m;
            var fillQuantity = 1;

            option.ExerciseSettlement = SettlementType.Cash;
            var orderFee = new OrderFee(new CashAmount(1, "EUR"));
            var order    = new OptionExerciseOrder(Symbols.SPY_C_192_Feb19_2016, fillQuantity, DateTime.UtcNow);

            fakeOrderProcessor.AddOrder(order);
            var orderDirection = fillQuantity > 0 ? OrderDirection.Buy : OrderDirection.Sell;
            var fill           = new OrderEvent(order.Id, option.Symbol, reference, OrderStatus.Filled, orderDirection, fillPrice, fillQuantity, orderFee);

            portfolio.ProcessFill(fill);

            // (1000 (price) - 192 (call strike)) * 1 quantity => 808 EUR
            Assert.AreEqual(10, option.Holdings.TotalFees); // 1 * 10 (conversion rate to account currency)
            // 808 - 1000 (price) - 1 fee
            Assert.AreEqual(-193, portfolio.CashBook["EUR"].Amount);
            // 100000 initial amount, no fee deducted
            Assert.AreEqual(100000, portfolio.CashBook[Currencies.USD].Amount);
        }
        public void DeserializesOptionExpireOrder()
        {
            var expected = new OptionExerciseOrder(Symbols.SPY_P_192_Feb19_2016, 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
            {
                Id           = 12345,
                ContingentId = 123456,
                BrokerId     = new List <string> {
                    "727", "54970"
                }
            };

            // Note: Order price equals strike price found in Symbol object
            // Price = Symbol.ID.StrikePrice

            TestOrderType(expected);
        }
Example #6
0
        /// <summary>
        /// Default option exercise model for the basic equity/index option security class.
        /// </summary>
        /// <param name="option">Option we're trading this order</param>
        /// <param name="order">Order to update</param>
        public OrderEvent OptionExercise(Option option, OptionExerciseOrder order)
        {
            //Default order event to return
            var utcTime       = option.LocalTime.ConvertToUtc(option.Exchange.TimeZone);
            var deliveryEvent = new OrderEvent(order, utcTime, 0);

            // make sure the exchange is open before filling
            if (!IsExchangeOpen(option))
            {
                return(deliveryEvent);
            }

            //Order price for a option exercise order model is the strike price
            deliveryEvent.FillPrice    = order.Price;
            deliveryEvent.FillQuantity = option.GetExerciseQuantity(order.Quantity);
            deliveryEvent.OrderFee     = option.FeeModel.GetOrderFee(option, order);
            deliveryEvent.Status       = OrderStatus.Filled;

            return(deliveryEvent);
        }
        private decimal EstimateArbitragePnL(Option option, OptionHolding holding, Security underlying)
        {
            // no-arb argument:
            // if our long deep ITM position has a large B/A spread and almost no time value, it may be interesting for us
            // to exercise the option and close the resulting position in underlying instrument, if we want to exit now.

            // User's short option position is our long one.
            // In order to sell ITM position we take option bid price as an input
            var optionPrice = option.BidPrice;

            // we are interested in underlying bid price if we exercise calls and want to sell the underlying immediately.
            // we are interested in underlying ask price if we exercise puts
            var underlyingPrice = option.Symbol.ID.OptionRight == OptionRight.Call ?
                                  underlying.BidPrice :
                                  underlying.AskPrice;

            var underlyingQuantity = option.Symbol.ID.OptionRight == OptionRight.Call ?
                                     option.GetExerciseQuantity((int)holding.AbsoluteQuantity) :
                                     -option.GetExerciseQuantity((int)holding.AbsoluteQuantity);

            // Scenario 1 (base): we just close option position
            var marketOrder1 = new MarketOrder(option.Symbol, -holding.Quantity, option.LocalTime.ConvertToUtc(option.Exchange.TimeZone));
            var orderFee1    = option.FeeModel.GetOrderFee(option, marketOrder1);

            var basePnL = (optionPrice - holding.AveragePrice) * -holding.Quantity * option.QuoteCurrency.ConversionRate * option.SymbolProperties.ContractMultiplier - orderFee1;

            // Scenario 2 (alternative): we exercise option and then close underlying position
            var optionExerciseOrder2 = new OptionExerciseOrder(option.Symbol, (int)holding.AbsoluteQuantity, option.LocalTime.ConvertToUtc(option.Exchange.TimeZone));
            var optionOrderFee2      = option.FeeModel.GetOrderFee(option, optionExerciseOrder2);

            var undelyingMarketOrder2 = new MarketOrder(underlying.Symbol, -underlyingQuantity, underlying.LocalTime.ConvertToUtc(underlying.Exchange.TimeZone));
            var undelyingOrderFee2    = underlying.FeeModel.GetOrderFee(underlying, undelyingMarketOrder2);

            // calculating P/L of the two transactions (exercise option and then close underlying position)
            var altPnL = (underlyingPrice - option.StrikePrice) * underlyingQuantity * underlying.QuoteCurrency.ConversionRate * option.ContractUnitOfTrade
                         - undelyingOrderFee2
                         - holding.AveragePrice * holding.AbsoluteQuantity * option.SymbolProperties.ContractMultiplier * option.QuoteCurrency.ConversionRate
                         - optionOrderFee2;

            return(altPnL - basePnL);
        }
Example #8
0
        /// <summary>
        /// Default option exercise model for the basic equity/index option security class.
        /// </summary>
        /// <param name="option">Option we're trading this order</param>
        /// <param name="order">Order to update</param>
        public IEnumerable <OrderEvent> OptionExercise(Option option, OptionExerciseOrder order)
        {
            var underlying = option.Underlying;
            var utcTime    = option.LocalTime.ConvertToUtc(option.Exchange.TimeZone);

            var inTheMoney   = option.IsAutoExercised(underlying.Close);
            var isAssignment = inTheMoney && option.Holdings.IsShort;

            yield return(new OrderEvent(
                             order.Id,
                             option.Symbol,
                             utcTime,
                             OrderStatus.Filled,
                             GetOrderDirection(order.Quantity),
                             0.0m,
                             order.Quantity,
                             OrderFee.Zero,
                             GetContractHoldingsAdjustmentFillTag(inTheMoney, isAssignment)
                             )
            {
                IsAssignment = isAssignment
            });

            // TODO : Support Manual Exercise of OTM contracts [ inTheMoney = false ]
            if (inTheMoney && option.ExerciseSettlement == SettlementType.PhysicalDelivery)
            {
                var exerciseQuantity = option.GetExerciseQuantity(order.Quantity);

                yield return(new OrderEvent(
                                 order.Id,
                                 underlying.Symbol,
                                 utcTime,
                                 OrderStatus.Filled,
                                 GetOrderDirection(exerciseQuantity),
                                 order.Price,
                                 exerciseQuantity,
                                 OrderFee.Zero,
                                 isAssignment ? "Option Assignment" : "Option Exercise"
                                 ));
            }
        }