fd-open-data-protocol 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/PKG-INFO +89 -3
  2. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/README.md +88 -2
  3. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol/__init__.py +1 -1
  4. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol/schema.py +84 -16
  5. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/concepts.yaml +230 -0
  6. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/crosswalks/datacommons-worldbank.yaml +51 -0
  7. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/entity_types.yaml +99 -0
  8. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/event_types.yaml +17 -0
  9. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/qualifiers.yaml +51 -0
  10. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/relation_types.yaml +73 -0
  11. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary/units.yaml +94 -0
  12. fd_open_data_protocol-0.3.0/fd_open_data_protocol/vocabulary.py +349 -0
  13. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol.egg-info/PKG-INFO +89 -3
  14. fd_open_data_protocol-0.3.0/fd_open_data_protocol.egg-info/SOURCES.txt +23 -0
  15. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/pyproject.toml +5 -0
  16. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/tests/test_loader.py +35 -0
  17. fd_open_data_protocol-0.3.0/tests/test_schema_vocabulary.py +86 -0
  18. fd_open_data_protocol-0.3.0/tests/test_vocabulary.py +186 -0
  19. fd_open_data_protocol-0.2.0/fd_open_data_protocol.egg-info/SOURCES.txt +0 -13
  20. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol/constants.py +0 -0
  21. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol/loader.py +0 -0
  22. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol/provider.py +0 -0
  23. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol.egg-info/dependency_links.txt +0 -0
  24. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol.egg-info/requires.txt +0 -0
  25. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/fd_open_data_protocol.egg-info/top_level.txt +0 -0
  26. {fd_open_data_protocol-0.2.0 → fd_open_data_protocol-0.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fd-open-data-protocol
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: The open-data datasource protocol: a manifest contract a datasource exposes to be ingested by fd-open-data-mcp (or any consumer).
5
5
  Author: FindDataOfficial
6
6
  License: MIT
@@ -99,7 +99,7 @@ my-source = "my_pkg.catalog:CATALOG"
99
99
  - **`DatasourceManifest`**: name, label, source_url, scanner_mode, ranking_seed, functions[], concepts[], entities[], entity_definitions[], relationships[], fetch.
100
100
  - **`FunctionSpec`**: command, category, description, parameters[], columns[], frequency, verified.
101
101
  - **`ColumnSpec`**: name, type, description, meaning, semantic_type, `frequency` + `datasource` (column-level).
102
- - **`ConceptHint`**: column, concept, `entity_type`, `measure`, unit, frequency, confidence.
102
+ - **`ConceptHint`**: column, concept, `entity_type`, `measure`, unit, frequency, confidence, `concept_family` (optional).
103
103
  - **`EntitySpec`**: entity_type, coverage ("universe"|"explicit"), codes[] (for explicit coverage).
104
104
  - **`Entity`**: entity_type, code, name_en, name_zh, metadata{}, relationships[].
105
105
  - **`EntityRelationship`**: target_entity_type, target_code, relation_type, confidence, metadata{}.
@@ -149,9 +149,33 @@ entity_definitions:
149
149
 
150
150
  When included, entities are registered in the ontology database during `register_datasource()`.
151
151
 
152
+ #### Reserved metadata key: `external_ids`
153
+
154
+ An entity definition may anchor itself in an external entity graph under the
155
+ reserved metadata key `external_ids`. Registration persists each entry as a
156
+ per-source identifier, so consumers can resolve the external id back to the
157
+ local entity.
158
+
159
+ ```yaml
160
+ entity_definitions:
161
+ - entity_type: country
162
+ code: CN
163
+ name_en: China
164
+ metadata:
165
+ external_ids:
166
+ wikidata: Q148 # Wikidata QID (Q followed by digits)
167
+ datacommons: country/CHN # Data Commons DCID
168
+ ```
169
+
170
+ Supported anchor sources are `wikidata` (QID, validated as `Q<digits>`) and
171
+ `datacommons` (non-empty DCID). A malformed or unknown anchor is logged and
172
+ skipped — it never fails registration.
173
+
152
174
  ### Canonical Entity Types
153
175
 
154
- All `entity_type` values must be from this vocabulary:
176
+ The entity-type vocabulary is defined by
177
+ [`fd_open_data_protocol/vocabulary/entity_types.yaml`](fd_open_data_protocol/vocabulary/entity_types.yaml)
178
+ (14 types) and is the authority for manifest validation:
155
179
 
156
180
  | Type | Description | Example IDs |
157
181
  |------|-------------|-------------|
@@ -165,7 +189,69 @@ All `entity_type` values must be from this vocabulary:
165
189
  | `crypto` | Cryptocurrencies | btc, eth |
166
190
  | `organization` | General orgs | org_code |
167
191
  | `industry` | Classifications | shenwan_1_01, gics_10 |
192
+ | `exchange` | Exchanges / venues | XNYS, XNAS, SSE |
168
193
  | `company` | Public companies | AAPL, TSLA |
194
+ | `commodity` | Raw goods | steel, oil, grain |
195
+ | `person` | Humans (fund managers) | person_code |
196
+
197
+ ## Semantic vocabulary
198
+
199
+ The protocol ships the publishable semantic core of FindData as versioned YAML
200
+ under [`fd_open_data_protocol/vocabulary/`](fd_open_data_protocol/vocabulary/):
201
+
202
+ | File | Registry |
203
+ |------|----------|
204
+ | `entity_types.yaml` | entity types (the manifest vocabulary above) |
205
+ | `concepts.yaml` | concept families + their seeded Variables |
206
+ | `qualifiers.yaml` | qualifiers (nominal_current, real_constant, ppp, per_capita, growth, ...) |
207
+ | `units.yaml` | units of measure (UN/CEFACT codes + ISO 4217 currencies) |
208
+ | `relation_types.yaml` | entity relationship types |
209
+ | `event_types.yaml` | event types (empty in this release) |
210
+ | `crosswalks/*.yaml` | Variable ↔ external-vocabulary assertions |
211
+
212
+ The vocabulary files ship as package data (`0.3.0`+), so `load_vocabulary()`
213
+ works from an installed wheel with no checkout on disk.
214
+
215
+ ```python
216
+ from fd_open_data_protocol.vocabulary import load_vocabulary, validate_vocabulary
217
+
218
+ vocab = load_vocabulary() # shipped files
219
+ vocab = load_vocabulary("/path/to/dir") # or an explicit directory
220
+ vocab.version # release version of the file set
221
+ vocab.get("concept", "GDP").uri # https://schema.finddata.tech/concept/GDP
222
+ vocab.entity_type_ids() # the manifest entity-type vocabulary
223
+ vocab.seeded_variables() # Variables a family declares
224
+ errors = validate_vocabulary() # [] when the file set is valid
225
+ ```
226
+
227
+ Every entry carries a stable URI of the form
228
+ `https://schema.finddata.tech/<kind>/<Id>`, where `<kind>` is one of
229
+ `entity-type`, `concept`, `qualifier`, `unit`, `relation-type`, `event-type`.
230
+
231
+ **Stability rules.** A URI is never reassigned to a different meaning and
232
+ entries are never deleted. Retirement is expressed with a `superseded_by`
233
+ pointer to the successor entry, which keeps the URI resolvable. The file set
234
+ carries one release `version`, and the loader rejects a file set whose files
235
+ disagree.
236
+
237
+ ## Concept families and Variables
238
+
239
+ Concepts are two-level. A **concept family** (`fd:GDP`, `fd:Population`) is the
240
+ small curated vocabulary from `concepts.yaml`; a **Variable** is the qualified
241
+ combination `(code, entity_type, measure, unit, frequency)` — the identity a
242
+ datasource actually binds columns to.
243
+
244
+ A manifest concept hint may point at its family with the optional
245
+ `concept_family` field, which the loader validates against `concepts.yaml`:
246
+
247
+ ```yaml
248
+ concepts:
249
+ - {column: close, concept: price.close, entity_type: stock, unit: currency,
250
+ frequency: daily, concept_family: PriceClose}
251
+ ```
252
+
253
+ Omitting it preserves the previous behaviour — no family validation occurs, and
254
+ the consumer derives a family from the concept code.
169
255
 
170
256
  ## Manifest Declaration Requirement
171
257
 
@@ -86,7 +86,7 @@ my-source = "my_pkg.catalog:CATALOG"
86
86
  - **`DatasourceManifest`**: name, label, source_url, scanner_mode, ranking_seed, functions[], concepts[], entities[], entity_definitions[], relationships[], fetch.
87
87
  - **`FunctionSpec`**: command, category, description, parameters[], columns[], frequency, verified.
88
88
  - **`ColumnSpec`**: name, type, description, meaning, semantic_type, `frequency` + `datasource` (column-level).
89
- - **`ConceptHint`**: column, concept, `entity_type`, `measure`, unit, frequency, confidence.
89
+ - **`ConceptHint`**: column, concept, `entity_type`, `measure`, unit, frequency, confidence, `concept_family` (optional).
90
90
  - **`EntitySpec`**: entity_type, coverage ("universe"|"explicit"), codes[] (for explicit coverage).
91
91
  - **`Entity`**: entity_type, code, name_en, name_zh, metadata{}, relationships[].
92
92
  - **`EntityRelationship`**: target_entity_type, target_code, relation_type, confidence, metadata{}.
@@ -136,9 +136,33 @@ entity_definitions:
136
136
 
137
137
  When included, entities are registered in the ontology database during `register_datasource()`.
138
138
 
139
+ #### Reserved metadata key: `external_ids`
140
+
141
+ An entity definition may anchor itself in an external entity graph under the
142
+ reserved metadata key `external_ids`. Registration persists each entry as a
143
+ per-source identifier, so consumers can resolve the external id back to the
144
+ local entity.
145
+
146
+ ```yaml
147
+ entity_definitions:
148
+ - entity_type: country
149
+ code: CN
150
+ name_en: China
151
+ metadata:
152
+ external_ids:
153
+ wikidata: Q148 # Wikidata QID (Q followed by digits)
154
+ datacommons: country/CHN # Data Commons DCID
155
+ ```
156
+
157
+ Supported anchor sources are `wikidata` (QID, validated as `Q<digits>`) and
158
+ `datacommons` (non-empty DCID). A malformed or unknown anchor is logged and
159
+ skipped — it never fails registration.
160
+
139
161
  ### Canonical Entity Types
140
162
 
141
- All `entity_type` values must be from this vocabulary:
163
+ The entity-type vocabulary is defined by
164
+ [`fd_open_data_protocol/vocabulary/entity_types.yaml`](fd_open_data_protocol/vocabulary/entity_types.yaml)
165
+ (14 types) and is the authority for manifest validation:
142
166
 
143
167
  | Type | Description | Example IDs |
144
168
  |------|-------------|-------------|
@@ -152,7 +176,69 @@ All `entity_type` values must be from this vocabulary:
152
176
  | `crypto` | Cryptocurrencies | btc, eth |
153
177
  | `organization` | General orgs | org_code |
154
178
  | `industry` | Classifications | shenwan_1_01, gics_10 |
179
+ | `exchange` | Exchanges / venues | XNYS, XNAS, SSE |
155
180
  | `company` | Public companies | AAPL, TSLA |
181
+ | `commodity` | Raw goods | steel, oil, grain |
182
+ | `person` | Humans (fund managers) | person_code |
183
+
184
+ ## Semantic vocabulary
185
+
186
+ The protocol ships the publishable semantic core of FindData as versioned YAML
187
+ under [`fd_open_data_protocol/vocabulary/`](fd_open_data_protocol/vocabulary/):
188
+
189
+ | File | Registry |
190
+ |------|----------|
191
+ | `entity_types.yaml` | entity types (the manifest vocabulary above) |
192
+ | `concepts.yaml` | concept families + their seeded Variables |
193
+ | `qualifiers.yaml` | qualifiers (nominal_current, real_constant, ppp, per_capita, growth, ...) |
194
+ | `units.yaml` | units of measure (UN/CEFACT codes + ISO 4217 currencies) |
195
+ | `relation_types.yaml` | entity relationship types |
196
+ | `event_types.yaml` | event types (empty in this release) |
197
+ | `crosswalks/*.yaml` | Variable ↔ external-vocabulary assertions |
198
+
199
+ The vocabulary files ship as package data (`0.3.0`+), so `load_vocabulary()`
200
+ works from an installed wheel with no checkout on disk.
201
+
202
+ ```python
203
+ from fd_open_data_protocol.vocabulary import load_vocabulary, validate_vocabulary
204
+
205
+ vocab = load_vocabulary() # shipped files
206
+ vocab = load_vocabulary("/path/to/dir") # or an explicit directory
207
+ vocab.version # release version of the file set
208
+ vocab.get("concept", "GDP").uri # https://schema.finddata.tech/concept/GDP
209
+ vocab.entity_type_ids() # the manifest entity-type vocabulary
210
+ vocab.seeded_variables() # Variables a family declares
211
+ errors = validate_vocabulary() # [] when the file set is valid
212
+ ```
213
+
214
+ Every entry carries a stable URI of the form
215
+ `https://schema.finddata.tech/<kind>/<Id>`, where `<kind>` is one of
216
+ `entity-type`, `concept`, `qualifier`, `unit`, `relation-type`, `event-type`.
217
+
218
+ **Stability rules.** A URI is never reassigned to a different meaning and
219
+ entries are never deleted. Retirement is expressed with a `superseded_by`
220
+ pointer to the successor entry, which keeps the URI resolvable. The file set
221
+ carries one release `version`, and the loader rejects a file set whose files
222
+ disagree.
223
+
224
+ ## Concept families and Variables
225
+
226
+ Concepts are two-level. A **concept family** (`fd:GDP`, `fd:Population`) is the
227
+ small curated vocabulary from `concepts.yaml`; a **Variable** is the qualified
228
+ combination `(code, entity_type, measure, unit, frequency)` — the identity a
229
+ datasource actually binds columns to.
230
+
231
+ A manifest concept hint may point at its family with the optional
232
+ `concept_family` field, which the loader validates against `concepts.yaml`:
233
+
234
+ ```yaml
235
+ concepts:
236
+ - {column: close, concept: price.close, entity_type: stock, unit: currency,
237
+ frequency: daily, concept_family: PriceClose}
238
+ ```
239
+
240
+ Omitting it preserves the previous behaviour — no family validation occurs, and
241
+ the consumer derives a family from the concept code.
156
242
 
157
243
  ## Manifest Declaration Requirement
158
244
 
@@ -5,4 +5,4 @@ concept hints + fetch reference) so that fd-open-data-mcp - or any consumer -
5
5
  can ingest it via ``register_datasource``. Ship one manifest file -> the
