alpaca-py-nopandas 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. alpaca/__init__.py +2 -0
  2. alpaca/broker/__init__.py +8 -0
  3. alpaca/broker/client.py +2360 -0
  4. alpaca/broker/enums.py +528 -0
  5. alpaca/broker/models/__init__.py +7 -0
  6. alpaca/broker/models/accounts.py +347 -0
  7. alpaca/broker/models/cip.py +265 -0
  8. alpaca/broker/models/documents.py +159 -0
  9. alpaca/broker/models/funding.py +114 -0
  10. alpaca/broker/models/journals.py +71 -0
  11. alpaca/broker/models/rebalancing.py +80 -0
  12. alpaca/broker/models/trading.py +13 -0
  13. alpaca/broker/requests.py +1135 -0
  14. alpaca/common/__init__.py +6 -0
  15. alpaca/common/constants.py +13 -0
  16. alpaca/common/enums.py +64 -0
  17. alpaca/common/exceptions.py +47 -0
  18. alpaca/common/models.py +21 -0
  19. alpaca/common/requests.py +82 -0
  20. alpaca/common/rest.py +438 -0
  21. alpaca/common/types.py +7 -0
  22. alpaca/common/utils.py +89 -0
  23. alpaca/data/__init__.py +5 -0
  24. alpaca/data/enums.py +184 -0
  25. alpaca/data/historical/__init__.py +13 -0
  26. alpaca/data/historical/corporate_actions.py +76 -0
  27. alpaca/data/historical/crypto.py +299 -0
  28. alpaca/data/historical/news.py +63 -0
  29. alpaca/data/historical/option.py +230 -0
  30. alpaca/data/historical/screener.py +72 -0
  31. alpaca/data/historical/stock.py +226 -0
  32. alpaca/data/historical/utils.py +30 -0
  33. alpaca/data/live/__init__.py +11 -0
  34. alpaca/data/live/crypto.py +168 -0
  35. alpaca/data/live/news.py +62 -0
  36. alpaca/data/live/option.py +88 -0
  37. alpaca/data/live/stock.py +199 -0
  38. alpaca/data/live/websocket.py +390 -0
  39. alpaca/data/mappings.py +84 -0
  40. alpaca/data/models/__init__.py +7 -0
  41. alpaca/data/models/bars.py +83 -0
  42. alpaca/data/models/base.py +45 -0
  43. alpaca/data/models/corporate_actions.py +309 -0
  44. alpaca/data/models/news.py +90 -0
  45. alpaca/data/models/orderbooks.py +59 -0
  46. alpaca/data/models/quotes.py +78 -0
  47. alpaca/data/models/screener.py +68 -0
  48. alpaca/data/models/snapshots.py +132 -0
  49. alpaca/data/models/trades.py +204 -0
  50. alpaca/data/requests.py +580 -0
  51. alpaca/data/timeframe.py +148 -0
  52. alpaca/py.typed +0 -0
  53. alpaca/trading/__init__.py +5 -0
  54. alpaca/trading/client.py +784 -0
  55. alpaca/trading/enums.py +412 -0
  56. alpaca/trading/models.py +697 -0
  57. alpaca/trading/requests.py +604 -0
  58. alpaca/trading/stream.py +225 -0
  59. alpaca_py_nopandas-0.1.0.dist-info/LICENSE +201 -0
  60. alpaca_py_nopandas-0.1.0.dist-info/METADATA +299 -0
  61. alpaca_py_nopandas-0.1.0.dist-info/RECORD +62 -0
  62. alpaca_py_nopandas-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,347 @@
