Overall Statistics
Total Trades
27
Average Win
0.04%
Average Loss
-0.02%
Compounding Annual Return
-10.497%
Drawdown
22.300%
Expectancy
0.222
Net Profit
-3.686%
Sharpe Ratio
0.043
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.65
Alpha
0.179
Beta
-8.46
Annual Standard Deviation
0.503
Annual Variance
0.253
Information Ratio
0.006
Tracking Error
0.503
Treynor Ratio
-0.003
Total Fees
$4.25
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;

// Short Condor - the same as Short Strangle but with limited loss
// sell 1 ATM Call and 1 ATM Put with the same expiration date 
// and on the same distance from the underlying price
// then buy 1 OTM Call and 1 OTM Put to protect ourselves if market goes against us

namespace QuantConnect 
{
    public partial class ShortCondor : QCAlgorithm 
    {
		string iSymbol = "MSFT";

		DateTime iTime;

        public override void Initialize()
        {
        	SetCash(10000);
            SetStartDate(2018, 1, 1);
            SetEndDate(DateTime.Now.Date); 
            SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage);
			AddEquity(iSymbol, Resolution.Minute);
       }
        
        public void OnData(TradeBars data) 
        {
        	if (IsMarketOpen(iSymbol) == false)
        	{
        		return;
        	}
        	
        	if (IsNewBar(TimeSpan.FromHours(1)) == false)
        	{
        		return;
        	}
        	
        	var price = Securities[iSymbol].Price;
        	
			// If options were exercised and we were assigned to buy shares, sell them immediately

			if (Portfolio[iSymbol].Invested)
			{
				MarketOrder(iSymbol, -100);
			}
			
			if (Portfolio.Invested == false)
			{
				var contracts = OptionChainProvider.GetOptionContractList(iSymbol, Time);
				
				// Choose all contracts within a month and strike price $1 to $5 from current underlying price
				
				var atmCalls = 
					from c in contracts
                    where c.ID.OptionRight == OptionRight.Call
                    where c.ID.StrikePrice - price < 3 && c.ID.StrikePrice - price > 1
                    where (c.ID.Date - Time).TotalDays < 35 && (c.ID.Date - Time).TotalDays > 0
                    select c;
				
				var atmPuts = 
					from c in contracts
                    where c.ID.OptionRight == OptionRight.Put
                    where price - c.ID.StrikePrice < 3 && price - c.ID.StrikePrice > 1
                    where (c.ID.Date - Time).TotalDays < 35 && (c.ID.Date - Time).TotalDays > 0
                    select c;

				// Choose all contracts within a month and strike price $1 to $5 from current underlying price
				
				var otmCalls = 
					from c in contracts
                    where c.ID.OptionRight == OptionRight.Call
                    where c.ID.StrikePrice - price < 7 && c.ID.StrikePrice - price > 5
                    where (c.ID.Date - Time).TotalDays < 35 && (c.ID.Date - Time).TotalDays > 0
                    select c;
				
				var otmPuts = 
					from c in contracts
                    where c.ID.OptionRight == OptionRight.Put
                    where price - c.ID.StrikePrice < 7 && price - c.ID.StrikePrice > 5
                    where (c.ID.Date - Time).TotalDays < 35 && (c.ID.Date - Time).TotalDays > 0
                    select c;

				// Take ATM options with the MIN expiration date and MAX distance from underlying price

                var contractAtmCall = atmCalls
                	.OrderBy(o => o.ID.Date)
                	.ThenByDescending(o => o.ID.StrikePrice - price)
					.FirstOrDefault();

				var contractAtmPut = atmPuts
                	.OrderBy(o => o.ID.Date)
                	.ThenByDescending(o => price - o.ID.StrikePrice)
					.FirstOrDefault();
					
				// Take OTM options with the MIN expiration date and MAX distance from underlying price

                var contractOtmCall = otmCalls
                	.OrderBy(o => o.ID.Date)
                	.ThenByDescending(o => o.ID.StrikePrice - price)
					.FirstOrDefault();

				var contractOtmPut = otmPuts
                	.OrderBy(o => o.ID.Date)
                	.ThenByDescending(o => price - o.ID.StrikePrice)
					.FirstOrDefault();

				// If we found such options - open trade

				if (contractAtmCall != null && 
					contractAtmPut != null && 
					contractOtmCall != null && 
					contractOtmPut != null)
				{
	                AddOptionContract(contractAtmCall, Resolution.Minute);
	                AddOptionContract(contractAtmPut, Resolution.Minute);
	                AddOptionContract(contractOtmCall, Resolution.Minute);
	                AddOptionContract(contractOtmPut, Resolution.Minute);
	                MarketOrder(contractAtmCall, -1);
	                MarketOrder(contractAtmPut, -1);
	                MarketOrder(contractOtmCall, 1);
	                MarketOrder(contractOtmPut, 1);
				}
			}
        }

		public bool IsNewBar(TimeSpan interval, int points = 1)
		{
			var date = Securities[iSymbol].LocalTime;

			if ((date - iTime).TotalSeconds > interval.TotalSeconds * points)
			{
				iTime = new DateTime(date.Ticks - date.Ticks % interval.Ticks, date.Kind);
				return true;
			}

			return false;
		}
    }
}