architect_api/folio/
mod.rs

1use crate::{
2    orderflow::{AberrantFill, Fill, Order},
3    symbology::{ExecutionVenue, Product, TradableProduct},
4    AccountId, AccountIdOrName, OrderId, TraderIdOrEmail,
5};
6use chrono::{DateTime, Utc};
7use derive::grpc;
8use derive_more::{Deref, DerefMut};
9use rust_decimal::Decimal;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use serde_with::skip_serializing_none;
13use std::collections::BTreeMap;
14
15#[grpc(package = "json.architect")]
16#[grpc(service = "Folio", name = "account_summary", response = "AccountSummary")]
17#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
18pub struct AccountSummaryRequest {
19    pub account: AccountIdOrName,
20}
21
22#[grpc(package = "json.architect")]
23#[grpc(
24    service = "Folio",
25    name = "account_summaries",
26    response = "AccountSummariesResponse"
27)]
28#[skip_serializing_none]
29#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
30pub struct AccountSummariesRequest {
31    #[serde(default)]
32    pub trader: Option<TraderIdOrEmail>,
33    /// If trader and accounts are both None, return all accounts for the user
34    #[serde(default)]
35    pub accounts: Option<Vec<AccountIdOrName>>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
39pub struct AccountSummariesResponse {
40    pub account_summaries: Vec<AccountSummary>,
41}
42
43#[skip_serializing_none]
44#[derive(Debug, Deref, DerefMut, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct AccountSummary {
46    pub account: AccountId,
47    pub timestamp: DateTime<Utc>,
48    pub balances: AccountBalances,
49    pub positions: AccountPositions,
50    #[deref]
51    #[deref_mut]
52    #[serde(flatten)]
53    pub statistics: AccountStatistics,
54}
55
56impl AccountSummary {
57    pub fn new(account: AccountId, timestamp: DateTime<Utc>) -> Self {
58        Self {
59            account,
60            timestamp,
61            balances: BTreeMap::new(),
62            positions: BTreeMap::new(),
63            statistics: AccountStatistics::default(),
64        }
65    }
66}
67
68pub type AccountBalances = BTreeMap<Product, Decimal>;
69pub type AccountPositions = BTreeMap<TradableProduct, Vec<AccountPosition>>;
70
71#[skip_serializing_none]
72#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
73pub struct AccountStatistics {
74    /// Total account equity; net liquidation value.
75    pub equity: Option<Decimal>,
76    /// Margin requirement calculated for worst-case based on open positions and working orders.
77    pub total_margin: Option<Decimal>,
78    /// Margin requirement based on current positions only.
79    pub position_margin: Option<Decimal>,
80    // CR alee: rename to withdrawable_cash
81    /// Cash available to withdraw.
82    pub cash_excess: Option<Decimal>,
83    /// Total purchasing power; post-multiplied.
84    /// (e.g. for cash margin account could be 2x available cash)
85    pub purchasing_power: Option<Decimal>,
86    pub unrealized_pnl: Option<Decimal>,
87    pub realized_pnl: Option<Decimal>,
88    /// Yesterday total account equity.
89    pub yesterday_equity: Option<Decimal>,
90}
91
92#[skip_serializing_none]
93#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
94#[cfg_attr(feature = "juniper", derive(juniper::GraphQLObject))]
95pub struct AccountPosition {
96    pub quantity: Decimal,
97    /// NB: the meaning of this field varies by reporting venue
98    pub trade_time: Option<DateTime<Utc>>,
99    /// Cost basis of the position, if known.
100    pub cost_basis: Option<Decimal>,
101    /// Unrealized PNL of the position, if known.
102    pub unrealized_pnl: Option<Decimal>,
103    pub break_even_price: Option<Decimal>,
104    pub liquidation_price: Option<Decimal>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
108pub struct AccountHistoryRequest {
109    pub account: AccountIdOrName,
110    pub from_inclusive: Option<DateTime<Utc>>,
111    pub to_exclusive: Option<DateTime<Utc>>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
115pub struct AccountHistoryResponse {
116    pub history: Vec<AccountSummary>,
117}
118
119#[grpc(package = "json.architect")]
120#[grpc(
121    service = "Folio",
122    name = "historical_fills",
123    response = "HistoricalFillsResponse"
124)]
125#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
126pub struct HistoricalFillsRequest {
127    pub venue: Option<ExecutionVenue>,
128    pub account: Option<AccountIdOrName>,
129    pub trader: Option<TraderIdOrEmail>,
130    pub order_id: Option<OrderId>,
131    pub from_inclusive: Option<DateTime<Utc>>,
132    pub to_exclusive: Option<DateTime<Utc>>,
133    /// Default maximum is 1000.
134    pub limit: Option<u32>,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
138pub struct HistoricalFillsResponse {
139    pub fills: Vec<Fill>,
140    pub aberrant_fills: Vec<AberrantFill>,
141}
142
143#[grpc(package = "json.architect")]
144#[grpc(
145    service = "Folio",
146    name = "historical_orders",
147    response = "HistoricalOrdersResponse"
148)]
149#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
150pub struct HistoricalOrdersRequest {
151    /// if order_ids is not empty, the limit field is ignored
152    pub order_ids: Option<Vec<OrderId>>,
153    pub venue: Option<ExecutionVenue>,
154    pub account: Option<AccountIdOrName>,
155    pub trader: Option<TraderIdOrEmail>,
156    pub parent_order_id: Option<OrderId>,
157    pub from_inclusive: Option<DateTime<Utc>>,
158    pub to_exclusive: Option<DateTime<Utc>>,
159    /// Default maximum is 1000.
160    pub limit: Option<u32>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
164pub struct HistoricalOrdersResponse {
165    pub orders: Vec<Order>,
166}