finance_query/models/discovery/figi.rs
1//! Security-identifier mapping models.
2//!
3//! Populated by the OpenFIGI adapter, which resolves a CUSIP, ISIN, SEDOL, or
4//! FIGI to the instruments carrying it.
5
6use serde::{Deserialize, Serialize};
7
8/// One instrument matching a security identifier.
9///
10/// A single CUSIP or ISIN maps to **many** instruments — one per venue the
11/// security trades on — which is why resolution returns a list. Entries that
12/// share a `composite_figi` are the same security on different venues; the
13/// `share_class_figi` groups share classes across countries.
14///
15/// Obtain via [`openfigi::resolve_cusip`](crate::openfigi::resolve_cusip) and
16/// friends.
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19#[non_exhaustive]
20pub struct SecurityMapping {
21 /// The instrument's Financial Instrument Global Identifier.
22 pub figi: String,
23 /// Ticker symbol, as the venue lists it.
24 pub ticker: Option<String>,
25 /// Security name (usually the issuer).
26 pub name: Option<String>,
27 /// Exchange code — `"US"` for the composite, otherwise a venue code.
28 pub exchange_code: Option<String>,
29 /// FIGI of the country-level composite this instrument rolls up to.
30 pub composite_figi: Option<String>,
31 /// FIGI shared by every listing of this share class worldwide.
32 pub share_class_figi: Option<String>,
33 /// Instrument type, e.g. `"Common Stock"`, `"ETP"`.
34 pub security_type: Option<String>,
35 /// Market sector, e.g. `"Equity"`, `"Corp"`, `"Govt"`.
36 pub market_sector: Option<String>,
37}
38
39/// Narrows which instruments a mapping returns.
40///
41/// The default matches every venue and only currently listed equities.
42#[derive(Debug, Clone, Default, PartialEq, Eq)]
43#[non_exhaustive]
44pub struct MappingFilter {
45 /// Keep only instruments on this exchange code, e.g. `"US"` for the
46 /// country composite.
47 pub exchange_code: Option<String>,
48 /// Also match equities that are no longer listed, such as delisted stocks.
49 pub include_unlisted: bool,
50}
51
52impl MappingFilter {
53 /// Match only this exchange code, e.g. `"US"`.
54 pub fn exchange_code(mut self, code: impl Into<String>) -> Self {
55 self.exchange_code = Some(code.into());
56 self
57 }
58
59 /// Also match delisted and otherwise unlisted equities.
60 pub fn include_unlisted(mut self, include: bool) -> Self {
61 self.include_unlisted = include;
62 self
63 }
64}
65
66/// The kind of identifier being resolved.
67///
68/// Maps onto OpenFIGI's `idType` values.
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
70#[non_exhaustive]
71pub enum SecurityIdKind {
72 /// North American security identifier (9 characters).
73 Cusip,
74 /// International Securities Identification Number (12 characters).
75 Isin,
76 /// UK/Ireland security identifier (7 characters).
77 Sedol,
78 /// A FIGI, resolved to its siblings.
79 Figi,
80 /// Exchange ticker symbol.
81 Ticker,
82}
83
84impl SecurityIdKind {
85 /// The `idType` string OpenFIGI expects.
86 pub fn as_str(self) -> &'static str {
87 match self {
88 Self::Cusip => "ID_CUSIP",
89 Self::Isin => "ID_ISIN",
90 Self::Sedol => "ID_SEDOL",
91 Self::Figi => "ID_BB_GLOBAL",
92 Self::Ticker => "TICKER",
93 }
94 }
95}
96
97impl std::fmt::Display for SecurityIdKind {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.write_str(self.as_str())
100 }
101}