Inspiration

Portfolio Watchdog

Inspiration

The idea started from a simple frustration: most "AI trading tools" out there are really just a machine learning model that spits out a label — BUY, SELL, or HOLD — when you ask it. That's not an agent, that's a classifier wearing a trenchcoat. There's no perception, no reasoning you can inspect, no autonomy — just a single forward pass through a model.

I have a genuine, ongoing interest in algorithmic trading and quantitative finance, and I'd previously built pattern-detection and backtesting tools in that space. But when the All Things Agentic Hackathon's Taskmaster track asked for something that "takes action, not one that only writes text" and "proves it can do the heavy lifting for you," it reframed the whole problem for me. The interesting challenge wasn't "can I predict a stock price" — it's "can I build something that genuinely perceives an environment, reasons about what it sees, decides on its own, and explains itself the whole way through." Portfolio Watchdog is my answer to that: an autonomous agent that watches a stock watchlist, reasons over what it finds using Gemini, and acts — with every single decision logged and explained, so nothing it does is a black box.

What it does

Portfolio Watchdog monitors five stocks (AAPL, MSFT, GOOGL, TSLA, NVDA) on its own. For each one, it:

  1. Pulls real recent price data
  2. Detects classic candlestick patterns (engulfing, hammer, doji, shooting star) using hand-written rules — fully transparent, no black-box classifier
  3. Hands the price action and detected patterns to Gemini 3.5, which reasons over the evidence and returns a structured decision — BUY, SELL, or HOLD — along with a confidence score and a written explanation grounded in the actual data it was given
  4. Executes a simulated trade based on that decision
  5. Logs everything — decision, confidence, reasoning, and the underlying evidence — to a persistent record A dashboard shows this all happening live: the portfolio's simulated cash and positions, each ticker's current state, and a decision log where the agent's reasoning is front and center, not hidden behind a click.

How we built it

The backend is Python and FastAPI, chosen because the financial-data ecosystem (yfinance, pandas) is Python-first, and Google's GenAI SDK has strong, well-documented Python support. Each responsibility lives in its own file — data fetching, pattern detection, the Gemini reasoning call, and trade execution/logging are fully decoupled, so a failure in one (say, a flaky data fetch for one ticker) never takes down the rest of a monitoring cycle.

For the agent's reasoning core, we use the Gemini API via the official google-genai Python SDK, calling gemini-3.5-flash with a forced JSON response schema — this guarantees a structured, parseable decision every time, rather than hoping the model formats its answer correctly. We deliberately chose the GenAI SDK over the more elaborate Agent Development Kit (ADK): both are valid, hackathon-approved agent frameworks, but given the tight solo timeline, the GenAI SDK let us build a genuinely agentic reasoning loop — perceive, reason, decide, act — without the added structural overhead of ADK's abstractions.

The whole thing is deployed on Cloud Run, satisfying the Google Cloud infrastructure requirement, with a minimum instance count kept warm so a built-in scheduler can run monitoring cycles automatically during market hours, not just when a human clicks a button.

The frontend went through real iteration. We used Google Stitch to generate the dashboard's visual design — a dark, terminal-style aesthetic — then wired it to real backend data with vanilla JavaScript fetch() calls, replacing every placeholder number with a live value pulled from the agent's actual state.

What we learned

Autonomy and financial rigor are different axes, and it's worth being honest about which one you're optimizing for. Candlestick patterns over a short price window are not, by themselves, a rigorous trading edge — a real analyst would bring far more context (fundamentals, sector trends, news, longer time horizons). We learned to be clear-eyed about this rather than oversell it: the project's value isn't in generating alpha, it's in demonstrating a genuinely autonomous, transparent, explainable agent loop. Once we reframed the goal that way, decisions about scope (five tickers, five simple patterns, a forced reasoning schema) made a lot more sense.

Forcing structured output changes everything about building with an LLM. Early on, we considered just asking Gemini to "respond in JSON" in plain language — but committing to the SDK's actual schema-enforcement feature meant we never had to write brittle parsing logic or handle malformed responses. It also meant we could safely automate trade execution directly from the model's output, since the shape of that output was guaranteed.

Free-tier API quotas are a real constraint worth designing around, not just tolerating. We hit Gemini's free-tier daily request cap during active development and testing. Rather than upgrading to a paid tier, we built automatic key rotation across multiple API keys, switching only on actual quota-exhaustion errors (never on unrelated failures like auth or network issues) — a small piece of engineering that made iterative development sustainable without adding billing risk.

A UI is not "done" when it looks good — it's done when every number on the screen is real. We went through more than one visual redesign of the dashboard, and each time, the harder and more important work wasn't picking colors or fonts, it was systematically replacing every hardcoded placeholder value with a live call to a real backend endpoint, and handling the case where that endpoint is unreachable.

Challenges we faced

A single unclosed HTML <script> tag disabled the entire frontend. One stray tag caused a JavaScript parse error that silently killed every function in the app — the page rendered perfectly and did nothing at all. It was a reminder that a parse-time failure in JavaScript doesn't degrade gracefully; it takes out the whole file, and the smallest defects can have the largest blast radius.

Understanding exactly how Gemini's free-tier rate limit worked took real investigation. The limit is per-project and per-day, not per-key — meaning generating additional keys within the same project doesn't multiply your quota on its own. Once we understood the actual mechanism, we designed key rotation around genuinely separate keys (still within the free tier, deliberately not upgrading to paid) rather than a workaround that wouldn't have worked at all.

Cloud Run's stateless, scale-to-zero-by-default model doesn't naturally support a background scheduler. A scheduled job that should run automatically at fixed market hours needs a warm, persistently running process — which conflicts with Cloud Run's default behavior of spinning containers down when idle. We addressed this by explicitly configuring a minimum instance count, accepting the small always-on cost in exchange for reliable, genuinely unattended autonomous operation — which is, after all, the entire point of the project.

Local development and cloud deployment are not the same environment, and assuming they are causes real bugs. Getting from "works on my machine" to "works on Cloud Run" surfaced real issues that never appeared locally: a hardcoded localhost API URL in the frontend, a frontend served by a separate process instead of the same container as the backend, and a SQLite database that resets on every cold start since Cloud Run's filesystem isn't persistent. Each of these needed a deliberate fix rather than being something we could ignore until deployment day.

Simplicity had to be defended against feature creep, again and again. Every layer of this project could have been made more sophisticated — more tickers, more patterns, a persistent cloud database from day one, a full agent framework instead of the lighter GenAI SDK. Given a genuinely tight solo timeline, the real skill wasn't building more, it was consistently choosing the smallest version of each piece that still honestly demonstrated the thing we set out to prove: an agent that watches, thinks, decides, and acts, and can show its work the whole way through.

What it does

How we built it

Challenges we ran into

Accomplishments that we're proud of

What we learned

What's next for Portfolio watchdog

Built With

Share this project:

Updates

Submission history