Citadel Sector Pods AI Trading Team¶
This strategy is inspired by the pod-style structure associated with Ken Griffin’s Citadel and other multi-manager platforms. The idea is simple: do not ask one generalist to understand every market at once. Give each specialist a clear lane, let them pitch their strongest idea, then put a risk manager and portfolio manager above the debate.
In Lumibot, that becomes an AI trading team. Five independent sector-pod research branches study different parts of the market, their evidence converges into a risk manager, and only the portfolio manager can build the diversified allocation and place broker orders. It is a good example when you want to test whether specialist agents can create better decisions than one broad prompt.
The diagram uses parallel branches to show that all five pods are peer inputs with no dependency on one another. The current example invokes those branches sequentially before the fan-in; it does not claim simultaneous model execution.
These are educational examples with no affiliation or endorsement from Citadel or its personnel, and are not replicas of a proprietary strategy.
How the team works¶
technology_podlooks at technology and communications exposure.financials_podlooks at financials and rate-sensitive exposure.healthcare_podlooks at healthcare and defensive growth.energy_podlooks at energy and commodity-sensitive exposure.consumer_podlooks at consumer and housing-sensitive exposure.risk_managerchallenges crowding, drawdown, macro, and reversal risk.portfolio_managerbuilds a diversified three-or-more-sector allocation and is the only agent allowed to place broker orders.
Run it with a broker¶
The file defaults to broker-connected execution. With Alpaca, it runs in paper
mode unless you set ALPACA_IS_PAPER=false.
export OPENAI_API_KEY='your-key-here'
export AI_TRADING_TEAM_MODEL='openai/gpt-6-luna'
export ALPACA_API_KEY='your-alpaca-key'
export ALPACA_API_SECRET='your-alpaca-secret'
export ALPACA_IS_PAPER=true
python lumibot/example_strategies/ai_trading_team_citadel_sector_pods.py
Backtest it¶
Use the same strategy class and change IS_BACKTESTING = False to IS_BACKTESTING = True in the runner:
export OPENAI_API_KEY='your-key-here'
export AI_TRADING_TEAM_MODEL='openai/gpt-6-luna'
python lumibot/example_strategies/ai_trading_team_citadel_sector_pods.py
Example code¶
Regular ETF source:
"""Citadel / Surveyor-inspired sector-pod AI trading team example.
Regular sector ETF data-on variant. Uses LumiBot's default built-in tools,
including FRED/ALFRED macro tools when FRED_API_KEY is supplied, Alpaca News
when ALPACA_NEWS_API_KEY / ALPACA_NEWS_API_SECRET are supplied, SEC tools,
market state, account state, and order tools. It preserves the sector-pod debate
structure but requires a diversified final allocation.
"""
import os
from lumibot.credentials import IS_BACKTESTING
from lumibot.entities import Asset, TradingFee
from lumibot.strategies.strategy import Strategy
from lumibot.traders import Trader
ORDER_READINESS_RULE = (
"Immediately before every buy or sell order, call account_portfolio, "
"account_positions, and market_last_price for the exact ordered symbol in "
"this same agent run, then call orders_submit_order. LumiBot rejects blind "
"orders with ORDER_READINESS_REQUIRED when those readiness calls are missing."
)
DATA_USAGE_RULE = (
"Use official LumiBot built-in tools by their real names: get_fred_snapshot, "
"get_fred_latest, get_fred_series, and list_fred_series for macro evidence; "
"alpaca_news for recent market, sector, rates, and ETF-proxy headlines; SEC "
"tools are available and optional when company or sector fundamentals matter. "
"Keep tool use bounded: at most one FRED snapshot or short series request and "
"one Alpaca News call per agent run; set Alpaca News limit <= 5; do not paginate "
"or repeatedly re-check the same evidence. Do not rely on a custom public CSV FRED helper."
)
DIVERSIFICATION_RULE = (
"Preserve the sector-pod process and convert it into a diversified portfolio. "
"Hold at least three sector ETFs in normal conditions. Do not buy a single "
"sector ETF with nearly all capital unless the only non-sector allocation is "
"cash-like SHV due to explicit risk-off evidence."
)
class AITradingTeamCitadelSectorPodsStrategy(Strategy):
parameters = {
"universe": [
"XLK", "XLF", "XLV", "XLE", "XLY", "XLI", "XLP", "XLU", "XLB", "XLRE", "XLC", "SHV",
],
"min_positions": 3,
}
def initialize(self):
self.sleeptime = "1D"
model = os.environ.get("AI_TRADING_TEAM_MODEL", "openai/gpt-6-luna")
self.agents.create(
name="technology_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank technology and communications sector ETFs. First call alpaca_news for XLK/XLC/QQQ/SMH-relevant headlines and call get_fred_snapshot or get_fred_latest for rates, growth, and liquidity context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE
),
)
self.agents.create(
name="financials_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank financial and rate-sensitive sector ETFs. First call get_fred_snapshot or get_fred_latest for yield curve, credit, liquidity, and policy-rate context, then call alpaca_news for financial-sector headlines. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE
),
)
self.agents.create(
name="healthcare_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank healthcare and defensive growth sector ETFs. Call alpaca_news for healthcare/biotech/defensive-growth headlines and use FRED tools for macro risk context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE
),
)
self.agents.create(
name="energy_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank energy and commodity-sensitive sector ETFs. Call alpaca_news for oil/energy headlines and get_fred_snapshot/get_fred_latest for inflation, rates, dollar, and growth context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE
),
)
self.agents.create(
name="consumer_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank consumer discretionary, staples, and housing-sensitive sector ETFs. Call alpaca_news for consumer/housing headlines and FRED tools for inflation, income, rates, and growth context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE
),
)
self.agents.create(
name="risk_manager",
model=model,
allow_trading=False,
system_prompt=(
"Compare the pod picks. Challenge crowding, factor exposure, drawdown risk, reversal risk, and macro contradictions. "
"Check whether pods actually used get_fred_snapshot/get_fred_latest and alpaca_news. Do not re-call tools unless pod evidence is entirely absent; if you must, make only one short FRED call and one Alpaca News call with limit <= 5. "
+ DATA_USAGE_RULE + " " + DIVERSIFICATION_RULE
),
)
self.agents.create(
name="portfolio_manager",
model=model,
allow_trading=True,
system_prompt=(
"Allocate across the best sector ETFs from the pod process. Build a diversified portfolio of at least three positions in normal conditions, using variable weights based on pod conviction and risk-manager objections. "
"Do not make a one-sector all-in trade. Reconcile any override of pod advice or risk-manager warnings. "
+ DATA_USAGE_RULE + " " + DIVERSIFICATION_RULE + " " + ORDER_READINESS_RULE
),
)
def on_trading_iteration(self):
context = {
"date": self.get_datetime().date().isoformat(),
"universe": self.parameters["universe"],
"min_positions": self.parameters["min_positions"],
"data_expectation": "Use get_fred_snapshot/get_fred_latest and alpaca_news commonly; smoke tests inspect agent_detail for actual tool calls.",
"portfolio_expectation": "Portfolio manager should normally hold at least three sector ETFs and avoid single-sector all-in behavior.",
"data_tool_validation_run_id": "2026-07-08-fresh-alpaca-news-fred-smoke-v1",
}
technology = self.agents["technology_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank technology/communications sector opportunities.",
context=context,
)
financials = self.agents["financials_pod"].run(
task_prompt="Call get_fred_snapshot or get_fred_latest and alpaca_news, then rank financial/rate-sensitive sector opportunities.",
context=context,
)
healthcare = self.agents["healthcare_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank healthcare/defensive-growth sector opportunities.",
context=context,
)
energy = self.agents["energy_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank energy/commodity-sensitive sector opportunities.",
context=context,
)
consumer = self.agents["consumer_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank consumer/housing-sensitive sector opportunities.",
context=context,
)
risk = self.agents["risk_manager"].run(
task_prompt="Compare all pod picks, challenge concentration/crowding/macro risks, and recommend a diversified 3+ sector allocation.",
context={**context, "technology": technology.summary, "financials": financials.summary, "healthcare": healthcare.summary, "energy": energy.summary, "consumer": consumer.summary},
)
self.agents["portfolio_manager"].run(
task_prompt=(
"Rebalance into the best diversified 3+ sector ETF portfolio. Do not sell everything into one strongest ETF. "
"Before each order, call account_portfolio, account_positions, and market_last_price for the exact ordered symbol in this same run. "
"Explain which pod advice you accepted or rejected and cite FRED/Alpaca evidence used."
),
context={**context, "technology": technology.summary, "financials": financials.summary, "healthcare": healthcare.summary, "energy": energy.summary, "consumer": consumer.summary, "risk": risk.summary},
)
if __name__ == "__main__":
quote_asset = Asset("USD", Asset.AssetType.FOREX)
params = AITradingTeamCitadelSectorPodsStrategy.parameters
if IS_BACKTESTING:
trading_fee = TradingFee(percent_fee=0.001)
AITradingTeamCitadelSectorPodsStrategy.backtest(
datasource_class=None,
benchmark_asset=Asset("SPY", Asset.AssetType.STOCK),
buy_trading_fees=[trading_fee],
sell_trading_fees=[trading_fee],
quote_asset=quote_asset,
parameters=params,
)
else:
trader = Trader()
strategy = AITradingTeamCitadelSectorPodsStrategy(
quote_asset=quote_asset,
parameters=params,
)
trader.add_strategy(strategy)
trader.run_all()
Leveraged ETF source:
"""Citadel / Surveyor-inspired sector-pod AI trading team example.
Leveraged sector ETF data-on variant. Uses LumiBot's default built-in tools,
including FRED/ALFRED macro tools when FRED_API_KEY is supplied, Alpaca News
when ALPACA_NEWS_API_KEY / ALPACA_NEWS_API_SECRET are supplied, SEC tools,
market state, account state, and order tools. The trade universe is 2x/3x
leveraged sector and broad ETFs plus SHV/cash as a rare escape hatch.
"""
import os
from lumibot.credentials import IS_BACKTESTING
from lumibot.entities import Asset, TradingFee
from lumibot.strategies.strategy import Strategy
from lumibot.traders import Trader
ORDER_READINESS_RULE = (
"Immediately before every buy or sell order, call account_portfolio, "
"account_positions, and market_last_price for the exact ordered symbol in "
"this same agent run, then call orders_submit_order. LumiBot rejects blind "
"orders with ORDER_READINESS_REQUIRED when those readiness calls are missing."
)
DATA_USAGE_RULE = (
"Use official LumiBot built-in tools by their real names: get_fred_snapshot, "
"get_fred_latest, get_fred_series, and list_fred_series for macro evidence; "
"alpaca_news for recent market, sector, rates, and ETF-proxy headlines; SEC "
"tools are available and optional when company or sector fundamentals matter. "
"Keep tool use bounded: at most one FRED snapshot or short series request and "
"one Alpaca News call per agent run; set Alpaca News limit <= 5; do not paginate "
"or repeatedly re-check the same evidence. Do not rely on a custom public CSV FRED helper."
)
LEVERAGE_RULE = (
"This is a leveraged ETF strategy. Use only symbols from the leveraged universe plus SHV/cash-like exposure. "
"Stay biased toward diversified 3x exposure when evidence supports risk-taking; use 2x as a risk-down choice; "
"use inverse leveraged ETFs only with explicit downside or hedge evidence. Hold at least three positions in normal conditions, "
"and do not make a single-sector all-in bet. SHV/cash may count as one position when the model refuses every reasonable leveraged setup."
)
class AITradingTeamCitadelSectorPodsStrategy(Strategy):
parameters = {
"universe": [
"TECL", "TECS", "SOXL", "SOXS", "FNGU", "FNGD", "WEBL", "WEBS",
"FAS", "FAZ", "DPST", "WDRW", "CURE", "RXD", "LABU", "LABD",
"ERX", "ERY", "GUSH", "DRIP", "WANT", "NEED", "RETL", "DUSL",
"SIJ", "MATL", "UTSL", "SDP", "DRN", "DRV", "NAIL", "UPRO",
"SPXU", "SSO", "SDS", "TQQQ", "SQQQ", "QLD", "QID", "TNA",
"TZA", "SHV",
],
"min_positions": 3,
}
def initialize(self):
self.sleeptime = "1D"
model = os.environ.get("AI_TRADING_TEAM_MODEL", "openai/gpt-6-luna")
self.agents.create(
name="technology_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank leveraged technology, communications, internet, AI, and semiconductor ETFs. First call alpaca_news for TECL/SOXL/FNGU/WEBL proxy headlines and call get_fred_snapshot or get_fred_latest for rates, growth, and liquidity context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="financials_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank leveraged financial, bank, and rate-sensitive ETFs. First call get_fred_snapshot or get_fred_latest for yield curve, credit, liquidity, and policy-rate context, then call alpaca_news for financial-sector headlines. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="healthcare_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank leveraged healthcare, biotech, and defensive-growth ETFs. Call alpaca_news for healthcare/biotech/defensive-growth headlines and use FRED tools for macro risk context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="energy_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank leveraged energy, oil, commodity, and materials ETFs. Call alpaca_news for oil/energy/materials headlines and get_fred_snapshot/get_fred_latest for inflation, rates, dollar, and growth context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="consumer_pod",
model=model,
allow_trading=False,
system_prompt=(
"Rank leveraged consumer discretionary, staples, retail, housing, industrials, utilities, and real estate ETFs. Call alpaca_news for consumer/housing/defensive-sector headlines and FRED tools for inflation, income, rates, and growth context. "
"Use exact symbols from the universe only. " + DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="risk_manager",
model=model,
allow_trading=False,
system_prompt=(
"Compare the pod picks. Challenge crowding, factor exposure, drawdown risk, reversal risk, macro contradictions, inverse ETF decay, and single-sector concentration. "
"Check whether pods actually used get_fred_snapshot/get_fred_latest and alpaca_news. Do not re-call tools unless pod evidence is entirely absent; if you must, make only one short FRED call and one Alpaca News call with limit <= 5. "
+ DATA_USAGE_RULE + " " + LEVERAGE_RULE
),
)
self.agents.create(
name="portfolio_manager",
model=model,
allow_trading=True,
system_prompt=(
"Allocate across the best leveraged ETFs from the pod process. Build a diversified portfolio of at least three positions in normal conditions, using variable weights based on pod conviction and risk-manager objections. "
"Favor 3x ETFs for high-conviction sector sleeves, use 2x when conviction or drawdown risk is lower, and use inverse ETFs only as a carefully justified hedge or downside exposure. "
"Do not make a one-sector all-in trade. Reconcile any override of pod advice or risk-manager warnings. "
+ DATA_USAGE_RULE + " " + LEVERAGE_RULE + " " + ORDER_READINESS_RULE
),
)
def on_trading_iteration(self):
context = {
"date": self.get_datetime().date().isoformat(),
"universe": self.parameters["universe"],
"min_positions": self.parameters["min_positions"],
"data_expectation": "Use get_fred_snapshot/get_fred_latest and alpaca_news commonly; smoke tests inspect agent_detail for actual tool calls.",
"leverage_expectation": "Use only leveraged ETFs plus SHV/cash escape, hold at least three positions, and avoid single-sector all-in behavior.",
"data_tool_validation_run_id": "2026-07-08-fresh-alpaca-news-fred-smoke-v1",
}
technology = self.agents["technology_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank leveraged technology/communications/semiconductor opportunities.",
context=context,
)
financials = self.agents["financials_pod"].run(
task_prompt="Call get_fred_snapshot or get_fred_latest and alpaca_news, then rank leveraged financial/rate-sensitive opportunities.",
context=context,
)
healthcare = self.agents["healthcare_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank leveraged healthcare/biotech/defensive-growth opportunities.",
context=context,
)
energy = self.agents["energy_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank leveraged energy/commodity/materials opportunities.",
context=context,
)
consumer = self.agents["consumer_pod"].run(
task_prompt="Call alpaca_news and FRED tools, then rank leveraged consumer/housing/defensive/real-estate opportunities.",
context=context,
)
risk = self.agents["risk_manager"].run(
task_prompt="Compare all pod picks, challenge concentration/crowding/macro/inverse-decay risks, and recommend a diversified 3+ leveraged ETF allocation.",
context={**context, "technology": technology.summary, "financials": financials.summary, "healthcare": healthcare.summary, "energy": energy.summary, "consumer": consumer.summary},
)
self.agents["portfolio_manager"].run(
task_prompt=(
"Rebalance into the best diversified 3+ leveraged ETF portfolio. Bias toward 3x ETFs, use 2x only as a risk-down choice, and use inverse ETFs only with explicit hedge/downside evidence. "
"Do not sell everything into one strongest ETF. Before each order, call account_portfolio, account_positions, and market_last_price for the exact ordered symbol in this same run. "
"Explain which pod advice you accepted or rejected and cite FRED/Alpaca evidence used."
),
context={**context, "technology": technology.summary, "financials": financials.summary, "healthcare": healthcare.summary, "energy": energy.summary, "consumer": consumer.summary, "risk": risk.summary},
)
if __name__ == "__main__":
quote_asset = Asset("USD", Asset.AssetType.FOREX)
params = AITradingTeamCitadelSectorPodsStrategy.parameters
if IS_BACKTESTING:
trading_fee = TradingFee(percent_fee=0.001)
AITradingTeamCitadelSectorPodsStrategy.backtest(
datasource_class=None,
benchmark_asset=Asset("SPY", Asset.AssetType.STOCK),
buy_trading_fees=[trading_fee],
sell_trading_fees=[trading_fee],
quote_asset=quote_asset,
parameters=params,
)
else:
trader = Trader()
strategy = AITradingTeamCitadelSectorPodsStrategy(
quote_asset=quote_asset,
parameters=params,
)
trader.add_strategy(strategy)
trader.run_all()