Skip to main content

arvo_api/generated/
arvo.research.v1.rs

1// This file is @generated by prost-build.
2#[derive(serde::Serialize, serde::Deserialize)]
3#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
4pub struct Strategy {
5    #[prost(string, tag = "1")]
6    pub name: ::prost::alloc::string::String,
7    #[prost(string, tag = "2")]
8    pub label: ::prost::alloc::string::String,
9    /// The resolution it runs at, e.g. "1d" or "5m".
10    #[prost(string, tag = "3")]
11    pub interval: ::prost::alloc::string::String,
12    /// What the rule claims about how prices behave.
13    #[prost(string, tag = "4")]
14    pub premise: ::prost::alloc::string::String,
15    /// True when the rule ranks instruments against each other and needs a set.
16    #[prost(bool, tag = "5")]
17    pub ranks_a_set: bool,
18    /// Backtests one study runs: what a front end's progress indicator promises.
19    #[prost(uint32, tag = "6")]
20    pub backtests: u32,
21}
22#[derive(serde::Serialize, serde::Deserialize)]
23#[derive(Clone, PartialEq, ::prost::Message)]
24pub struct Strategies {
25    #[prost(message, repeated, tag = "1")]
26    pub strategies: ::prost::alloc::vec::Vec<Strategy>,
27}
28#[derive(serde::Serialize, serde::Deserialize)]
29#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
30pub struct FindingSummary {
31    #[prost(string, tag = "1")]
32    pub id: ::prost::alloc::string::String,
33    /// What was run, e.g. "study", "walk-forward" or "panel".
34    #[prost(string, tag = "2")]
35    pub kind: ::prost::alloc::string::String,
36    #[prost(string, tag = "3")]
37    pub subject: ::prost::alloc::string::String,
38    /// "Supported", "NotSupported" or "Inconclusive".
39    #[prost(string, tag = "4")]
40    pub verdict: ::prost::alloc::string::String,
41    /// RFC 3339.
42    #[prost(string, tag = "5")]
43    pub recorded_at: ::prost::alloc::string::String,
44    /// The agent or script that ran it; empty for a person.
45    #[prost(string, tag = "6")]
46    pub author: ::prost::alloc::string::String,
47    /// Which rule or ruleset ran, by the name the picker shows. A ruleset is
48    /// the file `rulesets/<name>.json` in the project.
49    #[prost(string, tag = "7")]
50    pub strategy: ::prost::alloc::string::String,
51    /// The engine build that produced it (#189): the git commit, with `-dirty`
52    /// when the tree had uncommitted changes, or `unknown` for a build made
53    /// outside a checkout.
54    #[prost(string, tag = "8")]
55    pub code_commit: ::prost::alloc::string::String,
56    /// The ruleset document's content hash at run time, when the strategy was
57    /// a ruleset rather than a shipped rule; empty otherwise. A finding whose
58    /// hash no longer matches the file is stale: the rule it measured is not
59    /// the rule the file now holds.
60    #[prost(string, tag = "9")]
61    pub ruleset_hash: ::prost::alloc::string::String,
62}
63#[derive(serde::Serialize, serde::Deserialize)]
64#[derive(Clone, PartialEq, ::prost::Message)]
65pub struct Findings {
66    #[prost(message, repeated, tag = "1")]
67    pub findings: ::prost::alloc::vec::Vec<FindingSummary>,
68    /// Records in the evidence store that could not be read.
69    #[prost(uint32, tag = "2")]
70    pub unreadable: u32,
71}
72#[derive(serde::Serialize, serde::Deserialize)]
73#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
74pub struct FindingId {
75    #[prost(string, tag = "1")]
76    pub id: ::prost::alloc::string::String,
77}
78#[derive(serde::Serialize, serde::Deserialize)]
79#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
80pub struct FindingIds {
81    #[prost(string, repeated, tag = "1")]
82    pub ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
83}
84#[derive(serde::Serialize, serde::Deserialize)]
85#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
86pub struct Advice {
87    /// "blocking", "warning" or "note".
88    #[prost(string, tag = "1")]
89    pub severity: ::prost::alloc::string::String,
90    #[prost(string, tag = "2")]
91    pub finding: ::prost::alloc::string::String,
92    #[prost(string, tag = "3")]
93    pub action: ::prost::alloc::string::String,
94    #[prost(string, tag = "4")]
95    pub evidence: ::prost::alloc::string::String,
96}
97/// One finding: the verdict and how far it may be read, before any number.
98#[derive(serde::Serialize, serde::Deserialize)]
99#[derive(Clone, PartialEq, ::prost::Message)]
100pub struct Finding {
101    #[prost(message, optional, tag = "1")]
102    pub summary: ::core::option::Option<FindingSummary>,
103    /// A plain instruction on how far the verdict may be read. Read first.
104    #[prost(string, tag = "2")]
105    pub read_this_first: ::prost::alloc::string::String,
106    #[prost(string, repeated, tag = "3")]
107    pub reasons: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
108    #[prost(message, repeated, tag = "4")]
109    pub advice: ::prost::alloc::vec::Vec<Advice>,
110    /// The numbers, which differ by kind: the search and the out-of-sample
111    /// metrics for a study, the stitched record for a walk-forward, the pooled
112    /// outcome for a panel. JSON, so a new number is not a new message.
113    #[prost(string, tag = "5")]
114    pub detail_json: ::prost::alloc::string::String,
115    /// Files kept with the finding (#157).
116    #[prost(message, repeated, tag = "6")]
117    pub attachments: ::prost::alloc::vec::Vec<Attachment>,
118}
119/// One file kept with a finding: bytes stored once by content hash, listed
120/// on the record.
121#[derive(serde::Serialize, serde::Deserialize)]
122#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
123pub struct Attachment {
124    #[prost(string, tag = "1")]
125    pub name: ::prost::alloc::string::String,
126    #[prost(string, tag = "2")]
127    pub media_type: ::prost::alloc::string::String,
128    /// blake3 of the bytes, hex.
129    #[prost(string, tag = "3")]
130    pub hash: ::prost::alloc::string::String,
131    #[prost(uint64, tag = "4")]
132    pub bytes: u64,
133    /// RFC 3339.
134    #[prost(string, tag = "5")]
135    pub added_at: ::prost::alloc::string::String,
136}
137/// A file to keep with a finding the caller already recorded or ran.
138#[derive(serde::Serialize, serde::Deserialize)]
139#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
140pub struct AttachRequest {
141    #[prost(string, tag = "1")]
142    pub finding_id: ::prost::alloc::string::String,
143    /// As the author names it: `report.md`, `equity.png`.
144    #[prost(string, tag = "2")]
145    pub name: ::prost::alloc::string::String,
146    /// `text/markdown`, `image/png`; empty means application/octet-stream.
147    #[prost(string, tag = "3")]
148    pub media_type: ::prost::alloc::string::String,
149    #[prost(bytes = "vec", tag = "4")]
150    pub data: ::prost::alloc::vec::Vec<u8>,
151}
152#[derive(serde::Serialize, serde::Deserialize)]
153#[derive(Clone, PartialEq, ::prost::Message)]
154pub struct Attachments {
155    #[prost(message, repeated, tag = "1")]
156    pub attachments: ::prost::alloc::vec::Vec<Attachment>,
157}
158#[derive(serde::Serialize, serde::Deserialize)]
159#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
160pub struct AttachmentRef {
161    #[prost(string, tag = "1")]
162    pub finding_id: ::prost::alloc::string::String,
163    #[prost(string, tag = "2")]
164    pub hash: ::prost::alloc::string::String,
165}
166#[derive(serde::Serialize, serde::Deserialize)]
167#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
168pub struct RunRequest {
169    #[prost(string, tag = "1")]
170    pub instrument: ::prost::alloc::string::String,
171    #[prost(string, tag = "2")]
172    pub strategy: ::prost::alloc::string::String,
173    /// Who is running this, e.g. "script:momentum-scan". Required: a run is
174    /// saved as this author's and deflated against everything the author has
175    /// run, so a script iterating until something passes does not make it pass.
176    #[prost(string, tag = "3")]
177    pub author: ::prost::alloc::string::String,
178    /// Where in the author's code the call was made, as "path:line", so the
179    /// workbench can put the finding's caveats against that line. Optional.
180    #[prost(string, tag = "4")]
181    pub origin: ::prost::alloc::string::String,
182}
183/// Bars, or the regimes read off them, over a window of the library (#195).
184#[derive(serde::Serialize, serde::Deserialize)]
185#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
186pub struct BarsRequest {
187    #[prost(string, tag = "1")]
188    pub instrument: ::prost::alloc::string::String,
189    /// "1day" when absent; "5minute" and the other minute steps where the
190    /// library holds them.
191    #[prost(string, optional, tag = "2")]
192    pub interval: ::core::option::Option<::prost::alloc::string::String>,
193    /// YYYY-MM-DD, inclusive. The library's whole range when absent.
194    #[prost(string, optional, tag = "3")]
195    pub from: ::core::option::Option<::prost::alloc::string::String>,
196    #[prost(string, optional, tag = "4")]
197    pub to: ::core::option::Option<::prost::alloc::string::String>,
198    /// At most this many bars, from the end of the window. 60 when absent;
199    /// never more than 2000.
200    #[prost(uint32, optional, tag = "5")]
201    pub last: ::core::option::Option<u32>,
202}
203#[derive(serde::Serialize, serde::Deserialize)]
204#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
205pub struct StudyRequest {
206    #[prost(string, tag = "1")]
207    pub instrument: ::prost::alloc::string::String,
208    /// A rule or ruleset name; the default rule when absent.
209    #[prost(string, optional, tag = "2")]
210    pub strategy: ::core::option::Option<::prost::alloc::string::String>,
211}
212#[derive(serde::Serialize, serde::Deserialize)]
213#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
214pub struct BookRequest {
215    #[prost(string, repeated, tag = "1")]
216    pub instruments: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
217    #[prost(string, optional, tag = "2")]
218    pub strategy: ::core::option::Option<::prost::alloc::string::String>,
219    #[prost(uint32, optional, tag = "3")]
220    pub max_concurrent_positions: ::core::option::Option<u32>,
221    #[prost(uint32, optional, tag = "4")]
222    pub max_per_sector: ::core::option::Option<u32>,
223}
224#[derive(serde::Serialize, serde::Deserialize)]
225#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
226pub struct SharedExperiment {
227    /// The file's text, as the person pasted or opened it.
228    #[prost(string, tag = "1")]
229    pub text: ::prost::alloc::string::String,
230    #[prost(string, tag = "2")]
231    pub instrument: ::prost::alloc::string::String,
232}
233/// One point of an equity curve. `at` is `YYYY-MM-DDTHH:MM:SS` or a date.
234#[derive(serde::Serialize, serde::Deserialize)]
235#[derive(Clone, PartialEq, ::prost::Message)]
236pub struct Point {
237    #[prost(string, tag = "1")]
238    pub at: ::prost::alloc::string::String,
239    #[prost(double, tag = "2")]
240    pub equity: f64,
241}
242/// One trade in a ledger: a round trip, or a position still open at the end
243/// (empty `closed`, no `exit`).
244#[derive(serde::Serialize, serde::Deserialize)]
245#[derive(Clone, PartialEq, ::prost::Message)]
246pub struct LedgerTrade {
247    /// `SYMBOL.VENUE`; empty when it is the experiment's own instrument.
248    #[prost(string, tag = "1")]
249    pub instrument: ::prost::alloc::string::String,
250    #[prost(string, tag = "2")]
251    pub opened: ::prost::alloc::string::String,
252    #[prost(string, tag = "3")]
253    pub closed: ::prost::alloc::string::String,
254    /// "long" or "short"; empty means long.
255    #[prost(string, tag = "4")]
256    pub direction: ::prost::alloc::string::String,
257    #[prost(double, tag = "5")]
258    pub quantity: f64,
259    #[prost(double, tag = "6")]
260    pub entry: f64,
261    #[prost(double, optional, tag = "7")]
262    pub exit: ::core::option::Option<f64>,
263    #[prost(double, tag = "8")]
264    pub pnl: f64,
265    #[prost(double, tag = "9")]
266    pub commission: f64,
267    /// "signal", "stop", "halted", "expired" or "still_open"; empty means signal.
268    #[prost(string, tag = "10")]
269    pub exit_reason: ::prost::alloc::string::String,
270    /// What the rule saw at entry (#190): the condition that fired, the value it
271    /// was judged on, the regime it saw, and the quantity it asked the gate for.
272    /// Absent on a trade recorded before the journal or opened by no rule.
273    #[prost(string, optional, tag = "11")]
274    pub rule: ::core::option::Option<::prost::alloc::string::String>,
275    #[prost(double, optional, tag = "12")]
276    pub signal: ::core::option::Option<f64>,
277    #[prost(string, optional, tag = "13")]
278    pub regime: ::core::option::Option<::prost::alloc::string::String>,
279    #[prost(double, optional, tag = "14")]
280    pub asked: ::core::option::Option<f64>,
281}
282/// Evidence an engine Arvo did not run computed (ADR-0026). What a run
283/// produces, before anyone concludes anything from it; Arvo computes the
284/// verdict. There is no field for a verdict, a metric or a p-value.
285#[derive(serde::Serialize, serde::Deserialize)]
286#[derive(Clone, PartialEq, ::prost::Message)]
287pub struct ReportRequest {
288    /// As RunRequest: who is recording this, and where in their code.
289    #[prost(string, tag = "1")]
290    pub author: ::prost::alloc::string::String,
291    #[prost(string, tag = "2")]
292    pub origin: ::prost::alloc::string::String,
293    /// The hypothesis: an id, and the claim in prose.
294    #[prost(string, tag = "3")]
295    pub hypothesis_id: ::prost::alloc::string::String,
296    #[prost(string, tag = "4")]
297    pub claim: ::prost::alloc::string::String,
298    /// The experiment as data.
299    #[prost(string, tag = "5")]
300    pub instrument: ::prost::alloc::string::String,
301    /// ISO dates, inclusive.
302    #[prost(string, tag = "6")]
303    pub from: ::prost::alloc::string::String,
304    #[prost(string, tag = "7")]
305    pub to: ::prost::alloc::string::String,
306    /// As arvo_data spells it: "1day", "5minute".
307    #[prost(string, tag = "8")]
308    pub interval: ::prost::alloc::string::String,
309    /// The engine's own dataset: an id, and a content hash of what it read.
310    #[prost(string, tag = "9")]
311    pub dataset_id: ::prost::alloc::string::String,
312    #[prost(string, tag = "10")]
313    pub dataset_version: ::prost::alloc::string::String,
314    /// "split" (the default) or "total_return".
315    #[prost(string, tag = "11")]
316    pub adjustment: ::prost::alloc::string::String,
317    /// The engine's own strategy name, and its parameters.
318    #[prost(string, tag = "12")]
319    pub strategy: ::prost::alloc::string::String,
320    #[prost(map = "string, double", tag = "13")]
321    pub params: ::std::collections::HashMap<::prost::alloc::string::String, f64>,
322    /// The cost model the run assumed.
323    #[prost(double, tag = "14")]
324    pub commission_bps: f64,
325    #[prost(double, tag = "15")]
326    pub slippage_bps: f64,
327    #[prost(double, tag = "16")]
328    pub per_fill: f64,
329    /// The risk model, as far as the run assumed one.
330    #[prost(double, optional, tag = "17")]
331    pub stop_atr_multiple: ::core::option::Option<f64>,
332    /// Zero means the curve's first point.
333    #[prost(double, tag = "18")]
334    pub starting_cash: f64,
335    /// What computed this, by name and version.
336    #[prost(string, tag = "19")]
337    pub engine: ::prost::alloc::string::String,
338    /// The evidence.
339    #[prost(message, repeated, tag = "20")]
340    pub strategy_curve: ::prost::alloc::vec::Vec<Point>,
341    #[prost(message, repeated, tag = "21")]
342    pub ledger: ::prost::alloc::vec::Vec<LedgerTrade>,
343    /// Buy-and-hold over the same window and capital. Without it the finding
344    /// is Inconclusive: a return with nothing to beat is not a result.
345    #[prost(message, repeated, tag = "22")]
346    pub benchmark_curve: ::prost::alloc::vec::Vec<Point>,
347    /// How many trials the author's whole search has run (ADR-0014).
348    #[prost(uint32, optional, tag = "23")]
349    pub trials: ::core::option::Option<u32>,
350}
351#[derive(serde::Serialize, serde::Deserialize)]
352#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
353pub struct ReportFigure {
354    #[prost(string, tag = "1")]
355    pub finding_id: ::prost::alloc::string::String,
356    /// The equity chart the front end captured, base64 PNG. Absent is a report
357    /// with no figure, not an error: only a window can draw one.
358    #[prost(string, optional, tag = "2")]
359    pub figure: ::core::option::Option<::prost::alloc::string::String>,
360}
361#[derive(serde::Serialize, serde::Deserialize)]
362#[derive(Clone, PartialEq, ::prost::Message)]
363pub struct TradeExport {
364    #[prost(string, tag = "1")]
365    pub name: ::prost::alloc::string::String,
366    /// The rows as the front end has them, in the order it is showing them. The
367    /// engine does not derive these from the finding, because the sort order is
368    /// the view's, and an export that silently differed from the table above it
369    /// would be worse than none.
370    #[prost(message, repeated, tag = "2")]
371    pub rows: ::prost::alloc::vec::Vec<TradeRow>,
372}
373/// One round trip, as a trades table shows it and a CSV export writes it.
374#[derive(serde::Serialize, serde::Deserialize)]
375#[derive(Clone, PartialEq, ::prost::Message)]
376pub struct TradeRow {
377    /// Which instrument the round trip was in. Empty on an ordinary study,
378    /// whose subject line already says; on a book it is the difference between
379    /// a usable export and trades from three instruments with no way to tell
380    /// them apart.
381    #[prost(string, tag = "1")]
382    pub instrument: ::prost::alloc::string::String,
383    #[prost(string, tag = "2")]
384    pub opened: ::prost::alloc::string::String,
385    #[prost(string, tag = "3")]
386    pub closed: ::prost::alloc::string::String,
387    #[prost(string, tag = "4")]
388    pub direction: ::prost::alloc::string::String,
389    #[prost(double, tag = "5")]
390    pub quantity: f64,
391    #[prost(double, tag = "6")]
392    pub entry: f64,
393    #[prost(double, optional, tag = "7")]
394    pub exit: ::core::option::Option<f64>,
395    #[prost(double, tag = "8")]
396    pub pnl: f64,
397    #[prost(double, tag = "9")]
398    pub commission: f64,
399    #[prost(double, optional, tag = "10")]
400    pub held_days: ::core::option::Option<f64>,
401    #[prost(string, tag = "11")]
402    pub exit_reason: ::prost::alloc::string::String,
403    /// What the rule saw at entry (#190): the condition that fired, the value it
404    /// was judged on, the regime it saw, and the quantity it asked the gate for.
405    /// Absent on a trade recorded before the journal or opened by no rule.
406    #[prost(string, optional, tag = "12")]
407    pub rule: ::core::option::Option<::prost::alloc::string::String>,
408    #[prost(double, optional, tag = "13")]
409    pub signal: ::core::option::Option<f64>,
410    #[prost(string, optional, tag = "14")]
411    pub regime: ::core::option::Option<::prost::alloc::string::String>,
412    #[prost(double, optional, tag = "15")]
413    pub asked: ::core::option::Option<f64>,
414}
415/// A ruleset parameter: one value fixes it, several search it.
416#[derive(serde::Serialize, serde::Deserialize)]
417#[derive(Clone, PartialEq, ::prost::Message)]
418pub struct Param {
419    #[prost(string, tag = "1")]
420    pub name: ::prost::alloc::string::String,
421    #[prost(double, repeated, tag = "2")]
422    pub values: ::prost::alloc::vec::Vec<f64>,
423}
424#[derive(serde::Serialize, serde::Deserialize)]
425#[derive(Clone, PartialEq, ::prost::Message)]
426pub struct Fixed {
427    #[prost(string, tag = "1")]
428    pub name: ::prost::alloc::string::String,
429    #[prost(double, tag = "2")]
430    pub value: f64,
431}
432/// One file under `<project>`/rulesets/, as the picker sees it.
433#[derive(serde::Serialize, serde::Deserialize)]
434#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
435pub struct Ruleset {
436    #[prost(string, tag = "1")]
437    pub path: ::prost::alloc::string::String,
438    #[prost(string, tag = "2")]
439    pub name: ::prost::alloc::string::String,
440    #[prost(string, tag = "3")]
441    pub label: ::prost::alloc::string::String,
442    #[prost(string, tag = "4")]
443    pub rule: ::prost::alloc::string::String,
444    #[prost(string, tag = "5")]
445    pub interval: ::prost::alloc::string::String,
446    #[prost(uint32, tag = "6")]
447    pub searches: u32,
448    /// Why it cannot be run, when it cannot.
449    #[prost(string, optional, tag = "7")]
450    pub problem: ::core::option::Option<::prost::alloc::string::String>,
451}
452#[derive(serde::Serialize, serde::Deserialize)]
453#[derive(Clone, PartialEq, ::prost::Message)]
454pub struct Rulesets {
455    #[prost(message, repeated, tag = "1")]
456    pub rulesets: ::prost::alloc::vec::Vec<Ruleset>,
457}
458#[derive(serde::Serialize, serde::Deserialize)]
459#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
460pub struct RulesetPath {
461    #[prost(string, tag = "1")]
462    pub path: ::prost::alloc::string::String,
463}
464/// A grid ruleset's parts, for a form.
465#[derive(serde::Serialize, serde::Deserialize)]
466#[derive(Clone, PartialEq, ::prost::Message)]
467pub struct RulesetForm {
468    #[prost(string, tag = "1")]
469    pub name: ::prost::alloc::string::String,
470    #[prost(string, tag = "2")]
471    pub rule: ::prost::alloc::string::String,
472    #[prost(string, tag = "3")]
473    pub label: ::prost::alloc::string::String,
474    #[prost(string, tag = "4")]
475    pub premise: ::prost::alloc::string::String,
476    #[prost(message, repeated, tag = "5")]
477    pub params: ::prost::alloc::vec::Vec<Param>,
478}
479/// A rule this build implements, with the search it ships.
480#[derive(serde::Serialize, serde::Deserialize)]
481#[derive(Clone, PartialEq, ::prost::Message)]
482pub struct Rule {
483    #[prost(string, tag = "1")]
484    pub name: ::prost::alloc::string::String,
485    #[prost(string, tag = "2")]
486    pub label: ::prost::alloc::string::String,
487    #[prost(string, tag = "3")]
488    pub premise: ::prost::alloc::string::String,
489    #[prost(string, tag = "4")]
490    pub interval: ::prost::alloc::string::String,
491    #[prost(message, repeated, tag = "5")]
492    pub fixed: ::prost::alloc::vec::Vec<Fixed>,
493    #[prost(message, repeated, tag = "6")]
494    pub axes: ::prost::alloc::vec::Vec<Param>,
495    #[prost(bool, tag = "7")]
496    pub ranks_a_set: bool,
497    #[prost(bool, tag = "8")]
498    pub trades_options: bool,
499}
500#[derive(serde::Serialize, serde::Deserialize)]
501#[derive(Clone, PartialEq, ::prost::Message)]
502pub struct Rules {
503    #[prost(message, repeated, tag = "1")]
504    pub rules: ::prost::alloc::vec::Vec<Rule>,
505}
506/// The project's risk file (.arvo/risk.json), as read for the next study.
507#[derive(serde::Serialize, serde::Deserialize)]
508#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
509pub struct RiskModel {
510    #[prost(string, tag = "1")]
511    pub path: ::prost::alloc::string::String,
512    #[prost(bool, tag = "2")]
513    pub exists: bool,
514    /// The model in force, as JSON: the file's when it reads, the shipped one
515    /// when it does not.
516    #[prost(string, tag = "3")]
517    pub model_json: ::prost::alloc::string::String,
518    /// Why the file was refused, when it was.
519    #[prost(string, optional, tag = "4")]
520    pub error: ::core::option::Option<::prost::alloc::string::String>,
521}
522/// The dividend bias, measured.
523///
524/// On split-adjusted prices no dividend is paid to anything in a backtest.
525/// Both sides forgo them — but the benchmark held through every ex-date and a
526/// rule in the market some of the time did not, so the margin between them is
527/// overstated in the strategy's favour, and \[`Self::corrected_excess`\] takes it
528/// off. On total-return prices the distributions are already in the returns and
529/// the same measurement describes what the margin is made of instead.
530/// A study's result after tax. See `arvo_research::tax` for what is modelled.
531#[derive(serde::Serialize, serde::Deserialize)]
532#[derive(Clone, Copy, PartialEq, ::prost::Message)]
533pub struct AfterTaxView {
534    #[prost(double, tag = "1")]
535    pub strategy_return: f64,
536    #[prost(double, tag = "2")]
537    pub benchmark_return: f64,
538    /// `strategy_return - benchmark_return`: the margin a taxable account
539    /// would actually have kept.
540    #[prost(double, tag = "3")]
541    pub excess: f64,
542    #[prost(double, tag = "4")]
543    pub strategy_tax: f64,
544    #[prost(double, tag = "5")]
545    pub benchmark_tax: f64,
546    #[prost(double, tag = "6")]
547    pub short_term_rate: f64,
548    #[prost(double, tag = "7")]
549    pub long_term_rate: f64,
550}
551/// What one account holding every member of a panel would have done.
552///
553/// The panel's pooled figures average its members. This combines them, which
554/// is a different number in the place that matters: falls that did not
555/// coincide hurt a book less than they hurt its average member.
556#[derive(serde::Serialize, serde::Deserialize)]
557#[derive(Clone, Copy, PartialEq, ::prost::Message)]
558pub struct BookView {
559    #[prost(message, optional, tag = "1")]
560    pub metrics: ::core::option::Option<MetricsView>,
561    /// Mean member drawdown less the book's. Positive is diversification;
562    /// zero or below means the members fell together and the panel was one bet.
563    #[prost(double, tag = "2")]
564    pub diversification: f64,
565}
566/// How much of a panel's apparent breadth is real.
567///
568/// The pooled statistics read as evidence in proportion to the instrument
569/// count — three that agree feel like three times the confidence of one. They
570/// are not, if the three moved together.
571#[derive(serde::Serialize, serde::Deserialize)]
572#[derive(Clone, PartialEq, ::prost::Message)]
573pub struct BreadthView {
574    #[prost(string, repeated, tag = "1")]
575    pub instruments: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
576    /// Square and symmetric. `None` where a pair had too little overlap to
577    /// say — which is different from a correlation of zero.
578    #[prost(message, repeated, tag = "2")]
579    pub correlations: ::prost::alloc::vec::Vec<CorrelationRow>,
580    #[prost(double, optional, tag = "3")]
581    pub mean_correlation: ::core::option::Option<f64>,
582    /// How many independent instruments the panel behaves like.
583    #[prost(double, optional, tag = "4")]
584    pub effective: ::core::option::Option<f64>,
585    /// How much the pooled average's certainty is overstated by counting
586    /// instruments instead of independent ones.
587    #[prost(double, optional, tag = "5")]
588    pub overstatement: ::core::option::Option<f64>,
589}
590/// One finding in a side-by-side comparison.
591#[derive(serde::Serialize, serde::Deserialize)]
592#[derive(Clone, PartialEq, ::prost::Message)]
593pub struct ComparisonRowView {
594    #[prost(string, tag = "1")]
595    pub id: ::prost::alloc::string::String,
596    #[prost(string, tag = "2")]
597    pub subject: ::prost::alloc::string::String,
598    #[prost(string, tag = "3")]
599    pub kind: ::prost::alloc::string::String,
600    #[prost(string, tag = "4")]
601    pub strategy_name: ::prost::alloc::string::String,
602    #[prost(string, tag = "5")]
603    pub verdict: ::prost::alloc::string::String,
604    #[prost(string, tag = "6")]
605    pub recorded_at: ::prost::alloc::string::String,
606    #[prost(double, tag = "7")]
607    pub total_return: f64,
608    #[prost(double, tag = "8")]
609    pub excess_return: f64,
610    #[prost(double, optional, tag = "9")]
611    pub sharpe: ::core::option::Option<f64>,
612    #[prost(double, tag = "10")]
613    pub max_drawdown: f64,
614    #[prost(uint32, tag = "11")]
615    pub trades: u32,
616    #[prost(double, optional, tag = "12")]
617    pub win_rate: ::core::option::Option<f64>,
618    #[prost(double, optional, tag = "13")]
619    pub profit_factor: ::core::option::Option<f64>,
620    /// Whether the data behind it has changed since it was recorded.
621    #[prost(bool, optional, tag = "14")]
622    pub stale: ::core::option::Option<bool>,
623}
624/// Several findings, read against each other.
625#[derive(serde::Serialize, serde::Deserialize)]
626#[derive(Clone, PartialEq, ::prost::Message)]
627pub struct ComparisonView {
628    #[prost(message, repeated, tag = "1")]
629    pub rows: ::prost::alloc::vec::Vec<ComparisonRowView>,
630    #[prost(message, repeated, tag = "2")]
631    pub curves: ::prost::alloc::vec::Vec<NamedCurveView>,
632    /// The best out-of-sample Sharpe among them, and the score the best of a
633    /// comparison this size would be expected to reach with no skill at all.
634    ///
635    /// The point of the whole screen. Comparing six strategies and keeping the
636    /// best one is a search of size six, and until now nothing counted it:
637    /// each finding deflated the grid *inside* it and none of them knew about
638    /// the other five.
639    #[prost(double, optional, tag = "3")]
640    pub best_sharpe: ::core::option::Option<f64>,
641    #[prost(double, optional, tag = "4")]
642    pub expected_best_under_null: ::core::option::Option<f64>,
643    #[prost(bool, tag = "5")]
644    pub survived_deflation: bool,
645    /// What is worth saying about the comparison itself.
646    #[prost(string, repeated, tag = "6")]
647    pub notes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
648}
649/// One row of a correlation matrix. A cell with no value is a pair with too
650/// little overlap to say anything about, which is not the same as zero.
651#[derive(serde::Serialize, serde::Deserialize)]
652#[derive(Clone, PartialEq, ::prost::Message)]
653pub struct CorrelationRow {
654    #[prost(message, repeated, tag = "1")]
655    pub cells: ::prost::alloc::vec::Vec<OptionalDouble>,
656}
657/// One point on a curve, in the shape a chart library wants: an ISO date and
658/// a value.
659#[derive(serde::Serialize, serde::Deserialize)]
660#[derive(Clone, Copy, PartialEq, ::prost::Message)]
661pub struct CurvePoint {
662    /// Seconds since the epoch, not a date string.
663    ///
664    /// A date was enough while every curve was daily and is not once two
665    /// points can share a day: the chart keys points by time, so an intraday
666    /// series collapsed to dates loses every point but the last of each day.
667    /// The previous version did exactly that, deliberately and with a comment
668    /// saying so — this is what removing the limitation instead looks like.
669    #[prost(int64, tag = "1")]
670    pub time: i64,
671    #[prost(double, tag = "2")]
672    pub value: f64,
673}
674/// Where a replay first stopped matching the record.
675#[derive(serde::Serialize, serde::Deserialize)]
676#[derive(Clone, PartialEq, ::prost::Message)]
677pub struct DivergenceView {
678    #[prost(string, tag = "1")]
679    pub what: ::prost::alloc::string::String,
680    #[prost(uint32, optional, tag = "2")]
681    pub at: ::core::option::Option<u32>,
682    #[prost(string, optional, tag = "3")]
683    pub when: ::core::option::Option<::prost::alloc::string::String>,
684    #[prost(double, tag = "4")]
685    pub recorded: f64,
686    #[prost(double, tag = "5")]
687    pub replayed: f64,
688    /// Gap relative to the recorded value, so a report can separate a
689    /// rounding difference from a different answer.
690    #[prost(double, tag = "6")]
691    pub relative: f64,
692}
693#[derive(serde::Serialize, serde::Deserialize)]
694#[derive(Clone, Copy, PartialEq, ::prost::Message)]
695pub struct DividendGapView {
696    /// Distributions that went ex inside the window.
697    ///
698    /// Zero is a real answer and a good one: these instruments pay nothing, so
699    /// the margin needs no correction.
700    #[prost(uint32, tag = "1")]
701    pub events: u32,
702    #[prost(double, tag = "2")]
703    pub strategy_income: f64,
704    #[prost(double, tag = "3")]
705    pub benchmark_income: f64,
706    /// The gap as a fraction of starting capital, in the same units as the
707    /// excess return it comes off.
708    #[prost(double, tag = "4")]
709    pub overstatement: f64,
710    /// The excess return with the gap taken out, where taking it out means
711    /// anything.
712    ///
713    /// `None` on a total-return dataset: the distributions are already in the
714    /// excess return there, so subtracting the gap again would report a margin
715    /// smaller than the account earned. The rest of this view still holds —
716    /// only the subtraction stops being valid.
717    #[prost(double, optional, tag = "5")]
718    pub corrected_excess: ::core::option::Option<f64>,
719    /// False when some instrument the run held has no distribution series, in
720    /// which case the figure is a floor rather than the answer.
721    #[prost(bool, tag = "6")]
722    pub complete: bool,
723    #[prost(uint32, tag = "7")]
724    pub covered: u32,
725    #[prost(uint32, tag = "8")]
726    pub instruments: u32,
727}
728/// One fold of a walk-forward, flattened for display.
729#[derive(serde::Serialize, serde::Deserialize)]
730#[derive(Clone, PartialEq, ::prost::Message)]
731pub struct FoldView {
732    #[prost(string, tag = "1")]
733    pub chose_on: ::prost::alloc::string::String,
734    #[prost(string, tag = "2")]
735    pub judged_on: ::prost::alloc::string::String,
736    #[prost(message, repeated, tag = "3")]
737    pub params: ::prost::alloc::vec::Vec<NamedNumber>,
738    #[prost(double, tag = "4")]
739    pub strategy_return: f64,
740    #[prost(double, tag = "5")]
741    pub benchmark_return: f64,
742    #[prost(uint32, tag = "6")]
743    pub trades: u32,
744    /// Whether this fold's winner beat what a no-skill search of that size
745    /// would produce. Per fold, because a procedure that selects noise in most
746    /// periods has not been shown to select.
747    #[prost(bool, tag = "7")]
748    pub survived_deflation: bool,
749}
750#[derive(serde::Serialize, serde::Deserialize)]
751#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
752pub struct HistoryEntryView {
753    #[prost(string, tag = "1")]
754    pub id: ::prost::alloc::string::String,
755    #[prost(string, tag = "2")]
756    pub kind: ::prost::alloc::string::String,
757    #[prost(string, tag = "3")]
758    pub subject: ::prost::alloc::string::String,
759    #[prost(string, tag = "4")]
760    pub verdict: ::prost::alloc::string::String,
761    #[prost(string, tag = "5")]
762    pub recorded_at: ::prost::alloc::string::String,
763    /// True when the data this was produced from no longer matches disk, or
764    /// the ruleset it ran has changed since. `None` when the data it
765    /// referenced can no longer be found at all.
766    #[prost(bool, optional, tag = "6")]
767    pub stale: ::core::option::Option<bool>,
768    /// The agent that ran it, or `None` for a person. `default` for a view
769    /// built before agents could run research.
770    #[prost(string, optional, tag = "7")]
771    pub agent: ::core::option::Option<::prost::alloc::string::String>,
772    /// Where the agent's code asked for it, as `path:line`, when it said.
773    #[prost(string, optional, tag = "8")]
774    pub origin: ::core::option::Option<::prost::alloc::string::String>,
775    /// The size of the search an agent's finding was held to.
776    #[prost(uint32, optional, tag = "9")]
777    pub trials: ::core::option::Option<u32>,
778    /// How many files are kept with it (#157).
779    #[prost(uint32, tag = "10")]
780    pub attachments: u32,
781    /// What produced it (#189): the engine build, and for a ruleset the
782    /// document's hash at run time. Two findings from different versions of
783    /// one ruleset are told apart by this.
784    #[prost(string, tag = "11")]
785    pub code_commit: ::prost::alloc::string::String,
786    #[prost(string, tag = "12")]
787    pub ruleset_hash: ::prost::alloc::string::String,
788    /// Why `stale` is set: `data`, `ruleset`, or `data and ruleset`. Empty
789    /// when fresh, and when the data is gone altogether.
790    #[prost(string, tag = "13")]
791    pub stale_reason: ::prost::alloc::string::String,
792}
793/// What the workbench shows before anything has been run.
794/// Everything in research memory, and what could not be read of it.
795#[derive(serde::Serialize, serde::Deserialize)]
796#[derive(Clone, PartialEq, ::prost::Message)]
797pub struct HistoryView {
798    #[prost(message, repeated, tag = "1")]
799    pub entries: ::prost::alloc::vec::Vec<HistoryEntryView>,
800    #[prost(message, repeated, tag = "2")]
801    pub unreadable: ::prost::alloc::vec::Vec<UnreadableView>,
802}
803/// What one member of a book actually contributed.
804///
805/// A book reports one return for several instruments, and the single most
806/// useful question about it is which of them produced that return. The panel
807/// answers the same question by running members separately; a book cannot,
808/// because the members interfere — so it has to be read out of the ledger.
809#[derive(serde::Serialize, serde::Deserialize)]
810#[derive(Clone, PartialEq, ::prost::Message)]
811pub struct MemberView {
812    #[prost(string, tag = "1")]
813    pub instrument: ::prost::alloc::string::String,
814    #[prost(uint32, tag = "2")]
815    pub trades: u32,
816    /// Realised profit, net of what the venue charged.
817    #[prost(double, tag = "3")]
818    pub pnl: f64,
819    /// This member's share of the book's total realised profit.
820    ///
821    /// `None` when the book realised nothing at all, rather than a share of
822    /// zero — which would read as a measurement.
823    #[prost(double, optional, tag = "4")]
824    pub share: ::core::option::Option<f64>,
825    /// True when the member never opened a position.
826    ///
827    /// The failure mode a shared account introduces: an instrument that was
828    /// asked for, funded by nothing, and silently absent from every number.
829    #[prost(bool, tag = "5")]
830    pub silent: bool,
831}
832#[derive(serde::Serialize, serde::Deserialize)]
833#[derive(Clone, Copy, PartialEq, ::prost::Message)]
834pub struct MetricsView {
835    #[prost(double, tag = "1")]
836    pub total_return: f64,
837    #[prost(double, tag = "2")]
838    pub cagr: f64,
839    #[prost(double, tag = "3")]
840    pub max_drawdown: f64,
841    #[prost(double, tag = "4")]
842    pub volatility: f64,
843    #[prost(double, optional, tag = "5")]
844    pub sharpe: ::core::option::Option<f64>,
845    #[prost(double, optional, tag = "6")]
846    pub sortino: ::core::option::Option<f64>,
847    #[prost(double, optional, tag = "7")]
848    pub calmar: ::core::option::Option<f64>,
849    /// Probability the true Sharpe is above zero, given the sample.
850    ///
851    /// The second number a Sharpe needs. 1.2 from forty returns and 1.2 from
852    /// four thousand print identically and are not the same finding.
853    #[prost(double, optional, tag = "8")]
854    pub psr: ::core::option::Option<f64>,
855    #[prost(uint32, tag = "9")]
856    pub trades: u32,
857}
858/// One month of the strategy's return, for the heatmap.
859#[derive(serde::Serialize, serde::Deserialize)]
860#[derive(Clone, Copy, PartialEq, ::prost::Message)]
861pub struct MonthlyReturnView {
862    #[prost(int32, tag = "1")]
863    pub year: i32,
864    #[prost(uint32, tag = "2")]
865    pub month: u32,
866    #[prost(double, tag = "3")]
867    pub value: f64,
868}
869/// A named equity curve, for drawing several on one chart.
870#[derive(serde::Serialize, serde::Deserialize)]
871#[derive(Clone, PartialEq, ::prost::Message)]
872pub struct NamedCurveView {
873    #[prost(string, tag = "1")]
874    pub name: ::prost::alloc::string::String,
875    #[prost(message, repeated, tag = "2")]
876    pub points: ::prost::alloc::vec::Vec<CurvePoint>,
877}
878/// What a front end renders.
879///
880/// These are the shapes the engine answers with. They are here rather than
881/// in a Rust crate both sides link so that the contract has no language in
882/// it: a front end in any language generates these and reads a finding
883/// natively (#127).
884///
885/// Generated once from the desktop's Rust, then maintained here. Field numbers are
886/// the contract; add, never renumber.
887/// A parameter and its value, in the order a run chose them. Ordered, so a
888/// repeated field rather than a map.
889#[derive(serde::Serialize, serde::Deserialize)]
890#[derive(Clone, PartialEq, ::prost::Message)]
891pub struct NamedNumber {
892    #[prost(string, tag = "1")]
893    pub name: ::prost::alloc::string::String,
894    #[prost(double, tag = "2")]
895    pub value: f64,
896}
897#[derive(serde::Serialize, serde::Deserialize)]
898#[derive(Clone, Copy, PartialEq, ::prost::Message)]
899pub struct OptionalDouble {
900    #[prost(double, optional, tag = "1")]
901    pub value: ::core::option::Option<f64>,
902}
903/// One instrument's out-of-sample outcome under the panel's configuration.
904#[derive(serde::Serialize, serde::Deserialize)]
905#[derive(Clone, PartialEq, ::prost::Message)]
906pub struct OutcomeView {
907    #[prost(string, tag = "1")]
908    pub instrument: ::prost::alloc::string::String,
909    #[prost(double, tag = "2")]
910    pub strategy_return: f64,
911    #[prost(double, tag = "3")]
912    pub benchmark_return: f64,
913    #[prost(double, tag = "4")]
914    pub excess_return: f64,
915    #[prost(double, tag = "5")]
916    pub max_drawdown: f64,
917    #[prost(uint32, tag = "6")]
918    pub trades: u32,
919}
920/// A panel study, flattened for display.
921#[derive(serde::Serialize, serde::Deserialize)]
922#[derive(Clone, PartialEq, ::prost::Message)]
923pub struct PanelView {
924    /// The stored finding this view came from, so the window can ask for
925    /// something to be done to the record it is showing — a report composed
926    /// from it, a file kept with it. Empty for a view that was never
927    /// recorded. `default` because every view built before this had none.
928    #[prost(string, tag = "1")]
929    pub id: ::prost::alloc::string::String,
930    #[prost(string, tag = "2")]
931    pub verdict: ::prost::alloc::string::String,
932    #[prost(string, repeated, tag = "3")]
933    pub reasons: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
934    #[prost(message, repeated, tag = "4")]
935    pub recommendations: ::prost::alloc::vec::Vec<RecommendationView>,
936    #[prost(uint32, tag = "5")]
937    pub instruments: u32,
938    #[prost(uint32, tag = "6")]
939    pub total_trades: u32,
940    #[prost(double, tag = "7")]
941    pub mean_excess_return: f64,
942    #[prost(uint32, tag = "8")]
943    pub beat_benchmark: u32,
944    #[prost(double, tag = "9")]
945    pub mean_max_drawdown: f64,
946    #[prost(message, optional, tag = "10")]
947    pub breadth: ::core::option::Option<BreadthView>,
948    #[prost(message, optional, tag = "11")]
949    pub book: ::core::option::Option<BookView>,
950    #[prost(double, tag = "12")]
951    pub worst_max_drawdown: f64,
952    #[prost(uint32, tag = "13")]
953    pub trials: u32,
954    #[prost(double, tag = "14")]
955    pub best_sharpe: f64,
956    #[prost(double, optional, tag = "15")]
957    pub expected_best_under_null: ::core::option::Option<f64>,
958    #[prost(bool, tag = "16")]
959    pub survived_deflation: bool,
960    #[prost(string, tag = "17")]
961    pub in_sample: ::prost::alloc::string::String,
962    #[prost(string, tag = "18")]
963    pub out_of_sample: ::prost::alloc::string::String,
964    #[prost(message, repeated, tag = "19")]
965    pub selected_params: ::prost::alloc::vec::Vec<NamedNumber>,
966    #[prost(message, repeated, tag = "20")]
967    pub per_instrument: ::prost::alloc::vec::Vec<OutcomeView>,
968    #[prost(string, repeated, tag = "21")]
969    pub failures: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
970    #[prost(string, tag = "22")]
971    pub dataset_version: ::prost::alloc::string::String,
972    #[prost(string, tag = "23")]
973    pub strategy_name: ::prost::alloc::string::String,
974    #[prost(double, tag = "24")]
975    pub starting_cash: f64,
976    #[prost(double, tag = "25")]
977    pub commission_bps: f64,
978    #[prost(double, tag = "26")]
979    pub slippage_bps: f64,
980    #[prost(string, tag = "27")]
981    pub engine: ::prost::alloc::string::String,
982}
983/// One thing to do about a finding, flattened for display.
984#[derive(serde::Serialize, serde::Deserialize)]
985#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
986pub struct RecommendationView {
987    #[prost(string, tag = "1")]
988    pub severity: ::prost::alloc::string::String,
989    #[prost(string, tag = "2")]
990    pub finding: ::prost::alloc::string::String,
991    #[prost(string, tag = "3")]
992    pub action: ::prost::alloc::string::String,
993    #[prost(string, tag = "4")]
994    pub evidence: ::prost::alloc::string::String,
995}
996/// A stored finding, reopened.
997#[derive(serde::Serialize, serde::Deserialize)]
998#[derive(Clone, PartialEq, ::prost::Message)]
999pub struct RecordView {
1000    #[prost(oneof = "record_view::Of", tags = "1, 2, 3, 4")]
1001    pub of: ::core::option::Option<record_view::Of>,
1002}
1003/// Nested message and enum types in `RecordView`.
1004pub mod record_view {
1005    #[derive(serde::Serialize, serde::Deserialize)]
1006    #[derive(Clone, PartialEq, ::prost::Oneof)]
1007    pub enum Of {
1008        #[prost(message, tag = "1")]
1009        Study(super::StudyView),
1010        #[prost(message, tag = "2")]
1011        Panel(super::PanelView),
1012        #[prost(message, tag = "3")]
1013        Walkforward(super::WalkForwardView),
1014        #[prost(message, tag = "4")]
1015        Reported(super::ReportedView),
1016    }
1017}
1018/// What came back from re-running a stored finding.
1019///
1020/// A finding whose numbers cannot be regenerated is not evidence, so this is
1021/// the check the whole evidence store rests on.
1022#[derive(serde::Serialize, serde::Deserialize)]
1023#[derive(Clone, PartialEq, ::prost::Message)]
1024pub struct ReplayView {
1025    /// `reproduced`, `data-changed`, `engine-changed`, `diverged`,
1026    /// `not-replayable` or `failed`. A slug so the window can style it
1027    /// without parsing prose.
1028    #[prost(string, tag = "1")]
1029    pub outcome: ::prost::alloc::string::String,
1030    /// Whether the finding still stands. Only a clean reproduction counts:
1031    /// changed data or a changed engine leaves the claim untested, which is
1032    /// not the same as confirmed.
1033    #[prost(bool, tag = "2")]
1034    pub holds: bool,
1035    #[prost(string, tag = "3")]
1036    pub detail: ::prost::alloc::string::String,
1037    #[prost(message, optional, tag = "4")]
1038    pub divergence: ::core::option::Option<DivergenceView>,
1039}
1040/// A finding an engine Arvo did not run computed, judged by Arvo
1041/// (ADR-0026). Shown as what it is: the numbers and the verdict, and where
1042/// the data lives.
1043#[derive(serde::Serialize, serde::Deserialize)]
1044#[derive(Clone, PartialEq, ::prost::Message)]
1045pub struct ReportedView {
1046    #[prost(string, tag = "1")]
1047    pub id: ::prost::alloc::string::String,
1048    #[prost(string, tag = "2")]
1049    pub hypothesis: ::prost::alloc::string::String,
1050    #[prost(string, tag = "3")]
1051    pub claim: ::prost::alloc::string::String,
1052    #[prost(string, tag = "4")]
1053    pub instrument: ::prost::alloc::string::String,
1054    #[prost(string, tag = "5")]
1055    pub engine: ::prost::alloc::string::String,
1056    #[prost(string, tag = "6")]
1057    pub from: ::prost::alloc::string::String,
1058    #[prost(string, tag = "7")]
1059    pub to: ::prost::alloc::string::String,
1060    #[prost(string, tag = "8")]
1061    pub interval: ::prost::alloc::string::String,
1062    /// `id@version`: the engine's own dataset, not in Arvo's library.
1063    #[prost(string, tag = "9")]
1064    pub dataset: ::prost::alloc::string::String,
1065    #[prost(string, tag = "10")]
1066    pub strategy: ::prost::alloc::string::String,
1067    #[prost(string, tag = "11")]
1068    pub verdict: ::prost::alloc::string::String,
1069    #[prost(string, repeated, tag = "12")]
1070    pub reasons: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
1071    #[prost(uint32, tag = "13")]
1072    pub trades: u32,
1073    #[prost(uint32, optional, tag = "14")]
1074    pub trials: ::core::option::Option<u32>,
1075    /// Absent when there was no benchmark to judge against.
1076    #[prost(double, optional, tag = "15")]
1077    pub total_return: ::core::option::Option<f64>,
1078    #[prost(double, optional, tag = "16")]
1079    pub excess_return: ::core::option::Option<f64>,
1080    #[prost(double, optional, tag = "17")]
1081    pub sharpe: ::core::option::Option<f64>,
1082    #[prost(double, optional, tag = "18")]
1083    pub max_drawdown: ::core::option::Option<f64>,
1084    #[prost(string, tag = "19")]
1085    pub recorded_at: ::prost::alloc::string::String,
1086    #[prost(string, tag = "20")]
1087    pub author: ::prost::alloc::string::String,
1088    /// The files kept with it: a report, a figure, the trades (#157).
1089    #[prost(message, repeated, tag = "21")]
1090    pub attachments: ::prost::alloc::vec::Vec<Attachment>,
1091}
1092/// How much one parameter moved across the folds.
1093#[derive(serde::Serialize, serde::Deserialize)]
1094#[derive(Clone, PartialEq, ::prost::Message)]
1095pub struct StabilityView {
1096    #[prost(string, tag = "1")]
1097    pub axis: ::prost::alloc::string::String,
1098    #[prost(uint32, tag = "2")]
1099    pub distinct: u32,
1100    #[prost(double, tag = "3")]
1101    pub modal: f64,
1102    #[prost(double, tag = "4")]
1103    pub modal_share: f64,
1104}
1105/// The full result of a study, flattened for display.
1106#[derive(serde::Serialize, serde::Deserialize)]
1107#[derive(Clone, PartialEq, ::prost::Message)]
1108pub struct StudyView {
1109    /// The stored finding this view came from, so the window can ask for
1110    /// something to be done to the record it is showing — a report composed
1111    /// from it, a file kept with it. Empty for a view that was never
1112    /// recorded. `default` because every view built before this had none.
1113    #[prost(string, tag = "1")]
1114    pub id: ::prost::alloc::string::String,
1115    #[prost(string, tag = "2")]
1116    pub instrument: ::prost::alloc::string::String,
1117    /// Every instrument the run held, head first.
1118    ///
1119    /// One entry is an ordinary study. More than one is a book: the same rule
1120    /// on several instruments settling against a single account, where a
1121    /// position one member takes is capital another cannot have.
1122    ///
1123    /// `default` because this is a persisted format — a finding recorded
1124    /// before a run could hold more than one loads as what it was.
1125    #[prost(string, repeated, tag = "3")]
1126    pub instruments: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
1127    /// What each member of a book contributed. Empty for a single study.
1128    #[prost(message, repeated, tag = "4")]
1129    pub members: ::prost::alloc::vec::Vec<MemberView>,
1130    #[prost(string, tag = "5")]
1131    pub verdict: ::prost::alloc::string::String,
1132    #[prost(string, repeated, tag = "6")]
1133    pub reasons: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
1134    #[prost(uint32, tag = "7")]
1135    pub trials: u32,
1136    /// Configurations tried elsewhere before a shared experiment arrived,
1137    /// counted into the bar. `default`: a view built before sharing had none.
1138    #[prost(uint32, tag = "8")]
1139    pub prior_trials: u32,
1140    #[prost(double, tag = "9")]
1141    pub best_sharpe: f64,
1142    #[prost(double, optional, tag = "10")]
1143    pub expected_best_under_null: ::core::option::Option<f64>,
1144    #[prost(bool, tag = "11")]
1145    pub survived_deflation: bool,
1146    /// Every configuration the search tried, not only the one it picked.
1147    #[prost(message, optional, tag = "12")]
1148    pub surface: ::core::option::Option<SurfaceView>,
1149    #[prost(string, tag = "13")]
1150    pub in_sample: ::prost::alloc::string::String,
1151    #[prost(string, tag = "14")]
1152    pub out_of_sample: ::prost::alloc::string::String,
1153    #[prost(message, repeated, tag = "15")]
1154    pub selected_params: ::prost::alloc::vec::Vec<NamedNumber>,
1155    #[prost(message, optional, tag = "16")]
1156    pub strategy: ::core::option::Option<MetricsView>,
1157    #[prost(message, optional, tag = "17")]
1158    pub benchmark: ::core::option::Option<MetricsView>,
1159    /// Uncorrected. \[`Self::dividend_gap`\] sits beside it rather than being
1160    /// folded in: a number silently adjusted by something the reader cannot see
1161    /// is what this platform exists to stop.
1162    #[prost(double, tag = "18")]
1163    pub excess_return: f64,
1164    /// How much of that margin is the dividend bias rather than skill.
1165    ///
1166    /// `None` means it was never measured — no distribution series is held for
1167    /// these instruments. The bias is real either way; only its size is
1168    /// unknown, and `recommendations` says so.
1169    #[prost(message, optional, tag = "19")]
1170    pub dividend_gap: ::core::option::Option<DividendGapView>,
1171    /// Both sides after capital-gains tax at stated rates, sold at the end
1172    /// (#26). Beside the excess return for the same reason as the dividend
1173    /// gap. `None` when the curves are too short to tax.
1174    #[prost(message, optional, tag = "20")]
1175    pub after_tax: ::core::option::Option<AfterTaxView>,
1176    /// The two curves behind the numbers. A table says a strategy returned
1177    /// less than the market; a chart says whether it did so steadily or lost
1178    /// it all in one month, and those are different findings.
1179    #[prost(message, repeated, tag = "21")]
1180    pub strategy_curve: ::prost::alloc::vec::Vec<CurvePoint>,
1181    #[prost(message, repeated, tag = "22")]
1182    pub benchmark_curve: ::prost::alloc::vec::Vec<CurvePoint>,
1183    /// The instrument's own bars over the judged period, with every entry and
1184    /// exit marked on them.
1185    ///
1186    /// The view that shows what the rule *did* rather than what it added up
1187    /// to. A summary cannot say the entries all landed on three days, or that
1188    /// every winner came out of one gap; this says it at a glance.
1189    #[prost(message, repeated, tag = "23")]
1190    pub price: ::prost::alloc::vec::Vec<CandlePoint>,
1191    #[prost(message, repeated, tag = "24")]
1192    pub markers: ::prost::alloc::vec::Vec<TradeMarkerView>,
1193    /// The rest of a book's instruments, each with its own bars and its own
1194    /// trades. Empty for a single study.
1195    ///
1196    /// The head instrument is deliberately *not* repeated here — it is already
1197    /// \[`Self::price`\] and \[`Self::markers`\] above. The shape mirrors
1198    /// `Experiment.alongside`, which is head plus the rest for the same reason:
1199    /// carrying the head twice would put a third of a three-member book's
1200    /// candles on the wire for nothing.
1201    #[prost(message, repeated, tag = "25")]
1202    pub alongside_charts: ::prost::alloc::vec::Vec<InstrumentChartView>,
1203    /// Depth below the running peak, as a percentage.
1204    #[prost(message, repeated, tag = "26")]
1205    pub underwater: ::prost::alloc::vec::Vec<CurvePoint>,
1206    /// What is wrong with the bars this was produced from.
1207    #[prost(message, repeated, tag = "27")]
1208    pub data_findings: ::prost::alloc::vec::Vec<
1209        super::super::market::v1::DataFindingView,
1210    >,
1211    /// Every round trip, so nobody has to take the summary on trust.
1212    #[prost(message, repeated, tag = "28")]
1213    pub trades: ::prost::alloc::vec::Vec<TradeRowView>,
1214    /// Month-by-month, so a total return can be read as steady or as one
1215    /// lucky quarter. Derived from the same curve, not a second measurement.
1216    #[prost(message, repeated, tag = "29")]
1217    pub monthly: ::prost::alloc::vec::Vec<MonthlyReturnView>,
1218    /// The round trips behind the return, and what they cost.
1219    #[prost(message, optional, tag = "30")]
1220    pub trades_detail: ::core::option::Option<TradesView>,
1221    /// What to do about this finding, most stopping first.
1222    ///
1223    /// Derived on read rather than stored, so a finding pulled out of memory
1224    /// is read against today's rules rather than the ones in force when it
1225    /// was recorded.
1226    #[prost(message, repeated, tag = "31")]
1227    pub recommendations: ::prost::alloc::vec::Vec<RecommendationView>,
1228    /// The dataset this result was produced from, as a content hash. Compared
1229    /// against the live one to decide whether the result is still current.
1230    #[prost(string, tag = "32")]
1231    pub dataset_version: ::prost::alloc::string::String,
1232    #[prost(string, tag = "33")]
1233    pub strategy_name: ::prost::alloc::string::String,
1234    #[prost(double, tag = "34")]
1235    pub starting_cash: f64,
1236    #[prost(double, tag = "35")]
1237    pub commission_bps: f64,
1238    #[prost(double, tag = "36")]
1239    pub slippage_bps: f64,
1240    #[prost(string, tag = "37")]
1241    pub engine: ::prost::alloc::string::String,
1242}
1243/// One configuration's cell on the search surface.
1244#[derive(serde::Serialize, serde::Deserialize)]
1245#[derive(Clone, Copy, PartialEq, ::prost::Message)]
1246pub struct SurfaceCell {
1247    #[prost(double, tag = "1")]
1248    pub x: f64,
1249    #[prost(double, tag = "2")]
1250    pub y: f64,
1251    #[prost(double, tag = "3")]
1252    pub sharpe: f64,
1253    /// Whether this is the configuration that was chosen.
1254    #[prost(bool, tag = "4")]
1255    pub selected: bool,
1256    /// Whether it beat what a no-skill search of this size would produce.
1257    ///
1258    /// The distinction the whole chart is drawn around. A cell below the bar
1259    /// is not a weak result, it is *not a result* — a score a coin-flipping
1260    /// search of the same size would have been expected to reach anyway.
1261    #[prost(bool, tag = "5")]
1262    pub above_null: bool,
1263}
1264/// The in-sample score of every configuration the search tried.
1265///
1266/// # Why this exists at all
1267///
1268/// Reporting only the winner shows two completely different situations
1269/// identically: a broad region of configurations that all scored well, which
1270/// suggests something real and robust to the exact parameters; and one bright
1271/// cell surrounded by nothing, which is what fitting noise looks like from
1272/// above. The verdict machinery already deflates for the *size* of the search;
1273/// this is the part a person has to look at.
1274#[derive(serde::Serialize, serde::Deserialize)]
1275#[derive(Clone, PartialEq, ::prost::Message)]
1276pub struct SurfaceView {
1277    /// The two axes drawn, by name.
1278    #[prost(string, tag = "1")]
1279    pub x_axis: ::prost::alloc::string::String,
1280    #[prost(string, tag = "2")]
1281    pub y_axis: ::prost::alloc::string::String,
1282    #[prost(double, repeated, tag = "3")]
1283    pub x_values: ::prost::alloc::vec::Vec<f64>,
1284    #[prost(double, repeated, tag = "4")]
1285    pub y_values: ::prost::alloc::vec::Vec<f64>,
1286    #[prost(message, repeated, tag = "5")]
1287    pub cells: ::prost::alloc::vec::Vec<SurfaceCell>,
1288    /// The bar a cell has to clear to be worth anything. `None` when there
1289    /// were too few trials to say.
1290    #[prost(double, optional, tag = "6")]
1291    pub null_bar: ::core::option::Option<f64>,
1292    #[prost(double, tag = "7")]
1293    pub best: f64,
1294    /// Axes not drawn, because a surface has two dimensions and a grid may
1295    /// have more. Named so nobody reads the chart as the whole search.
1296    #[prost(string, repeated, tag = "8")]
1297    pub collapsed: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
1298}
1299/// Where a trade happened, to be drawn on the price.
1300#[derive(serde::Serialize, serde::Deserialize)]
1301#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
1302pub struct TradeMarkerView {
1303    #[prost(int64, tag = "1")]
1304    pub time: i64,
1305    /// `entry` or `exit`; the chart decides shape and side from it.
1306    #[prost(string, tag = "2")]
1307    pub kind: ::prost::alloc::string::String,
1308    /// `stop` or `signal` for an exit, so a stop-out is visually distinct
1309    /// from a rule that chose to leave. Empty for an entry.
1310    #[prost(string, tag = "3")]
1311    pub reason: ::prost::alloc::string::String,
1312    #[prost(string, tag = "4")]
1313    pub label: ::prost::alloc::string::String,
1314}
1315/// One round trip, as a table row.
1316///
1317/// Every field the ledger holds, because the point of a table is that nobody
1318/// has to decide in advance which column someone will want to sort by. The
1319/// aggregate statistics above it answer "how did it do"; this answers "what
1320/// did it actually do", and those are different questions with different
1321/// failure modes — an expectancy of +£300 built from one +£9,000 trade and
1322/// nineteen losses is a fact only the rows show.
1323#[derive(serde::Serialize, serde::Deserialize)]
1324#[derive(Clone, PartialEq, ::prost::Message)]
1325pub struct TradeRowView {
1326    /// Which instrument this round trip was in.
1327    ///
1328    /// Empty for a run recorded before the ledger named instruments, and for
1329    /// an ordinary single-instrument study where the subject line already
1330    /// says it. Only a book shows the column.
1331    #[prost(string, tag = "1")]
1332    pub instrument: ::prost::alloc::string::String,
1333    #[prost(string, tag = "2")]
1334    pub opened: ::prost::alloc::string::String,
1335    /// Empty while the position is still open at the end of the run.
1336    #[prost(string, tag = "3")]
1337    pub closed: ::prost::alloc::string::String,
1338    #[prost(string, tag = "4")]
1339    pub direction: ::prost::alloc::string::String,
1340    #[prost(double, tag = "5")]
1341    pub quantity: f64,
1342    #[prost(double, tag = "6")]
1343    pub entry: f64,
1344    /// `None` while still open, so the table shows a gap rather than a price
1345    /// nobody traded at.
1346    #[prost(double, optional, tag = "7")]
1347    pub exit: ::core::option::Option<f64>,
1348    #[prost(double, tag = "8")]
1349    pub pnl: f64,
1350    #[prost(double, tag = "9")]
1351    pub commission: f64,
1352    /// Days held. Fractional, because an intraday trade held forty minutes is
1353    /// not "0 days" — it is 0.03, and rounding it away would make every
1354    /// intraday ledger look like a column of zeroes.
1355    #[prost(double, optional, tag = "10")]
1356    pub held_days: ::core::option::Option<f64>,
1357    /// `signal`, `stop`, or `open`.
1358    #[prost(string, tag = "11")]
1359    pub exit_reason: ::prost::alloc::string::String,
1360    /// What the rule saw at entry (#190): the condition that fired, the value it
1361    /// was judged on, the regime it saw, and the quantity it asked the gate for.
1362    /// Absent on a trade recorded before the journal or opened by no rule.
1363    #[prost(string, optional, tag = "12")]
1364    pub rule: ::core::option::Option<::prost::alloc::string::String>,
1365    #[prost(double, optional, tag = "13")]
1366    pub signal: ::core::option::Option<f64>,
1367    #[prost(string, optional, tag = "14")]
1368    pub regime: ::core::option::Option<::prost::alloc::string::String>,
1369    #[prost(double, optional, tag = "15")]
1370    pub asked: ::core::option::Option<f64>,
1371}
1372/// What the round trips looked like, flattened for display.
1373///
1374/// Beside the metrics rather than inside them: metrics come from the equity
1375/// curve and these come from the ledger, and keeping the two apart is what
1376/// makes it obvious which is which when they say different things.
1377#[derive(serde::Serialize, serde::Deserialize)]
1378#[derive(Clone, Copy, PartialEq, ::prost::Message)]
1379pub struct TradesView {
1380    #[prost(uint32, tag = "1")]
1381    pub closed: u32,
1382    #[prost(uint32, tag = "2")]
1383    pub still_open: u32,
1384    #[prost(double, optional, tag = "3")]
1385    pub win_rate: ::core::option::Option<f64>,
1386    #[prost(double, optional, tag = "4")]
1387    pub profit_factor: ::core::option::Option<f64>,
1388    #[prost(double, optional, tag = "5")]
1389    pub expectancy: ::core::option::Option<f64>,
1390    #[prost(double, optional, tag = "6")]
1391    pub average_win: ::core::option::Option<f64>,
1392    #[prost(double, optional, tag = "7")]
1393    pub average_loss: ::core::option::Option<f64>,
1394    /// Mean holding period in days, which is the unit a reader thinks in and
1395    /// the one that decides short- versus long-term tax treatment.
1396    #[prost(double, optional, tag = "8")]
1397    pub average_holding_days: ::core::option::Option<f64>,
1398    /// Every fee and commission the venue charged, in account currency.
1399    ///
1400    /// Fees only — slippage is charged inside the fill prices and is already
1401    /// reflected in the return, not here. Naming this `fees` rather than
1402    /// `cost` is the whole point: a reader who took it for the total cost of
1403    /// trading would be short by the spread assumption on every round trip.
1404    #[prost(double, tag = "9")]
1405    pub fees_paid: f64,
1406    /// Fees as a fraction of starting capital, so they can be read against
1407    /// the return directly.
1408    #[prost(double, tag = "10")]
1409    pub fees_fraction: f64,
1410    #[prost(uint32, tag = "11")]
1411    pub signal_exits: u32,
1412    #[prost(uint32, tag = "12")]
1413    pub stop_exits: u32,
1414}
1415/// A finding that could not be read, and why.
1416///
1417/// Shown rather than logged. Four findings were once lost to a field rename
1418/// and the only trace was a warning nobody had reason to look at — a research
1419/// store that quietly forgets things is worse than one that says it has.
1420#[derive(serde::Serialize, serde::Deserialize)]
1421#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
1422pub struct UnreadableView {
1423    #[prost(string, tag = "1")]
1424    pub id: ::prost::alloc::string::String,
1425    #[prost(string, tag = "2")]
1426    pub reason: ::prost::alloc::string::String,
1427}
1428/// A walk-forward run, flattened for display.
1429#[derive(serde::Serialize, serde::Deserialize)]
1430#[derive(Clone, PartialEq, ::prost::Message)]
1431pub struct WalkForwardView {
1432    /// The stored finding this view came from, so the window can ask for
1433    /// something to be done to the record it is showing — a report composed
1434    /// from it, a file kept with it. Empty for a view that was never
1435    /// recorded. `default` because every view built before this had none.
1436    #[prost(string, tag = "1")]
1437    pub id: ::prost::alloc::string::String,
1438    #[prost(string, tag = "2")]
1439    pub instrument: ::prost::alloc::string::String,
1440    #[prost(string, tag = "3")]
1441    pub verdict: ::prost::alloc::string::String,
1442    #[prost(string, repeated, tag = "4")]
1443    pub reasons: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
1444    #[prost(message, repeated, tag = "5")]
1445    pub recommendations: ::prost::alloc::vec::Vec<RecommendationView>,
1446    #[prost(message, repeated, tag = "6")]
1447    pub folds: ::prost::alloc::vec::Vec<FoldView>,
1448    #[prost(uint32, tag = "7")]
1449    pub folds_surviving_deflation: u32,
1450    /// Folds in which the selected configuration never opened a position — the
1451    /// symptom of a step too short for the rule's warm-up.
1452    #[prost(uint32, tag = "8")]
1453    pub folds_without_trades: u32,
1454    /// How the selection moved. The thing only a rolling procedure can show.
1455    #[prost(message, repeated, tag = "9")]
1456    pub stability: ::prost::alloc::vec::Vec<StabilityView>,
1457    #[prost(message, optional, tag = "10")]
1458    pub strategy: ::core::option::Option<MetricsView>,
1459    #[prost(message, optional, tag = "11")]
1460    pub benchmark: ::core::option::Option<MetricsView>,
1461    #[prost(double, tag = "12")]
1462    pub excess_return: f64,
1463    #[prost(message, repeated, tag = "13")]
1464    pub strategy_curve: ::prost::alloc::vec::Vec<CurvePoint>,
1465    #[prost(message, repeated, tag = "14")]
1466    pub benchmark_curve: ::prost::alloc::vec::Vec<CurvePoint>,
1467    #[prost(message, repeated, tag = "15")]
1468    pub price: ::prost::alloc::vec::Vec<CandlePoint>,
1469    #[prost(message, repeated, tag = "16")]
1470    pub markers: ::prost::alloc::vec::Vec<TradeMarkerView>,
1471    #[prost(message, repeated, tag = "17")]
1472    pub underwater: ::prost::alloc::vec::Vec<CurvePoint>,
1473    /// What is wrong with the bars this was produced from.
1474    #[prost(message, repeated, tag = "18")]
1475    pub data_findings: ::prost::alloc::vec::Vec<
1476        super::super::market::v1::DataFindingView,
1477    >,
1478    #[prost(message, repeated, tag = "19")]
1479    pub trades: ::prost::alloc::vec::Vec<TradeRowView>,
1480    #[prost(message, optional, tag = "20")]
1481    pub trades_detail: ::core::option::Option<TradesView>,
1482    #[prost(int64, tag = "21")]
1483    pub in_sample_days: i64,
1484    #[prost(int64, tag = "22")]
1485    pub step_days: i64,
1486    #[prost(bool, tag = "23")]
1487    pub anchored: bool,
1488    #[prost(string, tag = "24")]
1489    pub dataset_version: ::prost::alloc::string::String,
1490    #[prost(string, tag = "25")]
1491    pub strategy_name: ::prost::alloc::string::String,
1492    #[prost(double, tag = "26")]
1493    pub starting_cash: f64,
1494    #[prost(double, tag = "27")]
1495    pub commission_bps: f64,
1496    #[prost(double, tag = "28")]
1497    pub slippage_bps: f64,
1498    #[prost(string, tag = "29")]
1499    pub engine: ::prost::alloc::string::String,
1500}
1501/// One bar, as the chart wants it.
1502/// One bar of the library, as the research tier reads it (#195).
1503#[derive(serde::Serialize, serde::Deserialize)]
1504#[derive(Clone, PartialEq, ::prost::Message)]
1505pub struct BarView {
1506    /// When the bar opened.
1507    #[prost(string, tag = "1")]
1508    pub at: ::prost::alloc::string::String,
1509    #[prost(double, tag = "2")]
1510    pub open: f64,
1511    #[prost(double, tag = "3")]
1512    pub high: f64,
1513    #[prost(double, tag = "4")]
1514    pub low: f64,
1515    #[prost(double, tag = "5")]
1516    pub close: f64,
1517    #[prost(double, tag = "6")]
1518    pub volume: f64,
1519}
1520#[derive(serde::Serialize, serde::Deserialize)]
1521#[derive(Clone, PartialEq, ::prost::Message)]
1522pub struct BarsView {
1523    #[prost(string, tag = "1")]
1524    pub instrument: ::prost::alloc::string::String,
1525    #[prost(string, tag = "2")]
1526    pub interval: ::prost::alloc::string::String,
1527    #[prost(message, repeated, tag = "3")]
1528    pub bars: ::prost::alloc::vec::Vec<BarView>,
1529}
1530/// The regime each bar closed in: "trending up", "trending down" or
1531/// "ranging", absent until the lookback has filled. Labelled after the fact
1532/// over the closes, so it says what the market was doing and not what a rule
1533/// could have known at the time.
1534#[derive(serde::Serialize, serde::Deserialize)]
1535#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
1536pub struct RegimePointView {
1537    #[prost(string, tag = "1")]
1538    pub at: ::prost::alloc::string::String,
1539    #[prost(string, optional, tag = "2")]
1540    pub regime: ::core::option::Option<::prost::alloc::string::String>,
1541}
1542#[derive(serde::Serialize, serde::Deserialize)]
1543#[derive(Clone, PartialEq, ::prost::Message)]
1544pub struct RegimeView {
1545    #[prost(string, tag = "1")]
1546    pub instrument: ::prost::alloc::string::String,
1547    #[prost(string, tag = "2")]
1548    pub interval: ::prost::alloc::string::String,
1549    /// Bars each label looks back over.
1550    #[prost(uint32, tag = "3")]
1551    pub lookback: u32,
1552    /// The last bar's regime, when it has one.
1553    #[prost(string, optional, tag = "4")]
1554    pub current: ::core::option::Option<::prost::alloc::string::String>,
1555    #[prost(message, repeated, tag = "5")]
1556    pub points: ::prost::alloc::vec::Vec<RegimePointView>,
1557    /// How many of the returned bars were in each regime.
1558    #[prost(map = "string, uint32", tag = "6")]
1559    pub shares: ::std::collections::HashMap<::prost::alloc::string::String, u32>,
1560}
1561#[derive(serde::Serialize, serde::Deserialize)]
1562#[derive(Clone, Copy, PartialEq, ::prost::Message)]
1563pub struct CandlePoint {
1564    #[prost(int64, tag = "1")]
1565    pub time: i64,
1566    #[prost(double, tag = "2")]
1567    pub open: f64,
1568    #[prost(double, tag = "3")]
1569    pub high: f64,
1570    #[prost(double, tag = "4")]
1571    pub low: f64,
1572    #[prost(double, tag = "5")]
1573    pub close: f64,
1574}
1575/// One instrument's bars with its own trades marked on them.
1576///
1577/// A book holds several, and each chart must show only the round trips that
1578/// happened in *its* instrument. Plotting the whole ledger on one member's
1579/// prices puts entries on days that instrument never traded.
1580#[derive(serde::Serialize, serde::Deserialize)]
1581#[derive(Clone, PartialEq, ::prost::Message)]
1582pub struct InstrumentChartView {
1583    #[prost(string, tag = "1")]
1584    pub instrument: ::prost::alloc::string::String,
1585    #[prost(message, repeated, tag = "2")]
1586    pub price: ::prost::alloc::vec::Vec<CandlePoint>,
1587    #[prost(message, repeated, tag = "3")]
1588    pub markers: ::prost::alloc::vec::Vec<TradeMarkerView>,
1589}
1590/// A finding's caveat, against the script line that produced the finding:
1591/// what the Problems panel lists with source "Arvo" (ADR-0021).
1592#[derive(serde::Serialize, serde::Deserialize)]
1593#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
1594pub struct ResearchProblemView {
1595    /// Relative to the project folder.
1596    #[prost(string, tag = "1")]
1597    pub path: ::prost::alloc::string::String,
1598    #[prost(uint32, tag = "2")]
1599    pub line: u32,
1600    /// `error`, `warning` or `info`.
1601    #[prost(string, tag = "3")]
1602    pub severity: ::prost::alloc::string::String,
1603    #[prost(string, tag = "4")]
1604    pub message: ::prost::alloc::string::String,
1605    /// The finding it comes from, to open.
1606    #[prost(string, tag = "5")]
1607    pub finding: ::prost::alloc::string::String,
1608}
1609/// The Problems panel's rows.
1610///
1611/// A list, as a message: an RPC returns one message, never a bare repeated
1612/// field, so a call that answers with a list needs a name for the list.
1613#[derive(serde::Serialize, serde::Deserialize)]
1614#[derive(Clone, PartialEq, ::prost::Message)]
1615pub struct ProblemsView {
1616    #[prost(message, repeated, tag = "1")]
1617    pub problems: ::prost::alloc::vec::Vec<ResearchProblemView>,
1618}