Overall Statistics |
Total Trades 2 Average Win 0% Average Loss 0% Compounding Annual Return 33.667% Drawdown 0.500% Expectancy 0 Net Profit 0% Sharpe Ratio 3.157 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.011 Beta 0.476 Annual Standard Deviation 0.062 Annual Variance 0.004 Information Ratio -2.818 Tracking Error 0.068 Treynor Ratio 0.41 Total Fees $0.50 |
namespace Quantconnect { public partial class OptionSellAlgo : QCAlgorithm { string _symbol = "VXX"; Symbol _equitySymbol; Symbol _optionSymbol; private Slice lastSlice = null; private bool orderedOnce = false; public override void Initialize(){ SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage); SetStartDate(2014, 3, 1); SetEndDate(2014, 3, 5); //Each contract requires approximately 75% of the sale price. Look into creating own margin model //At 3/3 Contract of VXX at ~45 required 3550 SetCash(10000); var equity = AddEquity(_symbol, Resolution.Minute); _equitySymbol = equity.Symbol; Securities[_symbol].SetDataNormalizationMode(DataNormalizationMode.TotalReturn); var option = AddOption(_symbol); option.MarginModel = new IBOptionMarginModel(); _optionSymbol = option.Symbol; option.SetFilter(universe => //Select the data source using a universe that includes weekly options expiring within a month from symbol in universe.Expiration(TimeSpan.FromDays(20), TimeSpan.FromDays(30)).IncludeWeeklys() //Filter the data Only Calls where symbol.ID.OptionRight == OptionRight.Call && //Between 25 and 30% (symbol.ID.StrikePrice - universe.Underlying.Price) / universe.Underlying.Price <= 0.30m && (symbol.ID.StrikePrice - universe.Underlying.Price) / universe.Underlying.Price >= 0.25m //Select and return the option symbols select symbol); Schedule.On(DateRules.EveryDay(_symbol), TimeRules.At(9, 35), () =>{ ConsiderTrade(); }); } public override void OnData(Slice data){ if (IsWarmingUp) {return;} lastSlice = data; } public override void OnEndOfDay(){ if (lastSlice == null) {return;} Debug(String.Format("{0} closed at {1}", _symbol, lastSlice.Bars[_symbol].Close.ToString("#.####"))); } private void ConsiderTrade(){ Debug("Considering trade"); if (orderedOnce || lastSlice == null || lastSlice.Bars == null || !lastSlice.Bars.ContainsKey(_symbol)) {return;} OrderCallOption(lastSlice); } public void OrderCallOption(Slice slice){ Debug("Ordering Call Option"); OptionChain chain; //Output the entire chain to the chain variable //Then use the from to filter only the option that we want //The current filter is finding the first call strike under market price expiring today if (slice.OptionChains.TryGetValue(_optionSymbol, out chain)){ var contracts = ( from optionContract in chain.OrderByDescending(x => x.Strike) where optionContract.Strike > chain.Underlying.Price select optionContract ).Take(200); //Loop through the entire chain and display it //Later on enhance this to pick the correct option based off margin and other factors OptionContract contract = null; foreach (OptionContract _contract in contracts){ Decimal pctOtm = ((_contract.Strike - _contract.UnderlyingLastPrice) / _contract.UnderlyingLastPrice)*100; Debug(String.Format("Chain=>Option Contract. Strike {0}, ULPrice={1}, Bid={2}, Ask={3}, Expiry={4} {5}, {6}%", _contract.Strike, _contract.UnderlyingLastPrice, _contract.BidPrice, _contract.AskPrice, _contract.Expiry, _contract.Expiry.DayOfWeek.ToString(), pctOtm.ToString("#.####") )); if (contract == null) { contract = _contract; } } if ((contract != null) && !orderedOnce){ //orderedOnce = true; int numContracts = -1; string message = String.Format("Order Option Contract. Strike {0} x {1}, ULPrice={2}, Bid={3}, Ask={4}, Expiry={5} {6}",numContracts,contract.Strike,contract.UnderlyingLastPrice,contract.BidPrice,contract.AskPrice,contract.Expiry,contract.Expiry.DayOfWeek.ToString()); Debug(message); MarketOrder(contract.Symbol, numContracts); } else Debug("No Option Contract Found"); } else Debug("No Option Contract Found [TryGetValue]"); } public override void OnOrderEvent(OrderEvent fill) { string message = String.Format("Order {0} {1} x {2} at {3} commission={4} OrderId={5}", fill.Status.ToString(), fill.FillQuantity, fill.Symbol, fill.FillPrice, fill.OrderFee, fill.OrderId); Debug(message); } } }
using System; using QuantConnect.Orders; using QuantConnect.Securities.Option; namespace QuantConnect.Securities { /// <summary> /// Represents a simple option margining model. /// </summary> /// <remarks> /// Options are not traded on margin. Margin requirements exist though for those portfolios with short positions. /// Current implementation covers only single long/naked short option positions. /// </remarks> public class IBOptionMarginModel : ISecurityMarginModel { // initial margin private decimal _optionMarginRequirement = 1; private decimal _nakedPositionMarginRequirement = 0.1m; private decimal _nakedPositionMarginRequirementOTM = 0.2m; /// <summary> /// Initializes a new instance of the <see cref="IBOptionMarginModel"/> /// </summary> public IBOptionMarginModel() { } /// <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 virtual decimal GetLeverage(Security security) { // Options are not traded on margin return 1; } /// <summary> /// Sets the leverage for the applicable securities, i.e, options. /// </summary> /// <param name="security"></param> /// <param name="leverage">The new leverage</param> public virtual void SetLeverage(Security security, decimal leverage) { // Options are leveraged products and different leverage cannot be set by user. throw new InvalidOperationException("Options are leveraged products and different leverage cannot be set by user"); } /// <summary> /// Gets the total margin required to execute the specified order in units of the account currency including fees /// </summary> /// <param name="security">The security to compute initial margin for</param> /// <param name="order">The order to be executed</param> /// <returns>The total margin in terms of the currency quoted in the order</returns> public virtual decimal GetInitialMarginRequiredForOrder(Security security, Order order) { //Get the order value from the non-abstract order classes (MarketOrder, LimitOrder, StopMarketOrder) //Market order is approximated from the current security price and set in the MarketOrder Method in QCAlgorithm. var orderFees = security.FeeModel.GetOrderFee(security, order); var value = order.GetValue(security); var orderValue = value * GetInitialMarginRequirement(security, value); return orderValue + Math.Sign(orderValue) * orderFees; } /// <summary> /// Gets the margin currently alloted to the specified holding /// </summary> /// <param name="security">The security to compute maintenance margin for</param> /// <returns>The maintenance margin required for the </returns> public virtual decimal GetMaintenanceMargin(Security security) { return security.Holdings.AbsoluteHoldingsCost*GetMaintenanceMarginRequirement(security, security.Holdings.HoldingsCost); } /// <summary> /// Gets the margin cash available for a trade /// </summary> /// <param name="portfolio">The algorithm's portfolio</param> /// <param name="security">The security to be traded</param> /// <param name="direction">The direction of the trade</param> /// <returns>The margin available for the trade</returns> public virtual decimal GetMarginRemaining(SecurityPortfolioManager portfolio, Security security, OrderDirection direction) { var holdings = security.Holdings; if (direction == OrderDirection.Hold) { return portfolio.MarginRemaining; } //If the order is in the same direction as holdings, our remaining cash is our cash //In the opposite direction, our remaining cash is 2 x current value of assets + our cash if (holdings.IsLong) { switch (direction) { case OrderDirection.Buy: return portfolio.MarginRemaining; case OrderDirection.Sell: return // portion of margin to close the existing position GetMaintenanceMargin(security) + // portion of margin to open the new position security.Holdings.AbsoluteHoldingsValue * GetInitialMarginRequirement(security, security.Holdings.HoldingsValue) + portfolio.MarginRemaining; } } else if (holdings.IsShort) { switch (direction) { case OrderDirection.Buy: return // portion of margin to close the existing position GetMaintenanceMargin(security) + // portion of margin to open the new position security.Holdings.AbsoluteHoldingsValue * GetInitialMarginRequirement(security, security.Holdings.HoldingsValue) + portfolio.MarginRemaining; case OrderDirection.Sell: return portfolio.MarginRemaining; } } //No holdings, return cash return portfolio.MarginRemaining; } /// <summary> /// The percentage of an order's absolute cost that must be held in free cash in order to place the order /// </summary> public decimal GetInitialMarginRequirement(Security security) { return GetInitialMarginRequirement(security, security.Holdings.HoldingsValue); } /// <summary> /// The percentage of the holding's absolute cost that must be held in free cash in order to avoid a margin call /// </summary> public decimal GetMaintenanceMarginRequirement(Security security) { return GetMaintenanceMarginRequirement(security, security.Holdings.HoldingsValue); } /// <summary> /// The percentage of an order's absolute cost that must be held in free cash in order to place the order /// </summary> protected decimal GetInitialMarginRequirement(Security security, decimal holding) { return GetMarginRequirement(security, holding); } /// <summary> /// The percentage of the holding's absolute cost that must be held in free cash in order to avoid a margin call /// </summary> protected decimal GetMaintenanceMarginRequirement(Security security, decimal holding) { return GetMarginRequirement(security, holding); } /// <summary> /// Private method takes option security and its holding and returns required margin. Method considers all short positions naked. /// </summary> /// <param name="security">Option security</param> /// <param name="value">Holding value</param> /// <returns></returns> private decimal GetMarginRequirement(Security security, decimal value) { var option = (Option.Option)security; if (option.Close == 0m || option.StrikePrice == 0m || option.Underlying == null || option.Underlying.Close == 0m) { return 0m; } if (value > 0m) { return _optionMarginRequirement; } else { var absValue = -value; var optionProperties = (OptionSymbolProperties)option.SymbolProperties; var underlying = option.Underlying; // inferring ratios of the option and its underlying to get underlying security value var multiplierRatio = underlying.SymbolProperties.ContractMultiplier / optionProperties.ContractMultiplier; var quantityRatio = optionProperties.ContractUnitOfTrade; var priceRatio = underlying.Close / option.Close; var underlyingValueRatio = multiplierRatio * quantityRatio * priceRatio; // calculating underlying security value less out-of-the-money amount var amountOTM = option.Right == OptionRight.Call ? Math.Max(0, option.StrikePrice - underlying.Close): Math.Max(0, underlying.Close - option.StrikePrice); var priceRatioOTM = amountOTM / option.Close; var underlyingValueRatioOTM = multiplierRatio * quantityRatio * priceRatioOTM; return _optionMarginRequirement + Math.Max(_nakedPositionMarginRequirement * underlyingValueRatio, _nakedPositionMarginRequirementOTM * underlyingValueRatio - underlyingValueRatioOTM); } } } }