How to Build a Free AI Premarket Analyst with Claude + Codex

This is the companion to my YouTube video

Every prompt I paste on camera is in this post, in a code block, ready to copy. No email required. Total reading time: about 10 minutes. Total setup time if you follow along: 30 to 45 minutes.

By the end you’ll have a free AI premarket analyst that:

  1. Designs the report first, so the AI fills in the same clean shape every single morning
  2. Gathers live market data for free with no API keys (movers, catalysts, levels, econ calendar)
  3. Runs your real backtested rules as pass or fail flags, so the AI never invents a pick
  4. Phones in a second, rival AI brain (OpenAI Codex) to fact check the first one, blind
  5. Merges the two without averaging them and emails you the finished report before the open

This is the third video in my AI trading series, and it is the free, no-broker-needed entry point. Parts 1 and 2 are linked at the bottom.


One honest disclaimer before we start

Building this does not make you a trader. This is decision support, not signals. The rules pick the watchlist, the two AIs judge quality, and you are still the one who makes the trade.

AI is just slop without real trading knowledge behind it. AI is a multiplier. I might be bad at math, but I know multiplying by zero is still zero. If your trading knowledge is zero, AI multiplies that into a whole lot of nothing. You need a real strategy first. Then AI becomes a tool to sharpen your edge instead of inventing nonsense.

I am also not a developer. I have no background in coding or tech. But I am a trader, and I am leveraging AI to automate my process. So if a non technical person like me can do this, so can you.


What you need

The whole point of this build is that it costs basically nothing to run. No data subscriptions, no scanners, no API bills.

ToolWhyCost
Claude CodeThe first AI brain, and the assistant that writes all the code for you.$20/mo Pro to start
OpenAI Codex CLIThe second, rival AI brain. Runs on a ChatGPT Plus plan.$20/mo (ChatGPT Plus)
yfinance, feedparser, requestsFree, keyless Python libraries for market data, news, and the econ calendar.Free
ResendFree email API to deliver the report to your inbox.Free tier
Discord webhook (optional)A free second channel to post the report into a Discord server.Free

If you already pay for Claude and ChatGPT, your marginal cost to run this every morning is zero.


The big idea (read this before you build)

Two ideas make this whole thing work.

First, design the report you want, then build backward toward it. Most people start with code. I start with the finished report. Once the shape exists, every step we build just fills in one piece of it. Same shape every morning, so I can read it in five seconds.

Second, two rival brains beat one confident one. AI hallucinates and makes careless mistakes. So we hand the exact same data to two different AIs from two different companies. They never see each other’s work. I only trust the names they both agree on. Where they disagree, that gap is the most valuable thing on the screen, and it tells me where to be careful.

Here is the whole machine:

REPORT_TEMPLATE.md  (the shape I want)
        |
scan.py  ->  packet.json  ->  Claude  -.
                            ->  Codex  -+->  merge  ->  REPORT.md  ->  HTML  ->  email + Discord

Pre-flight (about 2 minutes)

Open Terminal and make a fresh, empty project folder, then launch Claude Code inside it.

mkdir ~/Documents/premarket-analyst-demo && cd ~/Documents/premarket-analyst-demo && claude

💡 Don’t have Claude Code yet? Install it first with curl -fsSL https://claude.ai/install.sh | bash, sign in with a paid Claude account, then run claude --version to confirm.

Now your very first prompt. From here on, you live in Claude Code and just talk to it in plain English.Copy

Set this project up: create a Python virtual environment at .venv and install yfinance, feedparser, markdown, and requests. Then confirm they imported cleanly.

You should see: a .venv folder and a clean install.


Stage 1 — Design the report (the template)

Before anything else, I hand Claude the empty shell of my perfect premarket report. Every section I want, in order. This template is the north star. Every step after it just fills in a piece.

