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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//! Cash that moves into or out of an account other than by a trade: perpetual funding, margin
//! interest, stock borrow fees and rebates.
//!
//! An account stream reports each such movement the venue posts as
//! [`AccountEventKind::CashFlow`](crate::AccountEventKind::CashFlow), carrying a [`CashFlow`]. The
//! library delivers the venue's own figures; rates, day counts and what to do with the flows stay
//! the consumer's.
use ;
use ;
use Decimal;
use ;
use SmolStr;
use ;
/// One movement of cash into or out of an account that is not a trade, as the venue posted it.
///
/// Sent as [`AccountEventKind::CashFlow`](crate::AccountEventKind::CashFlow). A flow is a delta:
/// apply each one once. The engine adds a flow attributed to an instrument to the `carry` of that
/// instrument's open position (see `Position::carry` in `rustrade`), and applies none to
/// balances. A venue's balances already include the flows it has posted, so adding a flow to a
/// balance read after it counts the flow twice. Carry a venue has accrued but not yet posted is no
/// flow: a venue that reports it puts it in
/// [`Balance::accrued`](crate::balance::Balance::accrued).
///
/// # Delivery
///
/// Each producer says how it avoids sending one flow twice, and what identifies a flow when the
/// venue gives it no [`id`](Self::id). Known producers, as of writing:
/// - Hyperliquid perpetuals: funding, as [`CashFlowKind::Funding`]. See the client's rustdoc.
/// - Alpaca: margin interest, fees and pass-through charges and rebates, read on request by
/// `AlpacaClient::fetch_cash_flows` rather than streamed, with Alpaca's activity id. The caller
/// drops what it has already read.
/// - Binance margin: interest, as [`CashFlowKind::MarginInterest`], read on request by
/// `BinanceMargin::fetch_margin_interest` rather than streamed, with Binance's transaction id.
/// The caller drops what it has already read.
/// - The simulated venue: whatever its configured
/// [`HoldingCostModel`](crate::holding_cost::HoldingCostModel)s and
/// [`MarginInterestModel`](crate::margin::MarginInterestModel) charge, and the
/// [`LiquidationFee`](CashFlowKind::LiquidationFee) of a configured
/// [`SpotMarginLiquidation`](crate::margin::SpotMarginLiquidation), each flow once, with an id
/// from its own sequence.
/// What a [`CashFlow`] is for.
///
/// Each variant carries the venue's own figures where it reports them, and `None` where it does
/// not.
/// When in a loan's life a [`CashFlowKind::MarginInterest`] charge falls.
///
/// A venue charges the interest on a new loan when it is taken and again at each of its charging
/// boundaries. A charge on a new loan can carry a time before the position it belongs to opened,
/// since a venue may stamp it at the start of the period the loan was taken in.
/// A venue's own identifier for one [`CashFlow`], carried through opaquely.
///
/// Like [`TradeId`](crate::trade::TradeId), its uniqueness is the venue's to define and may be
/// scoped to an asset or instrument rather than global. A consumer that needs a key should
/// qualify it by exchange and asset or instrument. `Ord` is byte order, not time order.
;
/// What one read of a venue's cash flows over a span returned.
///
/// `resume` says whether the read stopped before the span's end:
/// - `None`: every flow in the span the venue still holds, and the client reports, is in `flows`.
/// Each client documents the records it leaves out.
/// - `Some(t)`: the read stopped at its bound, and flows from `t` on may be missing from `flows`.
/// Read on from `start = t` with the same end. That read can return again flows this one
/// returned at or after `t`, so match them by [`CashFlowId`].
///
/// A venue also keeps its records for a limited time. `held_since` says when that limit cuts
/// into the span, so a caller can tell flows the venue no longer has from flows that never
/// happened.