1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! PULL-based corporate-action **sourcing** abstractions.
//!
//! This module models the *global-PULL reference-data* shape shared by providers such as
//! Massive/Polygon and Alpaca: query a provider by symbol + effective-date range and receive a
//! stream of corporate-action facts. The yielded fact is the
//! [`CorporateAction`](rustrade_instrument::corporate_action::CorporateAction) descriptor
//! (re-exported here), keyed by an unresolved provider symbol ([`SmolStr`](smol_str::SmolStr)); a
//! wrapper resolves the symbol to its engine instrument key and supplies the rounding policy +
//! stamping instant before injecting an engine event.
//!
//! # The kind lives in the trait name, not a filter
//!
//! There is deliberately **no unified `CorporateActionSource` with a `kinds` filter**. Reference
//! providers expose a *separate endpoint per action type* (splits vs dividends), so the action kind
//! is encoded in the trait itself: [`StockSplitSource`](crate::corporate_action::StockSplitSource)
//! fetches splits. A `DividendSource` sibling trait is the natural future addition when dividends
//! are needed — each fully typed, with no
//! discriminant enum to keep in lockstep with
//! [`CorporateActionKind`](rustrade_instrument::corporate_action::CorporateActionKind).
//!
//! # What is intentionally out of scope
//!
//! Account-scoped or push-based sources (e.g. Interactive Brokers' WSH / Flex Query feeds) do not
//! fit the global-by-symbol PULL model and are **intentionally not** expressed through this trait.
//! Such a source maps its data onto the same
//! [`CorporateAction`](rustrade_instrument::corporate_action::CorporateAction) descriptor via its
//! own adapter.
use NaiveDate;
use Constructor;
use Stream;
use SmolStr;
pub use ;
/// Filter for a PULL corporate-action reference-data query.
///
/// All fields are optional restrictions; the default (empty `symbols`, no date bounds) requests
/// every action a source knows about, subject to provider limits. Date bounds are inclusive and
/// expressed against the action's **effective date**.
///
/// # Symbols
///
/// `symbols` holds **provider** ticker strings (e.g. `"AAPL"`), not resolved engine keys. An empty
/// `symbols` list means "no symbol restriction". How a source maps multiple symbols onto its
/// transport (one request per symbol vs a single batched request) is an implementation detail.
// Public filter likely to grow (e.g. pagination cursor/limit). `#[non_exhaustive]` keeps adding
// fields non-breaking for downstream users; construct via `CorporateActionFilter::new(..)`, or
// `Default::default()` followed by per-field assignment when forward-compatibility matters
// (struct-update syntax is unavailable to downstream crates on a `#[non_exhaustive]` struct).
/// A source of **stock-split** corporate actions, fetched by symbol + effective-date range.
///
/// Implementors wrap a provider's splits endpoint (e.g. Massive's `/v3/reference/splits`) and yield
/// [`CorporateAction<SmolStr>`] descriptors — the split ratio computed via the shared
/// [`CorporateActionKind::stock_split`] helper, keyed by the provider symbol. The consumer resolves
/// the symbol to an engine instrument key and constructs the engine event.
///
/// The returned stream is lazy: items are produced as it is polled, and the stream is `Send` so it
/// can be driven from any async runtime/task.
///
/// # Object safety
///
/// This trait is **not object-safe**: `fetch_splits` returns `impl Stream + Send` (return-position
/// `impl Trait` in a trait method), which the compiler cannot erase to `dyn`. So
/// `Box<dyn StockSplitSource>` and `Vec<Box<dyn StockSplitSource>>` (e.g. a multi-provider routing
/// table) cannot be formed directly. To hold heterogeneous sources, dispatch over an enum of the
/// concrete types, or write a thin wrapper whose method calls `.boxed()` on the stream and erases to
/// `BoxStream<'_, Result<CorporateAction<SmolStr>, E>>`.