Here's the exact premarket report I want, the full section skeleton. Save it as REPORT_TEMPLATE.md and use it as the blueprint for the analyst and merge prompts we write later. Sections, in this order:
1. Title + dated subtitle (Claude + Codex, independent passes)
2. One-line disclaimer (rules pick the watchlist, both AIs judge quality, not financial advice)
3. Summary: the tape in one line + the catch we're watching + a one-line two-brain verdict
4. Pre-Market Gappers (each with its full catalyst headline)
5. Day Trading Watchlist (table: Ticker, Catalyst, Levels, Plan, Codex check, Conviction)
6. Swing Watchlist (table: Ticker, Catalyst, Trend context, Idea, Codex check, Conviction)
7. Market Trends of the Day
8. Technical Signals for Today
9. Economic Data, Rates and the Fed (from the econ calendar)
10. Coming Up (tomorrow's events + earnings)
11. Skips and Traps
12. Where the two brains landed (agreement, rules vs discretion, each brain's sharp catch)
Use a green/yellow/red conviction key. Casual Humbled Trader voice, no em dashes.

You should see: a REPORT_TEMPLATE.md with all 12 sections laid out as an empty skeleton. Most sections get filled by the scanner we build next. The Summary, Skips and Traps, and the two-brain section get filled by the AI layer in Stages 3 and 4.


Stage 2 — The gatherer (fill the data sections)

Now I build the part that fills the template’s data sections. First my validated rules, then one data collector that gathers everything and applies those rules as simple pass or fail flags. The code never has an opinion. That is the whole trick.

Step 2.1 — Write down your validated rules

Before the scanner, I give Claude my actual trading rules. These are backtested. The scanner encodes these, it does not make up its own. Don’t trade my setups? Delete them and paste your own. The whole thing molds to how you trade.Copy

You should see: a clean WATCHLIST_CRITERIA.md with both setups and the backtest stats.

💡 This is the difference between a useful tool and a toy. AI can only produce results as good as the input. Give it nothing, it hands you generic strategies. Give it your real edge, it sharpens it.

Step 2.2 — Build the gatherer (one big prompt)

This file has one job: gather data. No conviction, no buckets, no opinions. Gathering and thinking are two different jobs, and I keep them in two different places. And it is all free, no API keys.Copy

Now build the data gatherer: a single Python file scan.py that ONLY collects raw premarket data into one packet.json. It does ZERO analysis (no conviction, no buckets, no opinions). All judgment happens later in AI prompts. Keep the file small and copy-pasteable. Use only free, keyless libraries: yfinance, feedparser, and requests (zoneinfo is stdlib).

It must gather:

1) MARKET SNAPSHOT for these instruments (name -> yfinance symbol): S&P 500 ^GSPC, Dow ^DJI, Nasdaq ^IXIC, Russell 2000 ^RUT, VIX ^VIX, US 10Y ^TNX, US 3M ^IRX, WTI Oil CL=F, Dollar (DXY) DX-Y.NYB. For each: last, prev_close, change_pct from the last two daily closes.

2) LIVE TOP MOVERS via yfinance's keyless predefined screeners. Pull both "day_gainers" and "most_actives", dedupe by symbol, capture ticker, price, prev_close, gap_pct (regularMarketChangePercent), market_cap, volume, company name. If the live screener returns fewer than 5 names, fall back to a static UNIVERSE of large and active tickers (NVDA, AMD, AVGO, SMCI, MRVL, TSLA, AAPL, MSFT, META, AMZN, GOOGL, NFLX, DELL, SNOW, PLTR, COIN, MSTR, SOFI, RIVN, NIO, MARA, RIOT, BA, DIS, JPM, BAC, XOM, CVX, HOOD, UBER, CRWD, PANW, CELH, LULU, NKE, CAVA, DKNG, ARM, INTC, MU) computing gap from the last two daily closes. Record candidate_source so the packet says which path was used.

3) GAP FILTER: keep movers with absolute gap % >= 4 AND price >= $3, sort by absolute gap descending, keep the top 12.

4) MARKET-WIDE NEWS from free RSS via feedparser, these feeds: MarketWatch Top, MarketWatch RealTime, CNBC, Yahoo Finance, Google News Markets (markets/earnings, last 1 day). Strip HTML from summaries. Drop obvious SEO spam (titles matching "price prediction" or a "20xx-20xx" year range).

5) ECONOMIC CALENDAR (free, keyless): fetch US High-impact economic events for TODAY and TOMORROW (ET) from the ForexFactory data-partner this-week JSON feed at https://nfs.faireconomy.media/ff_calendar_thisweek.json. Keep only events where country is "USD" and impact is "High" (this captures data prints AND Fed events like FOMC and Powell). For each kept event record time_et, title, forecast, previous; split into today and tomorrow by ET date and sort each by time. Cache the raw weekly feed to a local dotfile with about a 4-hour TTL and a fetched_at timestamp, because the feed rate-limits (429) on rapid calls; if a live fetch fails, fall back to the last cached week and add a note. Be fully defensive: any failure returns an empty calendar with an error note, never raises. Put it in the packet under econ_calendar with source, filter, today_date, tomorrow_date, today, tomorrow.

