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
use chrono::{ DateTime, Utc };
use reqwest::Method;
use serde::Deserialize;
use snafu::{ ensure, ResultExt };

use crate::{ error, util, Alpaca, Result };

/// The status of the account
///
/// Most likely, the account status is ACTIVE unless there is any problem. The account status
/// may get in ACCOUNT_UPDATED when personal information is being updated from the dashboard,
/// in which case you may not be allowed trading for a short period of time until the change
/// is approved.
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum AccountStatus {
   /// The account information is being updated.
   AccountUpdated,

   /// The account is active for trading.
   Active,

   /// The final account approval is pending.
   ApprovalPending,

   /// The account is onboarding.
   Onboarding,

   /// The account application has been rejected.
   Rejected,

   /// The account application submission failed for some reason.
   SubmissionFailed,

   /// The account application has been submitted for review.
   Submitted
}

/// Important information related to an account.
///
/// Including account status, funds available for trade, funds available for withdrawal, and
/// various flags relevant to an account’s ability to trade.
///
/// An account maybe be blocked for just for trades (trades_blocked flag) or for both trades and
/// transfers (account_blocked flag) if Alpaca identifies the account to engaging in any suspicious
/// activity.
///
/// Also, in accordance with FINRA’s pattern day trading rule, an account may be flagged for
/// pattern day trading (pattern_day_trader flag), which would inhibit an account from placing any
/// further day-trades.
#[derive(Debug, Deserialize)]
pub struct Account {
   /// Account ID - a UUID
   pub id: String,

   /// Account number - a string different from the account ID
   #[serde(rename = "account_number")] pub number: String,

   /// Cash balance
   #[serde(deserialize_with = "util::to_f64")] pub cash: f64,

   /// The total equity in the account = cash + long_market_value + short_market_value
   #[serde(deserialize_with = "util::to_f64")] pub equity: f64,

   /// Real-time MtM value of all long positions held in the account
   #[serde(deserialize_with = "util::to_f64")] pub long_market_value: f64,

   /// Real-time MtM value of all short positions held in the account
   #[serde(deserialize_with = "util::to_f64")] pub short_market_value: f64,

   /// Current available $ buying power
   #[serde(deserialize_with = "util::to_f64")] pub buying_power: f64,

   /// Timestamp this account was created at
   #[serde(rename = "created_at")] pub created: DateTime<Utc>,

   /// If true, the account activity by user is prohibited.
   #[serde(rename = "account_blocked")] pub is_account_blocked:  bool,

   /// If true, the account has been flagged as a pattern day trader
   #[serde(rename = "pattern_day_trader")] pub is_pattern_day_trader: bool,

   /// If true, the account is not allowed to place orders due to customer request.
   #[serde(rename = "trade_suspended_by_user")] pub is_trade_suspended: bool,

   /// If true, the account is not allowed to place orders.
   #[serde(rename = "trading_blocked")] pub is_trading_blocked: bool,

   /// If true, the account is not allowed to request money transfers.
   #[serde(rename = "transfers_blocked")] pub is_transfers_blocked: bool,

   /// Account status
   pub status: AccountStatus,
}
impl Account {
   /// Gets the current account information
   ///
   /// # Example
   ///
   /// To get your current account information:
   ///
   /// ``` no run
   /// let alpaca = Alpaca::live("KEY_ID", "SECRET").await.unwrap();
   ///
   /// let account = Account::get(&alpaca).await.unwrap();
   /// ```
   pub async fn get(alpaca: &Alpaca) -> Result<Account> {
      let response = alpaca.request(Method::GET, "v2/account")?
         .send().await.context(error::RequestFailed)?;
      ensure!(response.status().is_success(), error::InvalidCredentials);

      Ok(response.json::<Account>().await.context(error::BadData)?)
   }
}