Tasty Condor – a bot that collects monthly premium trading Iron Condor spreads on SPY

April 11, 2017 | Jack Slocum

Earlier this week we introduced a new build of the Alta5 platform with additional support for option strategies, including Iron Condor spreads. Iron Condor is a popular delta neutral strategy used by professional money managers and individual investors to collect monthly premium and slowly profit from Theta (time decay). In this article, I will walk you through my process to build a bot that trades an Iron Condor on SPDR S&P 500 ETF (SPY) every month automatically.

Tasty Condor

There are many different variations to the Iron Condor strategy. The bot I created trades my personal favorite, a dynamic variation discussed by the wizard Tom Sosnoff of tastyTrade in this video. I call it… Tasty Condor.

  • The short and long legs are selected based on Delta, not strike price. The video suggests .3 for the short options and .05 for the long options.
  • Winners are closed at 50% of max profit.
  • Losers are closed at -2x max profit.
  • Select options from the standard monthly series expiring on the 3rd Friday of each month with at least 30 days to expiration.
  • SPY over SPX for increased liquidity.

Challenges

“Managing” winners and losers according to the recommendations in the video requires me to constantly be at my desk to monitor the market, create complex orders with multiple legs quickly (error prone) and manually repeat a cancel/replace order process until orders fill somewhere in the middle of the bid/ask spread. With multiple strategies running simultaneously and the market moving against me, the manual effort required can quickly become overwhelming. In the moment, that can lead to me taking shortcuts (e.g. taking the market price) or making mistakes (e.g. selecting buy to open instead of sell to open).

Alta5 was created to solve those problems. It allows me to run as many strategies as I want without being glued to the monitor, more efficiently than ever.

New Strategy

Once logged into Alta5, I selected Build in the top menu and then clicked New Strategy. Next, I filled in some basic info about the strategy and clicked Save.

 

new-strategy

Watchlist

Next I added a watchlist variable for SPY named $spy. A bot’s watchlist is similar to a watchlist in your favorite trading program except instead of displaying data about stocks in rows and columns for your eyes to scan, each stock is defined as a variable with the data as properties your bot can scan (e.g. $spy.bid or $spy.volume).

Inputs

In the video, Sosnoff discusses the advantages and risks of using various Delta values to select the legs. This is an excellent use case for a strategy Input. An Input allows you to set the value for a variable later, for each individual bot that uses the strategy. I want the Delta for both the short and long legs to be configurable, so I added two number inputs: $shortDelta and $longDelta. To add a number input, click the + button on the Inputs list and then select Number.

When starting a Tasty Condor bot, I’m now presented with a step for me to provide the value for the variables for that bot:

inputs

Events

When I trade this strategy manually, I select SPY in my watchlist in thinkorswim, find the first standard monthly series with at least 30 days to expiration, and then visually scan the rows for the correct options:

In Alta5, my bot mimics the same behavior using simple scripts that execute when events are triggered.

wake
The wake event is triggered first every morning when the market opens and is generally used to load any data your bot will scan. A bot will not start scanning for the day until the wake event has completed and all requested data is loaded.

For this strategy, I need to query for calls and puts from the first standard option series with at least 30 days until expiration. Similar to watchlist variables, all options returned by $data have properties that map to real-time market values that we can scan for the desired Delta value.

Here’s the query for the calls:

var price = $spy.last;

var cquery = {
    id: 'calls',
    type: 'call',
    symbol: 'SPY',
    days: 30,
    monthlyOnly: true,
    strike: [price, price + (price * .1)]
};

$spy is the watchlist variable added earlier. The query is a standard $data.option query object. Here’s a breakdown of the query options:

  • id  - Define a new bot variable named $calls with the results of the query.
  • type - The type of option, call or put.
  • symbol – The symbol of the option chain.
  • days – The minimum days to expiration for the option series.
  • monthlyOnly – Only standard monthly option series that expire on the 3rd Friday of each month.
  • strike – Select calls with a strike price between the current price and 10% above.

Here’s the full code for the wake event:

