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=Falseand 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 throughorders_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 )