6) PER-GAPPER ENRICHMENT:
- Catalyst headlines: combine yfinance per-ticker news with RSS headlines that match the ticker. Keep only headlines that name the ticker on a word boundary OR a DISTINCTIVE company-name token. Maintain a stopword list of generic company words (the, inc, corp, holdings, technologies, group, digital, applied, advanced, strategy, motors, energy, platforms, etc.) that must NOT match a company alone, because words like "Applied" cross-match unrelated firms. Rank primary publishers (Bloomberg, Reuters, CNBC, MarketWatch, Barron's, Yahoo Finance, WSJ, etc.) first. If nothing clean matches, set catalyst_found = false.
- Intraday levels from 5-min bars (prepost=True): VWAP, HOD, LOD, premarket high, premarket volume.
- Daily metrics from 1y of daily bars, excluding today's partial bar: 200-day SMA, prior-day high, prior close, today's open, 20-day average volume.
- RVOL = today's volume / 20-day average volume. Add a code comment that yfinance reports about 0 premarket volume, so a true premarket RVOL needs a premarket feed (e.g. Alpaca); full-day relative volume is the keyless stand-in.
- next earnings date.

7) DETERMINISTIC ELIGIBILITY FLAGS per gapper (these encode my validated rules from WATCHLIST_CRITERIA.md, computed in code, NOT by an AI):
- day_eligible = gap > 3 AND price > 3 AND market_cap > $1B AND rvol > 1.5 AND price > prior-day high
- swing_eligible = gap >= 8 AND price > 3 AND open > prior-day high AND open > 200-day SMA AND market_cap >= $800M AND a real catalyst exists

8) WRITE packet.json with these top-level keys: generated_at, candidate_source, trading_day_note, scan_params, criteria (plain-English description of both rule sets), market_snapshot, econ_calendar, gappers (each with all fields above plus the flags), market_news (top 20), and a gaps_to_fill list honestly noting what's missing (market-wide earnings only partial; intraday levels need intraday bars; premarket RVOL caveat).

Make it robust: wrap each network call so one bad ticker never crashes the run. Print progress to stdout as it goes. Do not use em dashes in comments or strings.

You should see: a single scan.py of roughly 300 to 400 lines, no extra files, no API keys.

💡 One prompt fills five sections of the template at once: the Pre-Market Gappers, the data behind the Day and Swing watchlists, Market Trends, Technical Signals, and Economic Data. Notice there is not one if bullish in here.

Step 2.3 — Run it and read the packet

Copy

Run scan.py with the project's virtual environment. When it finishes, summarize packet.json for me: how many gappers it found, how many US high-impact econ events it pulled for today, and on the first gapper show me the ticker plus the day_eligible, swing_eligible, and catalyst_found flags. Then open packet.json so I can scroll it.

You should see: progress lines, a WROTE packet.json line, and Claude’s summary of the flags. Those booleans are the rules talking. Everything after this is just two AIs reacting to this exact data.

💡 Honest heads up: some mornings the tape is quiet and the list is short. That is real, I am not going to fake a busy morning for the camera. If you want a fuller list for a demo, ask Claude to temporarily lower the gap filter to 2%.

Step 2.4 — (Optional) the catalyst-filter bug-fix beat

Naive keyword matching is a trap. A headline with the word “Applied” would tag three different companies. If Step 2.2 did not already nail the stopword list, harden it.Copy

Show me how scan.py matches a news headline to a ticker. Then harden it: a headline should only count as a catalyst if it names the ticker on a word boundary, or contains a DISTINCTIVE company-name token of 4+ letters. Generic words like "Applied", "Digital", "Holdings", "Technologies", "Strategy", "Energy", "Motors" must never match a company on their own, because they cross-match unrelated firms (for example "Applied" hitting both Applied Optoelectronics and Applied Digital). Add a NAME_STOP set for that and explain the fix in one comment.