/*
Loads calls and puts that are within 
normal trading range. (as arrays)
*/
var price = $spy.last;

var cquery = {
    id: 'calls',
    type: 'call',
    symbol: 'SPY',
    days: 30,
    monthlyOnly: true,
    strike: [price, price + (price * .1)]
};

var pquery = {
    id: 'puts',
    type: 'put',
    symbol: 'SPY',
    days: 30,
    monthlyOnly: true,
    strike: [price - (price * .15), price]
};

// executes both queries and calls $done when complete
$data.option(cquery).option(pquery).then($done);

At the end of the code above, I execute both queries using $data’s multi query support and $done will be called by then() when the results are loaded. The $done callback informs the bot that my script is “done” and it can start scanning.

scan
The scan event is triggered multiple times per second when the market is open, all data from the wake event is loaded and the bot has not hit the set opportunity limit.

To set the opportunity limit, I clicked on the More Options button in the header, then Settings and then I selected  “Allow 2 open opportunities” to allow a bot to open 2 opportunities at once (the default is 1).

In the scan code below, I first loop through the options loaded in the wake event ($calls and $puts) to search for the strike prices with Deltas nearest to $longDelta and $shortDelta. Then I call $bot.open twice with the necessary settings to open a bull put and bear call spread:

var shortPut, longPut,
    shortCall, longCall,
    put, call, i;

// loop from high strike to low
for(i = $puts.length-1; put = $puts[i]; i--){
    if(!shortPut && put.delta >= -$shortDelta){
        shortPut = put.strike;
    } else if(!longPut && put.delta >= -$longDelta){
        longPut = put.strike;
        break; // stop for loop
    }
}

// loop from low strike to high
for(i = 0; call = $calls[i]; i++){
    if(!shortCall && call.delta <= $shortDelta){
        shortCall = call.strike;
    } else if(!longCall && call.delta <= $longDelta){
        longCall = call.strike;
        break; // stop for loop
    }
}

var exp = $puts[0].expiration;

$bot.open({
    type: 'bullput',
    symbol: 'SPY',
    expiration: exp,
    legs: [shortPut, longPut]
});

$bot.open({
    type: 'bearcall',
    symbol: 'SPY',
    expiration: exp,
    legs: [shortCall, longCall]
});

monitor
The monitor event is triggered multiple times per second when the market is open, the wake event has completed and the bot has an open opportunity. It is generally used to check if any open opportunities should be closed.

Since a bot will be managing 2 opportunities at once, I use $bot.opps collection to get the sum of the collected premium and the total P/L. As per the video, it takes profit at 50% of total premium and closes losers at 2x total premium. If neither of those happen, it closes the opportunities 15 minutes before the market closes on the final trading day before expiration.

var opps = $bot.opps,
    premium = opps.sum('premium'),
    pnl = opps.sum('pnl');

// % of premium that can be taken as profit    
var gain = pnl ? pnl / premium : 0;

var closing = false;

if(gain >= .5){
    closing = '50% overall profit';
}else if(pnl <= -(premium * 2)){
    closing = '2x premium stop loss';
}else if($a5.isClosing(15) && opps[0].isLastTradingDay){
    closing = 'Close before expiration';
}

if(closing){
    for(var i = 0; i < opps.length; i++){
        opps[i].close(closing);
    }
}

That’s it!

The rest of the order execution process, including pricing and quantity, is handled by the Alta5 automation layer based on my settings.  Smart Pricing uses timed limit orders to get my order filled at the best price between the bid/ask spread and Alta5′s risk management layer will figure out the maximum quantity the bot can open based on capital draw limits.

What’s Next?

The Tasty Condor strategy is available for you to use and/or customize under Build -> Sample Strategies in Alta5. To install an editable copy, click Install strategy.

tasty-condor

I picked Iron Condor as the first tastyTrade strategy to turn into a bot because I know it well and I have had a lot of success with it. What strategies do you use? If you would like to see a sample created for another tastyTrade strategy, leave a comment with a link to the strategy/video and we’ll create a sample for you.

 

Comments

Join the Discussion