6
6
  datasource is added; no consumer-side wiring.
7
7
  """
8
- __version__ = "0.2.0"
8
+ __version__ = "0.3.0"
@@ -10,26 +10,70 @@ entity metadata (names, attributes, relationships) in the ontology database.
10
10
  """
11
11
  from __future__ import annotations
12
12
 
13
- from typing import Any, Optional
13
+ from functools import lru_cache
14
+ from typing import Any, Iterable, Optional
14
15
 
15
16
  from pydantic import BaseModel, Field, field_validator
16
17
 
17
18
 
18
- # Canonical entity type vocabulary - all entity_type values must be in this set
19
- ENTITY_TYPE_VOCABULARY: tuple[str, ...] = (
20
- "country", # ISO codes (CN, US, JP)
21
- "city", # Municipalities (beijing, shanghai)
22
- "stock", # A-shares (600000.SH, 000001.SZ)
23
- "fund", # ETFs/funds (etf_code, fund_code)
24
- "bond", # Bonds (bond_code)
25
- "index", # Indices (SH000001, SZ399001)
26
- "future", # Futures (cu2412, rb2401)
27
- "crypto", # Cryptocurrencies (btc, eth)
28
- "organization", # General organizations
29
- "industry", # Industry classifications (shenwan_1_01, gics_10)
30
- "exchange", # Securities exchanges / market venues (XNYS, XNAS, XASE)
31
- "company", # Public companies with sector (AAPL, TSLA)
32
- )
19
+ @lru_cache(maxsize=1)
20
+ def _concept_family_ids() -> frozenset[str]:
21
+ """Concept family ids from the shipped vocabulary (loaded once per process)."""
22
+ from fd_open_data_protocol.vocabulary import load_vocabulary
23
+
24
+ return frozenset(load_vocabulary().ids("concept"))
25
+
26
+
27
+ class _EntityTypeVocabulary:
28
+ """Lazy, file-sourced view of ``vocabulary/entity_types.yaml``.
29
+
30
+ Replaces the hardcoded tuple of entity types while keeping the public name
31
+ and the operations callers use (membership, iteration, ``len``, ``join``).
32
+ The file is read on first use, not at import time. An override can be
33
+ pinned for tests via :func:`set_entity_type_vocabulary`.
34
+ """
35
+
36
+ def __init__(self) -> None:
37
+ self._override: Optional[tuple[str, ...]] = None
38
+ self._cache: Optional[tuple[str, ...]] = None
39
+
40
+ def _values(self) -> tuple[str, ...]:
41
+ if self._override is not None:
42
+ return self._override
43
+ if self._cache is None:
44
+ from fd_open_data_protocol.vocabulary import load_vocabulary
45
+
46
+ self._cache = load_vocabulary().entity_type_ids()
47
+ return self._cache
48
+
49
+ def set(self, values: Optional[Iterable[str]] = None) -> None:
50
+ """Pin the vocabulary to ``values``, or reset to file-sourced when None."""
51
+ self._override = tuple(values) if values is not None else None
52
+
53
+ def __contains__(self, item: object) -> bool:
54
+ return item in self._values()
55
+
56
+ def __iter__(self):
57
+ return iter(self._values())
58
+
59
+ def __len__(self) -> int:
60
+ return len(self._values())
61
+
62
+ def __getitem__(self, index):
63
+ return self._values()[index]
64
+
65
+ def __repr__(self) -> str:
66
+ return repr(self._values())
67
+
68
+
69
+ # Canonical entity type vocabulary - all entity_type values must be in this set.
70
+ # Sourced from the shipped vocabulary file; see fd_open_data_protocol.vocabulary.
71
+ ENTITY_TYPE_VOCABULARY = _EntityTypeVocabulary()
72
+
73
+
74
+ def set_entity_type_vocabulary(values: Optional[Iterable[str]] = None) -> None:
75
+ """Test escape hatch: pin the entity-type vocabulary, or reset to file-sourced."""
76
+ ENTITY_TYPE_VOCABULARY.set(values)
33
77
 