You should see: a NAME_STOP set and word-boundary regex in scan.py, plus a short explanation. This is the unglamorous 10% that makes the difference.


Stage 3 — Two brains, independent passes

Now I hand the same packet to two different AIs from two different companies. Brain one is the Claude session I am already in. Brain two is OpenAI’s Codex, which I wire in so Claude can call it. They never see each other’s reasoning. The disagreement between them is the signal.

Step 3.1 — Bring Codex in as the second brain

First, a one-time setup in the terminal. Install OpenAI’s Codex CLI and log in with your ChatGPT plan.Copy

npm install -g @openai/codex
codex login

💡 On a ChatGPT Plus plan the second brain costs $0 marginal. This is the only paid-account step in the whole build besides Claude.

Then, back in Claude Code, build the little bridge between the two.Copy

Set up OpenAI's Codex CLI as my independent "second brain" that you can call from the shell. Create an executable shell script at ~/.claude/bin/codex-ask.sh that:
- takes a prompt as its first argument, or reads the prompt from stdin if no argument is given,
- runs: codex exec --skip-git-repo-check -s read-only -o <tmpfile> "$PROMPT" < /dev/null   (capturing its logs to a separate temp file),
- prints ONLY Codex's final answer (the contents of the output file) to stdout,
- if no answer came back, prints the captured log to stderr and exits 1.
Use set -uo pipefail and chmod +x it. Then test it by sending the one-line prompt "Reply with the single word: ready" through the wrapper and show me what Codex returns.

You should see: ~/.claude/bin/codex-ask.sh created and executable, and a test reply from Codex (for example “ready”).

🛠️ If it breaks: “command not found: codex” means the CLI is not installed or not on PATH, so install it and re-run codex login. An empty reply means you are not logged in, so run codex login again and re-test.

That little wrapper is the whole trick. Claude can run shell commands, so now Claude can hand the exact same data to Codex, in its own separate process, and read back an answer it had no part in writing. One brain is the Claude session I am in. The second brain is one shell command away. That is a real second opinion, not an echo.

Step 3.2 — Write both brain prompts and run them (one prompt)

Now both brains in one shot. I have Claude write the analyst prompt, write the rival’s prompt, then run both passes and show me the comparison.Copy

Build and run the two-brain layer in one go. Do all three:

A) Write prompt_claude.md, the "analyst" prompt that turns packet.json into a premarket report following REPORT_TEMPLATE.md. Instruct it to:
- Use ONLY packet data. Never invent catalysts, numbers, or headlines.
- Treat catalyst_found:false as a SKIP. Up on bad news (dilution, probe, miss) = TRAP.
- Build two watchlists from the precomputed flags: DAY = day_eligible:true, SWING = swing_eligible:true. A ticker can be on both. State the rule each flag encodes.
- For each DAY name, the entry plan from the live levels: break of premarket high and prior HOD in the 10:00am to 3:30pm ET window; stop 1% below PMH or LOD (= 1R); scale 1/3 at +1R, 1/3 at +2R, trail the last 1/3 on the 21-EMA; flat by 3:51pm; note price vs VWAP/PMH/HOD.
- For each SWING name, the full catalyst headline, the catalyst type, the theme, trend context (open vs 200d SMA and prior high), and a starter entry idea, management light.
- Score conviction by confluence: catalyst + macro fit + where price sits on the levels + whether the two brains agree.
- Output order: Summary; Pre-Market Gappers (full headlines); Day Trading Watchlist (table: Ticker | Catalyst | Levels | Plan | Conviction); Swing Watchlist (table: Ticker | Catalyst | Theme | Trend | Conviction); Market Trends; Technical Signals; Economic Data, Rates and the Fed (from econ_calendar.today, time ET + forecast vs previous; empty = light data day); Coming Up (econ_calendar.tomorrow + earnings); Skips and Traps.
- Voice: casual, witty, Humbled Trader, no em dashes.

B) Write prompt_codex.md, the INDEPENDENT second opinion that will run on OpenAI Codex (GPT-5.5). Tell it: it gets ONE input, packet.json; it has NOT seen anyone else's analysis and must not ask for it; form its own read. Per gapper: name the catalyst type (earnings/guidance > M&A > FDA > index inclusion > sympathy > analyst upgrade > none; catalyst_found false = skip); decide day vs swing vs skip; flag priced-in / sell-the-news; flag bad-news-green-candle traps; check macro fit vs the snapshot. Output: a one-line tape read, its own day and swing picks (ticker + one-line thesis + conviction), and skips/traps with why. Blunt, decisive, default to skepticism. End: trade where both agree, stand down or size down where they disagree, never average. No em dashes.

