Why portfolio-level framing is a different problem
Every other use case built on Konseki data — chat answers, pre-trade context, morning briefings, signal explanations, earnings analysis — operates on one symbol at a time. The model receives one JSON response and reasons about one position. A portfolio risk scanner starts from the same per-symbol data, but the question it's answering is structurally different: not "what does history say about this position," but "where is risk concentrated across everything I hold, and how does it compare across positions."
That second question can't be answered by running the single-symbol case ten or twenty times and concatenating the output. A model given ten separate, unconnected JSON blobs and asked to "summarize portfolio risk" will tend to produce ten separate summaries stitched together, not a genuine cross-position comparison. Getting an actual portfolio-level narrative requires assembling the per-symbol data into a structure the model can compare across, before it ever starts generating prose.
What to pull from each holding
For a portfolio scanner, the fields that matter most are the ones built specifically for risk and confidence framing rather than the full distribution detail:
| Field | What it contributes to the comparison |
|---|---|
tags.risk / tags.reliability | For that holding's most relevant forward window. |
match_quality.quality_tag | How trustworthy the comparison set is. |
returns.max_adverse_excursion | The worst historical drawdown the setup has produced. |
evidence_count / diversity.score | How much weight the holding's signal should carry. |
This is a narrower slice than what a single-symbol use case would use. A chat assistant answering a question about one stock benefits from the full distribution and the pre-written commentary fields. A portfolio scanner comparing twenty holdings needs a compact, consistent set of fields per holding so the comparison is apples-to-apples — pulling the full commentary text for every holding would bloat the prompt with detail that doesn't help the model compare positions, only describe each one individually.
Structuring the aggregation
The practical pattern is to build a single structured object before the model call, not after. For each holding, extract the narrow field set above into a consistent shape, and assemble these into one array covering the full portfolio — not twenty separate API responses — as the model's input:
{
"symbol": "NVDA",
"risk": "high_tail",
"reliability": "high",
"quality_tag": "strong",
"max_adverse_excursion": -0.184,
"evidence_count": 62
This matters because it puts the comparison work where it belongs: in the data structure, not in the model's reasoning.
A model handed a clean array where each entry has the same fields can directly compare tags.risk across entries, identify which holdings carry high_tail risk, and rank by max_adverse_excursion — because the structure already makes those comparisons mechanical rather than something the model has to extract from prose buried in each individual response.
What the narrative should actually surface
A useful portfolio risk narrative isn't a position-by-position recap — that's information the holder likely already has. The value is in what only becomes visible once positions are compared: which holdings carry elevated tail risk relative to the rest of the portfolio, whether risk is concentrated in a few positions or spread evenly, which signals are well-supported versus thin and less trustworthy, and which positions show a comparison set that's less reliable than the others.
This is also where tags.reliability earns its place in the aggregation:
high_tail risk backed by a thin, low-diversity evidence set — closer to a coincidental statistical artifact than a known risk.high_tail risk backed by a reliable historical signal — a known, well-evidenced risk worth real attention.A portfolio narrative that treats both identically is giving the holder less useful information than one that distinguishes them.
Why this needs daily refresh, not a one-time snapshot
Portfolio risk composition changes as market conditions shift, even when the underlying holdings don't change. A symbol that showed moderate historical risk last week can show elevated risk this week, because the benchmark condition the engine is matching against has moved.
This is the same reason single-symbol Konseki data is recomputed daily rather than cached — and it applies with more force at the portfolio level, because a risk concentration that wasn't visible last week can emerge purely from how individual holdings' conditions shifted, not from any change to the portfolio itself.
A portfolio scanner built on this data is most useful run on a regular cadence — daily or whenever a position changes — rather than as a one-time analysis, since the value is in catching a shift in risk concentration before it becomes obvious from price action alone.