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