C) Now run the two independent passes on packet.json:
- Claude's view: follow prompt_claude.md against packet.json and write it to claude_view.md.
- Codex's view (independent, blind, its own process): run this in the shell and save to codex_view.md:
   { cat prompt_codex.md; echo; echo "=== INPUT: packet.json ==="; cat packet.json; } | ~/.claude/bin/codex-ask.sh > codex_view.md
Then show me the first 30 lines of each so we can compare them side by side.

You should see: four files appear (prompt_claude.md, prompt_codex.md, claude_view.md, codex_view.md), with the two views shown side by side.

💡 The smarts live in these plain-English prompt files, not in code. If you can write the paragraph, you can change the strategy. And the rival is told it is blind, because two calls to the same model just agree with themselves.

🛠️ If it breaks: an empty codex_view.md means the Codex wrapper failed. Re-test the wrapper from Step 3.1, or carry on single-brain and say so.


Stage 4 — The merge (the editor that never averages)

Most people would blend the two answers into mush. We do the opposite. Claude’s calls stay Claude’s, Codex’s stay Codex’s. Claude assembles everything into the template, and its whole job is to show me where they agree and where they fight.Copy

Build the merge step and run it, in one go.

First write prompt_merge.md (Claude as the editor). It receives THREE inputs: packet.json, claude_view.md, codex_view.md, and it fills in REPORT_TEMPLATE.md.
Hard rules: Claude's calls stay Claude's, Codex's stay Codex's. NEVER average or rewrite either side's conviction. Use only what is in the three inputs. No em dashes, Humbled Trader voice.
Conviction key: 🟢 HIGH only when both agree AND clean; 🟡 MED when they agree but extended/priced-in or one is lukewarm; 🔴 LOW/skip when they conflict.
Output exactly this structure:
1. H1: # 🧠 AI PREMARKET REPORT — Humbled Trader
2. H3 date line: ### <Day> <YYYY-MM-DD> · <run time ET> · Claude + Codex (GPT-5.5), independent passes
3. H3: ### Watchlists built by the rules: Day = Trend Join Long · Swing = gap-up + real catalyst
4. Blockquote disclaimer: deterministic criteria decide membership, both AIs judge quality, RVOL caveat if intraday, not financial advice.
5. ## Summary: tape backdrop + the catch we're watching + a one-line two-brain verdict.
6. ## 📊 Pre-Market Gappers: each with its full catalyst headline.
7. ## ☀️ Day Trading Watchlist: table Ticker | Catalyst | Levels (live) | Plan (Trend Join) | 🤖 Codex | Conv.
8. ## 📈 Notable Swing Watchlist: table Ticker | Catalyst (headline) | Trend context | Idea | 🤖 Codex | Conv.
9. ## 📉 Market Trends of the Day: bullets.
10. ## 📊 Technical Signals for Today: bullets.
11. ## 💰 Economic Data, Rates & the Fed: from econ_calendar.today (time ET + forecast vs previous) plus rates from the snapshot; empty today = light data day, econ_calendar.error = feed unavailable.
12. ## 📅 Coming Up: from econ_calendar.tomorrow (time ET) plus notable earnings from the gappers.
13. ## 🚫 Skips & Traps: failed screens or flagged by either brain, with why.
14. --- then ## 🤖 Where the two brains landed: Agreement (trade the overlap); Rules vs discretion (names Codex liked that the screen rejected, and why); each brain's sharp catch the other missed; closing line "trade where they agree; where they disagree, stand down or size down; never average."

Then immediately run it: follow prompt_merge.md using packet.json, claude_view.md, and codex_view.md, stamp the date line with today's date and the current time in ET, and write the result to REPORT.md. Never average the two brains. When done, show me the section headers.

You should see: prompt_merge.md and then REPORT.md, the full report ending in the “Where the two brains landed” section. That bottom section is the product. Trade the overlap. Stand down where they fight.

