Skip to content

SPECIFICATION

A common spine for investment research.

The research object is a standardized JSON schema. Every note an analyst writes - on a single name, a sector, a factor, or a macro theme - resolves to the same eight fields, so a research engine can read, compare, and stress every view through one shape.

8
required fields
5
entity types, one shape
JSON
Schema 2020-12
0
free-text-only notes

THE SPINE

Eight fields, one object

Three families of information - what the entity is, what the analyst thinks, and how it behaves - collapse into a single record the engine can index.

Identity & quant
entity_namewho or what
entity_typethe lens
factor_exposuressigned loadings
peer_setcomparables
typeResearchObject
View & forward
thesisthe argument
catalystsdated events
risk_flagswarnings
regime_sensitivitymacro behavior

SCHEMA

The full definition

The same contract, two ways to consume it. Use the TypeScript interfaces in application code, or the JSON Schema to validate documents at the boundary.

typescriptresearch-object.ts
/** The common spine every research note resolves to. */export interface ResearchObject {  /** Canonical, human-readable name of the subject. */  entity_name: string;   /** Single name, sector, factor, theme, or basket. */  entity_type: EntityType;   /** Signed z-score loadings on the return-driving factors. */  factor_exposures: FactorExposure[];   /** Discrete, machine-readable warnings on the position. */  risk_flags: RiskFlag[];   /** The core argument: direction, conviction, horizon. */  thesis: Thesis;   /** Dated events that resolve the thesis. */  catalysts: Catalyst[];   /** Comparables and the basis for each comparison. */  peer_set: Peer[];   /** Expected behavior across named macro regimes. */  regime_sensitivity: RegimeSensitivity[];} export type EntityType =  | "issuer" | "sector" | "factor" | "theme" | "basket"; export interface FactorExposure {  factor: string;       // e.g. "value", "momentum", "rates_beta"  z_score: number;      // universe-relative, signed  source?: string;      // model or provider} export interface RiskFlag {  kind: RiskKind;  severity: Severity;  note?: string;} export interface Thesis {  direction: Direction;  conviction: Conviction;  horizon_months: number;  summary: string;  key_assumptions: string[];} export interface Catalyst {  label: string;  expected_date: string;   // ISO 8601 date  expected_direction: Direction;  impact: Severity;} export interface Peer {  entity: string;  relation: PeerRelation;} export interface RegimeSensitivity {  regime: string;       // e.g. "rising_rates", "risk_off"  stance: RegimeStance;  rationale?: string;}

FIELD REFERENCE

What each field means

Every field carries a definition and the reason it earns a place on the spine. Read these as the contract between the analyst who writes a note and the engine that consumes it.

01

entity_name

stringrequired

The display name of the entity the research object describes. Use the canonical issuer or instrument name so notes resolve to the same subject across analysts.

Why it is here. The join key analysts read. Pair it with a stable identifier in your own system so two notes about the same name never drift apart.

example
"NVIDIA Corporation"
02

entity_type

EntityTyperequired

A closed enum describing the class of subject: a single issuer, a sector, a factor, a macro theme, or a basket. One spine covers them all so a screen of single names and a thematic note speak the same language.

Why it is here. Drives how downstream consumers interpret the other fields. Factor exposures on an issuer mean something different than on a basket, and the type tells the reader which.

example
"issuer"
03

factor_exposures

FactorExposure[]required

The entity's loading on each style or risk factor, expressed as a z-score relative to the relevant universe. Positive is a tilt toward the factor, negative is away. This is the quantitative skeleton beneath the qualitative thesis.

Why it is here. Lets the engine net a name's exposures against the rest of the book and check that the thesis is not just an unintended factor bet in disguise.

example
[{ factor: "momentum", z_score: 1.4 }]
04

risk_flags

RiskFlag[]required

Structured warnings - liquidity, leverage, governance, concentration, event, regulatory - each with a severity and a one-line note. Distinct from the soft narrative of the thesis: these are the things that make risk sit up.

Why it is here. Aggregating flags across the book surfaces crowded risks no single note would reveal. Severity lets the engine sort and size accordingly.

example
[{ kind: "liquidity", severity: "medium" }]
05

thesis

Thesisrequired

The analyst's view in structured form - a direction (long, short, neutral), a conviction level, a time horizon, the summary argument, and the key assumptions it rests on. The qualitative heart of the object.

Why it is here. Keeping conviction and horizon as fields, not prose, lets the engine weight, decay, and review theses on schedule instead of letting them quietly go stale.

example
{ direction: "long", conviction: "high" }
06

catalysts

Catalyst[]required

The forward events - earnings, product launches, policy decisions, refinancings - that should validate or break the thesis, each with an expected date, an expected direction, and an estimated impact.

Why it is here. Turns a thesis into something testable on a calendar. The engine can rank the book by what is about to happen and review what already did.

example
[{ label: "Q4 earnings", date: "2026-02-18" }]
07

peer_set

Peer[]required

The set of entities this one is measured against, with the relationship that justifies each pairing (direct competitor, supplier, substitute, index member). Comparison is how relative value gets made.

Why it is here. Defines the universe for relative ranking and pairs. A long is only as good as the short it is funded against, and the peer set names the candidates.

example
[{ entity: "AMD", relation: "competitor" }]
08

regime_sensitivity

RegimeSensitivity[]required

Expected behavior under named macro regimes - rising rates, risk-off, high inflation, expansion - scored from strong headwind to strong tailwind. The bridge from a single-name view to a portfolio that has to survive the cycle.

Why it is here. Lets the engine stress the whole book against a regime shift and find theses that all depend on the same macro bet without anyone deciding to make it.

example
[{ regime: "rising_rates", stance: "headwind" }]

ENUMERATIONS

Closed value sets

The fields that drive engine behavior are constrained to fixed vocabularies, not free text - so sorting, scoring, and aggregation stay consistent across every note.

EntityType

The class of subject the object describes.

issuersectorfactorthemebasket
Direction

The directional stance of the thesis.

longshortneutral
Conviction

How strongly the view is held.

lowmediumhigh
Severity

Weight of a risk flag.

lowmediumhighcritical
RegimeStance

Expected behavior under a named regime.

strong_headwindheadwindneutraltailwindstrong_tailwind

WORKED EXAMPLE

A complete research object

A single long thesis, fully populated. Notice that nothing is prose-only: the conviction, the catalysts, and the regime stances are all structured for the engine to act on.

jsonnvda.research-object.json
{  "entity_name": "NVIDIA Corporation",  "entity_type": "issuer",  "factor_exposures": [    { "factor": "momentum", "z_score": 1.42 },    { "factor": "quality", "z_score": 0.88 },    { "factor": "value", "z_score": -1.15 }  ],  "risk_flags": [    { "kind": "concentration", "severity": "high",      "note": "Revenue concentrated in a few hyperscale buyers." },    { "kind": "valuation", "severity": "medium" }  ],  "thesis": {    "direction": "long",    "conviction": "high",    "horizon_months": 18,    "summary": "Accelerator demand outruns supply through the next"      "build-out cycle; margins hold above consensus.",    "key_assumptions": [      "Hyperscale capex grows double digits in 2026",      "No second-source displaces the software moat"    ]  },  "catalysts": [    { "label": "Q4 FY26 earnings", "expected_date": "2026-02-18",      "expected_direction": "long", "impact": "high" }  ],  "peer_set": [    { "entity": "Advanced Micro Devices", "relation": "competitor" },    { "entity": "Broadcom", "relation": "substitute" }  ],  "regime_sensitivity": [    { "regime": "rising_rates", "stance": "headwind" },    { "regime": "risk_off", "stance": "strong_headwind" },    { "regime": "expansion", "stance": "tailwind" }  ]}