Two-Agent SPX 0 DTE Bear Call ExperimentΒΆ

ai_spx_zero_dte_bear_call_team.py tests a strict two-agent architecture:

  • The researcher has allow_trading=False and gathers current SPX, account, chain, contract, Greek, quote, and package-price evidence.

  • The trader has allow_trading=True. It independently refreshes the evidence, validates every active Rule, decides whether to trade, submits any spread through orders_submit_multileg, and verifies the order and resulting positions.

Python schedules the two calls and passes the research summary forward. It does not select contracts or submit orders. The active Rules require SPX 0 DTE calls, a short call near 0.20 delta, a long call exactly five points higher, one new package per trading day, and atomic entry and exit.

The active broker must support atomic packages. Otherwise LumiBot rejects the request before submitting any child leg.

export GEMINI_API_KEY="your-key"
export BACKTESTING_DATA_SOURCE="ThetaData"
export DATADOWNLOADER_BASE_URL="https://<your-downloader-host>:8080"
export DATADOWNLOADER_API_KEY="your-downloader-key"
python -m lumibot.example_strategies.ai_spx_zero_dte_bear_call_team

Use a paper broker and a short historical window before considering any live workflow. The example proves architecture and mechanics, not profitability.

  1"""Two-agent SPX 0 DTE bear-call-spread experiment.
  2
  3The researcher is read only. The trader independently validates the evidence,
  4places any order through LumiBot tools, and verifies the resulting broker state.
  5"""
  6
  7import os
  8from datetime import datetime, timedelta
  9from pathlib import Path
 10
 11from lumibot.strategies.strategy import Strategy
 12
 13
 14def build_research_prompt(params: dict) -> str:
 15    return f"""
 16Research the current SPX 0 DTE bear call spread opportunity without trading.
 17Load the options-trading skill and obey the active Rules file. Inspect account
 18state, positions, open orders, the current SPX market, today's listed option
 19expiration, exact contract Greeks, and executable bid/ask quality.
 20
 21Evaluate a short call near +{params['target_delta']:.2f} delta with a long call
 22exactly {params['wing_width']:.0f} points higher. Report exact contract
 23identities, timestamps, deltas, quotes, signed package pricing, maximum loss,
 24and reasons to trade or not trade. Do not claim that an order was submitted.
 25""".strip()
 26
 27
 28def build_trader_prompt(params: dict) -> str:
 29    return f"""
 30You are the final validation and trading agent for an SPX 0 DTE bear call
 31spread. Load the options-trading skill and obey every active Rule.
 32
 33Review the research, then independently refresh account state, positions, open
 34orders, exact contracts, Greeks, and quotes. Trade only a short call near
 35+{params['target_delta']:.2f} delta with a listed long call exactly
 36{params['wing_width']:.0f} points higher. Require a positive net credit below
 37the {params['wing_width']:.0f}-point width. Risk no more than
 38{params['max_risk_pct']:.2%} of portfolio value and no more than
 39{params['max_contracts']} package per trading day.
 40
 41If all conditions pass, call orders_submit_multileg once for one atomic
 42multi-leg package. Never submit independent legs. After submission, verify the
 43submitted order with orders_get_status or orders_wait_for_terminal, then inspect
 44positions and open orders. If any condition cannot be proven, make a no-trade
 45decision and state the missing evidence. Manage an existing package before
 46considering a new entry, and close its legs as one atomic package.
 47""".strip()
 48
 49
 50class AISpxZeroDteBearCallTeamStrategy(Strategy):
 51    parameters = {
 52        "underlying": "SPX",
 53        "target_delta": 0.20,
 54        "wing_width": 5.0,
 55        "max_risk_pct": 0.01,
 56        "max_contracts": 1,
 57        "model": "gemini-3.5-flash-lite",
 58    }
 59
 60    def initialize(self):
 61        self.sleeptime = "5M"
 62        rules_path = Path(__file__).with_name("agent_rules") / "ai_spx_zero_dte_bear_call_team.rules.json"
 63        model = os.environ.get("AI_SPX_TEAM_MODEL", self.parameters["model"])
 64        self.agents.create(
 65            name="researcher",
 66            model=model,
 67            allow_trading=False,
 68            system_prompt=build_research_prompt(self.parameters),
 69            rules_path=rules_path,
 70        )
 71        self.agents.create(
 72            name="trader",
 73            model=model,
 74            allow_trading=True,
 75            system_prompt=build_trader_prompt(self.parameters),
 76            rules_path=rules_path,
 77        )
 78
 79    def on_trading_iteration(self):
 80        context = {
 81            "current_datetime": self.get_datetime().isoformat(),
 82            "strategy_parameters": dict(self.parameters),
 83        }
 84        research = self.agents["researcher"].run(
 85            task_prompt="Research today's exact SPX bear call spread opportunity.",
 86            context=context,
 87        )
 88        self.agents["trader"].run(
 89            task_prompt="Validate the research, make the final decision, and verify any trade.",
 90            context={**context, "research": research.summary},
 91        )
 92
 93
 94if __name__ == "__main__":
 95    backtesting_end = datetime.fromisoformat(
 96        os.environ.get("BACKTESTING_END", datetime.now().date().isoformat())
 97    )
 98    backtesting_start = datetime.fromisoformat(
 99        os.environ.get(
100            "BACKTESTING_START",
101            (backtesting_end - timedelta(days=7)).date().isoformat(),
102        )
103    )
104    AISpxZeroDteBearCallTeamStrategy.backtest(
105        None,
106        backtesting_start=backtesting_start,
107        backtesting_end=backtesting_end,
108        benchmark_asset="SPX",
109        budget=100_000,
110    )