Can an LLM Analyze Stocks? Only If the Context Has a Contract

Published Jul 28, 2026 · llmmarket-datareliability

In the previous post I listed five real failures from a market-analysis pipeline. The conclusion was that four of five had nothing to do with model choice — the model turned structured records into sentences correctly every time, and was correct about wrong inputs.

So the useful question is not which LLM. It is: what does the context have to guarantee before the model is allowed to write a sentence?

Here is the contract I ended up with.

Rule 1 — every field carries its provenance

A value in the context is never a bare number. It carries where it came from and when.

prev_close: 71_400
  source: daily_chart.stck_clpr
  as_of:  2026-07-27 (KST close)

This looks like overhead until the day two fields that mean different things collide. “Yesterday’s close” and “current price” are both a number of the same magnitude in the same currency. Without provenance, nothing in the pipeline can tell them apart — which is exactly how a gap direction ends up inverted.

The cheap version: prefix the key with the source (daily__prev_close, live__cur_price). You do not need a schema library to make a collision loud.

Rule 2 — completeness is a gate, not a field

The model never sees a partially-filled record. A record either satisfies its required set or it is dropped and counted.

REQUIRED = ("code", "cur_price", "prev_close", "volume")

ready  = [r for r in rows if all(r.get(k) is not None for k in REQUIRED)]
missing = len(rows) - len(ready)

Two things matter here.

Never default a missing value. get(key, 0) converts an absence into a claim. A price of zero is not “unknown,” it is a specific and wrong number, and any downstream formatter will render it as fact.

Report the drop count. If nine of ten records were dropped, the briefing needs to say so. Silence about what was excluded is how a pipeline degrades for weeks without anyone noticing.

Rule 3 — confidence is bounded by data quality

The failure that stuck with me most was a signal that read 0 KRW BUY (67%). The 67% came from indicator scores, which were fine. Nothing connected data completeness to confidence, so a record missing its price could still be reported at 67% conviction.

Confidence has to be the minimum of the model’s score and the data’s own quality:

quality = present_fields / len(REQUIRED)     # 0.0 .. 1.0
score   = min(indicator_score, quality)

If that seems crude — it is. It is also strictly better than the two numbers being unrelated, which was the previous state.

Rule 4 — external references are matched against a spec, not judged by plausibility

Any API path, TR code, field name, or symbol that the model produces gets checked against the provider’s specification file before it is used. Not reviewed for plausibility — matched, verbatim, as a string.

This is the check that catches fabricated infrastructure. The endpoint that cost me weeks of a dead feature looked exactly like the real ones: right prefix, right digit count, right URL shape. The only thing that distinguished it was that it did not appear in the spec workbook. A grep found that in a second; a code review never would have.

Rule 5 — the analysis path cannot write

The step that reads data and produces narrative gets read-only access to state. Writes belong to a separate, explicit step.

The reason is not tidiness. If analysis can write, then every exploratory run — every --dry-run, every reproduction of yesterday’s output — edits the dataset that tomorrow’s analysis will summarize. Contamination survives and gets averaged in. A crash would have been kinder.

The test that this actually holds: diff the state file before and after a dry run. If it differs by one byte, the flag is decoration.

What stays outside the model entirely

Some things should never be delegated to the model, regardless of how good it gets:

What is left for the model is what it is actually good at: turning a verified record set into readable prose, flagging which items are unusual relative to the rest, and phrasing uncertainty honestly.

That is a narrower job than “analyze stocks.” It is also the version that survives contact with production.

The boundary

This pipeline reads market data, computes indicators, and writes a briefing. It does not decide anything. The trading decisions are mine, made separately, and they stay out of what gets published here — partly because the strategy parameters are not the transferable part, and partly because the moment a system like this emits a recommendation, it needs a completely different set of guarantees than the ones above.

The engineering is the part worth sharing. The rest is not a content problem.


This describes the architecture of a data pipeline. It is not investment advice and not a recommendation to buy or sell any security.