We are spending the day building trading bots with Claude Code and running them against the same simulated market, live, at the same time. Most hackathons end with a room arguing about which idea was best. This one ends with a leaderboard that has been on the wall since lunchtime.
You will work in teams of about three. In the morning you build and test against a practice market where nothing counts. At half past twelve the real market opens for one hour, and whatever your bot does in that hour is your score. In the afternoon every team gets five minutes to say what they tried, where Claude Code genuinely helped, and where it produced confident nonsense.
The point is not to produce a trading system anybody keeps. It is to spend a day using Claude Code hard, under time pressure, on a problem where being sloppy is immediately visible to everyone in the room.
Your team starts with 100,000 in cash and access to a market of seven companies, plus an index fund that holds all of them. Everyone starts with exactly the same thing.
A headline lands roughly every minute. Some genuinely move a company's share price. Many are noise. A few say the opposite of what they mean.
You build it with Claude Code during the day. Whether it works out what the news means, or just trades the price action, is entirely up to you.
That is the whole brief. There are no restrictions on how, no marks for elegance, and no judging panel. Your final balance is the result.
A team API key, 100,000 in cash, and an HTTP API that tells you prices, publishes news, and accepts orders. Plus a machine that can already talk to Claude.
A program that runs unattended for an hour: watching the market, deciding what is worth acting on, and placing orders. In any language you like, using whatever approach you think will win.
Cash plus the value of what you hold, at the moment the market closes. Nothing else counts, and nothing from the practice round carries over.
Worth separating two things that sound the same and are not. Everybody builds their bot with Claude Code - that is the point of the day. Whether the bot itself calls a model while it is running is a completely separate decision, and it is yours.
Your machine can already call Claude over the LiteLLM proxy. Your bot sends each headline as it arrives and gets back a judgement: which company this actually affects, in which direction, and how confident the model is. You then decide what to do with that in your own code.
Why bother: the news is where the largest moves come from, and the feed is written so that reading it properly is genuinely hard. This is the only route that gets at that directly.
Never call a model at all. Watch prices, spot moves as they begin, follow trends, fade overreactions, spread risk across names, size by volatility, use the index fund as a base position. Ordinary quantitative rules, written and tuned by you.
Why bother: it is testable, it is fast, it never hallucinates, and it keeps working when an API call times out. A well-tuned mechanical bot will beat a badly wired clever one every time.
Most teams will end up somewhere in between, and that is probably the right answer: mechanical rules for risk, sizing and exits, where you want predictability, and a model call for the one question that actually needs judgement. Whichever way you go, the logic you care about should stay in code you wrote and can test.
Your machine can already talk to Claude, through the same configuration Claude Code itself uses. There is nothing to install, no key to request, and no reason to try running a model locally: the sandbox has two cores and no graphics card. The exact code is in Building it below.
Ask it what a story means and how confident it is. Keep how much to risk, when to stay out and when to sell in code you wrote. Those are the rules you will want to change at 12:15, and you cannot change a rule that lives inside a paragraph of prose.
When a story that matters is published, the price does not jump instantly. There is a window where the market has not moved yet and you still can.
A bot that buys the instant any headline appears will be inside the window every time, and will still lose, because roughly half the stories it reacts to either mean nothing or mean the opposite of what they look like.
Some stories move a price 1%. Some move it 8%. Getting the direction right on the small ones and putting your whole account behind them, while nibbling at the big ones, is how you finish mid-table with a great hit rate.
If "good words mean buy" worked, this would be a typing race. Here are the four traps, with invented examples. None of these companies exist in your market.
Every story arrives with a source attached.
There is more than one source. They are not equally reliable, and nobody is going to
say which is which. Working that out is worth a surprising amount, and the only way
to find it is to keep track of what happened after each one.
Same style as the real feed, none of the real content. See how you do before you teach a machine to do it.
This map is the difference between guessing and reasoning. When a story lands on one company, the interesting question is often which other company it just moved.
The eighth instrument is ORB, the Orbis Market Index Fund. It is an ETF: it holds all seven companies above, weighted by size, and it has no news of its own. Its price is only ever the weighted performance of what it holds.
Every company is capped at 30% of your portfolio. ORB is not capped at all, because it is diversified by construction. You can put the entire account into it. Buying the index and doing nothing else is a legitimate strategy, and it is roughly the benchmark everyone else is trying to beat.
An index fund owns everything, and everything includes whichever company is quietly having the worst day of its life. ORB will not fall as far as a single name can, but it does not get to opt out either.
All of them are enforced by the server, so there is no arguing with any of them at 12:40.
Identical for every team. Your score at the end is cash plus whatever your holdings are worth.
No single company may be worth more than 30% of your portfolio when you buy. An order that would breach it is rejected, not trimmed. The index fund is the exception and has no cap at all.
You can only sell what you already hold. So bad news is only useful to you if you own the thing, which makes knowing when to get out as important as when to get in.
Every buy and every sell pays a small spread. Trade forty times on noise and you have handed back more than most teams make all hour.
Per team, not per person. Three people each running the bot share one budget. Polling harder is not a strategy.
One company will fall hard and fast during the live hour. You will not be told when or which. Decide now what your bot does when something it owns collapses.
This catches people out, so it is worth saying plainly. The 30% limit is applied at the moment an order is placed. If you buy right up to the cap and the price then rises, that position keeps growing as a share of your portfolio and nothing stops it. The server will never sell anything on your behalf. If you want to stay at 30%, you have to trim it yourself. In testing, a bot that repeatedly topped a winner up to the cap ended the hour with far more than 30% of its money in it, which was fine right up until it was not.
None of this is required and none of it is strategy advice. It is the set of things that, in testing, made the difference between a bot that traded all hour and a bot that was still being debugged at 12:50.
Before any strategy, any model call, any structure. Prove the key works, the order format is right, and you can see the result. Everything else is easier once something round-trips.
import httpx
API = httpx.Client(base_url="http://SERVER:3015",
headers={"X-API-Key": "tk_yourteamkey"}, timeout=10)
s = API.get("/snapshot").json()
print(s["state"], s["portfolio"]["cash"])
print(API.post("/order", json={"symbol": "NWL", "side": "buy", "quantity": 1}).json())
If that prints a fill, you are further along than you think. Open the inspector page in a browser next to it and watch the position appear.
The single highest-leverage thing you can do. Put a CLAUDE.md in your
project directory containing the constraints. Every Claude Code session in that folder
picks it up, so you stop re-explaining the market and it stops writing code that
breaks rules it was never told about.
# Trading bot for the Trading Floor Challenge ## Rules this code must never violate - Long only. Never sell more than we currently hold. - Max 30% of portfolio value in any one company, checked at order time. ORB is an index fund and is NOT capped. - 60 requests per minute per key, shared by the whole team. Poll GET /snapshot (one call), never four separate endpoints. - Quantities are positive whole numbers. - Use the server clock from the response, never local time. ## API Base URL: http://SERVER:3015 - full reference at /docs Do not invent endpoints. If unsure, check /docs first.
That last line matters more than it looks. The most common failure mode we saw was a confidently written client calling endpoints that do not exist.
"Write a function that takes a news item and returns the parsed JSON verdict from the model." Then: "Write a function that turns a verdict plus my portfolio into an order size, respecting the 30% cap." Then wire them together yourself. Each piece is small enough to read, and you can test it without the market open.
"Build me a trading bot for this API." You will get 300 plausible lines, it will be wrong in two places you cannot see, and you will spend the morning bisecting something you did not write. Under time pressure that is the expensive path.
Two more that pay off immediately: ask it to write you a replay harness that feeds saved news items through your logic with no server, so you can test decisions in a second instead of waiting for the market. And ask it to write the tests for your sizing function. Position sizing is where teams lose, and it is trivially unit-testable.
Skip this part if your bot is not going to read the news. Section 5 is the mechanical route.
Your machine already has credentials. Claude Code authenticates through a LiteLLM proxy using two environment variables that are already set, and your bot can reuse them exactly as they are. Nothing to install, nothing to request, no key to manage. This is an ordinary outbound HTTPS call, the same as everything else your bot does.
import os, json, anthropic
llm = anthropic.Anthropic(
base_url=os.environ["ANTHROPIC_BASE_URL"],
auth_token=os.environ["ANTHROPIC_AUTH_TOKEN"],
)
def assess(item, relationships):
r = llm.messages.create(
model="claude-haiku-4-5", # fast and cheap; you are in a loop
max_tokens=350,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content":
f"Company relationships:\n{relationships}\n\n"
f"Source: {item['source']}\n"
f"Headline: {item['headline']}\n"
f"Body: {item['body']}"}],
)
return json.loads(r.content[0].text)
claude-sonnet-5 and
claude-opus-5 are also available and are worth trying offline on
headlines you got wrong, but latency costs you window.Ask the model what a story implies, not what you should do. The buy or sell decision belongs in your code, where you can change it without re-reading a paragraph of English.
That surface wording is frequently the opposite of the real implication. That a story may move a company it never names, and here is the relationship map. That many stories move nothing and saying so is a valid answer. That being unsure is information you want back, not something to hide behind a confident number.
The affected symbol or symbols. Direction. A conviction from 0 to 1. An expected magnitude. And one short sentence of reasoning, which costs almost nothing and is the only thing that will make your debrief interesting.
Treat low conviction as a reason not to trade, rather than a reason to trade small. Those are different rules and they produce very different afternoons.
Entirely legitimate, and for a team that would rather write and tune rules than engineer prompts, probably the faster path to something that works. These are the angles this particular market actually offers. None of them require a single API call to a model.
This is the big one, and it is a direct consequence of how the market is built. A story does not move the price instantly: the move begins about 90 seconds later and then plays out over roughly two minutes. So a price that has just started moving decisively is very often a price that will keep moving in that direction for another minute or so. You do not need to know why. You only need to notice early and be confident it is a real move rather than noise.
The baseline wobble is small and constant; a news-driven move is larger and sustained. Those are statistically distinguishable, which means the whole problem can be posed as "is this move bigger than this instrument normally wobbles". Compute each name's normal variation over the session and treat anything well outside it as an event. Note the instruments genuinely differ: one of them is roughly twice as jumpy as the calmest.
The company map is published and machine readable. If one company starts moving hard on news, the companies connected to it very often move shortly afterwards. You can exploit that mechanically, without understanding a single word of the story: detect a decisive move in one name, then look at what depends on it.
Moves settle at a new level rather than continuing forever, so a price that has run a long way in two minutes is usually done running. Mean reversion works on the tail of a completed move. It works very badly on a move that has only just started, and catastrophically on a company that is genuinely in trouble. Know which you are looking at.
If you have no view on how big a move will be, let the instrument tell you. Smaller positions in the jumpy names, larger in the calm ones, so no single holding dominates your outcome. This alone puts you ahead of most teams, and it is about fifteen lines of code.
The index fund has no position cap, so you can park most of the account in it and trade actively around the edges with the rest. That way you are in the market earning whatever the market does, instead of sitting in cash while your bot decides what it thinks, and your active bets are what you are actually judged on.
Counting positive and negative words in the headline. It is the first thing everyone thinks of, it takes ten minutes to write, and the feed is specifically constructed to defeat it. In testing, a keyword bot finished below a bot that never traded at all. If you want to read the news, read it properly. If you do not want to read the news, trade the prices. Do not do the thing in between.
To be straight about the trade-off, with real numbers. We built the drift-follower described above and ran it against eight strategies through a full session. It finished fifth of eight at +1.5%. It beat sitting in cash, and it beat keyword matching by a wide margin. It also lost heavily to the bots that actually understood what the stories meant, which finished north of +20%, and it paid one of the largest spread bills on the board getting there, because following moves means trading often.
Take that as calibration rather than discouragement. Ours was a first attempt with guessed thresholds and no tuning, which is exactly what you would have by mid-morning, and a tuned one would do better. But the honest summary is that the news is where the large moves are, and a bot that never looks at it is leaving the biggest edge in the market on the table. The counterweight is equally real: a working mechanical bot beats a clever one that is still throwing exceptions at 12:45, and that is not a hypothetical either.
Route A only.
You have about 90 seconds from a story appearing to the price starting to move. A model call is a few seconds, which is comfortable for one headline and not comfortable for five. Stories do arrive in bursts.
If your loop analyses headlines one after another while blocking, a busy minute can push your last decision outside the window it was for. Options, in increasing order of effort: analyse in a background thread while the main loop keeps polling; do them concurrently; or triage first, cheaply, and only spend a model call on stories that mention something you hold or something you might buy.
A rejected order returns an error code with a 4xx, not an exception.
If you are not checking the status, your bot will happily believe it owns something
it never bought. Log every rejection loudly.
Your bot will crash at least once. The server remembers your positions, your bot
does not. On startup, read /portfolio and /orders and
believe those rather than anything you kept in memory, and do not re-analyse news
you already traded.
Three people each running the bot while debugging shares one budget of 60. You will hit it, blame the server, and lose twenty minutes. Agree who is running the live one.
The 30% limit is checked when you buy and never again. A winner that keeps winning quietly becomes half your account. If you care about staying at 30%, you have to trim it yourself.
Three people cannot productively edit one file, and the morning is short. A split that works, because the interfaces between these are small and obvious:
Build these in order and stop wherever the clock runs out. Every rung is a working bot, which is the point: at no stage are you holding a half-finished one.
Polls the market, places one hardcoded order, prints the portfolio. Ten minutes. You now have something that cannot fail at 12:30 for a boring reason.
Polls /snapshot and acts on something. Route A: send each new
headline to the model, buy a fixed amount on a positive verdict, sell on a negative
one. Route B: detect a decisive move against that instrument's normal wobble and
follow it. Either one, at fixed size, will already beat several teams.
Position size scaled by conviction and expected magnitude. A stop loss and a take profit. Stops opening new positions near the close. This is where the leaderboard starts to separate, and it is mostly arithmetic rather than cleverness.
Keeps state per company rather than treating every signal as fresh, so new information about something you already hold makes you re-evaluate rather than just stacking another position on top. Route A adds source weighting and story arcs. Route B adds the relationship map and reacting to what a move implies for connected names. This is the bot that wins.
Every decision, with the headline, the model's verdict, its one-sentence reasoning, what you did, and what the price did next. It costs one line of code. It is how you will find the trade where the model was fluent, specific and completely wrong, and that trade is the most interesting thing you will have to say in the debrief.
What the game is, how the API works, and your team's key.
Real API, fake money, nothing scored. This is where you find out that your order format is wrong and that you hit the rate limit in ninety seconds. Much cheaper to learn now. The practice news is completely different from the afternoon's, so there is nothing to memorise.
Balances reset. Nothing from the morning carries over.
The real run, leaderboard on the big screen the whole time. Somewhere in the middle, the shock hits.
Orders stop being accepted. Your balance at that instant is your score.
Five minutes per team: what your strategy was, where Claude Code genuinely helped, and where it produced confident nonsense. This is usually the best part of the day.
Is this signal real, is it noise, and which company does it actually touch? Whether you answer that by reading the story or by measuring the price, everything downstream depends on getting it right.
A story worth 1% and a story worth 8% should not get the same amount of your money. Teams that read the market best and still lose almost always lost here.
Knowing when to sell, when to sit out entirely, and what to do when something you own falls off a cliff. Staying in cash is a decision, not an absence of one.
Trading every headline. Roughly half of them mean nothing. The spread quietly eats you while your hit rate looks respectable.
Going all in on one conviction. The cap stops the worst of it, but a maxed position in the wrong name when the shock lands is a very bad afternoon.
Buying and then not reading. Stories come in sequences. The thing that made you buy at 12:40 can be undone at 12:55, and only if you are still watching will you notice.
Trusting the headline. The body text is where the actual information is. Every trap in this game is sprung on someone who only read the first line.
Treating a denial as an answer. A company rejecting an allegation is not the same as the allegation being false, and a company that has reassured you three times has still only ever reassured you. Ask what would have to be true, and whether anything published so far actually establishes it.
Letting a winner become the whole account. The best performer in the market is the best performer right up until the moment it is the story instead. Size is a decision you have to keep making, not one you make once.
--no-llm
and it becomes a skeleton for a mechanical bot instead. It is deliberately mediocre
either way, so there is plenty to beat.