💡 The H1 title keeps an em dash because that is the literal title the report ships with. If you would rather honor the no-em-dash rule even there, tell Claude to swap the “—” for a “·” and it will carry through every report.


Stage 5 — Build the report page and email it

Turn the Markdown into a clean web page, then email it to your inbox. The email step skips cleanly if you have not set a key, so the pipeline never crashes on a missing config.

Step 5.1 — Build the HTML report and open it

Copy

Build render_report.py that turns the Markdown report into a clean, readable HTML page, then run it and open the result.
Usage: python render_report.py REPORT.md [YYYY-MM-DD]
- Convert Markdown to HTML using the markdown library with the tables, fenced_code, and sane_lists extensions.
- Style it simply and professionally: a plain header with the report title and the date, clear section headings, clean readable tables with a subtle header row and zebra striping, a comfortable reading font, max width about 900px, light background. Keep it neutral, no specific brand.
- Footer line: "Generated <timestamp> · Built by Claude + Codex · Educational only, not financial advice".
- Write the page to reports/premarket_<date>.html.
- Then run it on REPORT.md for today's date and open the generated HTML so I can see it.
Do not use em dashes.

You should see: render_report.py, a reports/ folder, and the clean report open in your browser. Same content, now it reads like a web page instead of a code dump.

Step 5.2 — Email it to your inbox with Resend

Step one, grab a free Resend account. Go to resend.com and sign up, no credit card needed. In the dashboard, go to API Keys, hit Create API Key, and copy it. It starts with “re_”. Treat it like a password.

Step two, one honest heads up about the sender. Out of the box, Resend lets you send from their sandbox address, onboarding@resend.dev. The catch is that the sandbox sender only delivers to the email address on your own Resend account. That is totally fine if you are emailing the report to yourself. If you ever want to send it to a different inbox, or make it come from your own domain so it looks legit, you verify a domain inside Resend by adding a couple of DNS records.

Step three, have Claude build the messenger.Copy

