# Building a stock-trading agent with ADK


The [Agent Development Kit](https://adk.dev/) (ADK) is Google’s open-source Python framework for building AI agents. You write the agent’s logic and the tools it can call, and ADK handles orchestrating everything — with evaluation and deployment built in too.

I wanted a slightly more interesting app than Hello World to exercise more parts of the platform, so I figured I’d write a little stock trading agent that applies a sentiment momentum trading strategy. We’ll use ADK and the Gemini API to execute trades on [Alpaca](https://alpaca.markets/), chosen for its REST API and free paper-trading account.

Tip: Prefer a fully-built solution? See the [completed example](#the-completed-example).

First, let’s set up our project directory and create a subfolder for our agent:

```shell
mkdir trading-agent-project
cd trading-agent-project
mkdir trading_agent
```

Get an API key from Alpaca’s "API Keys" box on the [account overview](https://app.alpaca.markets/user/profile#manage-accounts)
page.

![The Alpaca API key box](alpaca-example-key.png)
*The Alpaca API key box*

And a Google API key from [AI Studio](https://aistudio.google.com/app/api-keys).

Create a `.env` file at `trading_agent/.env` and populate it with your 3 keys:

```shell
# Google AI Studio / Vertex AI Key for the ADK Agent
GOOGLE_API_KEY=your-key

# Alpaca Paper Trading Keys
APCA_API_KEY_ID=your-key-id
APCA_API_SECRET_KEY=your-key
```

Note: I use this trading agent with paper trades only. It’s likely a terrible trading strategy, and also poorly executed, so I do not endorse it. If you build your own agent based on this prompt, I strongly advise you not to switch the API keys from paper trades to money trades. It makes for a fun demo though.

Next, create a file at `trading_agent/requirements.txt` to manage our dependencies, and add the following:

```
google-adk
alpaca-py
google-cloud-aiplatform[agent_engines,adk]
python-dotenv
```

*[requirements.txt](https://github.com/WilliamDenniss/agent-examples/blob/master/01_TradingAgent/trading_agent/requirements.txt)*

We'll need a Python environment with the dependencies installed, which we can use `venv` to manage. Install venv if not already installed (`apt update && apt install python3-venv`, or `sudo apt update && sudo apt install python3-venv` depending on your permissions).

Create the venv environment:

```shell
python3 -m venv trading-env
source trading-env/bin/activate
pip install -r trading_agent/requirements.txt
```

Now, we can use the Gemini CLI (or your preferred coding agent) to generate the ADK agent. Here’s my prompt:

```
You are operating from within a venv project folder. Create an AI agent using ADK in python in the sub-folder "trading_agent". It already contains a .env with the required keys. The agent will be executed with `adk run trading_agent`.

The agent is a stock trading bot that will use Alpaca with paper trades (not real money). Each execution, it performs the following actions:

1/ News lookup. Discover the latest financial news affecting companies, primarily the S&P 500

2/ Analyze the news for positive or negative sentiments using Gemini 2.5 Pro and assign a sentiment rating between -1 and 1. Ignore Stock Analyst Rating changes; market news only. Format as Primary ticker affected, news summary, score.

3/ Query current position portfolio from Alpaca markets

4/ For any stock currently held, if the sentiment is negative, sell the stock. If no negative sentiment, do not sell. For all trades, introduce a 1s delay to rate-limit API calls.

5/ Rank the news in order of positivity, and create market BUY trades for $1000 worth of EACH of up to 5 stock with high confidence positive sentiments NOT currently held (fractional shares are OK). If no positive sentiments, do not buy.

6/ Produce a summary of all orders placed with a summary of the news that led to the order, along with a sentiment score. Additionally, provide a market sentiment overview of the top 10 positive, and top 10 negative news stories (include the ticker, summary, and score).
```

Note: If you run out of Gemini CLI quota, you can use the same API key in the `.env` file above to authenticate the Gemini CLI (run `/auth` in Gemini, and enter the key).

It’s best to let Gemini run the agent the first time to iron out any bugs. Just be aware that however it runs, the trades are executing.

Here’s the Python agent code that I got from the Gemini CLI:

<details class="expander">
  <summary class="expander-summary">agent.py</summary>
  <div class="expander-content">
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  1
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  2
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  3
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  4
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  5
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  6
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  7
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  8
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">  9
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 10
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 11
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 12
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 13
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 14
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 15
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 16
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 17
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 18
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 19
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 20
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 21
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 22
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 23
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 24
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 25
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 26
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 27
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 28
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 29
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 30
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 31
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 32
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 33
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 34
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 35
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 36
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 37
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 38
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 39
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 40
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 41
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 42
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 43
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 44
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 45
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 46
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 47
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 48
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 49
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 50
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 51
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 52
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 53
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 54
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 55
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 56
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 57
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 58
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 59
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 60
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 61
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 62
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 63
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 64
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 65
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 66
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 67
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 68
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 69
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 70
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 71
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 72
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 73
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 74
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 75
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 76
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 77
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 78
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 79
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 80
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 81
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 82
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 83
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 84
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 85
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 86
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 87
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 88
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 89
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 90
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 91
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 92
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 93
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 94
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 95
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 96
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 97
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 98
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 99
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">100
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">101
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">102
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">103
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">104
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">105
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">106
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">107
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">108
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">109
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">110
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">111
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">112
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">113
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">114
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">115
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">116
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">117
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">118
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">119
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">120
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">121
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">122
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">123
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">124
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">125
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">126
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">127
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">128
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">129
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">130
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">131
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">132
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">133
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">134
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">135
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">136
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">137
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">138
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">139
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">140
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">141
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">142
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">143
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">144
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">145
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">146
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">147
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">148
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">149
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">150
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">151
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">152
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">153
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">154
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">155
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">156
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">157
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">158
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">159
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">160
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">161
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">162
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">163
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">164
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">165
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">166
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">167
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">168
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">169
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">170
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">171
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">172
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">173
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">174
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> os
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> time
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> datetime <span style="color:#f92672">import</span> datetime, timedelta
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> typing <span style="color:#f92672">import</span> List, Dict, Any, Optional
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> dotenv <span style="color:#f92672">import</span> load_dotenv
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> alpaca.data.historical <span style="color:#f92672">import</span> NewsClient, StockHistoricalDataClient
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> alpaca.data.requests <span style="color:#f92672">import</span> NewsRequest, StockLatestQuoteRequest
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> alpaca.trading.client <span style="color:#f92672">import</span> TradingClient
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> alpaca.trading.requests <span style="color:#f92672">import</span> MarketOrderRequest
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> alpaca.trading.enums <span style="color:#f92672">import</span> OrderSide, TimeInForce
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> google.adk.agents <span style="color:#f92672">import</span> Agent
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> vertexai <span style="color:#f92672">import</span> agent_engines
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Load environment variables</span>
</span></span><span style="display:flex;"><span>env_path <span style="color:#f92672">=</span> os<span style="color:#f92672">.</span>path<span style="color:#f92672">.</span>join(os<span style="color:#f92672">.</span>path<span style="color:#f92672">.</span>dirname(__file__), <span style="color:#e6db74">&#39;.env&#39;</span>)
</span></span><span style="display:flex;"><span>load_dotenv(env_path)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># API Keys</span>
</span></span><span style="display:flex;"><span>APCA_API_KEY_ID <span style="color:#f92672">=</span> os<span style="color:#f92672">.</span>getenv(<span style="color:#e6db74">&#39;APCA_API_KEY_ID&#39;</span>)
</span></span><span style="display:flex;"><span>APCA_API_SECRET_KEY <span style="color:#f92672">=</span> os<span style="color:#f92672">.</span>getenv(<span style="color:#e6db74">&#39;APCA_API_SECRET_KEY&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Initialize Alpaca Clients</span>
</span></span><span style="display:flex;"><span>trading_client <span style="color:#f92672">=</span> TradingClient(APCA_API_KEY_ID, APCA_API_SECRET_KEY, paper<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>news_client <span style="color:#f92672">=</span> NewsClient(APCA_API_KEY_ID, APCA_API_SECRET_KEY)
</span></span><span style="display:flex;"><span>stock_client <span style="color:#f92672">=</span> StockHistoricalDataClient(APCA_API_KEY_ID, APCA_API_SECRET_KEY)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Full S&amp;P 500 Tickers List (Retrieved April 2026)</span>
</span></span><span style="display:flex;"><span>SP500_TICKERS <span style="color:#f92672">=</span> [
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#e6db74">&#34;AAPL&#34;</span>, <span style="color:#e6db74">&#34;ABBV&#34;</span>, <span style="color:#e6db74">&#34;ABT&#34;</span>, <span style="color:#e6db74">&#34;ACGL&#34;</span>, <span style="color:#e6db74">&#34;ACN&#34;</span>, <span style="color:#e6db74">&#34;ADBE&#34;</span>, <span style="color:#e6db74">&#34;ADI&#34;</span>, <span style="color:#e6db74">&#34;ADM&#34;</span>, <span style="color:#e6db74">&#34;ADP&#34;</span>, <span style="color:#e6db74">&#34;ADSK&#34;</span>, <span style="color:#e6db74">&#34;AEE&#34;</span>, <span style="color:#e6db74">&#34;AEP&#34;</span>, <span style="color:#e6db74">&#34;AES&#34;</span>, <span style="color:#e6db74">&#34;AFL&#34;</span>, <span style="color:#e6db74">&#34;AIG&#34;</span>, <span style="color:#e6db74">&#34;AIZ&#34;</span>, <span style="color:#e6db74">&#34;AJG&#34;</span>, <span style="color:#e6db74">&#34;AKAM&#34;</span>, <span style="color:#e6db74">&#34;ALB&#34;</span>, <span style="color:#e6db74">&#34;ALGN&#34;</span>, <span style="color:#e6db74">&#34;ALL&#34;</span>, <span style="color:#e6db74">&#34;ALLE&#34;</span>, <span style="color:#e6db74">&#34;AMAT&#34;</span>, <span style="color:#e6db74">&#34;AMCR&#34;</span>, <span style="color:#e6db74">&#34;AMD&#34;</span>, <span style="color:#e6db74">&#34;AME&#34;</span>, <span style="color:#e6db74">&#34;AMGN&#34;</span>, <span style="color:#e6db74">&#34;AMP&#34;</span>, <span style="color:#e6db74">&#34;AMT&#34;</span>, <span style="color:#e6db74">&#34;AMZN&#34;</span>, <span style="color:#e6db74">&#34;ANET&#34;</span>, <span style="color:#e6db74">&#34;AON&#34;</span>, <span style="color:#e6db74">&#34;AOS&#34;</span>, <span style="color:#e6db74">&#34;APA&#34;</span>, <span style="color:#e6db74">&#34;APD&#34;</span>, <span style="color:#e6db74">&#34;APH&#34;</span>, <span style="color:#e6db74">&#34;APO&#34;</span>, <span style="color:#e6db74">&#34;APP&#34;</span>, <span style="color:#e6db74">&#34;APTV&#34;</span>, <span style="color:#e6db74">&#34;ARE&#34;</span>, <span style="color:#e6db74">&#34;ATO&#34;</span>, <span style="color:#e6db74">&#34;AVB&#34;</span>, <span style="color:#e6db74">&#34;AVGO&#34;</span>, <span style="color:#e6db74">&#34;AVY&#34;</span>, <span style="color:#e6db74">&#34;AWK&#34;</span>, <span style="color:#e6db74">&#34;AXON&#34;</span>, <span style="color:#e6db74">&#34;AXP&#34;</span>, <span style="color:#e6db74">&#34;AZO&#34;</span>, <span style="color:#e6db74">&#34;BA&#34;</span>, <span style="color:#e6db74">&#34;BAC&#34;</span>, <span style="color:#e6db74">&#34;BALL&#34;</span>, <span style="color:#e6db74">&#34;BAX&#34;</span>, <span style="color:#e6db74">&#34;BBY&#34;</span>, <span style="color:#e6db74">&#34;BDX&#34;</span>, <span style="color:#e6db74">&#34;BEN&#34;</span>, <span style="color:#e6db74">&#34;BF.B&#34;</span>, <span style="color:#e6db74">&#34;BG&#34;</span>, <span style="color:#e6db74">&#34;BIIB&#34;</span>, <span style="color:#e6db74">&#34;BK&#34;</span>, <span style="color:#e6db74">&#34;BKNG&#34;</span>, <span style="color:#e6db74">&#34;BKR&#34;</span>, <span style="color:#e6db74">&#34;BLDR&#34;</span>, <span style="color:#e6db74">&#34;BLK&#34;</span>, <span style="color:#e6db74">&#34;BMY&#34;</span>, <span style="color:#e6db74">&#34;BR&#34;</span>, <span style="color:#e6db74">&#34;BRO&#34;</span>, <span style="color:#e6db74">&#34;BRK.B&#34;</span>, <span style="color:#e6db74">&#34;BSX&#34;</span>, <span style="color:#e6db74">&#34;BWA&#34;</span>, <span style="color:#e6db74">&#34;BX&#34;</span>, <span style="color:#e6db74">&#34;BXP&#34;</span>, <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#e6db74">&#34;CAG&#34;</span>, <span style="color:#e6db74">&#34;CAH&#34;</span>, <span style="color:#e6db74">&#34;CARR&#34;</span>, <span style="color:#e6db74">&#34;CAT&#34;</span>, <span style="color:#e6db74">&#34;CB&#34;</span>, <span style="color:#e6db74">&#34;CBOE&#34;</span>, <span style="color:#e6db74">&#34;CBRE&#34;</span>, <span style="color:#e6db74">&#34;CCI&#34;</span>, <span style="color:#e6db74">&#34;CCL&#34;</span>, <span style="color:#e6db74">&#34;CDNS&#34;</span>, <span style="color:#e6db74">&#34;CDW&#34;</span>, <span style="color:#e6db74">&#34;CEG&#34;</span>, <span style="color:#e6db74">&#34;CF&#34;</span>, <span style="color:#e6db74">&#34;CFG&#34;</span>, <span style="color:#e6db74">&#34;CHD&#34;</span>, <span style="color:#e6db74">&#34;CHRW&#34;</span>, <span style="color:#e6db74">&#34;CHTR&#34;</span>, <span style="color:#e6db74">&#34;CI&#34;</span>, <span style="color:#e6db74">&#34;CINF&#34;</span>, <span style="color:#e6db74">&#34;CL&#34;</span>, <span style="color:#e6db74">&#34;CLX&#34;</span>, <span style="color:#e6db74">&#34;CMA&#34;</span>, <span style="color:#e6db74">&#34;CMCSA&#34;</span>, <span style="color:#e6db74">&#34;CME&#34;</span>, <span style="color:#e6db74">&#34;CMG&#34;</span>, <span style="color:#e6db74">&#34;CMI&#34;</span>, <span style="color:#e6db74">&#34;CMS&#34;</span>, <span style="color:#e6db74">&#34;CNC&#34;</span>, <span style="color:#e6db74">&#34;CNP&#34;</span>, <span style="color:#e6db74">&#34;COF&#34;</span>, <span style="color:#e6db74">&#34;COO&#34;</span>, <span style="color:#e6db74">&#34;COP&#34;</span>, <span style="color:#e6db74">&#34;COR&#34;</span>, <span style="color:#e6db74">&#34;COST&#34;</span>, <span style="color:#e6db74">&#34;CPAY&#34;</span>, <span style="color:#e6db74">&#34;CPB&#34;</span>, <span style="color:#e6db74">&#34;CPRT&#34;</span>, <span style="color:#e6db74">&#34;CPT&#34;</span>, <span style="color:#e6db74">&#34;CRL&#34;</span>, <span style="color:#e6db74">&#34;CRM&#34;</span>, <span style="color:#e6db74">&#34;CRWD&#34;</span>, <span style="color:#e6db74">&#34;CSCO&#34;</span>, <span style="color:#e6db74">&#34;CSGP&#34;</span>, <span style="color:#e6db74">&#34;CSX&#34;</span>, <span style="color:#e6db74">&#34;CTAS&#34;</span>, <span style="color:#e6db74">&#34;CTSH&#34;</span>, <span style="color:#e6db74">&#34;CTVA&#34;</span>, <span style="color:#e6db74">&#34;CVS&#34;</span>, <span style="color:#e6db74">&#34;CVX&#34;</span>, <span style="color:#e6db74">&#34;CZR&#34;</span>, <span style="color:#e6db74">&#34;D&#34;</span>, <span style="color:#e6db74">&#34;DAL&#34;</span>, <span style="color:#e6db74">&#34;DAY&#34;</span>, <span style="color:#e6db74">&#34;DD&#34;</span>, <span style="color:#e6db74">&#34;DE&#34;</span>, <span style="color:#e6db74">&#34;DECK&#34;</span>, <span style="color:#e6db74">&#34;DELL&#34;</span>, <span style="color:#e6db74">&#34;DFS&#34;</span>, <span style="color:#e6db74">&#34;DG&#34;</span>, <span style="color:#e6db74">&#34;DGX&#34;</span>, <span style="color:#e6db74">&#34;DHI&#34;</span>, <span style="color:#e6db74">&#34;DHR&#34;</span>, <span style="color:#e6db74">&#34;DIS&#34;</span>, <span style="color:#e6db74">&#34;DLR&#34;</span>, <span style="color:#e6db74">&#34;DLTR&#34;</span>, <span style="color:#e6db74">&#34;DOC&#34;</span>, <span style="color:#e6db74">&#34;DOV&#34;</span>, <span style="color:#e6db74">&#34;DOW&#34;</span>, <span style="color:#e6db74">&#34;DPZ&#34;</span>, <span style="color:#e6db74">&#34;DRI&#34;</span>, <span style="color:#e6db74">&#34;DTE&#34;</span>, <span style="color:#e6db74">&#34;DUK&#34;</span>, <span style="color:#e6db74">&#34;DVA&#34;</span>, <span style="color:#e6db74">&#34;DVN&#34;</span>, <span style="color:#e6db74">&#34;DXCM&#34;</span>, <span style="color:#e6db74">&#34;EA&#34;</span>, <span style="color:#e6db74">&#34;EBAY&#34;</span>, <span style="color:#e6db74">&#34;ECL&#34;</span>, <span style="color:#e6db74">&#34;ED&#34;</span>, <span style="color:#e6db74">&#34;EFX&#34;</span>, <span style="color:#e6db74">&#34;EG&#34;</span>, <span style="color:#e6db74">&#34;EIX&#34;</span>, <span style="color:#e6db74">&#34;EL&#34;</span>, <span style="color:#e6db74">&#34;ELV&#34;</span>, <span style="color:#e6db74">&#34;EMN&#34;</span>, <span style="color:#e6db74">&#34;EMR&#34;</span>, <span style="color:#e6db74">&#34;ENPH&#34;</span>, <span style="color:#e6db74">&#34;EOG&#34;</span>, <span style="color:#e6db74">&#34;EPAM&#34;</span>, <span style="color:#e6db74">&#34;EQT&#34;</span>, <span style="color:#e6db74">&#34;EQR&#34;</span>, <span style="color:#e6db74">&#34;ERIE&#34;</span>, <span style="color:#e6db74">&#34;ES&#34;</span>, <span style="color:#e6db74">&#34;ESS&#34;</span>, <span style="color:#e6db74">&#34;ETN&#34;</span>, <span style="color:#e6db74">&#34;ETR&#34;</span>, <span style="color:#e6db74">&#34;EVRG&#34;</span>, <span style="color:#e6db74">&#34;EW&#34;</span>, <span style="color:#e6db74">&#34;EXC&#34;</span>, <span style="color:#e6db74">&#34;EXPD&#34;</span>, <span style="color:#e6db74">&#34;EXPE&#34;</span>, <span style="color:#e6db74">&#34;EXR&#34;</span>, <span style="color:#e6db74">&#34;F&#34;</span>, <span style="color:#e6db74">&#34;FANG&#34;</span>, <span style="color:#e6db74">&#34;FAST&#34;</span>, <span style="color:#e6db74">&#34;FCX&#34;</span>, <span style="color:#e6db74">&#34;FDS&#34;</span>, <span style="color:#e6db74">&#34;FDX&#34;</span>, <span style="color:#e6db74">&#34;FE&#34;</span>, <span style="color:#e6db74">&#34;FFIV&#34;</span>, <span style="color:#e6db74">&#34;FI&#34;</span>, <span style="color:#e6db74">&#34;FICO&#34;</span>, <span style="color:#e6db74">&#34;FIS&#34;</span>, <span style="color:#e6db74">&#34;FITB&#34;</span>, <span style="color:#e6db74">&#34;FMC&#34;</span>, <span style="color:#e6db74">&#34;FOX&#34;</span>, <span style="color:#e6db74">&#34;FOXA&#34;</span>, <span style="color:#e6db74">&#34;FRT&#34;</span>, <span style="color:#e6db74">&#34;FSLR&#34;</span>, <span style="color:#e6db74">&#34;FTNT&#34;</span>, <span style="color:#e6db74">&#34;FTV&#34;</span>, <span style="color:#e6db74">&#34;GD&#34;</span>, <span style="color:#e6db74">&#34;GDDY&#34;</span>, <span style="color:#e6db74">&#34;GE&#34;</span>, <span style="color:#e6db74">&#34;GEHC&#34;</span>, <span style="color:#e6db74">&#34;GEN&#34;</span>, <span style="color:#e6db74">&#34;GEV&#34;</span>, <span style="color:#e6db74">&#34;GILD&#34;</span>, <span style="color:#e6db74">&#34;GIS&#34;</span>, <span style="color:#e6db74">&#34;GL&#34;</span>, <span style="color:#e6db74">&#34;GLW&#34;</span>, <span style="color:#e6db74">&#34;GM&#34;</span>, <span style="color:#e6db74">&#34;GNRC&#34;</span>, <span style="color:#e6db74">&#34;GOOG&#34;</span>, <span style="color:#e6db74">&#34;GOOGL&#34;</span>, <span style="color:#e6db74">&#34;GPC&#34;</span>, <span style="color:#e6db74">&#34;GPN&#34;</span>, <span style="color:#e6db74">&#34;GRMN&#34;</span>, <span style="color:#e6db74">&#34;GS&#34;</span>, <span style="color:#e6db74">&#34;GWW&#34;</span>, <span style="color:#e6db74">&#34;HAL&#34;</span>, <span style="color:#e6db74">&#34;HAS&#34;</span>, <span style="color:#e6db74">&#34;HBAN&#34;</span>, <span style="color:#e6db74">&#34;HCA&#34;</span>, <span style="color:#e6db74">&#34;HD&#34;</span>, <span style="color:#e6db74">&#34;HES&#34;</span>, <span style="color:#e6db74">&#34;HIG&#34;</span>, <span style="color:#e6db74">&#34;HII&#34;</span>, <span style="color:#e6db74">&#34;HLT&#34;</span>, <span style="color:#e6db74">&#34;HOLX&#34;</span>, <span style="color:#e6db74">&#34;HON&#34;</span>, <span style="color:#e6db74">&#34;HPE&#34;</span>, <span style="color:#e6db74">&#34;HPQ&#34;</span>, <span style="color:#e6db74">&#34;HRL&#34;</span>, <span style="color:#e6db74">&#34;HSIC&#34;</span>, <span style="color:#e6db74">&#34;HST&#34;</span>, <span style="color:#e6db74">&#34;HSY&#34;</span>, <span style="color:#e6db74">&#34;HUBB&#34;</span>, <span style="color:#e6db74">&#34;HUM&#34;</span>, <span style="color:#e6db74">&#34;HWM&#34;</span>, <span style="color:#e6db74">&#34;IBM&#34;</span>, <span style="color:#e6db74">&#34;ICE&#34;</span>, <span style="color:#e6db74">&#34;IDXX&#34;</span>, <span style="color:#e6db74">&#34;IEX&#34;</span>, <span style="color:#e6db74">&#34;IFF&#34;</span>, <span style="color:#e6db74">&#34;ILMN&#34;</span>, <span style="color:#e6db74">&#34;INCY&#34;</span>, <span style="color:#e6db74">&#34;INTC&#34;</span>, <span style="color:#e6db74">&#34;INTU&#34;</span>, <span style="color:#e6db74">&#34;INVH&#34;</span>, <span style="color:#e6db74">&#34;IP&#34;</span>, <span style="color:#e6db74">&#34;IPG&#34;</span>, <span style="color:#e6db74">&#34;IQV&#34;</span>, <span style="color:#e6db74">&#34;IR&#34;</span>, <span style="color:#e6db74">&#34;IRM&#34;</span>, <span style="color:#e6db74">&#34;ISRG&#34;</span>, <span style="color:#e6db74">&#34;IT&#34;</span>, <span style="color:#e6db74">&#34;ITW&#34;</span>, <span style="color:#e6db74">&#34;IVZ&#34;</span>, <span style="color:#e6db74">&#34;J&#34;</span>, <span style="color:#e6db74">&#34;JBHT&#34;</span>, <span style="color:#e6db74">&#34;JCI&#34;</span>, <span style="color:#e6db74">&#34;JKHY&#34;</span>, <span style="color:#e6db74">&#34;JNJ&#34;</span>, <span style="color:#e6db74">&#34;JPM&#34;</span>, <span style="color:#e6db74">&#34;K&#34;</span>, <span style="color:#e6db74">&#34;KDP&#34;</span>, <span style="color:#e6db74">&#34;KEY&#34;</span>, <span style="color:#e6db74">&#34;KEYS&#34;</span>, <span style="color:#e6db74">&#34;KHC&#34;</span>, <span style="color:#e6db74">&#34;KIM&#34;</span>, <span style="color:#e6db74">&#34;KLAC&#34;</span>, <span style="color:#e6db74">&#34;KMB&#34;</span>, <span style="color:#e6db74">&#34;KMI&#34;</span>, <span style="color:#e6db74">&#34;KMX&#34;</span>, <span style="color:#e6db74">&#34;KO&#34;</span>, <span style="color:#e6db74">&#34;KR&#34;</span>, <span style="color:#e6db74">&#34;KVUE&#34;</span>, <span style="color:#e6db74">&#34;L&#34;</span>, <span style="color:#e6db74">&#34;LDOS&#34;</span>, <span style="color:#e6db74">&#34;LEN&#34;</span>, <span style="color:#e6db74">&#34;LH&#34;</span>, <span style="color:#e6db74">&#34;LHX&#34;</span>, <span style="color:#e6db74">&#34;LII&#34;</span>, <span style="color:#e6db74">&#34;LIN&#34;</span>, <span style="color:#e6db74">&#34;LKQ&#34;</span>, <span style="color:#e6db74">&#34;LLY&#34;</span>, <span style="color:#e6db74">&#34;LMT&#34;</span>, <span style="color:#e6db74">&#34;LNT&#34;</span>, <span style="color:#e6db74">&#34;LOW&#34;</span>, <span style="color:#e6db74">&#34;LRCX&#34;</span>, <span style="color:#e6db74">&#34;LULU&#34;</span>, <span style="color:#e6db74">&#34;LUV&#34;</span>, <span style="color:#e6db74">&#34;LVS&#34;</span>, <span style="color:#e6db74">&#34;LW&#34;</span>, <span style="color:#e6db74">&#34;LYB&#34;</span>, <span style="color:#e6db74">&#34;LYV&#34;</span>, <span style="color:#e6db74">&#34;MA&#34;</span>, <span style="color:#e6db74">&#34;MAA&#34;</span>, <span style="color:#e6db74">&#34;MAR&#34;</span>, <span style="color:#e6db74">&#34;MAS&#34;</span>, <span style="color:#e6db74">&#34;MCD&#34;</span>, <span style="color:#e6db74">&#34;MCHP&#34;</span>, <span style="color:#e6db74">&#34;MCK&#34;</span>, <span style="color:#e6db74">&#34;MCO&#34;</span>, <span style="color:#e6db74">&#34;MDLZ&#34;</span>, <span style="color:#e6db74">&#34;MDT&#34;</span>, <span style="color:#e6db74">&#34;MET&#34;</span>, <span style="color:#e6db74">&#34;META&#34;</span>, <span style="color:#e6db74">&#34;MGM&#34;</span>, <span style="color:#e6db74">&#34;MHK&#34;</span>, <span style="color:#e6db74">&#34;MKC&#34;</span>, <span style="color:#e6db74">&#34;MLM&#34;</span>, <span style="color:#e6db74">&#34;MMC&#34;</span>, <span style="color:#e6db74">&#34;MMM&#34;</span>, <span style="color:#e6db74">&#34;MNST&#34;</span>, <span style="color:#e6db74">&#34;MO&#34;</span>, <span style="color:#e6db74">&#34;MOH&#34;</span>, <span style="color:#e6db74">&#34;MOS&#34;</span>, <span style="color:#e6db74">&#34;MPC&#34;</span>, <span style="color:#e6db74">&#34;MPWR&#34;</span>, <span style="color:#e6db74">&#34;MRK&#34;</span>, <span style="color:#e6db74">&#34;MRNA&#34;</span>, <span style="color:#e6db74">&#34;MS&#34;</span>, <span style="color:#e6db74">&#34;MSCI&#34;</span>, <span style="color:#e6db74">&#34;MSFT&#34;</span>, <span style="color:#e6db74">&#34;MSI&#34;</span>, <span style="color:#e6db74">&#34;MTB&#34;</span>, <span style="color:#e6db74">&#34;MTD&#34;</span>, <span style="color:#e6db74">&#34;MU&#34;</span>, <span style="color:#e6db74">&#34;NDAQ&#34;</span>, <span style="color:#e6db74">&#34;NDSN&#34;</span>, <span style="color:#e6db74">&#34;NEE&#34;</span>, <span style="color:#e6db74">&#34;NEM&#34;</span>, <span style="color:#e6db74">&#34;NFLX&#34;</span>, <span style="color:#e6db74">&#34;NI&#34;</span>, <span style="color:#e6db74">&#34;NKE&#34;</span>, <span style="color:#e6db74">&#34;NOC&#34;</span>, <span style="color:#e6db74">&#34;NOW&#34;</span>, <span style="color:#e6db74">&#34;NRG&#34;</span>, <span style="color:#e6db74">&#34;NSC&#34;</span>, <span style="color:#e6db74">&#34;NTAP&#34;</span>, <span style="color:#e6db74">&#34;NTRS&#34;</span>, <span style="color:#e6db74">&#34;NUE&#34;</span>, <span style="color:#e6db74">&#34;NVDA&#34;</span>, <span style="color:#e6db74">&#34;NVR&#34;</span>, <span style="color:#e6db74">&#34;NWS&#34;</span>, <span style="color:#e6db74">&#34;NWSA&#34;</span>, <span style="color:#e6db74">&#34;NXPI&#34;</span>, <span style="color:#e6db74">&#34;O&#34;</span>, <span style="color:#e6db74">&#34;ODFL&#34;</span>, <span style="color:#e6db74">&#34;OKE&#34;</span>, <span style="color:#e6db74">&#34;OMC&#34;</span>, <span style="color:#e6db74">&#34;ON&#34;</span>, <span style="color:#e6db74">&#34;ORCL&#34;</span>, <span style="color:#e6db74">&#34;ORLY&#34;</span>, <span style="color:#e6db74">&#34;OTIS&#34;</span>, <span style="color:#e6db74">&#34;OXY&#34;</span>, <span style="color:#e6db74">&#34;PANW&#34;</span>, <span style="color:#e6db74">&#34;PARA&#34;</span>, <span style="color:#e6db74">&#34;PAYC&#34;</span>, <span style="color:#e6db74">&#34;PAYX&#34;</span>, <span style="color:#e6db74">&#34;PCAR&#34;</span>, <span style="color:#e6db74">&#34;PCG&#34;</span>, <span style="color:#e6db74">&#34;PEAK&#34;</span>, <span style="color:#e6db74">&#34;PEG&#34;</span>, <span style="color:#e6db74">&#34;PEP&#34;</span>, <span style="color:#e6db74">&#34;PFE&#34;</span>, <span style="color:#e6db74">&#34;PFG&#34;</span>, <span style="color:#e6db74">&#34;PG&#34;</span>, <span style="color:#e6db74">&#34;PGR&#34;</span>, <span style="color:#e6db74">&#34;PH&#34;</span>, <span style="color:#e6db74">&#34;PHM&#34;</span>, <span style="color:#e6db74">&#34;PKG&#34;</span>, <span style="color:#e6db74">&#34;PLD&#34;</span>, <span style="color:#e6db74">&#34;PLTR&#34;</span>, <span style="color:#e6db74">&#34;PM&#34;</span>, <span style="color:#e6db74">&#34;PNC&#34;</span>, <span style="color:#e6db74">&#34;PNR&#34;</span>, <span style="color:#e6db74">&#34;PNW&#34;</span>, <span style="color:#e6db74">&#34;PODD&#34;</span>, <span style="color:#e6db74">&#34;POOL&#34;</span>, <span style="color:#e6db74">&#34;PPG&#34;</span>, <span style="color:#e6db74">&#34;PPL&#34;</span>, <span style="color:#e6db74">&#34;PRU&#34;</span>, <span style="color:#e6db74">&#34;PSA&#34;</span>, <span style="color:#e6db74">&#34;PSX&#34;</span>, <span style="color:#e6db74">&#34;PTC&#34;</span>, <span style="color:#e6db74">&#34;PWR&#34;</span>, <span style="color:#e6db74">&#34;PYPL&#34;</span>, <span style="color:#e6db74">&#34;QCOM&#34;</span>, <span style="color:#e6db74">&#34;QRVO&#34;</span>, <span style="color:#e6db74">&#34;RCL&#34;</span>, <span style="color:#e6db74">&#34;REG&#34;</span>, <span style="color:#e6db74">&#34;REGN&#34;</span>, <span style="color:#e6db74">&#34;RF&#34;</span>, <span style="color:#e6db74">&#34;RHI&#34;</span>, <span style="color:#e6db74">&#34;RJF&#34;</span>, <span style="color:#e6db74">&#34;RL&#34;</span>, <span style="color:#e6db74">&#34;RMD&#34;</span>, <span style="color:#e6db74">&#34;ROK&#34;</span>, <span style="color:#e6db74">&#34;ROL&#34;</span>, <span style="color:#e6db74">&#34;ROP&#34;</span>, <span style="color:#e6db74">&#34;ROST&#34;</span>, <span style="color:#e6db74">&#34;RSG&#34;</span>, <span style="color:#e6db74">&#34;RTX&#34;</span>, <span style="color:#e6db74">&#34;RVTY&#34;</span>, <span style="color:#e6db74">&#34;SBAC&#34;</span>, <span style="color:#e6db74">&#34;SBUX&#34;</span>, <span style="color:#e6db74">&#34;SCHW&#34;</span>, <span style="color:#e6db74">&#34;SHW&#34;</span>, <span style="color:#e6db74">&#34;SJM&#34;</span>, <span style="color:#e6db74">&#34;SLB&#34;</span>, <span style="color:#e6db74">&#34;SMCI&#34;</span>, <span style="color:#e6db74">&#34;SNA&#34;</span>, <span style="color:#e6db74">&#34;SNPS&#34;</span>, <span style="color:#e6db74">&#34;SO&#34;</span>, <span style="color:#e6db74">&#34;SOLV&#34;</span>, <span style="color:#e6db74">&#34;SPG&#34;</span>, <span style="color:#e6db74">&#34;SPGI&#34;</span>, <span style="color:#e6db74">&#34;SRE&#34;</span>, <span style="color:#e6db74">&#34;STE&#34;</span>, <span style="color:#e6db74">&#34;STLD&#34;</span>, <span style="color:#e6db74">&#34;STT&#34;</span>, <span style="color:#e6db74">&#34;STX&#34;</span>, <span style="color:#e6db74">&#34;STZ&#34;</span>, <span style="color:#e6db74">&#34;SWK&#34;</span>, <span style="color:#e6db74">&#34;SWKS&#34;</span>, <span style="color:#e6db74">&#34;SYF&#34;</span>, <span style="color:#e6db74">&#34;SYK&#34;</span>, <span style="color:#e6db74">&#34;SYY&#34;</span>, <span style="color:#e6db74">&#34;T&#34;</span>, <span style="color:#e6db74">&#34;TAP&#34;</span>, <span style="color:#e6db74">&#34;TDG&#34;</span>, <span style="color:#e6db74">&#34;TDY&#34;</span>, <span style="color:#e6db74">&#34;TECH&#34;</span>, <span style="color:#e6db74">&#34;TEL&#34;</span>, <span style="color:#e6db74">&#34;TER&#34;</span>, <span style="color:#e6db74">&#34;TFC&#34;</span>, <span style="color:#e6db74">&#34;TFX&#34;</span>, <span style="color:#e6db74">&#34;TGT&#34;</span>, <span style="color:#e6db74">&#34;TJX&#34;</span>, <span style="color:#e6db74">&#34;TKO&#34;</span>, <span style="color:#e6db74">&#34;TMUS&#34;</span>, <span style="color:#e6db74">&#34;TMO&#34;</span>, <span style="color:#e6db74">&#34;TPR&#34;</span>, <span style="color:#e6db74">&#34;TRGP&#34;</span>, <span style="color:#e6db74">&#34;TRMB&#34;</span>, <span style="color:#e6db74">&#34;TROW&#34;</span>, <span style="color:#e6db74">&#34;TRV&#34;</span>, <span style="color:#e6db74">&#34;TSCO&#34;</span>, <span style="color:#e6db74">&#34;TSLA&#34;</span>, <span style="color:#e6db74">&#34;TSN&#34;</span>, <span style="color:#e6db74">&#34;TT&#34;</span>, <span style="color:#e6db74">&#34;TTWO&#34;</span>, <span style="color:#e6db74">&#34;TXN&#34;</span>, <span style="color:#e6db74">&#34;TXT&#34;</span>, <span style="color:#e6db74">&#34;TYL&#34;</span>, <span style="color:#e6db74">&#34;UAL&#34;</span>, <span style="color:#e6db74">&#34;UBER&#34;</span>, <span style="color:#e6db74">&#34;UDR&#34;</span>, <span style="color:#e6db74">&#34;UHS&#34;</span>, <span style="color:#e6db74">&#34;ULTA&#34;</span>, <span style="color:#e6db74">&#34;UNH&#34;</span>, <span style="color:#e6db74">&#34;UNP&#34;</span>, <span style="color:#e6db74">&#34;UPS&#34;</span>, <span style="color:#e6db74">&#34;URI&#34;</span>, <span style="color:#e6db74">&#34;USB&#34;</span>, <span style="color:#e6db74">&#34;V&#34;</span>, <span style="color:#e6db74">&#34;VFC&#34;</span>, <span style="color:#e6db74">&#34;VICI&#34;</span>, <span style="color:#e6db74">&#34;VLO&#34;</span>, <span style="color:#e6db74">&#34;VLTO&#34;</span>, <span style="color:#e6db74">&#34;VMC&#34;</span>, <span style="color:#e6db74">&#34;VRSK&#34;</span>, <span style="color:#e6db74">&#34;VRSN&#34;</span>, <span style="color:#e6db74">&#34;VRTX&#34;</span>, <span style="color:#e6db74">&#34;VST&#34;</span>, <span style="color:#e6db74">&#34;VTR&#34;</span>, <span style="color:#e6db74">&#34;VTRS&#34;</span>, <span style="color:#e6db74">&#34;VZ&#34;</span>, <span style="color:#e6db74">&#34;WAB&#34;</span>, <span style="color:#e6db74">&#34;WAT&#34;</span>, <span style="color:#e6db74">&#34;WBA&#34;</span>, <span style="color:#e6db74">&#34;WBD&#34;</span>, <span style="color:#e6db74">&#34;WDC&#34;</span>, <span style="color:#e6db74">&#34;WEC&#34;</span>, <span style="color:#e6db74">&#34;WELL&#34;</span>, <span style="color:#e6db74">&#34;WFC&#34;</span>, <span style="color:#e6db74">&#34;WHR&#34;</span>, <span style="color:#e6db74">&#34;WM&#34;</span>, <span style="color:#e6db74">&#34;WMB&#34;</span>, <span style="color:#e6db74">&#34;WMT&#34;</span>, <span style="color:#e6db74">&#34;WRB&#34;</span>, <span style="color:#e6db74">&#34;WST&#34;</span>, <span style="color:#e6db74">&#34;WTW&#34;</span>, <span style="color:#e6db74">&#34;WY&#34;</span>, <span style="color:#e6db74">&#34;WYNN&#34;</span>, <span style="color:#e6db74">&#34;XEL&#34;</span>, <span style="color:#e6db74">&#34;XOM&#34;</span>, <span style="color:#e6db74">&#34;XYL&#34;</span>, <span style="color:#e6db74">&#34;YUM&#34;</span>, <span style="color:#e6db74">&#34;ZBH&#34;</span>, <span style="color:#e6db74">&#34;ZBRA&#34;</span>, <span style="color:#e6db74">&#34;ZION&#34;</span>, <span style="color:#e6db74">&#34;ZTS&#34;</span>
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">get_financial_news</span>() <span style="color:#f92672">-&gt;</span> str:
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Fetches the latest financial news for ALL S&amp;P 500 companies from the last 24 hours.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Splits into two batches to stay within URL length limits.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    start_time <span style="color:#f92672">=</span> datetime<span style="color:#f92672">.</span>now() <span style="color:#f92672">-</span> timedelta(days<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Split tickers into two batches of approx 250 each</span>
</span></span><span style="display:flex;"><span>    mid <span style="color:#f92672">=</span> len(SP500_TICKERS) <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    batches <span style="color:#f92672">=</span> [SP500_TICKERS[:mid], SP500_TICKERS[mid:]]
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    all_formatted_news <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> batch <span style="color:#f92672">in</span> batches:
</span></span><span style="display:flex;"><span>        request_params <span style="color:#f92672">=</span> NewsRequest(
</span></span><span style="display:flex;"><span>            symbols<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;,&#34;</span><span style="color:#f92672">.</span>join(batch),
</span></span><span style="display:flex;"><span>            start<span style="color:#f92672">=</span>start_time,
</span></span><span style="display:flex;"><span>            limit<span style="color:#f92672">=</span><span style="color:#ae81ff">50</span>
</span></span><span style="display:flex;"><span>        )
</span></span><span style="display:flex;"><span>        time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">1</span>)  <span style="color:#75715e"># Rate-limit delay</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>            news_response <span style="color:#f92672">=</span> news_client<span style="color:#f92672">.</span>get_news(request_params)
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> article <span style="color:#f92672">in</span> news_response<span style="color:#f92672">.</span>data[<span style="color:#e6db74">&#39;news&#39;</span>]:
</span></span><span style="display:flex;"><span>                <span style="color:#75715e"># Focus on news stories specific to 1-3 symbols</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;=</span> len(article<span style="color:#f92672">.</span>symbols) <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">3</span>:
</span></span><span style="display:flex;"><span>                    symbols_str <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;, &#34;</span><span style="color:#f92672">.</span>join(article<span style="color:#f92672">.</span>symbols)
</span></span><span style="display:flex;"><span>                    all_formatted_news<span style="color:#f92672">.</span>append(
</span></span><span style="display:flex;"><span>                        <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Ticker(s): </span><span style="color:#e6db74">{</span>symbols_str<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Headline: </span><span style="color:#e6db74">{</span>article<span style="color:#f92672">.</span>headline<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Summary: </span><span style="color:#e6db74">{</span>article<span style="color:#f92672">.</span>summary<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#e6db74">&#34;---&#34;</span>
</span></span><span style="display:flex;"><span>                    )
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">except</span> <span style="color:#a6e22e">Exception</span> <span style="color:#66d9ef">as</span> e:
</span></span><span style="display:flex;"><span>            print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Error fetching news for batch: </span><span style="color:#e6db74">{</span>str(e)<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> all_formatted_news:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;No relevant single-stock news found for the S&amp;P 500 in the last 24 hours.&#34;</span>
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>join(all_formatted_news)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">get_portfolio_status</span>() <span style="color:#f92672">-&gt;</span> Dict[str, Any]:
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;&#34;&#34;Queries Alpaca for account status and open positions.&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    account <span style="color:#f92672">=</span> trading_client<span style="color:#f92672">.</span>get_account()
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    positions <span style="color:#f92672">=</span> trading_client<span style="color:#f92672">.</span>get_all_positions()
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    pos_list <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> p <span style="color:#f92672">in</span> positions:
</span></span><span style="display:flex;"><span>        pos_list<span style="color:#f92672">.</span>append({
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;symbol&#34;</span>: p<span style="color:#f92672">.</span>symbol,
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;qty&#34;</span>: float(p<span style="color:#f92672">.</span>qty),
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;market_value&#34;</span>: float(p<span style="color:#f92672">.</span>market_value),
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;current_price&#34;</span>: float(p<span style="color:#f92672">.</span>current_price)
</span></span><span style="display:flex;"><span>        })
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;available_cash&#34;</span>: float(account<span style="color:#f92672">.</span>cash),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;positions&#34;</span>: pos_list
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">get_latest_price</span>(symbol: str) <span style="color:#f92672">-&gt;</span> float:
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;&#34;&#34;Retrieves the most recent ask price for a specific ticker.&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    request_params <span style="color:#f92672">=</span> StockLatestQuoteRequest(symbol_or_symbols<span style="color:#f92672">=</span>symbol)
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    quote <span style="color:#f92672">=</span> stock_client<span style="color:#f92672">.</span>get_stock_latest_quote(request_params)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> float(quote[symbol]<span style="color:#f92672">.</span>ask_price)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">place_trade_order</span>(symbol: str, side: str, amount_usd: Optional[float] <span style="color:#f92672">=</span> <span style="color:#66d9ef">None</span>, qty: Optional[float] <span style="color:#f92672">=</span> <span style="color:#66d9ef">None</span>) <span style="color:#f92672">-&gt;</span> str:
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;&#34;&#34;Places a market order (fractional shares supported for buys).&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    side <span style="color:#f92672">=</span> side<span style="color:#f92672">.</span>lower()
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> side <span style="color:#f92672">not</span> <span style="color:#f92672">in</span> [<span style="color:#e6db74">&#39;buy&#39;</span>, <span style="color:#e6db74">&#39;sell&#39;</span>]:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;Error: Side must be &#39;buy&#39; or &#39;sell&#39;.&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    order_side <span style="color:#f92672">=</span> OrderSide<span style="color:#f92672">.</span>BUY <span style="color:#66d9ef">if</span> side <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;buy&#39;</span> <span style="color:#66d9ef">else</span> OrderSide<span style="color:#f92672">.</span>SELL
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> amount_usd <span style="color:#f92672">is</span> <span style="color:#f92672">not</span> <span style="color:#66d9ef">None</span> <span style="color:#f92672">and</span> side <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;buy&#39;</span>:
</span></span><span style="display:flex;"><span>            order_request <span style="color:#f92672">=</span> MarketOrderRequest(
</span></span><span style="display:flex;"><span>                symbol<span style="color:#f92672">=</span>symbol,
</span></span><span style="display:flex;"><span>                notional<span style="color:#f92672">=</span>amount_usd,
</span></span><span style="display:flex;"><span>                side<span style="color:#f92672">=</span>order_side,
</span></span><span style="display:flex;"><span>                time_in_force<span style="color:#f92672">=</span>TimeInForce<span style="color:#f92672">.</span>DAY
</span></span><span style="display:flex;"><span>            )
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">elif</span> qty <span style="color:#f92672">is</span> <span style="color:#f92672">not</span> <span style="color:#66d9ef">None</span>:
</span></span><span style="display:flex;"><span>            order_request <span style="color:#f92672">=</span> MarketOrderRequest(
</span></span><span style="display:flex;"><span>                symbol<span style="color:#f92672">=</span>symbol,
</span></span><span style="display:flex;"><span>                qty<span style="color:#f92672">=</span>qty,
</span></span><span style="display:flex;"><span>                side<span style="color:#f92672">=</span>order_side,
</span></span><span style="display:flex;"><span>                time_in_force<span style="color:#f92672">=</span>TimeInForce<span style="color:#f92672">.</span>GTC
</span></span><span style="display:flex;"><span>            )
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;Error: Either amount_usd (for buy) or qty (for sell/buy) must be provided.&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>        order <span style="color:#f92672">=</span> trading_client<span style="color:#f92672">.</span>submit_order(order_data<span style="color:#f92672">=</span>order_request)
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Success: </span><span style="color:#e6db74">{</span>side<span style="color:#f92672">.</span>upper()<span style="color:#e6db74">}</span><span style="color:#e6db74"> order placed for </span><span style="color:#e6db74">{</span>symbol<span style="color:#e6db74">}</span><span style="color:#e6db74">. Order ID: </span><span style="color:#e6db74">{</span>order<span style="color:#f92672">.</span>id<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span> <span style="color:#a6e22e">Exception</span> <span style="color:#66d9ef">as</span> e:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;Failed to place </span><span style="color:#e6db74">{</span>side<span style="color:#e6db74">}</span><span style="color:#e6db74"> order for </span><span style="color:#e6db74">{</span>symbol<span style="color:#e6db74">}</span><span style="color:#e6db74">: </span><span style="color:#e6db74">{</span>str(e)<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Define the Agent</span>
</span></span><span style="display:flex;"><span>root_agent <span style="color:#f92672">=</span> Agent(
</span></span><span style="display:flex;"><span>    name<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;TradingAgent&#34;</span>,
</span></span><span style="display:flex;"><span>    model<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;gemini-2.5-pro&#34;</span>,
</span></span><span style="display:flex;"><span>    instruction<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    You are a sophisticated stock trading AI agent using Gemini 2.5 Pro. Your mission is to execute a daily trading cycle based on news sentiment for the entire S&amp;P 500.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    FOLLOW THESE STEPS IN ORDER:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    1. NEWS LOOKUP: Call `get_financial_news()` to discover the latest news affecting any of the 500 S&amp;P companies.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    2. SENTIMENT ANALYSIS: 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Analyze the news for positive or negative sentiments using Gemini 2.5 Pro and assign a sentiment rating between -1.0 and 1.0.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - CRITICAL: Ignore Stock Analyst Rating changes; market news only.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - CRITICAL: Only consider news stories specific to 1-3 stocks.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Format your tracking of each analyzed story as: Primary ticker affected, news summary, score.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    3. PORTFOLIO QUERY: Call `get_portfolio_status()`.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    4. SELL PHASE:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - For every stock held: If sentiment score is NEGATIVE (&lt; 0), sell ALL shares.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - If no negative sentiment, do not sell.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    5. BUY PHASE:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Identify stocks NOT held that have **high confidence positive sentiments**.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Rank by positivity.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Create market BUY trades for EXACTLY $1000 of EACH of **up to 5** stocks with highest scores.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - Stop if available cash is less than $1000.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    6. FINAL REPORT:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       Produce a comprehensive summary:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - SUMMARY OF ORDERS: List all orders placed with ticker, action, score, and news summary.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       - MARKET SENTIMENT OVERVIEW: Top 10 Positive and Top 10 Negative news stories (Ticker, Summary, and Score).
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Execute the entire cycle once when prompted.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>    tools<span style="color:#f92672">=</span>[get_financial_news, get_portfolio_status, get_latest_price, place_trade_order]
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Wrap in AdkApp for execution</span>
</span></span><span style="display:flex;"><span>app <span style="color:#f92672">=</span> agent_engines<span style="color:#f92672">.</span>AdkApp(agent<span style="color:#f92672">=</span>root_agent)
</span></span></code></pre></td></tr></table>
</div>
</div><p><em><a href="https://github.com/WilliamDenniss/agent-examples/blob/master/01_TradingAgent/trading_agent/agent.py">agent.py</a></em></p>
  </div>
</details>


To run the agent locally, from the project folder (with the venv environment active, if you need: `source trading-env/bin/activate`):

```shell
adk run trading_agent
```

You’ll need to prompt it like “go” to kick off the analysis. ADK agents can be quiet while they “think”. To get some feedback, tail the logs and watch the tool-calling in real time:

```shell
tail -F /tmp/agents_log/agent.latest.log
```

As requested, it made 5 paper trades on my account that will execute on open.

And here’s the summary (from 2026-04-21):

```
[TradingAgent]: ## FINAL REPORT

### SUMMARY OF ORDERS

| Ticker | Action | Sentiment Score | News Summary |
|---|---|---|---|
| ADBE | BUY | 0.9 | Adobe announced a large $25 billion stock buyback plan. |
| UNH | BUY | 0.9 | UnitedHealth reported a strong Q1 beat and raised its profit outlook, causing the stock to jump. |
| GTLB | BUY | 0.8 | GitLab shares are rising after announcing a collaboration with Amazon Web Services. |
| ISRG | BUY | 0.8 | Intuitive Surgical reported a strong Q1 with a double beat on earnings and revenue. |
| IBM | BUY | 0.7 | Positive preview for IBM's Q1 earnings, with expectations of a sixth consecutive double beat, driven by AI momentum. |

### MARKET SENTIMENT OVERVIEW

#### Top 10 Positive Stories

| Ticker | Summary | Score |
|---|---|---|
| ADBE | Adobe Announces $25B Buyback Plan Through April 2030 | 0.9 |
| UNH | UnitedHealth Stock Jumps After Q1 Beat — Here's What Execs Say Drove It | 0.9 |
| GTLB | GitLab Stock Jumps After The Close: Here's Why | 0.8 |
| ISRG | Intuitive Surgical Delivers Q1 Double Beat: ISRG Earnings Highlights | 0.8 |
| IBM | IBM Q1 Preview: Dow Giant Goes For Six Straight Double Beats As AI Momentum Builds | 0.7 |
| CB | Chubb Q1 Adj. EPS $6.82 Beats $6.60 Estimate, Sales $11.716B Beat $11.687B Estimate | 0.7 |
| TMUS | UPDATE: 'Deutsche Telekom Weighs Full Combination With T-Mobile' - Bloomberg | 0.7 |
| BA | 'Boeing 737 Max 7, 10 Models on Track for 2026 Certification, FAA Says'- Bloomberg | 0.6 |
| COIN | Kalshi, Polymarket Announce Plans To Launch Crypto Perpetual Futures: Report | 0.6 |
| META | Meta Platforms Breaking Ground On $1B First Data Center In Oklahoma | 0.6 |

#### Top 10 Negative Stories

| Ticker | Summary | Score |
|---|---|---|
| COIN | New York Attorney General Sues Coinbase Over Prediction Markets: COIN Slides 6% | -0.9 |
| UAL | United Airlines Holdings Lowers FY2026 Adj EPS Guidance from $12.00-$14.00 to $7.00-$11.00 vs $9.96 Est | -0.9 |
| COF | Capital One Misses Q1 Estimates — Stock Drops | -0.8 |
| PRU | 'Prudential's Japan operations suspected of fraud at Gibraltar Life unit'- Nikkei Asia | -0.8 |
| GM | 'GM suspends next-gen electric trucks amid pivot back to gas engines, hybrids'- Crain's Detroit Business | -0.7 |
| TSLA | Tesla California Sales Fall 24% In Q1 Despite Model Y Leading EV Sales | -0.7 |
| UAL | United Airlines Stock Slips As Softer 2026 Outlook Overshadows Q1 Earnings Beat | -0.7 |
| BX | Blackstone's Private Credit Fund Slashes Value Of ACI Group Holdings | -0.6 |
| COF | Capital One Financial Reveals March Domestic Credit Card Net Charge-Off Rate 5.09% | -0.5 |
| DHI | America's Largest Homebuilder D.R. Horton Says Affordability Is Hitting Housing Demand | -0.5 |
```


I built this after-hours, and the trades executed at open. Here’s where I stand at 1pm:

![My Alpaca paper-trading portfolio at 1pm](alpha-trades-1pm.png)

Alpaca allows for 3 paper trading accounts, so to “reset” you simply create a new account with the desired paper balance, get the new API keys and update your `.env` (after which you can delete the old paper account).

Next up, we can [deploy this agent to the cloud on Agent Platform](/ap/1-agent/1.2-deploy-to-ap-runtime/).

## The completed example

Here's the fully built example of the trading agent, ready to clone & run:

1\. Clone the repo:

```shell
git clone https://github.com/WilliamDenniss/agent-examples.git
cd agent-examples/01_TradingAgent
```

2\. Sign up for a free [Alpaca](https://alpaca.markets/) paper trading account and grab a [Google AI Studio](https://aistudio.google.com/app/api-keys) key, then put both in a `trading_agent/.env` file:

```shell
# Google AI Studio / Vertex AI Key for the ADK Agent
GOOGLE_API_KEY=your-key

# Alpaca Paper Trading Keys
APCA_API_KEY_ID=your-key-id
APCA_API_SECRET_KEY=your-key
```

Caution: Paper trades only—don’t point it at a real-money account!

3\. Set up a `venv` and install the deps:

```shell
python3 -m venv trading-env
source trading-env/bin/activate
pip install -r trading_agent/requirements.txt
```

4\. Run the agent:

```shell
adk run trading_agent
```

5\. Enter "go" or "trade" to kick it off.

6\. To deploy to Agent Platform runtime, run:

```shell
python deploy.py
```

View in the UI playground to kick off a remote trading session, or set the `RESOURCE_NAME`
environment variable, and trade via the CLI:

```shell
export RESOURCE_NAME=projects/.../locations/us-west1/reasoningEngines/...
./trade.sh
```

See [interacting with agent](/ap/1-agent/1.2-deploy-to-ap-runtime/#interacting-with-the-agent)
for how to trade with the deployed agent.