1
+ from datetime import datetime
2
+ from typing import Any, Dict, List, Optional
3
+ from uuid import UUID
4
+
5
+ from pydantic import TypeAdapter, ValidationInfo, field_validator, model_validator
6
+
7
+ from alpaca.broker.enums import (
8
+ AgreementType,
9
+ ClearingBroker,
10
+ EmploymentStatus,
11
+ FundingSource,
12
+ TaxIdType,
13
+ VisaType,
14
+ )
15
+ from alpaca.broker.models.documents import AccountDocument
16
+ from alpaca.common.models import ModelWithID
17
+ from alpaca.common.models import ValidateBaseModel as BaseModel
18
+ from alpaca.trading.enums import AccountStatus
19
+ from alpaca.trading.models import TradeAccount as BaseTradeAccount
20
+
21
+
22
+ class KycResults(BaseModel):
23
+ """
24
+ Hold information about the result of KYC.
25
+ ref. https://docs.alpaca.markets/reference/getaccount
26
+
27
+ Attributes:
28
+ reject (Optional[Dict[str, Any]]): The reason for the rejection
29
+ accept (Optional[Dict[str, Any]]): The reason for the acceptance
30
+ indeterminate (Optional[Dict[str, Any]]): The reason for the indeterminate result
31
+ additional_information (Optional[str]): Used to display a custom message
32
+ summary (Optional[str]): Either pass or fail. Used to indicate if KYC has completed and passed or not.
33
+ """
34
+
35
+ reject: Optional[Dict[str, Any]] = None
36
+ accept: Optional[Dict[str, Any]] = None
37
+ indeterminate: Optional[Dict[str, Any]] = None
38
+ additional_information: Optional[str] = None
39
+ summary: Optional[str] = None
40
+
41
+
42
+ class Contact(BaseModel):
43
+ """User contact details within Account Model
44
+
45
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
46
+
47
+ Attributes:
48
+ email_address (str): The user's email address
49
+ phone_number (str): The user's phone number. It should include the country code.
50
+ street_address (List[str]): The user's street address lines.
51
+ unit (Optional[str]): The user's apartment unit, if any.
52
+ city (str): The city the user resides in.
53
+ state (Optional[str]): The state the user resides in. This is required if country is 'USA'.
54
+ postal_code (str): The user's postal
55
+ country (str): The country the user resides in. 3 letter country code is permissible.
56
+ """
57
+
58
+ email_address: str
59
+ phone_number: Optional[str] = None
60
+ street_address: List[str]
61
+ unit: Optional[str] = None
62
+ city: str
63
+ state: Optional[str] = None
64
+ postal_code: Optional[str] = None
65
+ country: Optional[str] = None
66
+
67
+ @field_validator("state")
68
+ def usa_state_has_value(cls, v: str, validation: ValidationInfo, **kwargs) -> str:
69
+ """Validates that the state has a value if the country is USA
70
+
71
+ Args:
72
+ v (str): The state field's value
73
+ values (dict): The values of each field
74
+
75
+ Raises:
76
+ ValueError: State is required for country USA
77
+
78
+ Returns:
79
+ str: The value of the state field
80
+ """
81
+ values: dict = validation.data
82
+ if "country" in values and values["country"] == "USA" and v is None:
83
+ raise ValueError("State is required for country USA.")
84
+ return v
85
+
86
+
87
+ class Identity(BaseModel):
88
+ """User identity details within Account Model
89
+
90
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
91
+
92
+ Attributes:
93
+ given_name (str): The user's first name
94
+ middle_name (Optional[str]): The user's middle name, if any
95
+ family_name (str): The user's last name
96
+ date_of_birth (str): The user's date of birth
97
+ tax_id (Optional[str]): The user's country specific tax id, required if tax_id_type is provided
98
+ tax_id_type (Optional[TaxIdType]): The tax_id_type for the tax_id provided, required if tax_id provided
99
+ country_of_citizenship (Optional[str]): The country the user is a citizen
100
+ country_of_birth (Optional[str]): The country the user was born
101
+ country_of_tax_residence (str): The country the user files taxes
102
+ visa_type (Optional[VisaType]): Only used to collect visa types for users residing in the USA.
103
+ visa_expiration_date (Optional[str]): The date of expiration for visa, Required if visa_type is set.
104
+ date_of_departure_from_usa (Optional[str]): Required if visa_type = B1 or B2
105
+ permanent_resident (Optional[bool]): Only used to collect permanent residence status in the USA.
106
+ funding_source (Optional[List[FundingSource]]): How the user will fund their account
107
+ annual_income_min (Optional[float]): The minimum of the user's income range
108
+ annual_income_max (Optional[float]): The maximum of the user's income range
109
+ liquid_net_worth_min (Optional[float]): The minimum of the user's liquid net worth range
110
+ liquid_net_worth_max (Optional[float]): The maximum of the user's liquid net worth range
111
+ total_net_worth_min (Optional[float]): The minimum of the user's total net worth range
112
+ total_net_worth_max (Optional[float]): The maximum of the user's total net worth range
113
+ """
114
+
115
+ given_name: str
116
+ middle_name: Optional[str] = None
117
+ family_name: str
118
+ date_of_birth: Optional[str] = None
119
+ tax_id: Optional[str] = None
120
+ tax_id_type: Optional[TaxIdType] = None
121
+ country_of_citizenship: Optional[str] = None
122
+ country_of_birth: Optional[str] = None
123
+ country_of_tax_residence: str
124
+ visa_type: Optional[VisaType] = None
125
+ visa_expiration_date: Optional[str] = None
126
+ date_of_departure_from_usa: Optional[str] = None
127
+ permanent_resident: Optional[bool] = None
128
+ funding_source: Optional[List[FundingSource]] = None
129
+ annual_income_min: Optional[float] = None
130
+ annual_income_max: Optional[float] = None
131
+ liquid_net_worth_min: Optional[float] = None
132
+ liquid_net_worth_max: Optional[float] = None
133
+ total_net_worth_min: Optional[float] = None
134
+ total_net_worth_max: Optional[float] = None
135
+
136
+
137
+ class Disclosures(BaseModel):
138
+ """User disclosures within Account Model
139
+
140
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
141
+
142
+ Attributes:
143
+ is_control_person (bool): Whether user holds a controlling position in a publicly traded company
144
+ is_affiliated_exchange_or_finra (bool): If user is affiliated with any exchanges or FINRA
145
+ is_politically_exposed (bool): If user is politically exposed
146
+ immediate_family_exposed (bool): If user’s immediate family member is either politically exposed or holds a control position.
147
+ employment_status (EmploymentStatus): The employment status of the user
148
+ employer_name (str): The user's employer's name, if any
149
+ employer_address (str): The user's employer's address, if any
150
+ employment_position (str): The user's employment position, if any
151
+ """
152
+
153
+ is_control_person: Optional[bool] = None
154
+ is_affiliated_exchange_or_finra: Optional[bool] = None
155
+ is_politically_exposed: Optional[bool] = None
156
+ immediate_family_exposed: bool
157
+ employment_status: Optional[EmploymentStatus] = None
158
+ employer_name: Optional[str] = None
159
+ employer_address: Optional[str] = None
160
+ employment_position: Optional[str] = None
161
+
162
+
163
+ class Agreement(BaseModel):
164
+ """User agreements signed within Account Model
165
+
166
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
167
+
168
+ Attributes:
169
+ agreement (Agreement): The type of agreement signed by the user
170
+ signed_at (str): The timestamp the agreement was signed
171
+ ip_address (str): The ip_address the signed agreements were sent from by the user
172
+ revision (str): The revision date
173
+ """
174
+
175
+ agreement: AgreementType
176
+ signed_at: str
177
+ ip_address: str
178
+ revision: Optional[str] = None
179
+
180
+
181
+ class TrustedContact(BaseModel):
182
+ """User's trusted contact details within Account Model
183
+
184
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
185
+
186
+ Attributes:given_name
187
+ given_name (str): The first name of the user's trusted contact
188
+ family_name (str): The last name of the user's trusted contact
189
+ email_address (Optional[str]): The email address of the user's trusted contact
190
+ phone_number (Optional[str]): The email address of the user's trusted contact
191
+ city (Optional[str]): The email address of the user's trusted contact
192
+ state (Optional[str]): The email address of the user's trusted contact
193
+ postal_code (Optional[str]): The email address of the user's trusted contact
194
+ country (Optional[str]): The email address of the user's trusted contact
195
+ """
196
+
197
+ given_name: str
198
+ family_name: str
199
+ email_address: Optional[str] = None
200
+ phone_number: Optional[str] = None
201
+ street_address: Optional[str] = None
202
+ city: Optional[str] = None
203
+ state: Optional[str] = None
204
+ postal_code: Optional[str] = None
205
+ country: Optional[str] = None
206
+
207
+ @model_validator(mode="before")
208
+ def root_validator(cls, values: dict) -> dict:
209
+ has_phone_number = (
210
+ "phone_number" in values and values["phone_number"] is not None
211
+ )
212
+ has_street_address = (
213
+ "street_address" in values and values["street_address"] is not None
214
+ )
215
+ has_email_address = (
216
+ "email_address" in values and values["email_address"] is not None
217
+ )
218
+
219
+ if has_phone_number or has_street_address or has_email_address:
220
+ return values
221
+
222
+ raise ValueError("At least one method of contact required for trusted contact")
223
+
224
+
225
+ class Account(ModelWithID):
226
+ """Contains information pertaining to a specific brokerage account
227
+
228
+ see https://alpaca.markets/docs/broker/api-references/accounts/accounts/#the-account-model
229
+
230
+ The fields contact, identity, disclosures, agreements, documents, trusted_contact, and trading_configurations
231
+ are all optional and won't always be provided by the api depending on what endpoint you use and what options you
232
+ pass
233
+
234
+ Attributes:
235
+ id (str): The account uuid used to reference this account
236
+ account_number (str): A more human friendly identifier for this account
237
+ status (AccountStatus): The approval status of this account
238
+ crypto_status (Optional[AccountStatus]): The crypto trading status. Only present if crypto trading is enabled.
239
+ kyc_results (Optional[KycResult]): Hold information about the result of KYC.
240
+ currency (str): The currency the account's values are returned in
241
+ last_equity (str): The total equity value stored in the account
242
+ created_at (str): The timestamp when the account was created
243
+ contact (Optional[Contact]): The contact details for the account holder
244
+ identity (Optional[Identity]): The identity details for the account holder
245
+ disclosures (Optional[Disclosures]): The account holder's political disclosures
246
+ agreements (Optional[List[Agreement]]): The agreements the account holder has signed
247
+ documents (Optional[List[AccountDocument]]): The documents the account holder has submitted
248
+ trusted_contact (Optional[TrustedContact]): The account holder's trusted contact details
249
+ """
250
+
251
+ account_number: str
252
+ status: AccountStatus
253
+ crypto_status: Optional[AccountStatus] = None
254
+ kyc_results: Optional[KycResults] = None
255
+ currency: str
256
+ last_equity: str
257
+ created_at: str
258
+ contact: Optional[Contact] = None
259
+ identity: Optional[Identity] = None
260
+ disclosures: Optional[Disclosures] = None
261
+ agreements: Optional[List[Agreement]] = None
262
+ documents: Optional[List[AccountDocument]] = None
263
+ trusted_contact: Optional[TrustedContact] = None
264
+
265
+ def __init__(self, **response):
266
+ super().__init__(
267
+ id=(UUID(response["id"])),
268
+ account_number=(response["account_number"]),
269
+ status=(response["status"]),
270
+ crypto_status=(
271
+ response["crypto_status"] if "crypto_status" in response else None
272
+ ),
273
+ kyc_results=(
274
+ TypeAdapter(KycResults).validate_python(response["kyc_results"])
275
+ if "kyc_results" in response and response["kyc_results"] is not None
276
+ else None
277
+ ),
278
+ currency=(response["currency"]),
279
+ last_equity=(response["last_equity"]),
280
+ created_at=(response["created_at"]),
281
+ contact=(
282
+ TypeAdapter(Contact).validate_python(response["contact"])
283
+ if "contact" in response
284
+ else None
285
+ ),
286
+ identity=(
287
+ TypeAdapter(Identity).validate_python(response["identity"])
288
+ if "identity" in response
289
+ else None
290
+ ),
291
+ disclosures=(
292
+ TypeAdapter(Disclosures).validate_python(response["disclosures"])
293
+ if "disclosures" in response
294
+ else None
295
+ ),
296
+ agreements=(
297
+ TypeAdapter(List[Agreement]).validate_python(response["agreements"])
298
+ if "agreements" in response
299
+ else None
300
+ ),
301
+ documents=(
302
+ TypeAdapter(List[AccountDocument]).validate_python(
303
+ response["documents"]
304
+ )
305
+ if "documents" in response
306
+ else None
307
+ ),
308
+ trusted_contact=(
309
+ TypeAdapter(TrustedContact).validate_python(response["trusted_contact"])
310
+ if "trusted_contact" in response
311
+ else None
312
+ ),
313
+ )
314
+
315
+
316
+ class TradeAccount(BaseTradeAccount):
317
+ """
318
+ See Base TradeAccount model in common for full details on available fields.
319
+ Represents trading account information for an Account.
320
+
321
+ Attributes:
322
+ cash_withdrawable (Optional[str]): Cash available for withdrawal from the account
323
+ cash_transferable (Optional[str]): Cash available for transfer (JNLC) from the account
324
+ previous_close (Optional[datetime]): Previous sessions close time
325
+ last_long_market_value (Optional[str]): Value of all long positions as of previous trading day at 16:00:00 ET
326
+ last_short_market_value (Optional[str]): Value of all short positions as of previous trading day at 16:00:00 ET
327
+ last_cash (Optional[str]): Value of all cash as of previous trading day at 16:00:00 ET
328
+ last_initial_margin (Optional[str]): Value of initial_margin as of previous trading day at 16:00:00 ET
329
+ last_regt_buying_power (Optional[str]): Value of regt_buying_power as of previous trading day at 16:00:00 ET
330
+ last_daytrading_buying_power (Optional[str]): Value of daytrading_buying_power as of previous trading day at 16:00:00 ET
331
+ last_daytrade_count (Optional[int]): Value of daytrade_count as of previous trading day at 16:00:00 ET
332
+ last_buying_power (Optional[str]): Value of buying_power as of previous trading day at 16:00:00 ET
333
+ clearing_broker (Optional[ClearingBroker]): The Clearing broker for this account
334
+ """
335
+
336
+ cash_withdrawable: Optional[str]
337
+ cash_transferable: Optional[str]
338
+ previous_close: Optional[datetime]
339
+ last_long_market_value: Optional[str]
340
+ last_short_market_value: Optional[str]
341
+ last_cash: Optional[str]
342
+ last_initial_margin: Optional[str]
343
+ last_regt_buying_power: Optional[str]
344
+ last_daytrading_buying_power: Optional[str]
345
+ last_daytrade_count: Optional[int]
346
+ last_buying_power: Optional[str]
347
+ clearing_broker: Optional[ClearingBroker]
@@ -0,0 +1,265 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+ from uuid import UUID
4
+
5
+ from alpaca.common.models import ModelWithID, ValidateBaseModel as BaseModel
6
+
7
+ from alpaca.broker.enums import CIPApprovalStatus, CIPProvider, CIPResult, CIPStatus
8
+
9
+
10
+ class CIPKYCInfo(BaseModel):
11
+ """
12
+ Represents Know Your Customer (KYC) info for a CIPInfo
13
+
14
+ Attributes:
15
+ id (str): Your internal ID of check
16
+ risk_score (Optional[int]): Overall risk score returned by KYC provider or assessed
17
+ risk_level (Optional[str]): Overall risk level returned by KYC provider or assessed
18
+ risk_categories (Optional[List[str]]): The list of risk categories returned by the KYC provider or assessed
19
+ applicant_name (Optional[str]): Given and family name of applicant
20
+ email_address (Optional[str]): email address of applicant
21
+ nationality (Optional[str]): nationality of applicant
22
+ date_of_birth (Optional[datetime]): DOB of applicant
23
+ address (Optional[str]): Concatenated street address, city, state and country of applicant
24
+ postal_code (Optional[str]): postal code for `address` field
25
+ country_of_residency (Optional[str]): country for `address` field
26
+ kyc_completed_at (Optional[datetime]): Datetime that KYC check was completed at
27
+ ip_address (Optional[str]): ip address of applicant at time of KYC check
28
+ check_initiated_at (Optional[datetime]): start datetime of KYC check
29
+ check_completed_at (Optional[datetime]): completion datetime of KYC check
30
+ approval_status (Optional[CIPApprovalStatus]): Approval status of KYC check
31
+ approved_by (Optional[str]): Identifier of who approved KYC check
32
+ approved_reason (Optional[str]): Reason for approving this KYC check
33
+ approved_at (Optional[datetime]): Datetime that this KYC check was approved
34
+ """
35
+
36
+ id: str
37
+ risk_score: Optional[int] = None
38
+ risk_level: Optional[str] = None
39
+ risk_categories: Optional[List[str]] = None
40
+ applicant_name: Optional[str] = None
41
+ email_address: Optional[str] = None
42
+ nationality: Optional[str] = None
43
+ date_of_birth: Optional[datetime] = None
44
+ address: Optional[str] = None
45
+ postal_code: Optional[str] = None
46
+ country_of_residency: Optional[str] = None
47
+ kyc_completed_at: Optional[datetime] = None
48
+ ip_address: Optional[str] = None
49
+ check_initiated_at: Optional[datetime] = None
50
+ check_completed_at: Optional[datetime] = None
51
+ approval_status: Optional[CIPApprovalStatus] = None
52
+ approved_by: Optional[str] = None
53
+ approved_reason: Optional[str] = None
54
+ approved_at: Optional[datetime] = None
55
+
56
+
57
+ class CIPDocument(BaseModel):
58
+ """
59
+ Represents results of checking a document for CIPInfo
60
+
61
+ Attributes:
62
+ id (str): Your internal ID of check
63
+ result (Optional[CIPResult]): Overall result of specific check
64
+ status (Optional[CIPStatus]): Overall status of specific check
65
+ created_at (Optional[datetime]): Datetime for when this check was done
66
+ date_of_birth (Optional[datetime]): DOB for applicant if found on document
67
+ date_of_expiry (Optional[datetime]): date of expiry for the checked document
68
+ document_numbers (Optional[List[str]]): Number of the document that was checked
69
+ document_type (Optional[str]): Type of the document that was checked
70
+ first_name (Optional[str]): First name extracted from the document
71
+ last_name (Optional[str]): Last name extracted from the document
72
+ gender (Optional[str]): Gender info extracted from the document
73
+ issuing_country (Optional[str]): Country for which issued the document
74
+ nationality (Optional[str]): Nationality extracted from the document
75
+ age_validation (Optional[CIPResult]): Result of checks on whether the age calculated from the document’s date
76
+ of birth data point is greater than or equal to the minimum accepted age set at account level
77
+ compromised_document (Optional[CIPResult]): Result of check on whether the image of the document has been found
78
+ in our internal database of compromised documents
79
+ police_record (Optional[CIPStatus]): Result of check on whether the document has been identified as lost,
80
+ stolen or otherwise compromised
81
+ data_comparison (Optional[CIPResult]): Result of check on whether data on the document is consistent with data
82
+ provided when creating an applicant through the API
83
+ data_comparison_breakdown (Optional[str]): json object representing the results of the various sub-checks
84
+ done when calculating the result on `data_comparison`. Example: {“date_of_birth”: “clear”,
85
+ “date_of_expiry”: “clear” “document_numbers”: “clear”, “document_type”: “clear”, “first_name”: “clear”,
86
+ “gender”: “clear”, “issuing_country”: “clear”, “last_name”: “clear”}
87
+ image_integrity (Optional[CIPResult]): Result of checks on whether the document was of sufficient quality to
88
+ verify
89
+ image_integrity_breakdown (Optional[str]): json object representing the results of the various sub-checks done
90
+ when calculating the result on `image_integrity`. Example: example: {“colour_picture”: “clear”,
91
+ “conclusive_document_quality”: “clear”, “image_quality”: “clear”, “supported_document”: “clear”}
92
+ visual_authenticity (Optional[str]): json object representing the the various sub-checks done when determening
93
+ whether visual (non-textual) elements are correct given the document type. Example: {
94
+ “digital_tampering”: “clear”, “face_detection”: “clear”, “fonts”: “clear”, “original_document_present”:
95
+ “clear”, “picture_face_integrity”: “clear”, “security_features”: “clear”, “template”: “clear”}
96
+
97
+ """
98
+
99
+ id: str
100
+ result: Optional[CIPResult] = None
101
+ status: Optional[CIPStatus] = None
102
+ created_at: Optional[datetime] = None
103
+ date_of_birth: Optional[datetime] = None
104
+ date_of_expiry: Optional[datetime] = None
105
+ document_numbers: Optional[List[str]] = None
106
+ document_type: Optional[str] = None
107
+ first_name: Optional[str] = None
108
+ last_name: Optional[str] = None
109
+ gender: Optional[str] = None
110
+ issuing_country: Optional[str] = None
111
+ nationality: Optional[str] = None
112
+ age_validation: Optional[CIPResult] = None
113
+ compromised_document: Optional[CIPResult] = None
114
+ police_record: Optional[CIPStatus] = None
115
+ data_comparison: Optional[CIPResult] = None
116
+ data_comparison_breakdown: Optional[str] = None
117
+ image_integrity: Optional[CIPResult] = None
118
+ image_integrity_breakdown: Optional[str] = None
119
+ visual_authenticity: Optional[str] = None
120
+
121
+
122
+ class CIPPhoto(BaseModel):
123
+ """
124
+ Represents the results of checking a Photo for CIPInfo
125
+
126
+ Attributes:
127
+ id (str): Your internal ID of check
128
+ result (Optional[CIPResult]): Overall result of check
129
+ status (Optional[CIPStatus]): Overall status of check
130
+ created_at (Optional[datetime]): datetime of when check happened
131
+ face_comparision (Optional[CIPResult]): Checks whether the face in the document matches the face in the
132
+ live photo
133
+ face_comparison_breakdown (Optional[str]): a json object representing the breakdown of sub-checks done in
134
+ `face_comparison`. Example: {“face_match”:{“result”: “clear”,“properties”:{“score”: “80”}}}
135
+ image_integrity (Optional[CIPResult]): Checks whether the quality and integrity of the uploaded files were
136
+ sufficient to perform a face comparison
137
+ image_integrity_breakdown (Optional[str]): a json object representing the breakdown of sub-checks done in
138
+ `image_integrity`. Example {“face_detected”:{“result”: “clear”},“source_integrity”: {“result”: “clear”}}
139
+ visual_authenticity (Optional[CIPResult]): Checks whether the person in the live photo is real (not a spoof)
140
+ visual_authenticity_breakdown (Optional[str]): a json object representing the breakdown of sub-checks don in
141
+ `visual_authenticity`. Example {“spoofing_detection”: {“result”: “clear”,“properties”: {“score”: “26”}}}}
142
+ """
143
+
144
+ id: str
145
+ result: Optional[CIPResult] = None
146
+ status: Optional[CIPStatus] = None
147
+ created_at: Optional[datetime] = None
148
+ face_comparision: Optional[CIPResult] = None
149
+ face_comparison_breakdown: Optional[str] = None
150
+ image_integrity: Optional[CIPResult] = None
151
+ image_integrity_breakdown: Optional[str] = None
152
+ visual_authenticity: Optional[CIPResult] = None
153
+ visual_authenticity_breakdown: Optional[str] = None
154
+
155
+
156
+ class CIPIdentity(BaseModel):
157
+ """
158
+ Represents the results of running an identity check for a CIPInfo
159
+
160
+ Attributes:
161
+ id (str): Your internal ID of check
162
+ result (Optional[CIPResult]): Overall result of check
163
+ status (Optional[CIPStatus]): Overall status of check
164
+ created_at (Optional[datetime]): datetime when identity check happened
165
+ matched_address (Optional[CIPResult]): Represents of the address matched for the applicant
166
+ matched_addresses (Optional[str]): a json object representing the results of the check done in `matched_address`
167
+ Example: [{“id”: “19099121”,“match_types”:[“credit_agencies”,“voting_register”]}]
168
+ sources (Optional[CIPResult]): Shows the total number of sources found for applicant’s identity.
169
+ (TODO: What? This doesnt make any sense its a CIPResult not a number but that's whats in the docs)
170
+ sources_breakdown (Optional[str]): a json object representing the breakdown of `sources` field. For example:
171
+ {“total_sources”: {“result”: “clear”,“properties”: {“total_number_of_sources”: “3”}}}
172
+ address (Optional[CIPResult]): Result if it was cleared against a data source
173
+ address_breakdown (Optional[str]): a json object representing the breakdown of the `address` field. For example:
174
+ {“credit_agencies”: {“result”: “clear”,“properties”:{“number_of_matches”:“1”}}
175
+ date_of_birth (Optional[CIPResult]): Result if it was cleared against a data source
176
+ date_of_birth_breakdown (Optional[str]): a json object representing the breakdown of the `date_of_birth` field.
177
+ For example: example: {“credit_agencies”:{“result”: “clear”,“properties”: {“number_of_matches”: “1”}}
178
+ tax_id (Optional[CIPResult]): Result if it was cleared against a data source
179
+ tax_id_breakdown (Optional[str]): a json object representing the breakdown of the `tax_id` field
180
+ """
181
+
182
+ id: str
183
+ result: Optional[CIPResult] = None
184
+ status: Optional[CIPStatus] = None
185
+ created_at: Optional[datetime] = None
186
+ matched_address: Optional[CIPResult] = None
187
+ matched_addresses: Optional[str] = None
188
+ sources: Optional[CIPResult] = None
189
+ sources_breakdown: Optional[str] = None
190
+ address: Optional[CIPResult] = None
191
+ address_breakdown: Optional[str] = None
192
+ date_of_birth: Optional[CIPResult] = None
193
+ date_of_birth_breakdown: Optional[str] = None
194
+ tax_id: Optional[CIPResult] = None
195
+ tax_id_breakdown: Optional[str] = None
196
+
197
+
198
+ class CIPWatchlist(BaseModel):
199
+ """
200
+ Represents the result of checking to see if the applicant is in any watchlists for a CIPInfo
201
+
202
+ TODO: We're missing almost entirely documentation in prod for this as well as even internal documentation
203
+ no clue what these fields are supposed to be or if they're even close to correct.
204
+
205
+ Attributes:
206
+ id (str): Your internal ID of check
207
+ result (Optional[CIPResult]): Overall result of specific check
208
+ status (Optional[CIPStatus]): Overall status of specific check
209
+ created_at (Optional[datetime]): datetime when check happened
210
+ records (Optional[str]): a json object. Example [{“text”: “Record info”}]
211
+ politically_exposed_person (Optional[CIPResult]): Result if it was cleared against a data source
212
+ sanction (Optional[CIPResult]): Result if it was cleared against a data source
213
+ adverse_media (Optional[CIPResult]): Result if it was cleared against a data source
214
+ monitored_lists (Optional[CIPResult]): Result if it was cleared against a data source
215
+ """
216
+
217
+ id: str
218
+ result: Optional[CIPResult] = None
219
+ status: Optional[CIPStatus] = None
220
+ created_at: Optional[datetime] = None
221
+ records: Optional[str] = None
222
+ politically_exposed_person: Optional[CIPResult] = None
223
+ sanction: Optional[CIPResult] = None
224
+ adverse_media: Optional[CIPResult] = None
225
+ monitored_lists: Optional[CIPResult] = None
226
+
227
+
228
+ class CIPInfo(ModelWithID):
229
+ """
230
+ The Customer Identification Program (CIP) API allows you to submit the CIP results received from your KYC provider.
231
+
232
+ This model is how to represent that information when talking to Alpaca
233
+
234
+ Args:
235
+ id (UUID): ID of this CIPInfo
236
+ account_id (UUID): UUID of the Account instance this CIPInfo is for
237
+ provider_name (List[CIPProvider]): List of KYC providers this information came from
238
+ created_at (datetime): date and time this CIPInfo was first uploaded to Alpaca
239
+ updated_at (datetime): date and time that this CIPInfo was last update
240
+ kyc (Optional[CIPKYCInfo]): KYC info for this Account if any
241
+ document (Optional[CIPDocument]): Any CIP documents uploaded for this Account
242
+ photo (Optional[CIPPhoto]): Any photos attached for CIP
243
+ identity (Optional[CIPIdentity]): Any CIP Identity information
244
+ watchlist (Optional[CIPWatchlist]): Any CIP watchlist information
245
+ """
246
+
247
+ account_id: UUID
248
+ provider_name: List[CIPProvider]
249
+ created_at: datetime
250
+ updated_at: datetime
251
+ kyc: Optional[CIPKYCInfo] = None
252
+ document: Optional[CIPDocument] = None
253
+ photo: Optional[CIPPhoto] = None
254
+ identity: Optional[CIPIdentity] = None
255
+ watchlist: Optional[CIPWatchlist] = None
256
+
257
+ def __init__(self, *args, **kwargs):
258
+ # upcast into uuid
259
+ if "id" in kwargs and type(kwargs["id"]) == str:
260
+ kwargs["id"] = UUID(kwargs["id"])
261
+
262
+ if "account_id" in kwargs and type(kwargs["account_id"]) == str:
263
+ kwargs["account_id"] = UUID(kwargs["account_id"])
264
+
265
+ super().__init__(*args, **kwargs)