| Overall Statistics |
|
Total Trades 2 Average Win 0% Average Loss 0% Compounding Annual Return 19.447% Drawdown 1.000% Expectancy 0 Net Profit 0% Sharpe Ratio 3.338 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.233 Beta 0.655 Annual Standard Deviation 0.029 Annual Variance 0.001 Information Ratio 13.522 Tracking Error 0.022 Treynor Ratio 0.15 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, 8);
SetEndDate(2014,3, 12);
//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(10490);
var equity = AddEquity(_symbol, Resolution.Minute);
_equitySymbol = equity.Symbol;
Securities[_symbol].SetDataNormalizationMode(DataNormalizationMode.TotalReturn);
SetSecurityInitializer(new OptionInitializer());
var option = AddOption(_symbol);
_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 5 and 20%
(symbol.ID.StrikePrice - universe.Underlying.Price) / universe.Underlying.Price <= 0.20m &&
(symbol.ID.StrikePrice - universe.Underlying.Price) / universe.Underlying.Price >= 0.05m
//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;
//Initializes Logging
/// <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;
Console.WriteLine("multiplierRatio : " + multiplierRatio.ToString("0.00"));
var quantityRatio = optionProperties.ContractUnitOfTrade;
Console.WriteLine("quantityRatio : " + quantityRatio.ToString("0.00"));
Console.WriteLine("underlying.Close: " + underlying.Close.ToString() + " | option.Close: " + option.Close.ToString());
var underlyingValueRatio = multiplierRatio * quantityRatio * underlying.Close;
Console.WriteLine("underlyingValueRatio: " + underlyingValueRatio.ToString("0.00"));
// 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);
Console.WriteLine("option.StrikePrice: " + option.StrikePrice.ToString() + " | underlying.Close: " + underlying.Close.ToString() + " | amountOTM: " + amountOTM.ToString("0.00"));
var underlyingValueRatioOTM = multiplierRatio * quantityRatio * amountOTM;
Console.WriteLine("underlyingValueRatioOTM: " + underlyingValueRatioOTM.ToString("0.00"));
var marginReq = option.Close + Math.Max(_nakedPositionMarginRequirement * underlyingValueRatio,
_nakedPositionMarginRequirementOTM * underlyingValueRatio - underlyingValueRatioOTM);
Console.WriteLine("GetMarginRequirement: " + marginReq.ToString("0.00"));
return marginReq;
}
}
}
}using System;
using QuantConnect.Orders;
using QuantConnect.Securities.Option;
namespace Quantconnect
{
public class OptionInitializer : ISecurityInitializer
{
public void Initialize(Security security, bool seedSecurity)
{
if (security is Option){
security.MarginModel = new IBOptionMarginModel();
}
}
}
}