34
78
 
35
79
  class EntityRelationship(BaseModel):
@@ -156,6 +200,9 @@ class ConceptHint(BaseModel):
156
200
  unit: Optional[str] = None
157
201
  frequency: Optional[str] = None
158
202
  confidence: float = 0.9
203
+ # Optional reference to a concept family in vocabulary/concepts.yaml, tying
204
+ # this concept to the two-level semantic model. Omitted = no family check.
205
+ concept_family: Optional[str] = None
159
206
 
160
207
  @field_validator("entity_type")
161
208
  @classmethod
@@ -166,6 +213,18 @@ class ConceptHint(BaseModel):
166
213
  )
167
214
  return v
168
215
 
216
+ @field_validator("concept_family")
217
+ @classmethod
218
+ def validate_concept_family(cls, v: Optional[str]) -> Optional[str]:
219
+ if v is None:
220
+ return v
221
+ if v not in _concept_family_ids():
222
+ raise ValueError(
223
+ f"Unknown concept family '{v}'. Must be one of: "
224
+ f"{', '.join(sorted(_concept_family_ids()))}"
225
+ )
226
+ return v
227
+
169
228
 
170
229
  class FetchRef(BaseModel):
171
230
  runner: Optional[str] = None # built-in runner name
@@ -183,6 +242,15 @@ class EntitySpec(BaseModel):
183
242
  coverage: str = "universe" # "universe" or "explicit"
