Building My First AI Agents: The S&P 500 and IBEX 35 Quality Screeners
September 2026 Β· 6 min read Β· By Javier Audibert
I worked as the only finance person at a couple of startups: if a system didn't exist, I built it. That same instinct is what led me to build my first AI agent. It wasn't a "I want to learn machine learning" project, it was: I want a report every Monday telling me which companies deserve my time this week.
Today they're two tools that run themselves every week: the S&P 500 Quality Screener and the IBEX 35 one. They screen the whole index on fundamentals and technicals, and an AI agent researches the web and writes the final report. No server: the GitHub repo is the database, and the portal reads it live.
One clarification before going further: these screeners are personal projects, built in my own time to learn. They aren't professional work, they're not associated with any employer or client, and nothing they publish is investment advice. They're a tool for deciding which companies get my own research time β nothing more.
The filter: 6 criteria before any AI
Every run pulls the index constituents from Wikipedia and puts them through six criteria β four fundamental, two technical, via yfinance:
- ROE > 20% β the classic quality screen.
- ROA > 12% β a hard filter on the S&P 500; not on the IBEX 35 β more on that below.
- P/E < 20 β avoids overpaying for growth.
- Debt/Equity < 100% β screens out ROE inflated by leverage.
- RSI > 30 β excludes oversold names, with no cap so momentum isn't penalized.
- Price > 50-day moving average β confirms the trend is up.
Out of 500 companies, usually a couple dozen survive. That matters: the model reasons far better over 20 pre-screened companies than over 500 unfiltered ones.
The agent: Groq and a tool-use loop
Here's what makes this an agent and not just another script. The filter is deterministic: same inputs, same output. The agent isn't β you give it a goal and some tools, and it decides at each step whether it needs them. I use Groq with gpt-oss-120b and give it one single tool: a news search per ticker, declared as a JSON function-calling schema.
messages = [{"role": "user", "content": prompt_analista}]
while True:
response = client.chat.completions.create(
model="openai/gpt-oss-120b",
messages=messages,
tools=tools,
tool_choice="auto",
)
tool_calls = response.choices[0].message.tool_calls
if not tool_calls:
return response.choices[0].message.content # done β final report
messages.append(response.choices[0].message)
for tool_call in tool_calls:
ticker = json.loads(tool_call.function.arguments)["ticker"]
messages.append({"role": "tool", "tool_call_id": tool_call.id,
"name": "buscar_noticias_web",
"content": buscar_noticias_web(ticker)})
# loop again β the model sees the results and decides what's nextThat's it. That twenty-line while True loop is the agent: one model, one tool, and a loop that keeps going until the model itself decides it needs nothing more. No frameworks, no orchestrators.
What surprised me most the first time I ran it: the model doesn't follow a script. It decides ticker by ticker when to search, chaining several calls before it writes. It was the first time a script of mine felt less like code and more like delegating a task.
The whole pipeline lives in GitHub Actions: a weekly cron (0 6 * * 1, Mondays at 06:00 UTC) that runs the screener and commits the JSON back to the repo. There's no server and no database to maintain.
The second agent: what "quality" means in each market
For the IBEX 35 the temptation was to copy the whole file. Instead, I pulled everything that doesn't depend on the index β indicators, filter, tool and agent loop β into a shared module. Each screener came down to around 40 lines: how to fetch its tickers, plus one call into the generic runner.
run_pipeline(obtener_tickers_fn=obtener_tickers_sp500, ..., roa_minimo=0.12) # hard filter run_pipeline(obtener_tickers_fn=obtener_tickers_ibex35, ..., roa_minimo=None) # not a filter
The most interesting difference isn't technical, it's financial judgment. The IBEX 35 is full of banks and utilities, sectors where a low ROA is structural to the business, not a signal of poor quality. Applying the S&P 500 threshold would have screened out entire sectors for reasons that say nothing about those companies. The code only needed one parameter; the real work was deciding what the right criterion was.
Agents aren't just for IT people
I've never considered myself an engineer. I build things out of necessity, and that's why I think this pattern matters outside software: an agent is nothing more than a model, a few well-defined tools, and a loop. A marketing analyst can build the same pattern to decide when to pull analytics before drafting a report; someone in support, to search the knowledge base before answering a ticket. The tool changes, the loop doesn't.
And what stayed with me most from these two small projects: the hard part was never the AI. It was having clear judgment about my own domain β what makes a company high quality, and why that definition changes between Wall Street and the Ibex. Nobody automates that for you, and it's exactly what any finance, marketing or operations professional already does every day. Building the agent is, by comparison, the easy part.
See the agents in production β
Share this article