arvo-api 0.6.0

The types of Arvo's engine API, generated from its protobuf contract. Messages only, no transport, so it builds for WebAssembly.
Documentation
// This file is @generated by prost-build.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Instrument {
    /// e.g. "AAPL.RH"
    #[prost(string, tag = "1")]
    pub id: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub interval: ::prost::alloc::string::String,
    /// ISO dates, inclusive.
    #[prost(string, tag = "3")]
    pub from: ::prost::alloc::string::String,
    #[prost(string, tag = "4")]
    pub to: ::prost::alloc::string::String,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Instruments {
    #[prost(message, repeated, tag = "1")]
    pub instruments: ::prost::alloc::vec::Vec<Instrument>,
}
/// One trade off the live price stream.
///
/// Typed rather than a View: there are hundreds a minute, and the four fields
/// are the whole of it. Display only — a tick never becomes a bar, because the
/// data library is fetched files with a content hash and that hash is what
/// makes a stored verdict checkable.
/// One price, as it arrived.
///
/// Separate from `QuoteView` and deliberately thinner: a tick carries only
/// what moved. Which rows exist, and which of them you hold, is settled once
/// by the `Watchlist` call — a stream that also decided the row set would make
/// a socket blip look like a portfolio change.
///
/// `regular` is not decoration. Outside 09:30–16:00 the stream keeps sending,
/// on thin volume and wide spreads, and a pre-market print rendered
/// identically to a regular-session one is a worse answer than no price at
/// all. A front end marks it; it does not hide it.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct QuoteTick {
    /// The bare ticker, matching `QuoteView.symbol`.
    #[prost(string, tag = "1")]
    pub symbol: ::prost::alloc::string::String,
    #[prost(double, tag = "2")]
    pub price: f64,
    /// Move since the previous close, as a fraction.
    #[prost(double, optional, tag = "3")]
    pub change: ::core::option::Option<f64>,
    /// Whether this print happened in the regular session.
    #[prost(bool, tag = "4")]
    pub regular: bool,
}
/// The control tier (ADR-0018 point 4). Behind the control token, never the
/// research one: a script or an agent holding `engine.json` cannot reach it.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct InstrumentSearch {
    #[prost(string, tag = "1")]
    pub query: ::prost::alloc::string::String,
    /// The source to ask; the broker when absent.
    #[prost(string, optional, tag = "2")]
    pub source: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct FetchRequest {
    #[prost(string, tag = "1")]
    pub instrument: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub interval: ::prost::alloc::string::String,
    #[prost(uint32, optional, tag = "3")]
    pub days: ::core::option::Option<u32>,
    #[prost(string, optional, tag = "4")]
    pub source: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CompareRequest {
    #[prost(string, tag = "1")]
    pub instrument: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub interval: ::prost::alloc::string::String,
    #[prost(string, optional, tag = "3")]
    pub first: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(string, optional, tag = "4")]
    pub second: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(uint32, optional, tag = "5")]
    pub days: ::core::option::Option<u32>,
}
/// A stored finding, summarised for the history list.
/// Something wrong with the price series a result was produced from.
///
/// Shown beside the verdict rather than in a data screen nobody opens. A
/// verdict is only as good as the bars under it, and a backtest cannot tell an
/// unadjusted split from a crash — it will trade both and report a number
/// either way.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DataFindingView {
    /// `fault` for something that cannot legitimately be true of a price
    /// series, `suspect` for something merely unusual.
    #[prost(string, tag = "1")]
    pub severity: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub kind: ::prost::alloc::string::String,
    #[prost(string, optional, tag = "3")]
    pub at: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(string, tag = "4")]
    pub detail: ::prost::alloc::string::String,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct DataLibraryView {
    /// Shown so a user with no data knows where to put some.
    #[prost(string, tag = "1")]
    pub directory: ::prost::alloc::string::String,
    #[prost(message, repeated, tag = "2")]
    pub instruments: ::prost::alloc::vec::Vec<InstrumentView>,
}
/// What a fetch pulled in.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FetchView {
    #[prost(string, tag = "1")]
    pub instrument: ::prost::alloc::string::String,
    /// Which source answered. Part of the result rather than assumed, now that
    /// it is a choice: two vendors' copies of one ticker are two datasets.
    #[prost(string, tag = "2")]
    pub source: ::prost::alloc::string::String,
    #[prost(string, tag = "3")]
    pub interval: ::prost::alloc::string::String,
    #[prost(uint32, tag = "4")]
    pub bars: u32,
    /// Gap-fill bars the server synthesised, which were dropped. Surfaced
    /// rather than hidden: a series that is a quarter invented is one to know
    /// about before drawing a conclusion from it.
    #[prost(uint32, tag = "5")]
    pub interpolated: u32,
    #[prost(string, optional, tag = "6")]
    pub from: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(string, optional, tag = "7")]
    pub to: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(message, repeated, tag = "8")]
    pub data_findings: ::prost::alloc::vec::Vec<DataFindingView>,
    /// What changed against the copy already held, when there was one.
    ///
    /// A re-fetch that rewrites history stales every finding on the
    /// instrument, correctly, via the content hash. This says *why* it
    /// changed — a re-adjustment after a corporate action leaves the
    /// underlying facts intact, a revision does not, and the two want
    /// different responses.
    #[prost(string, optional, tag = "9")]
    pub revision: ::core::option::Option<::prost::alloc::string::String>,
    /// True only when the change was a genuine disagreement about prices,
    /// rather than a rescaling or extra coverage.
    #[prost(bool, tag = "10")]
    pub revised: bool,
    /// Cash distributions stored alongside the bars.
    ///
    /// `None` means the source does not serve dividends at all, which is a
    /// different fact from `Some(0)` — it looked, and the instrument paid none.
    /// Collapsing the two would report "no dividends" for an instrument that
    /// pays them, which is the direction the platform's excess-return bias
    /// already leans.
    #[prost(uint32, optional, tag = "11")]
    pub dividends: ::core::option::Option<u32>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct InstrumentView {
    #[prost(string, tag = "1")]
    pub id: ::prost::alloc::string::String,
    /// `None` when the file exists but holds no usable bars.
    #[prost(string, optional, tag = "2")]
    pub from: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(string, optional, tag = "3")]
    pub to: ::core::option::Option<::prost::alloc::string::String>,
    #[prost(uint32, tag = "4")]
    pub bars: u32,
    /// Content hash of the data as it stands right now. The workbench compares
    /// this against the hash recorded in a held result to tell whether that
    /// result still describes the data on disk.
    #[prost(string, optional, tag = "5")]
    pub fingerprint: ::core::option::Option<::prost::alloc::string::String>,
}
/// One instrument the broker knows about.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct MatchView {
    /// The Arvo id it would be filed under, ready to fetch.
    #[prost(string, tag = "1")]
    pub instrument: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub symbol: ::prost::alloc::string::String,
    #[prost(string, tag = "3")]
    pub name: ::prost::alloc::string::String,
    #[prost(double, optional, tag = "4")]
    pub price: ::core::option::Option<f64>,
    /// Move since the previous close, as a fraction.
    #[prost(double, optional, tag = "5")]
    pub change: ::core::option::Option<f64>,
    /// Whether the data library already holds this instrument.
    #[prost(bool, tag = "6")]
    pub held: bool,
}
/// One row of the watchlist: an instrument, priced now.
///
/// `held` is why this is not just a ticker — the same move means something
/// different depending on whether you own the thing.
///
/// # What is deliberately not here
///
/// The position's value. A holding is valued from the statement or the last
/// close on disk, never from the network (see `arvo_runtime::portfolio`), and
/// putting that figure beside a live price would show two numbers priced two
/// ways as though they agreed. The live price belongs to the watchlist; the
/// valuation belongs to the portfolio, and they stay apart.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct QuoteView {
    #[prost(string, tag = "1")]
    pub instrument: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub symbol: ::prost::alloc::string::String,
    /// `None` when the row exists but nothing has priced it yet — no broker
    /// session for the snapshot, and no tick arrived for it yet. Optional
    /// rather than zero because `$0.00` is a price, and a wrong one.
    #[prost(double, optional, tag = "3")]
    pub price: ::core::option::Option<f64>,
    /// Move since the previous close, as a fraction. `None` when there is a
    /// price but no previous close to measure it against.
    #[prost(double, optional, tag = "4")]
    pub change: ::core::option::Option<f64>,
    #[prost(bool, tag = "5")]
    pub held: bool,
}
/// What two sources say about the same instrument over the same window.
///
/// The verdict is \[`Self::summary`\] and the counts are beside it, deliberately:
/// two vendors disagreeing is the normal case and most of the ways they
/// disagree are not faults, so a bare count of differing bars is true, useless,
/// and the kind of thing that gets a check switched off.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SourceComparisonView {
    #[prost(string, tag = "1")]
    pub symbol: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub interval: ::prost::alloc::string::String,
    #[prost(string, tag = "3")]
    pub first: ::prost::alloc::string::String,
    #[prost(string, tag = "4")]
    pub second: ::prost::alloc::string::String,
    #[prost(uint32, tag = "5")]
    pub first_bars: u32,
    #[prost(uint32, tag = "6")]
    pub second_bars: u32,
    /// Bar instants present in both.
    #[prost(uint32, tag = "7")]
    pub shared: u32,
    /// Bars one has and the other does not. Independent of whether the shared
    /// ones agree: two sources can cover different sessions and match perfectly
    /// wherever they overlap.
    #[prost(uint32, tag = "8")]
    pub only_first: u32,
    #[prost(uint32, tag = "9")]
    pub only_second: u32,
    #[prost(string, tag = "10")]
    pub summary: ::prost::alloc::string::String,
    /// True only for a genuine price disagreement — not for a rescaling, which
    /// is an adjustment difference with neither side wrong, and not for a
    /// coverage difference.
    #[prost(bool, tag = "11")]
    pub diverged: bool,
    /// Why the two sources cannot be compared at face value, when they cannot.
    ///
    /// Neither axis it reports — how much of the tape a feed covers, and what
    /// the prices are adjusted for — is visible in the bars, so this comes from
    /// what each source declares rather than from any check. A thin feed and
    /// the consolidated tape report the same prices; only the volumes differ,
    /// and `agreement` deliberately does not compare volume.
    #[prost(string, optional, tag = "12")]
    pub basis_mismatch: ::core::option::Option<::prost::alloc::string::String>,
}
/// One source the app can fetch from.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SourceView {
    #[prost(string, tag = "1")]
    pub id: ::prost::alloc::string::String,
    #[prost(string, tag = "2")]
    pub label: ::prost::alloc::string::String,
    /// The namespace instruments fetched here are filed under. Shown because
    /// it is half of the instrument id a person will see afterwards.
    #[prost(string, tag = "3")]
    pub venue: ::prost::alloc::string::String,
    /// Whether it can fetch right now. Always true for a source needing no
    /// credential, which is the honest answer rather than a claim about a
    /// session that does not exist.
    #[prost(bool, tag = "4")]
    pub connected: bool,
    /// Whether this source has a browser sign-in, so the window does not offer
    /// a button for something that cannot be done.
    #[prost(bool, tag = "5")]
    pub needs_sign_in: bool,
    /// Whether this source is authorised by a key pair typed in once.
    ///
    /// Two flags rather than one enum, because a view is a flattened thing and
    /// this one crosses to a wasm window that depends on `serde` and nothing
    /// else. The single source of truth is `arvo_data::source::Credential`,
    /// read once in `list_sources` through a match the compiler keeps
    /// exhaustive — so the pair cannot drift from it, even though the pair by
    /// itself could express nonsense.
    #[prost(bool, tag = "6")]
    pub needs_keys: bool,
}
/// A list, as a message.
///
/// An RPC returns one message, never a bare repeated field, so a call that
/// answers with a list needs a name for the list. The wrapper is not
/// ceremony: it is where a total, a cursor or a "when this was read" goes
/// later, without renumbering what is already here.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SourcesView {
    #[prost(message, repeated, tag = "1")]
    pub sources: ::prost::alloc::vec::Vec<SourceView>,
}
/// What a search matched. A list, as a message; see `SourcesView`.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct MatchesView {
    #[prost(message, repeated, tag = "1")]
    pub matches: ::prost::alloc::vec::Vec<MatchView>,
}
/// The watchlist, priced. A list, as a message; see `SourcesView`.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WatchlistView {
    #[prost(message, repeated, tag = "1")]
    pub rows: ::prost::alloc::vec::Vec<QuoteView>,
}