184
243
  codes: Optional[list[str]] = None # required if coverage="explicit"
185
244
 
245
+ @field_validator("entity_type")
246
+ @classmethod
247
+ def validate_entity_type(cls, v: str) -> str:
248
+ if v not in ENTITY_TYPE_VOCABULARY:
249
+ raise ValueError(
250
+ f"Invalid entity_type '{v}'. Must be one of: {', '.join(ENTITY_TYPE_VOCABULARY)}"
251
+ )
252
+ return v
253
+
186
254
 
187
255
  class RelationshipSpec(BaseModel):
188
256
  """Relationship resolution declaration.
@@ -0,0 +1,230 @@
1
+ # FindData vocabulary — concept families.
2
+ #
3
+ # The first level of the two-level concept model. A *Concept family* is the
4
+ # small, curated semantic vocabulary (`fd:GDP`, `fd:Population`, ...); a
5
+ # *Variable* is the qualified five-tuple identity that lives in the MCP
6
+ # ontology store `concepts` table and carries `concept_code` pointing back here.
7
+ #
8
+ # URIs: https://schema.finddata.tech/concept/<id>
9
+ #
10
+ # `variables:` blocks are the initial seed content — the five-tuple identities
11
+ # `consume-concepts` materializes for that family. Families without a
12
+ # `variables:` block are declarative only (derivation links to them by code).
13
+ #
14
+ # Entries are never deleted — retirement is expressed with `superseded_by`.
15
+ version: "2026.09"
16
+ kind: concept
17
+ entries:
18
+ - id: GDP
19
+ label_en: Gross Domestic Product
20
+ label_zh: 国内生产总值
21
+ description: >-
22
+ The market value of all final goods and services produced within a
23
+ country's borders in a period. The qualified variants (nominal, real,
24
+ PPP, per-capita, growth) are distinct Variables of this family.
25
+ value_type: currency
26
+ unit_type: currency
27
+ dimensions: [nominal_current, real_constant, ppp, per_capita, per_capita_ppp, growth]
28
+ variables:
29
+ - {code: gdp, entity_type: country, measure: nominal_current, unit: usd, frequency: yearly}
30
+ - {code: gdp, entity_type: country, measure: real_constant, unit: usd, frequency: yearly}
31
+ - {code: gdp, entity_type: country, measure: growth, unit: "%", frequency: yearly}
32
+ - {code: gdp, entity_type: country, measure: per_capita, unit: usd, frequency: yearly}
33
+ - {code: gdp, entity_type: country, measure: per_capita_ppp, unit: international, frequency: yearly}
34
+
35
+ - id: Population
36
+ label_en: Population
37
+ label_zh: 人口
38
+ description: >-
39
+ Total resident population of an entity at a point in time. Aligns with
40
+ Data Commons Count_Person and World Bank SP.POP.TOTL.
41
+ value_type: count
42
+ unit_type: count
43
+ dimensions: []
44
+ variables:
45
+ - {code: population.total, entity_type: country, measure: "", unit: persons, frequency: yearly}
46
+
47
+ - id: PriceClose
48
+ label_en: Closing Price
49
+ label_zh: 收盘价
50
+ description: >-
51
+ Price of the last trade in a session — the canonical closing quote for a
52
+ listed instrument.
53
+ value_type: currency
54
+ unit_type: currency
55
+ dimensions: []
56
+ variables:
57
+ - {code: price.close, entity_type: stock, measure: "", unit: currency, frequency: daily}
58
+
59
+ - id: PriceOpen
60
+ label_en: Opening Price
61
+ label_zh: 开盘价
62
+ description: Price of the first trade in a session.
63
+ value_type: currency
64
+ unit_type: currency
65
+ dimensions: []
66
+ variables:
67
+ - {code: price.open, entity_type: stock, measure: "", unit: currency, frequency: daily}
68
+
69
+ - id: PriceHigh
70
+ label_en: Session High Price
71
+ label_zh: 最高价
72
+ description: Highest traded price during a session.
73
+ value_type: currency
74
+ unit_type: currency
75
+ dimensions: []
76
+ variables:
77
+ - {code: price.high, entity_type: stock, measure: "", unit: currency, frequency: daily}
78
+
79
+ - id: PriceLow
80
+ label_en: Session Low Price
81
+ label_zh: 最低价
82
+ description: Lowest traded price during a session.
83
+ value_type: currency
84
+ unit_type: currency
85
+ dimensions: []
86
+ variables:
87
+ - {code: price.low, entity_type: stock, measure: "", unit: currency, frequency: daily}
88
+
89
+ - id: PriceVolume
90
+ label_en: Traded Volume
91
+ label_zh: 成交量
92
+ description: Number of units traded during a session.
93
+ value_type: count
94
+ unit_type: count
95
+ dimensions: []
96
+ variables:
97
+ - {code: price.volume, entity_type: stock, measure: "", unit: shares, frequency: daily}
98
+
99
+ - id: PriceAmount
100
+ label_en: Traded Turnover
101
+ label_zh: 成交额
102
+ description: Monetary value traded during a session.
103
+ value_type: currency
104
+ unit_type: currency
105
+ dimensions: []
106
+ variables:
107
+ - {code: price.amount, entity_type: stock, measure: "", unit: currency, frequency: daily}
108
+
109
+ - id: NavUnit
110
+ label_en: Net Asset Value per Unit
111
+ label_zh: 单位净值
112
+ description: >-
113
+ Net asset value of one fund unit — the canonical daily price series for
114
+ funds and ETFs.
115
+ value_type: currency
116
+ unit_type: currency
117
+ dimensions: []
118
+ variables:
119
+ - {code: nav.unit, entity_type: fund, measure: "", unit: currency, frequency: daily}
120
+
121
+ - id: Revenue
122
+ label_en: Revenue
123
+ label_zh: 营业收入
124
+ description: Operating revenue recognized in a reporting period.
125
+ value_type: currency
126
+ unit_type: currency
127
+ dimensions: [growth]
128
+ variables:
129
+ - {code: financials.revenue, entity_type: stock, measure: "", unit: currency, frequency: yearly}
130
+
131
+ - id: NetProfit
132
+ label_en: Net Profit
133
+ label_zh: 净利润
134
+ description: Profit attributable to the reporting entity after tax.
135
+ value_type: currency
136
+ unit_type: currency
137
+ dimensions: [growth]
138
+ variables:
139
+ - {code: financials.net_profit, entity_type: stock, measure: "", unit: currency, frequency: yearly}
140
+
141
+ - id: TotalAssets
142
+ label_en: Total Assets
143
+ label_zh: 资产总计
144
+ description: Carrying amount of all assets at the reporting date.
145
+ value_type: currency
146
+ unit_type: currency
147
+ dimensions: []
148
+ variables:
149
+ - {code: financials.total_assets, entity_type: stock, measure: "", unit: currency, frequency: yearly}
150
+
151
+ - id: TotalLiabilities
152
+ label_en: Total Liabilities
153
+ label_zh: 负债合计
154
+ description: Carrying amount of all liabilities at the reporting date.
155
+ value_type: currency
156
+ unit_type: currency
157
+ dimensions: []
158
+ variables:
159
+ - {code: financials.total_liabilities, entity_type: stock, measure: "", unit: currency, frequency: yearly}
160
+
161
+ - id: Inflation
162
+ label_en: Inflation Rate
163
+ label_zh: 通货膨胀率
164
+ description: >-
165
+ Rate of change of a general price level, typically consumer prices.
166
+ Aligns with World Bank FP.CPI.TOTL.ZG.
167
+ value_type: ratio
168
+ unit_type: percent
169
+ dimensions: []
170
+ variables: []
171
+
172
+ - id: Unemployment
173
+ label_en: Unemployment Rate
174
+ label_zh: 失业率
175
+ description: >-
176
+ Share of the labour force that is without work and seeking it. Aligns
177
+ with World Bank SL.UEM.TOTL.ZS.
178
+ value_type: ratio
179
+ unit_type: percent
180
+ dimensions: []
181
+ variables: []
182
+
183
+ - id: LifeExpectancy
184
+ label_en: Life Expectancy
185
+ label_zh: 预期寿命
186
+ description: >-
187
+ Expected years of life at birth for a given population. Aligns with
188
+ World Bank SP.DYN.LE00.IN.
189
+ value_type: duration
190
+ unit_type: count
191
+ dimensions: []
192
+ variables: []
193
+
194
+ - id: CO2Emissions
195
+ label_en: CO2 Emissions
196
+ label_zh: 二氧化碳排放
197
+ description: >-
198
+ Carbon dioxide emissions from fuel combustion, total or per capita.
199
+ Aligns with World Bank EN.ATM.CO2E.KT and EN.ATM.CO2E.PC.
200
+ value_type: count
201
+ unit_type: count
202
+ dimensions: [per_capita]
203
+ variables: []
204
+
205
+ - id: DocTitle
206
+ label_en: Document Title
207
+ label_zh: 文档标题
208
+ description: Title of a published document (notice, report, filing).
209
+ value_type: text
210
+ unit_type: none
211
+ dimensions: []
212
+ variables: []
213
+
214
+ - id: DocDate
215
+ label_en: Document Date
216
+ label_zh: 文档日期
217
+ description: Publication or effective date of a document.
218
+ value_type: date
219
+ unit_type: none
220
+ dimensions: []
221
+ variables: []
222
+
223
+ - id: DocUrl
224
+ label_en: Document URL
225
+ label_zh: 文档链接
226
+ description: Canonical web address of a published document.
227
+ value_type: text
228
+ unit_type: none
229
+ dimensions: []
230
+ variables: []
@@ -0,0 +1,51 @@
1
+ # FindData vocabulary — crosswalk assertions (Data Commons + World Bank).
2
+ #
3
+ # Each mapping asserts that a FindData Variable (identified by its five-field
4
+ # identity tuple) corresponds to a term in an external vocabulary, with a
5
+ # SKOS-style relation and a confidence. `import-crosswalks` ingests these into
6
+ # the MCP `concept_mappings` table with provenance `registry`.
7
+ #
8
+ # Relation types: exact | close | broader | narrower | related
9
+ # (skos:exactMatch / closeMatch / broadMatch / narrowMatch / relatedMatch).
10
+ #
11
+ # URIs for the mapped Variables themselves are Phase 4; this release carries
12
+ # only family URIs.
13
+ version: "2026.09"
14
+ kind: crosswalk
15
+ mappings:
16
+ # --- Population -------------------------------------------------------------
17
+ - code: population.total
18
+ entity_type: country
19
+ measure: ""
20
+ unit: persons
21
+ frequency: yearly
22
+ vocabulary: datacommons
23
+ term: Count_Person
24
+ relation: exact
25
+ confidence: 1.0
26
+ note: Data Commons' generic population StatisticalVariable.
27
+
28
+ - code: population.total
29
+ entity_type: country
30
+ measure: ""
31
+ unit: persons
32
+ frequency: yearly
33
+ vocabulary: worldbank
34
+ term: SP.POP.TOTL
35
+ relation: exact
36
+ confidence: 1.0
37
+ note: World Bank "Population, total".
38
+
39
+ # --- GDP --------------------------------------------------------------------
40
+ - code: gdp
41
+ entity_type: country
42
+ measure: nominal_current
43
+ unit: usd
44
+ frequency: yearly
45
+ vocabulary: worldbank
46
+ term: NY.GDP.MKTP.CD
47
+ relation: exact
48
+ confidence: 1.0
49
+ note: World Bank "GDP (current US$)" — the nominal current-USD variable only;
50
+ the real/PPP/per-capita variants are separate Variables with their own
51
+ external terms (NY.GDP.MKTP.KD, NY.GDP.PCAP.CD, NY.GDP.PCAP.PP.CD).