Build deliver.py that emails the HTML report to my inbox via Resend, then send it.
Usage: python deliver.py reports/premarket_<date>.html <YYYY-MM-DD>
- Read RESEND_API_KEY and EMAIL_TO from a local .env (a tiny KEY=VALUE parser, no extra dependency; real environment variables win over the file). Optional EMAIL_FROM (default "AI Premarket Analyst <onboarding@resend.dev>").
- Send the full HTML report inline as the email body, subject "AI Premarket Report — <date>" (POST https://api.resend.com/emails).
- If the keys are missing, print a clear "email skipped, set RESEND_API_KEY + EMAIL_TO" line and exit cleanly, never crash.
- Also create a .env.example with RESEND_API_KEY and EMAIL_TO, each with a one-line note on where to get it.
Then create my .env from .env.example so I can paste my key in.
Do not use em dashes.

Then open .env and paste in your RESEND_API_KEY and EMAIL_TO. Treat both like passwords, blur them on camera.

Back in Claude Code, run it:Copy

Now run deliver.py with today's report HTML in the reports folder and today's date. Show me the output.

You should see: [deliver] email sent to ..., and the report landing in your inbox.

🛠️ If it breaks: Resend’s free tier only delivers to the email on your Resend account, so use that address as EMAIL_TO for the demo, or verify a domain.

💡 Notice what the code does if the keys are missing: it prints “email skipped” and moves on. It does not crash the whole thing. That is exactly what you want when this runs unattended every morning.

Bonus — post it to Discord too (free, optional)

That same deliver.py can also drop the report into a Discord channel through a free webhook. In your Discord server, go to a channel’s settings, Integrations, Webhooks, New Webhook, and copy the URL. Then add one line to your .env:Copy

DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...

Have Claude wire it up:Copy

Add an optional Discord delivery channel to deliver.py: if DISCORD_WEBHOOK_URL is set in .env, also post the report to that Discord webhook. Discord has a 2000-character limit per message, so split the report into safe chunks (by section, then paragraph, then line, hard-wrapping anything still too long) and post them in order. If the webhook is not set, skip it cleanly. No em dashes.

💡 My community lives on Discord, so I have the report post there too. Totally optional, but it is free, so why not.


Automate it every morning (optional, after the video)

Wire the conductor to a morning schedule and the report just shows up before the open, before you have even had coffee.Copy

Write run.sh, a single conductor script that runs the whole pipeline in order: scan.py, then Claude's view and Codex's view in parallel (independent passes), then the merge into REPORT.md, then render_report.py, then deliver.py. Load delivery keys from .env. Use a lock file so two runs never overlap. Print a clear progress line for each stage. Then set it up to run automatically on weekday mornings before the US open.

⚠️ Honest caveat: scheduling this on a laptop is fiddly. If the Mac is asleep at the scheduled time the job can miss, and macOS privacy (Full Disk Access) can block a scheduled script from reading your Documents folder. If you want it bulletproof, the cleaner path is to run it on a small always-on cloud box or a free scheduled CI job instead of your laptop. I cover the laptop gotchas in the video.


A word from this video’s sponsor, Questrade

We just spent this whole build automating the boring, repetitive part of trading. Questrade’s custom indexing does the same thing for the long-term side of your portfolio, automatically rebalancing a personalized index so you are not babysitting it. And right now they are running a contest where you can enter to win seventy thousand dollars. Check it out: [QUESTRADE_LINK].


The honest part

Real talk, because I am not going to sell you a money printer.

This is decision support, not signals. The rules pick the watchlist, the two AIs judge quality, and I am the one who makes the trade. It is educational, not financial advice.

One honest limitation: yfinance reports almost no premarket volume, so the RVOL number is a full-day stand-in until you wire in a real premarket data feed (like Alpaca). The tool says so in its own disclaimer, and so do I. If you run this in the actual premarket window, your day watchlist may be thin for that reason. Running it during market hours fills the RVOL in properly.

The point of this is not to replace you. It is to kill the seventeen tabs and hand you a clean starting point in five seconds.


What’s next: the rest of the series

This premarket analyst tells you what to watch, but it does not pull the trigger. The rest of the series goes deeper:

  • Part 1, TradingView + Claude: build a premarket scanner and backtest a PineScript day-trading strategy. [VIDEO_1_LINK]
  • Part 2, IBKR + Claude: turn that backtested strategy into a bot that places its own orders, manages stops, and force-closes before the bell. [VIDEO_2_LINK]
  • Part 3 (this one): the free, no-broker-needed premarket analyst.

Watch them in order if you are starting fresh. AI cannot make you profitable. You still need a strategy. So if you want mine, start with Part 1.


FAQ

Do I need to know how to code? No. Every prompt above is plain English. Claude does the coding part.

Do I need a brokerage account or a paid data feed? No. This is the free entry point. Market data comes from keyless yfinance, news from free RSS, and the econ calendar from a free feed. The only paid pieces are the Claude and ChatGPT plans you may already have.

Why two different AIs instead of just asking Claude twice? Two calls to the same model tend to agree with themselves. A second model from a different company forms a genuinely independent read, so when they agree it actually means something.

Does this place trades for me? No. This pipeline scans, analyzes, and reports. Execution is a separate setup, covered in Part 2 (IBKR).

Is my data safe? Yes. Everything runs locally on your machine. The only things that leave your computer are the report email (via Resend) and the optional Discord post, both of which you control.

Why is the RVOL number weird in the premarket? yfinance reports almost no premarket volume, so true premarket RVOL needs a paid premarket feed. The full-day relative volume is the honest keyless stand-in, and the report flags it.

Can I use my own strategy instead of yours? Absolutely. Your rules live in a plain text file (WATCHLIST_CRITERIA.md) and the scanner encodes them. Delete mine, paste yours, and the whole pipeline molds to how you trade.

Can I use Gemini or another model as the second brain? Yes, in principle. The second brain is just a shell command (codex-ask.sh). Swap in any CLI that takes a prompt on stdin and returns text, and point the wrapper at it.


Get the tools

Get Claude →

Get ChatGPT Plus (for Codex) →

Resend (free email API) →

Enter the Questrade contest →


Want the next post in your inbox?

Every weekend I send a free watchlist of trade ideas built on these exact strategies. No charge. Join the newsletter →.

And if you want real-time community, daily trade reviews, and live chart sessions, check out the Humbled Trader Community. That is where I spend most of my time.


Not financial advice. Not affiliated with Anthropic, OpenAI, Resend, or Questrade. Educational only. Trade your own plan.

The post How to Build a Free AI Premarket Analyst with Claude + Codex appeared first on Humbled Trader.

admin