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, NaiveTime, 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    /// map from TradableProduct to a list of AccountPosition
50    pub positions: AccountPositions,
51    #[deref]
52    #[deref_mut]
53    #[serde(flatten)]
54    pub statistics: AccountStatistics,
55}
56
57impl AccountSummary {
58    pub fn new(account: AccountId, timestamp: DateTime<Utc>) -> Self {
59        Self {
60            account,
61            timestamp,
62            balances: BTreeMap::new(),
63            positions: BTreeMap::new(),
64            statistics: AccountStatistics::default(),
65        }
66    }
67}
68
69pub type AccountBalances = BTreeMap<Product, Decimal>;
70pub type AccountPositions = BTreeMap<TradableProduct, Vec<AccountPosition>>;
71
72#[skip_serializing_none]
73#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
74pub struct AccountStatistics {
75    /// Total account equity; net liquidation value.
76    pub equity: Option<Decimal>,
77    /// Margin requirement calculated for worst-case based on open positions and working orders.
78    pub total_margin: Option<Decimal>,
79    /// Margin requirement based on current positions only.
80    pub position_margin: Option<Decimal>,
81    // CR alee: rename to withdrawable_cash
82    /// Cash available to withdraw.
83    pub cash_excess: Option<Decimal>,
84    /// Total purchasing power; post-multiplied.
85    /// (e.g. for cash margin account could be 2x available cash)
86    pub purchasing_power: Option<Decimal>,
87    pub unrealized_pnl: Option<Decimal>,
88    pub realized_pnl: Option<Decimal>,
89    /// Yesterday total account equity.
90    pub yesterday_equity: Option<Decimal>,
91}
92
93#[skip_serializing_none]
94#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
95#[cfg_attr(feature = "juniper", derive(juniper::GraphQLObject))]
96pub struct AccountPosition {
97    pub quantity: Decimal,
98    /// NB: the meaning of this field varies by reporting venue
99    pub trade_time: Option<DateTime<Utc>>,
100    /// Cost basis of the position, if known.
101    pub cost_basis: Option<Decimal>,
102    /// Unrealized PNL of the position, if known.
103    pub unrealized_pnl: Option<Decimal>,
104    // CR alee: rename break_even_price to entry_price
105    pub break_even_price: Option<Decimal>,
106    pub liquidation_price: Option<Decimal>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
110#[cfg_attr(feature = "juniper", derive(juniper::GraphQLEnum))]
111pub enum AccountHistoryGranularity {
112    FiveMinutes,
113    Hourly,
114    Daily,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
118pub struct AccountHistoryRequest {
119    pub account: AccountIdOrName,
120    pub from_inclusive: Option<DateTime<Utc>>,
121    pub to_exclusive: Option<DateTime<Utc>>,
122    /// Default maximum of 100 data points.  If the number of data points
123    /// between from_inclusive and to_exclusive exceeds the limit, the
124    /// response will be truncated.  Data is always returned in descending
125    /// timestamp order.
126    pub limit: Option<i32>,
127    pub granularity: Option<AccountHistoryGranularity>,
128    /// For daily granularity, the UTC time of day to use for each day.
129    ///
130    /// Currently the seconds and subseconds parts are ignored.
131    pub time_of_day: Option<NaiveTime>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
135pub struct AccountHistoryResponse {
136    pub history: Vec<AccountSummary>,
137}
138
139#[grpc(package = "json.architect")]
140#[grpc(
141    service = "Folio",
142    name = "historical_fills",
143    response = "HistoricalFillsResponse"
144)]
145#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
146pub struct HistoricalFillsRequest {
147    pub symbol: Option<TradableProduct>,
148    pub venue: Option<ExecutionVenue>,
149    pub account: Option<AccountIdOrName>,
150    pub trader: Option<TraderIdOrEmail>,
151    pub order_id: Option<OrderId>,
152    pub from_inclusive: Option<DateTime<Utc>>,
153    pub to_exclusive: Option<DateTime<Utc>>,
154    /// Default maximum is 1000.
155    pub limit: Option<u32>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
159pub struct HistoricalFillsResponse {
160    pub fills: Vec<Fill>,
161    pub aberrant_fills: Vec<AberrantFill>,
162}
163
164#[grpc(package = "json.architect")]
165#[grpc(
166    service = "Folio",
167    name = "historical_orders",
168    response = "HistoricalOrdersResponse"
169)]
170#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
171pub struct HistoricalOrdersRequest {
172    /// if order_ids is not empty, the limit field is ignored
173    pub order_ids: Option<Vec<OrderId>>,
174    pub venue: Option<ExecutionVenue>,
175    pub account: Option<AccountIdOrName>,
176    pub trader: Option<TraderIdOrEmail>,
177    pub parent_order_id: Option<OrderId>,
178    pub from_inclusive: Option<DateTime<Utc>>,
179    pub to_exclusive: Option<DateTime<Utc>>,
180    /// Default maximum is 1000.
181    pub limit: Option<u32>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
185pub struct HistoricalOrdersResponse {
186    pub orders: Vec<Order>,
187}