Next-Day SPY Iron Condors with a Price-Based Early Exit
Summary
This Python strategy sells a short-dated SPY iron condor near the end of each trading day, targeting expiration on the next trading day. It skips a new position when the prior day's VIX close exceeded 25. Otherwise, an AI trading agent selects short put and call options near 0.14 delta and buys options one dollar farther out to cap losses, sizing the trade so the maximum loss is about 3% of the account. The strategy also directs the agent to sell any SPY shares received through exercise.
A separate five-minute check monitors the underlying price relative to the midpoint and half-width of the short strikes. Once the price has moved at least 40% of that half-width toward either short strike, the agent is asked to close the condor. The code includes hooks for backtesting and live operation, but provides no performance results. It does not detail fill assumptions, transaction costs, assignment handling beyond selling shares, or how the options agent verifies available contracts and order execution.
Key ideas
- The strategy opens next-day SPY iron condors near the close, subject to a prior-day VIX filter.
- It uses short options near 0.14 delta and protective options one dollar farther out.
- Position sizing aims to cap maximum loss at about 3% of account value.
- A five-minute price check requests an early exit after a defined move toward either short strike.
- The code provides no performance evidence or detailed treatment of execution costs.
Tags
Full text
# ai_iron_condor.py
```py
"""AI Iron Condor.
Every afternoon at 3:45 PM the AI sells a SPY iron condor that expires the next
trading day and lets it expire. Between those runs, plain Python checks SPY every
5 minutes for free and wakes the AI only when SPY runs too close to one of the
short strikes, so the AI can close the condor early.
"""
from lumibot.strategies import Strategy
class AIIronCondorStrategy(Strategy):
parameters = {"symbol": "SPY", "stop_at": 0.4}
def initialize(self):
self.sleeptime = "5M" # how often plain Python checks the stop (no AI call)
self.minutes_before_closing = 15 # before_market_closes runs at 3:45 PM
self.agents.create(
name="trader",
allow_trading=True,
system_prompt=(
"You trade SPY iron condors that expire the next trading day. When it is time to open one, "
"first check the VIX: if it closed above 25 yesterday, do not trade today. Otherwise sell an "
"iron condor on SPY that expires the next trading day: sell a put and a call near 0.14 delta, "
"and buy a put and a call one dollar farther out to cap the loss. Size it so the most we can "
"lose is about 3% of the account. Then hold it until it expires. If we ever hold SPY shares "
"because an option was exercised, sell them."
),
)
def before_market_closes(self):
self.agents["trader"].run(task_prompt="It is 3:45 PM. Open today's iron condor.")
def on_trading_iteration(self):
# The stop, in plain Python: how far SPY has moved from the middle of the condor toward a short strike.
shorts = [p.asset.strike for p in self.get_positions() if p.asset.asset_type == "option" and p.quantity < 0]
if len(shorts) != 2 or any(order.is_active() for order in self.get_orders()):
return
middle, half_width = (max(shorts) + min(shorts)) / 2, (max(shorts) - min(shorts)) / 2
price = self.get_last_price(self.parameters["symbol"])
if price and abs(price - middle) >= self.parameters["stop_at"] * half_width:
self.agents["trader"].run(
task_prompt=f"SPY is at {price}, close to one of our short strikes. Close the whole iron condor now."
)
if __name__ == "__main__":
from lumibot.credentials import IS_BACKTESTING
if IS_BACKTESTING:
from lumibot.backtesting import AlpacaBacktesting
AIIronCondorStrategy.backtest(AlpacaBacktesting)
else:
AIIronCondorStrategy().run_live()
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.