TradeObservationCreatedPayload trade.observation.created@1

Generated at from openvibe-contracts v0.34.2 and openvibe-sdk v0.5.0.

Version
1.0.0
Owner
trade
Visibility
first-party
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/events/payloads/trade.observation.created.v1.json

trade.observation.created v1 (OpenVibe.Trade server/domain/observations.js record). A market observation was recorded: one value a source stated for an instrument (metric, the decimal exactly as stated, unit, currency when monetary, period), when it was true per the source (observed_at), when the source was fetched (retrieved_at) and when Trade recorded it, with the source reference. Recorded by a feed service through POST /api/v1/observations (trade.observation.write) or by the Sources sync (server/domain/sync.js). Only on creation: a replay of the same (source_key, source_ref) sends nothing, and a different value under the same reference is refused. Written in the transaction that inserted the immutable row, together with the source's freshness update (trade.source.recovered|stale), alert evaluation (trade.alert.triggered) and the instrument's Search document. Leaves out the freshness verdict (computed at read time) and recorded_by (the envelope actor). Envelope: subject { type: observation, id }, visibility public, priority low, actor service:<recording service> (service:trade for the Sources sync). Information only, not investment advice.

Fields

FieldTypeRequiredDescriptionConstraints
instrumentobjectyes
  • no other fields
instrument.idstringyes
  • pattern ^ins_[0-9A-HJKMNP-TV-Z]{26}$
instrument.symbolstringyes
  • pattern ^[A-Z0-9][A-Z0-9.-]{0,15}$
idstringyes
  • pattern ^obs_[0-9A-HJKMNP-TV-Z]{26}$
metricstringyese.g. price.close, volume, us-gaap:Revenues.
  • pattern ^[A-Za-z][A-Za-z0-9_.:-]{0,79}$
valuestringyesThe decimal exactly as the source stated it (text, never rounded).
  • pattern ^-?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$
  • maxLength 64
unitstringyese.g. USD, shares, USD/shares.
  • pattern ^[A-Za-z][A-Za-z0-9/%._-]{0,19}$
currencystring | nullyesISO 4217 when the value is monetary; null otherwise.
  • pattern ^[A-Z]{3}$
periodstring | nullyesThe period the value covers when the source states one (e.g. a fiscal quarter).
  • minLength 1
  • maxLength 40
observed_atstringyesWhen the value was true, per the source.
  • format date-time
retrieved_atstringyesWhen the source was fetched.
  • format date-time
recorded_atstringyesWhen Trade recorded the row.
  • format date-time
max_age_secinteger | nullyesThe value's own maximum age, when the recorder gave one.
  • minimum 60
  • maximum 315360000
sourceobjectyes
  • no other fields
source.keystringyesOpenVibe.Sources source key.
  • pattern ^[a-z0-9][a-z0-9-]{1,63}$
source.item_idstring | nullyesThe Sources item the value came from, when there is one.
  • pattern ^itm_[0-9A-HJKMNP-TV-Z]{26}$
source.urlstring | nullyesThe source's page for the value (absolute http(s) URL, normalised).
  • pattern ^https?://
source.refstringyesThe source's own reference for this datum; unique per source_key.
  • minLength 1
  • maxLength 300

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: price-close
{
  "instrument": {
    "id": "ins_01JAB2C3D4E5F6G7H8J9K0MNPQ",
    "symbol": "ACME"
  },
  "id": "obs_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "metric": "price.close",
  "value": "10.50",
  "unit": "USD",
  "currency": "USD",
  "period": null,
  "observed_at": "2026-09-22T11:59:00.000Z",
  "retrieved_at": "2026-09-22T12:00:00.000Z",
  "recorded_at": "2026-09-22T12:00:03.412Z",
  "max_age_sec": null,
  "source": {
    "key": "test-feed",
    "item_id": null,
    "url": "https://example.org/acme/close",
    "ref": "r1"
  }
}
Valid: shares-outstanding
{
  "instrument": {
    "id": "ins_01JAB2C3D4E5F6G7H8J9K0MNPQ",
    "symbol": "ACME"
  },
  "id": "obs_01JAB2C3D4E5F6G7H8J9K0MNPS",
  "metric": "dei:EntityCommonStockSharesOutstanding",
  "value": "152300000",
  "unit": "shares",
  "currency": null,
  "period": "2026-06-30",
  "observed_at": "2026-06-30T00:00:00.000Z",
  "retrieved_at": "2026-09-23T03:10:00.000Z",
  "recorded_at": "2026-09-23T03:10:02.000Z",
  "max_age_sec": 7776000,
  "source": {
    "key": "sec-xbrl-filings",
    "item_id": "itm_01JAB2C3D4E5F6G7H8J9K0MNPT",
    "url": null,
    "ref": "0000000000-26-000123:dei:EntityCommonStockSharesOutstanding"
  }
}
Rejected: missing-observed-at
{
  "instrument": {
    "id": "ins_01JAB2C3D4E5F6G7H8J9K0MNPQ",
    "symbol": "ACME"
  },
  "id": "obs_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "metric": "price.close",
  "value": "10.50",
  "unit": "USD",
  "currency": "USD",
  "period": null,
  "retrieved_at": "2026-09-22T12:00:00.000Z",
  "recorded_at": "2026-09-22T12:00:03.412Z",
  "max_age_sec": null,
  "source": {
    "key": "test-feed",
    "item_id": null,
    "url": "https://example.org/acme/close",
    "ref": "r1"
  }
}
Rejected: numeric-value
{
  "instrument": {
    "id": "ins_01JAB2C3D4E5F6G7H8J9K0MNPQ",
    "symbol": "ACME"
  },
  "id": "obs_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "metric": "price.close",
  "value": 10.5,
  "unit": "USD",
  "currency": "USD",
  "period": null,
  "observed_at": "2026-09-22T11:59:00.000Z",
  "retrieved_at": "2026-09-22T12:00:00.000Z",
  "recorded_at": "2026-09-22T12:00:03.412Z",
  "max_age_sec": null,
  "source": {
    "key": "test-feed",
    "item_id": null,
    "url": "https://example.org/acme/close",
    "ref": "r1"
  }
}
Rejected: with-freshness
{
  "instrument": {
    "id": "ins_01JAB2C3D4E5F6G7H8J9K0MNPQ",
    "symbol": "ACME"
  },
  "id": "obs_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "metric": "price.close",
  "value": "10.50",
  "unit": "USD",
  "currency": "USD",
  "period": null,
  "observed_at": "2026-09-22T11:59:00.000Z",
  "retrieved_at": "2026-09-22T12:00:00.000Z",
  "recorded_at": "2026-09-22T12:00:03.412Z",
  "max_age_sec": null,
  "source": {
    "key": "test-feed",
    "item_id": null,
    "url": "https://example.org/acme/close",
    "ref": "r1"
  },
  "freshness": {
    "stale": false
  }
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('trade.observation.created@1', value);   // { valid, errors: [{ path, message }] }