TL;DR
Build a iron condor in four steps: describe it to Aurora, check the saved rules, backtest it, follow a trade. Start from the worked example below: copy its rules, then change the ticker, dates or exits and test your version. On SPY in 2024 it returned -5.50% against 25.30% for SPY, and its maximum drawdown was 5.63%.
How to build a iron condor

1. Describe it to Aurora
Open the prepared request. Aurora receives the exact rules shown here and checks them without saving a portfolio. Review its preview before choosing whether to save or test your own version.
A preview of the rules and their validation result. Any invalid inputs are identified before you decide what to save.
2. Check the saved rules
Start with the actual rules used in this example. Days to expiration means the days remaining until the option expires. The complete editor inputs and SDK functions are available below.
- Entry
- Open when SPY’s 14-day relative strength index (RSI) is between 45 and 55, and no matching option position is open.
- Position sizing
- One strategy unit; leg ratios apply. Buying power, collateral and liquidity can restrict orders.
- Signal exit
- Close all matching option legs when RSI falls below 40 or rises above 60, or when 14 or fewer days remain until expiration.
- Starting capital
- $10,000.00
- Leg 1
- Buy 1 put contract per unit, targeting a strike 10% below SPY’s price. Choose the nearest available expiry 30 to 45 days away.
- Leg 2
- Sell 1 put contract per unit, targeting a strike 5% below SPY’s price. Choose the nearest available expiry 30 to 45 days away.
- Leg 3
- Sell 1 call contract per unit, targeting a strike 5% above SPY’s price. Choose the nearest available expiry 30 to 45 days away.
- Leg 4
- Buy 1 call contract per unit, targeting a strike 10% above SPY’s price. Choose the nearest available expiry 30 to 45 days away.
The entry decides when to open. The leg selectors choose contracts. The allocation sets size, and the exit decides when to close. Keep these parts together in your draft.
- Iron condor 2024-12-31, 21:00:00 UTC
- 9,449.69
- Full-capital SPY buy and hold 2024-12-31, 21:00:00 UTC
- 12,530.29
3. Backtest it
Compare the two recorded curves and the result below. SPY invests the full starting balance; this options candidate uses its saved allocation. Their fees and invested capital differ.
- Candidate vs full-capital SPY
- -5.50% vs 25.30%
The requested period was 2024-01-01 through 2024-12-31. The candidate’s largest reported decline was 5.63%, with $197.60 in recorded commissions. Quote coverage is not certified for strategy comparison; inspect the retained quote checks before comparing these strategies.
4. Follow one trade
Buying to open purchases an option; selling to open writes it. Closing reverses that position. Multiply each premium below by 100 shares per contract and its quantity, then subtract the recorded fees to follow the cash flow.
- Call · $655 strike
- Dec 27, 2024 14:31 UTC: buy to open 1 at $0.0680 per share; $0.65 fee. Dec 30, 2024 14:31 UTC: sell to close 1 at $0.0450 per share; $0.65 fee.
- Put · $538 strike
- Dec 27, 2024 14:31 UTC: buy to open 1 at $1.0363 per share; $0.65 fee. Dec 30, 2024 14:31 UTC: sell to close 1 at $1.5200 per share; $0.65 fee.
- Call · $625 strike
- Dec 27, 2024 14:31 UTC: sell to open 1 at $0.8547 per share; $0.65 fee. Dec 30, 2024 14:31 UTC: buy to close 1 at $0.3375 per share; $0.65 fee.
- Put · $568 strike
- Dec 27, 2024 14:31 UTC: sell to open 1 at $2.5779 per share; $0.65 fee. Dec 30, 2024 14:31 UTC: buy to close 1 at $4.3050 per share; $0.65 fee.
These Filled orders show one captured position from the run. Its recorded opening and closing cash flows sum to $-80.11 after commissions. Inspect every leg and ratio; the engine's closed-trade count can count option legs rather than whole spread round trips.
Four steps take a iron condor from an idea to a tested strategy. Each step uses the SPY worked example.
The rules that define it
Entry
45 <= RSI(SPY,14,Day) <= 55 AND zero matching option positions
Position sizing
One strategy unit; leg ratios apply. Buying power, collateral and liquidity can restrict orders.
Signal exit
RSI(SPY,14,Day) < 40 OR > 60; close whole matching spread at 14 or fewer DTE
Starting capital
$10000.00
Spread type
ironCondor
Execution
Market; $0.65 commission per option contract, default 0.5 half-spread fraction plus applicable liquidity impact.
Show the table · 6 rows, 2 columns
| Rule | Saved candidate |
|---|---|
| Entry | 45 <= RSI(SPY,14,Day) <= 55 AND zero matching option positions |
| Position sizing | One strategy unit; leg ratios apply. Buying power, collateral and liquidity can restrict orders. |
| Signal exit | RSI(SPY,14,Day) < 40 OR > 60; close whole matching spread at 14 or fewer DTE |
| Starting capital | $10000.00 |
| Spread type | ironCondor |
| Execution | Market; $0.65 commission per option contract, default 0.5 half-spread fraction plus applicable liquidity impact. |
No matching rows. Clear the filter to see all records.
Contract selectors and ratios
Inspect contract selectors and ratios
Strike distances are percentages of the underlying price, not fixed market strikes or delta targets. Positive distance means out of the money: a higher strike for calls and a lower strike for puts. Negative distance means in the money; zero targets at the money (ATM). Days to expiration (DTE) measures the time remaining until a contract expires. Nearest expiration must lie within each leg's DTE range. Inspect the resolved contracts rather than assuming the authored offsets produce exact strike widths.
All option legs use the same requested expiry window. Verify actual shared expiration and the resulting quantities in the contract-resolution and fill records.
Scroll sideways to compare all columns. Select a heading to sort.
| 1 | long | put | 10% | 1 | 30 to 45 DTE |
| 2 | short | put | 5% | 1 | 30 to 45 DTE |
| 3 | short | call | 5% | 1 | 30 to 45 DTE |
| 4 | long | call | 10% | 1 | 30 to 45 DTE |
No matching rows. Clear the filter to see all records.
Save it as a draft
Show how to save the draft
Ask Aurora to build the rules above, review the preview, then save the draft while keeping automated trading off. A chat draft is inspected in Portfolio > Drafts or Aurora; the native Strategies editor belongs to a paper or live portfolio.
In an inactive native portfolio, use Open Options Position, choose the matching structure preset and verify each leg above. Under Allocation, set Type Contracts and Amount 1. Add the entry conditions, including zero matching option positions. Add both Close Options Position rules separately, matching SPY and the spread type with close scope spread and quantity all. A preset adds contract legs; it does not supply the complete entry or exit algorithm.
Create and backtest with Python
Use the Python SDK instead of Aurora
Python SDK 1.42.0. Save the runner below as run_iron_condor.py.
Install and download
python3 -m pip install nexustrade==1.42.0
export NEXUSTRADE_API_KEY="YOUR_API_KEY"
curl --fail --output iron_condor.py https://nexustrade.io/seo/strategy-examples/iron-condor.py
Create, test and inspect
from iron_condor import create_iron_condor, backtest_iron_condor
book = create_iron_condor()
completed = backtest_iron_condor()
print(completed["result"])
Run
python3 run_iron_condor.py
Python strategy and backtest functions
View complete Python SDK functions
The backtest function submits the 2024 test with SPY as its benchmark, records events and waits for the result. Use a new request key when changing rules, dates or fees.
View complete example
import nexustrade as nt
def create_iron_condor():
asset = nt.stock_asset("SPY")
return nt.portfolio(
"Public SEO example - Iron condor",
[
nt.strategy(
"Open Iron condor",
(((nt.RSI(asset, 14, "Day") >= nt.Value(45)) & (nt.RSI(asset, 14, "Day") <= nt.Value(55))) & (nt.OptionPositionCount("SPY", "put", "long", "ironCondor") == nt.Value(0))),
nt.open_option(
builder=nt.options_builder(
legs=[
nt.leg(
option_type="put",
direction="long",
min_days_to_expiration=30,
max_days_to_expiration=45,
preference="nearest",
distance=10,
ratio=1
),
nt.leg(
option_type="put",
direction="short",
min_days_to_expiration=30,
max_days_to_expiration=45,
preference="nearest",
distance=5,
ratio=1
),
nt.leg(
option_type="call",
direction="short",
min_days_to_expiration=30,
max_days_to_expiration=45,
preference="nearest",
distance=5,
ratio=1
),
nt.leg(
option_type="call",
direction="long",
min_days_to_expiration=30,
max_days_to_expiration=45,
preference="nearest",
distance=10,
ratio=1
)
],
underlying_symbol="SPY",
spread_type="ironCondor"
),
allocation={'type': 'contracts', 'amount': 1}
)
),
nt.strategy(
"Close when signal invalidates",
((nt.RSI(asset, 14, "Day") < nt.Value(40)) | (nt.RSI(asset, 14, "Day") > nt.Value(60))),
nt.close_option(
underlyings=['SPY'],
spread_type="ironCondor",
close_scope="spread",
quantity={'type': 'all'}
)
),
nt.strategy(
"Close at 14 DTE",
(nt.Value(1) > nt.Value(0)),
nt.close_option(
underlyings=['SPY'],
spread_type="ironCondor",
close_scope="spread",
quantity={'type': 'all'},
triggers=[nt.dte_trigger(max_dte=14)]
)
),
],
initial_value=10000,
supports_fractional_shares=False,
alerts_enabled=False,
dividend_policy='cash',
)
def backtest_iron_condor(client=None):
client = client or nt.NexusTradeClient.from_environment()
operation = client.create_backtest(
nt.backtest(
create_iron_condor(),
start_date="2024-01-01", end_date="2024-12-31",
interval="Day", baseline_symbol="SPY",
initial_value=10000, generate_events=True,
dividend_policy="cash",
fee_config={"Stock": {"type": "percent", "amount": 0.1},
"Cryptocurrency": {"type": "percent", "amount": 0.7},
"Option": {"type": "dollars", "amount": 0.65}},
),
idempotency_key="explore-iron-condor-2024-spy-v1",
)
return client.wait_for_backtest(operation["id"])
# Build locally: book = create_iron_condor()
# Run and inspect: completed = backtest_iron_condor(); print(completed["result"])
Create and backtest with TypeScript
Use the TypeScript SDK instead of Aurora
TypeScript SDK 1.42.0. Save the runner below as run-iron-condor.ts.
Install and download
npm install nexustrade@1.42.0
npm install --save-dev tsx
export NEXUSTRADE_API_KEY="YOUR_API_KEY"
curl --fail --output iron-condor.ts https://nexustrade.io/seo/strategy-examples/iron-condor.ts
Create, test and inspect
import { createIronCondor, backtestIronCondor } from "./iron-condor";
async function main() {
const book = createIronCondor();
const completed = await backtestIronCondor();
console.log(completed.result);
}
main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
Run
npx tsx run-iron-condor.ts
TypeScript strategy and backtest functions
View complete TypeScript SDK functions
The same rules, dates and fees are used in both SDKs. The backtest function keeps its request key across retries.
import * as nt from "nexustrade";
export function createIronCondor() {
const asset = nt.stockAsset("SPY");
return nt.portfolio(
"Public SEO example - Iron condor",
[
nt.strategy(
"Open Iron condor",
nt.and(
nt.and(
nt.gte(nt.RSI(asset, 14, "Day"), nt.Value(45)),
nt.lte(nt.RSI(asset, 14, "Day"), nt.Value(55))
),
nt.eq(nt.OptionPositionCount("SPY", "put", "long", "ironCondor"), nt.Value(0))
),
nt.openOption({ builder: nt.optionsBuilder({ legs: [nt.leg({ optionType: "put", direction: "long", minDaysToExpiration: 30, maxDaysToExpiration: 45, preference: "nearest", distance: 10, ratio: 1 }), nt.leg({ optionType: "put", direction: "short", minDaysToExpiration: 30, maxDaysToExpiration: 45, preference: "nearest", distance: 5, ratio: 1 }), nt.leg({ optionType: "call", direction: "short", minDaysToExpiration: 30, maxDaysToExpiration: 45, preference: "nearest", distance: 5, ratio: 1 }), nt.leg({ optionType: "call", direction: "long", minDaysToExpiration: 30, maxDaysToExpiration: 45, preference: "nearest", distance: 10, ratio: 1 })], underlyingSymbol: "SPY", spreadType: "ironCondor" }), allocation: {"type": "contracts", "amount": 1} })
),
nt.strategy(
"Close when signal invalidates",
nt.or(nt.lt(nt.RSI(asset, 14, "Day"), nt.Value(40)), nt.gt(nt.RSI(asset, 14, "Day"), nt.Value(60))),
nt.closeOption({ underlyings: ["SPY"], spreadType: "ironCondor", closeScope: "spread", quantity: {"type": "all"} })
),
nt.strategy(
"Close at 14 DTE",
nt.gt(nt.Value(1), nt.Value(0)),
nt.closeOption({ underlyings: ["SPY"], spreadType: "ironCondor", closeScope: "spread", quantity: {"type": "all"}, triggers: [nt.dteTrigger({ maxDte: 14 })] })
),
],
{ initialValue: 10000, supportsFractionalShares: false, alertsEnabled: false, dividendPolicy: "cash" }
);
}
export async function backtestIronCondor(client = new nt.NexusTradeClient()) {
const operation = await client.createBacktest(
nt.backtest(createIronCondor(), {
startDate: "2024-01-01", endDate: "2024-12-31",
interval: "Day", baselineSymbol: "SPY",
initialValue: 10000, generateEvents: true,
dividendPolicy: "cash",
feeConfig: {
Stock: { type: "percent", amount: 0.1 },
Cryptocurrency: { type: "percent", amount: 0.7 },
Option: { type: "dollars", amount: 0.65 },
},
}),
{ idempotencyKey: "explore-iron-condor-2024-spy-v1" }
);
if (typeof operation.id !== "string") throw new Error("Missing backtest ID");
return client.waitForBacktest(operation.id);
}
// Build locally: const book = createIronCondor();
// Run and inspect: const completed = await backtestIronCondor(); console.log(completed.result);
Start from this example
The worked example below is a starting point for you to copy. Open its exact rules in Aurora, then change the ticker, dates, legs or exits and backtest your own version.
Worked example to copy: SPY, 2024
- Iron condor 2024-12-31, 21:00:00 UTC
- 9,449.69
- Full-capital SPY buy and hold 2024-12-31, 21:00:00 UTC
- 12,530.29
- Return
- -5.50%
- SPY buy and hold
- 25.30%
- Max drawdown
- 5.63%
- Closed option legs
- 152
- Commissions
- $197.60
Show the table · 16 rows, 2 columns
Scroll sideways to compare all columns. Select a heading to sort.
| Status | COMPLETE |
| Requested period | 2024-01-01 through 2024-12-31 |
| Starting capital | $10000.00 |
| Modeled return | -5.50% |
| Reported maximum drawdown | 5.63% |
| Full-capital SPY comparator return | 25.30% |
| Recorded commissions | $197.60 |
| Engine closed-trade count | 152 |
| Peak reserved collateral | $3338.00 |
| Median reserved collateral while holding positions | $2752.00 |
| Pricing contract version | 8 |
| Observed / synthetic half-spread calls | 393 / 224 |
| Unknown-timing quote accesses | 17841 |
| Missing-current-quote checks | 0 |
| Rejected fill groups / marks | 0 / 0 |
| Stale basket / single-option marks | 7 / 0 |
No matching rows. Clear the filter to see all records.
How the example did on SPY, 2024-01-01 to 2024-12-31, starting with $10,000.
One trade from the example
One position from the worked example, opened Dec 27, 2024 and closed Dec 30, 2024.
- Long $655 call
- −$2.30
- Long $538 put
- +$48.37
- Short $625 call
- +$51.72
- Short $568 put
- −$172.71
- Commissions
- −$5.20
- Net
- −$80.11
Explain this options decision with Aurora
Ask Aurora to connect the recorded signal, contract choice, allocation and fills. It receives this page's captured decision and order fields, so you can follow its explanation back to each value.
Inspect the worked example's records
The example trade's fills
2024-12-27 14:31:00
ContractSPY250131C00655000
ActionBuy to open
Contracts1
Premium per share$0.0680
Fee$0.65
2024-12-27 14:31:00
ContractSPY250131P00538000
ActionBuy to open
Contracts1
Premium per share$1.0363
Fee$0.65
2024-12-27 14:31:00
ContractSPY250131C00625000
ActionSell to open
Contracts1
Premium per share$0.8547
Fee$0.65
2024-12-27 14:31:00
ContractSPY250131P00568000
ActionSell to open
Contracts1
Premium per share$2.5779
Fee$0.65
2024-12-30 14:31:00
ContractSPY250131C00625000
ActionBuy to close
Contracts1
Premium per share$0.3375
Fee$0.65
2024-12-30 14:31:00
ContractSPY250131P00568000
ActionBuy to close
Contracts1
Premium per share$4.3050
Fee$0.65
2024-12-30 14:31:00
ContractSPY250131C00655000
ActionSell to close
Contracts1
Premium per share$0.0450
Fee$0.65
2024-12-30 14:31:00
ContractSPY250131P00538000
ActionSell to close
Contracts1
Premium per share$1.5200
Fee$0.65
Recorded rows in source order; spacing does not represent elapsed time.
Show the table · 8 rows, 6 columns
Scroll sideways to compare all columns. Select a heading to sort.
| 2024-12-27 14:31:00 | SPY250131C00655000 | Buy to open | 1 | $0.0680 | $0.65 |
| 2024-12-27 14:31:00 | SPY250131P00538000 | Buy to open | 1 | $1.0363 | $0.65 |
| 2024-12-27 14:31:00 | SPY250131C00625000 | Sell to open | 1 | $0.8547 | $0.65 |
| 2024-12-27 14:31:00 | SPY250131P00568000 | Sell to open | 1 | $2.5779 | $0.65 |
| 2024-12-30 14:31:00 | SPY250131C00625000 | Buy to close | 1 | $0.3375 | $0.65 |
| 2024-12-30 14:31:00 | SPY250131P00568000 | Buy to close | 1 | $4.3050 | $0.65 |
| 2024-12-30 14:31:00 | SPY250131C00655000 | Sell to close | 1 | $0.0450 | $0.65 |
| 2024-12-30 14:31:00 | SPY250131P00538000 | Sell to close | 1 | $1.5200 | $0.65 |
No matching rows. Clear the filter to see all records.
Each premium is per share; one contract is 100 shares.
Inspect a contract-resolution audit
Inspect a contract-resolution audit
This is the latest retained resolution attempt, which can belong to a different position than the matched trade above. Its outcome, capital and risk codes explain what the resolver accepted or rejected at that decision. Follow the resulting Order events to see its fill status.
{
"time": "2024-12-27T14:31:00.000Z",
"status": "success",
"reason": null,
"riskAudit": {
"rulesetVersion": 1,
"outcome": "allowed",
"longSharesAvailable": 0,
"unhedgedShortCallContractsPerSpread": 0,
"buyingPowerEffective": 9529.797432210462,
"allocationRequested": 1,
"allocation": {
"type": "contracts",
"amount": 1
},
"portfolioValue": 9529.797432210462,
"underlyingPrice": 597.5399780273438,
"maxLossPerUnit": 2769,
"finalContractQuantity": 1,
"collateralReserved": 2769,
"committedCostBefore": 0
}
}Inspect the largest decline in the exported history
Inspect the largest decline in the exported history
Scroll sideways to compare all columns. Select a heading to sort.
| 2024-01-16T21:00:00.000Z | $10132.07 | $-119.00 | $2177.00 |
| 2024-12-30T21:00:00.000Z | $9449.69 | $0.00 | $0.00 |
No matching rows. Clear the filter to see all records.
The exported grid's largest peak-to-trough decline was 5.63%, from $10013.07 at 2024-01-16T21:00:00.000Z to $9449.69 at 2024-12-30T21:00:00.000Z. The engine reported maximum drawdown of 5.63%. Compare the history snapshots with the reported statistic and inspect the events around this period.
Plan a separate variant and later test
Review the optional next experiment
After reviewing the recorded example, use the prepared request above for the original rules. This optional plan covers a separate variant and a later test.
Create one variant, then test unseen dates
Ask: "Change only the timed close trigger from 14 DTE to 10 DTE. Show the rule diff and compare both candidates on the 2024 development period with every other setting fixed." After choosing, freeze the rules and select another test period you have not inspected. The displayed 2024 results already make 2024 a viewed development period. Keep any later revisions in a new research cycle.
Explore this strategy further
Inspect explore this strategy further
Inspect matched quantities, actual strike widths, expirations and all close orders. For sold options, review collateral and exercise or assignment exposure separately from premium income. A condition firing can emit zero close orders; look at its evaluation and the Filled-order records.
Try another date range or change one rule, then compare the new backtest with this saved 2024 result. Inspect which trades and periods explain the difference.
No comments yet.