1#![allow(missing_docs)]
8
9use crate::client::AlpacaHttpClient;
10use alpaca_base::{OAuthToken, Result, types::*};
11use chrono::{DateTime, NaiveDate, Utc};
12use serde::{Deserialize, Serialize};
13use uuid::Uuid;
14
15impl AlpacaHttpClient {
16 pub async fn get_account(&self) -> Result<Account> {
20 self.get("/v2/account").await
21 }
22
23 pub async fn get_account_configurations(&self) -> Result<AccountConfigurations> {
25 self.get("/v2/account/configurations").await
26 }
27
28 pub async fn update_account_configurations(
30 &self,
31 config: &AccountConfigurations,
32 ) -> Result<AccountConfigurations> {
33 self.patch("/v2/account/configurations", config).await
34 }
35
36 pub async fn get_account_activities(
38 &self,
39 params: &ActivityParams,
40 ) -> Result<Vec<AccountActivity>> {
41 self.get_with_params("/v2/account/activities", params).await
42 }
43
44 pub async fn get_portfolio_history(
46 &self,
47 params: &PortfolioHistoryParams,
48 ) -> Result<PortfolioHistory> {
49 self.get_with_params("/v2/account/portfolio/history", params)
50 .await
51 }
52
53 pub async fn get_assets(&self, params: &AssetParams) -> Result<Vec<Asset>> {
57 self.get_with_params("/v2/assets", params).await
58 }
59
60 pub async fn get_asset(&self, asset_id: &Uuid) -> Result<Asset> {
62 self.get(&format!("/v2/assets/{}", asset_id)).await
63 }
64
65 pub async fn get_asset_by_symbol(&self, symbol: &str) -> Result<Asset> {
67 self.get(&format!("/v2/assets/{}", symbol)).await
68 }
69
70 pub async fn get_orders(&self, params: &OrderParams) -> Result<Vec<Order>> {
74 self.get_with_params("/v2/orders", params).await
75 }
76
77 pub async fn create_order(&self, order: &CreateOrderRequest) -> Result<Order> {
79 self.post("/v2/orders", order).await
80 }
81
82 pub async fn get_order(&self, order_id: &Uuid) -> Result<Order> {
84 self.get(&format!("/v2/orders/{}", order_id)).await
85 }
86
87 pub async fn get_order_by_client_id(&self, client_order_id: &str) -> Result<Order> {
89 self.get(&format!(
90 "/v2/orders:by_client_order_id?client_order_id={}",
91 client_order_id
92 ))
93 .await
94 }
95
96 pub async fn replace_order(
98 &self,
99 order_id: &Uuid,
100 order: &ReplaceOrderRequest,
101 ) -> Result<Order> {
102 self.patch(&format!("/v2/orders/{}", order_id), order).await
103 }
104
105 pub async fn cancel_order(&self, order_id: &Uuid) -> Result<()> {
107 self.delete(&format!("/v2/orders/{}", order_id)).await
108 }
109
110 pub async fn cancel_all_orders(&self) -> Result<Vec<CancelOrderResponse>> {
112 self.delete("/v2/orders").await
113 }
114
115 pub async fn get_positions(&self) -> Result<Vec<Position>> {
119 self.get("/v2/positions").await
120 }
121
122 pub async fn get_position(&self, symbol: &str) -> Result<Position> {
124 self.get(&format!("/v2/positions/{}", symbol)).await
125 }
126
127 pub async fn close_all_positions(
129 &self,
130 cancel_orders: bool,
131 ) -> Result<Vec<ClosePositionResponse>> {
132 let url = format!("/v2/positions?cancel_orders={}", cancel_orders);
133 self.delete(&url).await
134 }
135
136 pub async fn close_position(
138 &self,
139 symbol: &str,
140 _params: &ClosePositionRequest,
141 ) -> Result<Order> {
142 self.delete(&format!("/v2/positions/{}", symbol)).await
143 }
144
145 pub async fn get_watchlists(&self) -> Result<Vec<Watchlist>> {
149 self.get("/v2/watchlists").await
150 }
151
152 pub async fn create_watchlist(&self, watchlist: &CreateWatchlistRequest) -> Result<Watchlist> {
154 self.post("/v2/watchlists", watchlist).await
155 }
156
157 pub async fn get_watchlist(&self, watchlist_id: &Uuid) -> Result<Watchlist> {
159 self.get(&format!("/v2/watchlists/{}", watchlist_id)).await
160 }
161
162 pub async fn update_watchlist(
164 &self,
165 watchlist_id: &Uuid,
166 watchlist: &UpdateWatchlistRequest,
167 ) -> Result<Watchlist> {
168 self.put(&format!("/v2/watchlists/{}", watchlist_id), watchlist)
169 .await
170 }
171
172 pub async fn delete_watchlist(&self, watchlist_id: &Uuid) -> Result<()> {
174 self.delete(&format!("/v2/watchlists/{}", watchlist_id))
175 .await
176 }
177
178 pub async fn add_to_watchlist(&self, watchlist_id: &Uuid, symbol: &str) -> Result<Watchlist> {
180 let request = AddToWatchlistRequest {
181 symbol: symbol.to_string(),
182 };
183 self.post(&format!("/v2/watchlists/{}", watchlist_id), &request)
184 .await
185 }
186
187 pub async fn remove_from_watchlist(&self, watchlist_id: &Uuid, symbol: &str) -> Result<()> {
189 self.delete(&format!("/v2/watchlists/{}/{}", watchlist_id, symbol))
190 .await
191 }
192
193 pub async fn get_bars(&self, symbol: &str, params: &BarsParams) -> Result<BarsResponse> {
197 self.get_with_params(&format!("/v2/stocks/{}/bars", symbol), params)
198 .await
199 }
200
201 pub async fn get_quotes(&self, symbol: &str, params: &QuotesParams) -> Result<QuotesResponse> {
203 self.get_with_params(&format!("/v2/stocks/{}/quotes", symbol), params)
204 .await
205 }
206
207 pub async fn get_trades(&self, symbol: &str, params: &TradesParams) -> Result<TradesResponse> {
209 self.get_with_params(&format!("/v2/stocks/{}/trades", symbol), params)
210 .await
211 }
212
213 pub async fn get_latest_bar(&self, symbol: &str) -> Result<LatestBarResponse> {
215 self.get(&format!("/v2/stocks/{}/bars/latest", symbol))
216 .await
217 }
218
219 pub async fn get_latest_quote(&self, symbol: &str) -> Result<LatestQuoteResponse> {
221 self.get(&format!("/v2/stocks/{}/quotes/latest", symbol))
222 .await
223 }
224
225 pub async fn get_latest_trade(&self, symbol: &str) -> Result<LatestTradeResponse> {
227 self.get(&format!("/v2/stocks/{}/trades/latest", symbol))
228 .await
229 }
230
231 pub async fn get_calendar(&self, params: &CalendarParams) -> Result<Vec<Calendar>> {
235 self.get_with_params("/v2/calendar", params).await
236 }
237
238 pub async fn get_clock(&self) -> Result<Clock> {
240 self.get("/v2/clock").await
241 }
242
243 pub async fn get_news(&self, params: &NewsParams) -> Result<NewsResponse> {
247 self.get_with_params("/v1beta1/news", params).await
248 }
249
250 pub async fn get_crypto_bars(
254 &self,
255 symbol: &str,
256 params: &CryptoBarsParams,
257 ) -> Result<CryptoBarsResponse> {
258 self.get_with_params(&format!("/v1beta1/crypto/{}/bars", symbol), params)
259 .await
260 }
261
262 pub async fn get_crypto_quotes(
264 &self,
265 symbol: &str,
266 params: &CryptoQuotesParams,
267 ) -> Result<CryptoQuotesResponse> {
268 self.get_with_params(&format!("/v1beta1/crypto/{}/quotes", symbol), params)
269 .await
270 }
271
272 pub async fn get_crypto_trades(
274 &self,
275 symbol: &str,
276 params: &CryptoTradesParams,
277 ) -> Result<CryptoTradesResponse> {
278 self.get_with_params(&format!("/v1beta1/crypto/{}/trades", symbol), params)
279 .await
280 }
281}
282
283#[derive(Debug, Serialize, Deserialize)]
286pub struct AccountConfigurations {
287 pub dtbp_check: Option<String>,
288 pub trade_confirm_email: Option<String>,
289 pub suspend_trade: Option<bool>,
290 pub no_shorting: Option<bool>,
291 pub max_margin_multiplier: Option<String>,
292 pub pdt_check: Option<String>,
293 pub max_dte: Option<i32>,
294}
295
296#[derive(Debug, Serialize, Deserialize)]
297pub struct ActivityParams {
298 pub activity_type: Option<ActivityType>,
299 pub date: Option<String>,
300 pub until: Option<String>,
301 pub after: Option<String>,
302 pub direction: Option<String>,
303 pub page_size: Option<u32>,
304 pub page_token: Option<String>,
305}
306
307#[derive(Debug, Serialize, Deserialize)]
308pub struct PortfolioHistoryParams {
309 pub period: Option<String>,
310 pub timeframe: Option<String>,
311 pub date_end: Option<String>,
312 pub extended_hours: Option<bool>,
313}
314
315#[derive(Debug, Serialize, Deserialize)]
316pub struct AssetParams {
317 pub status: Option<AssetStatus>,
318 pub asset_class: Option<AssetClass>,
319 pub exchange: Option<String>,
320 pub attributes: Option<String>,
321}
322
323#[derive(Debug, Default, Serialize, Deserialize)]
325pub struct OrderParams {
326 pub status: Option<OrderQueryStatus>,
328 pub limit: Option<u32>,
330 pub after: Option<DateTime<Utc>>,
332 pub until: Option<DateTime<Utc>>,
334 pub direction: Option<SortDirection>,
336 pub nested: Option<bool>,
338 pub symbols: Option<String>,
340 pub side: Option<OrderSide>,
342}
343
344impl OrderParams {
345 #[must_use]
347 pub fn new() -> Self {
348 Self::default()
349 }
350
351 #[must_use]
353 pub fn status(mut self, status: OrderQueryStatus) -> Self {
354 self.status = Some(status);
355 self
356 }
357
358 #[must_use]
360 pub fn limit(mut self, limit: u32) -> Self {
361 self.limit = Some(limit);
362 self
363 }
364
365 #[must_use]
367 pub fn after(mut self, after: DateTime<Utc>) -> Self {
368 self.after = Some(after);
369 self
370 }
371
372 #[must_use]
374 pub fn until(mut self, until: DateTime<Utc>) -> Self {
375 self.until = Some(until);
376 self
377 }
378
379 #[must_use]
381 pub fn direction(mut self, direction: SortDirection) -> Self {
382 self.direction = Some(direction);
383 self
384 }
385
386 #[must_use]
388 pub fn nested(mut self, nested: bool) -> Self {
389 self.nested = Some(nested);
390 self
391 }
392
393 #[must_use]
395 pub fn symbols(mut self, symbols: impl Into<String>) -> Self {
396 self.symbols = Some(symbols.into());
397 self
398 }
399
400 #[must_use]
402 pub fn side(mut self, side: OrderSide) -> Self {
403 self.side = Some(side);
404 self
405 }
406}
407
408#[derive(Debug, Default, Serialize, Deserialize)]
412pub struct CreateOrderRequest {
413 pub symbol: String,
415 pub qty: Option<String>,
417 pub notional: Option<String>,
419 pub side: OrderSide,
421 #[serde(rename = "type")]
423 pub order_type: OrderType,
424 pub time_in_force: TimeInForce,
426 pub limit_price: Option<String>,
428 pub stop_price: Option<String>,
430 pub trail_price: Option<String>,
432 pub trail_percent: Option<String>,
434 pub extended_hours: Option<bool>,
436 pub client_order_id: Option<String>,
438 pub order_class: Option<OrderClass>,
440 pub take_profit: Option<TakeProfit>,
442 pub stop_loss: Option<StopLoss>,
444 pub position_intent: Option<PositionIntent>,
446 #[serde(skip_serializing_if = "Option::is_none")]
448 pub gtd_date: Option<NaiveDate>,
449}
450
451impl CreateOrderRequest {
452 #[must_use]
454 pub fn market(symbol: impl Into<String>, side: OrderSide, qty: impl Into<String>) -> Self {
455 Self {
456 symbol: symbol.into(),
457 qty: Some(qty.into()),
458 side,
459 order_type: OrderType::Market,
460 time_in_force: TimeInForce::Day,
461 ..Default::default()
462 }
463 }
464
465 #[must_use]
467 pub fn limit(
468 symbol: impl Into<String>,
469 side: OrderSide,
470 qty: impl Into<String>,
471 limit_price: impl Into<String>,
472 ) -> Self {
473 Self {
474 symbol: symbol.into(),
475 qty: Some(qty.into()),
476 side,
477 order_type: OrderType::Limit,
478 time_in_force: TimeInForce::Day,
479 limit_price: Some(limit_price.into()),
480 ..Default::default()
481 }
482 }
483
484 #[must_use]
486 pub fn stop(
487 symbol: impl Into<String>,
488 side: OrderSide,
489 qty: impl Into<String>,
490 stop_price: impl Into<String>,
491 ) -> Self {
492 Self {
493 symbol: symbol.into(),
494 qty: Some(qty.into()),
495 side,
496 order_type: OrderType::Stop,
497 time_in_force: TimeInForce::Day,
498 stop_price: Some(stop_price.into()),
499 ..Default::default()
500 }
501 }
502
503 #[must_use]
505 pub fn stop_limit(
506 symbol: impl Into<String>,
507 side: OrderSide,
508 qty: impl Into<String>,
509 stop_price: impl Into<String>,
510 limit_price: impl Into<String>,
511 ) -> Self {
512 Self {
513 symbol: symbol.into(),
514 qty: Some(qty.into()),
515 side,
516 order_type: OrderType::StopLimit,
517 time_in_force: TimeInForce::Day,
518 stop_price: Some(stop_price.into()),
519 limit_price: Some(limit_price.into()),
520 ..Default::default()
521 }
522 }
523
524 #[must_use]
526 pub fn trailing_stop_price(
527 symbol: impl Into<String>,
528 side: OrderSide,
529 qty: impl Into<String>,
530 trail_price: impl Into<String>,
531 ) -> Self {
532 Self {
533 symbol: symbol.into(),
534 qty: Some(qty.into()),
535 side,
536 order_type: OrderType::TrailingStop,
537 time_in_force: TimeInForce::Day,
538 trail_price: Some(trail_price.into()),
539 ..Default::default()
540 }
541 }
542
543 #[must_use]
545 pub fn trailing_stop_percent(
546 symbol: impl Into<String>,
547 side: OrderSide,
548 qty: impl Into<String>,
549 trail_percent: impl Into<String>,
550 ) -> Self {
551 Self {
552 symbol: symbol.into(),
553 qty: Some(qty.into()),
554 side,
555 order_type: OrderType::TrailingStop,
556 time_in_force: TimeInForce::Day,
557 trail_percent: Some(trail_percent.into()),
558 ..Default::default()
559 }
560 }
561
562 #[must_use]
568 pub fn bracket(
569 symbol: impl Into<String>,
570 side: OrderSide,
571 qty: impl Into<String>,
572 order_type: OrderType,
573 take_profit: TakeProfit,
574 stop_loss: StopLoss,
575 ) -> Self {
576 Self {
577 symbol: symbol.into(),
578 qty: Some(qty.into()),
579 side,
580 order_type,
581 time_in_force: TimeInForce::Day,
582 order_class: Some(OrderClass::Bracket),
583 take_profit: Some(take_profit),
584 stop_loss: Some(stop_loss),
585 ..Default::default()
586 }
587 }
588
589 #[must_use]
594 pub fn oco(
595 symbol: impl Into<String>,
596 side: OrderSide,
597 qty: impl Into<String>,
598 take_profit: TakeProfit,
599 stop_loss: StopLoss,
600 ) -> Self {
601 Self {
602 symbol: symbol.into(),
603 qty: Some(qty.into()),
604 side,
605 order_type: OrderType::Limit,
606 time_in_force: TimeInForce::Day,
607 order_class: Some(OrderClass::Oco),
608 take_profit: Some(take_profit),
609 stop_loss: Some(stop_loss),
610 ..Default::default()
611 }
612 }
613
614 #[must_use]
619 pub fn oto(
620 symbol: impl Into<String>,
621 side: OrderSide,
622 qty: impl Into<String>,
623 order_type: OrderType,
624 stop_loss: StopLoss,
625 ) -> Self {
626 Self {
627 symbol: symbol.into(),
628 qty: Some(qty.into()),
629 side,
630 order_type,
631 time_in_force: TimeInForce::Day,
632 order_class: Some(OrderClass::Oto),
633 stop_loss: Some(stop_loss),
634 ..Default::default()
635 }
636 }
637
638 #[must_use]
640 pub fn time_in_force(mut self, tif: TimeInForce) -> Self {
641 self.time_in_force = tif;
642 self
643 }
644
645 #[must_use]
647 pub fn with_limit_price(mut self, price: impl Into<String>) -> Self {
648 self.limit_price = Some(price.into());
649 self
650 }
651
652 #[must_use]
654 pub fn extended_hours(mut self, enabled: bool) -> Self {
655 self.extended_hours = Some(enabled);
656 self
657 }
658
659 #[must_use]
661 pub fn client_order_id(mut self, id: impl Into<String>) -> Self {
662 self.client_order_id = Some(id.into());
663 self
664 }
665
666 #[must_use]
668 pub fn position_intent(mut self, intent: PositionIntent) -> Self {
669 self.position_intent = Some(intent);
670 self
671 }
672
673 #[must_use]
675 pub fn gtd_date(mut self, date: NaiveDate) -> Self {
676 self.time_in_force = TimeInForce::Gtd;
677 self.gtd_date = Some(date);
678 self
679 }
680}
681
682#[derive(Debug, Default, Serialize, Deserialize)]
684pub struct ReplaceOrderRequest {
685 pub qty: Option<String>,
687 pub time_in_force: Option<TimeInForce>,
689 pub limit_price: Option<String>,
691 pub stop_price: Option<String>,
693 pub trail: Option<String>,
695 pub client_order_id: Option<String>,
697}
698
699impl ReplaceOrderRequest {
700 #[must_use]
702 pub fn new() -> Self {
703 Self::default()
704 }
705
706 #[must_use]
708 pub fn qty(mut self, qty: impl Into<String>) -> Self {
709 self.qty = Some(qty.into());
710 self
711 }
712
713 #[must_use]
715 pub fn time_in_force(mut self, tif: TimeInForce) -> Self {
716 self.time_in_force = Some(tif);
717 self
718 }
719
720 #[must_use]
722 pub fn limit_price(mut self, price: impl Into<String>) -> Self {
723 self.limit_price = Some(price.into());
724 self
725 }
726
727 #[must_use]
729 pub fn stop_price(mut self, price: impl Into<String>) -> Self {
730 self.stop_price = Some(price.into());
731 self
732 }
733
734 #[must_use]
736 pub fn trail(mut self, trail: impl Into<String>) -> Self {
737 self.trail = Some(trail.into());
738 self
739 }
740
741 #[must_use]
743 pub fn client_order_id(mut self, id: impl Into<String>) -> Self {
744 self.client_order_id = Some(id.into());
745 self
746 }
747}
748
749#[derive(Debug, Serialize, Deserialize)]
750pub struct CancelOrderResponse {
751 pub id: Uuid,
752 pub status: i32,
753}
754
755#[derive(Debug, Serialize, Deserialize)]
756pub struct ClosePositionResponse {
757 pub symbol: String,
758 pub status: i32,
759}
760
761#[derive(Debug, Serialize, Deserialize, Default)]
763pub struct ClosePositionRequest {
764 pub qty: Option<String>,
766 pub percentage: Option<String>,
768}
769
770impl ClosePositionRequest {
771 #[must_use]
773 pub fn new() -> Self {
774 Self::default()
775 }
776
777 #[must_use]
779 pub fn qty(mut self, qty: impl Into<String>) -> Self {
780 self.qty = Some(qty.into());
781 self
782 }
783
784 #[must_use]
786 pub fn percentage(mut self, percentage: impl Into<String>) -> Self {
787 self.percentage = Some(percentage.into());
788 self
789 }
790}
791
792#[derive(Debug, Serialize, Deserialize)]
793pub struct CreateWatchlistRequest {
794 pub name: String,
795 pub symbols: Option<Vec<String>>,
796}
797
798#[derive(Debug, Serialize, Deserialize)]
799pub struct UpdateWatchlistRequest {
800 pub name: Option<String>,
801 pub symbols: Option<Vec<String>>,
802}
803
804#[derive(Debug, Serialize, Deserialize)]
805pub struct AddToWatchlistRequest {
806 pub symbol: String,
807}
808
809#[derive(Debug, Serialize, Deserialize)]
810pub struct BarsParams {
811 pub start: Option<DateTime<Utc>>,
812 pub end: Option<DateTime<Utc>>,
813 pub timeframe: Option<String>,
814 pub page_token: Option<String>,
815 pub limit: Option<u32>,
816 pub asof: Option<String>,
817 pub feed: Option<String>,
818 pub sort: Option<String>,
819}
820
821#[derive(Debug, Serialize, Deserialize)]
822pub struct BarsResponse {
823 pub bars: Vec<Bar>,
824 pub symbol: String,
825 pub next_page_token: Option<String>,
826}
827
828#[derive(Debug, Serialize, Deserialize)]
829pub struct QuotesParams {
830 pub start: Option<DateTime<Utc>>,
831 pub end: Option<DateTime<Utc>>,
832 pub page_token: Option<String>,
833 pub limit: Option<u32>,
834 pub asof: Option<String>,
835 pub feed: Option<String>,
836 pub sort: Option<String>,
837}
838
839#[derive(Debug, Serialize, Deserialize)]
840pub struct QuotesResponse {
841 pub quotes: Vec<Quote>,
842 pub symbol: String,
843 pub next_page_token: Option<String>,
844}
845
846#[derive(Debug, Serialize, Deserialize)]
847pub struct TradesParams {
848 pub start: Option<DateTime<Utc>>,
849 pub end: Option<DateTime<Utc>>,
850 pub page_token: Option<String>,
851 pub limit: Option<u32>,
852 pub asof: Option<String>,
853 pub feed: Option<String>,
854 pub sort: Option<String>,
855}
856
857#[derive(Debug, Serialize, Deserialize)]
858pub struct TradesResponse {
859 pub trades: Vec<Trade>,
860 pub symbol: String,
861 pub next_page_token: Option<String>,
862}
863
864#[derive(Debug, Serialize, Deserialize)]
865pub struct LatestBarResponse {
866 pub bar: Bar,
867 pub symbol: String,
868}
869
870#[derive(Debug, Serialize, Deserialize)]
871pub struct LatestQuoteResponse {
872 pub quote: Quote,
873 pub symbol: String,
874}
875
876#[derive(Debug, Serialize, Deserialize)]
877pub struct LatestTradeResponse {
878 pub trade: Trade,
879 pub symbol: String,
880}
881
882#[derive(Debug, Serialize, Deserialize)]
883pub struct CalendarParams {
884 pub start: Option<String>,
885 pub end: Option<String>,
886}
887
888#[derive(Debug, Serialize, Deserialize)]
889pub struct NewsParams {
890 pub symbols: Option<String>,
891 pub start: Option<DateTime<Utc>>,
892 pub end: Option<DateTime<Utc>>,
893 pub sort: Option<String>,
894 pub include_content: Option<bool>,
895 pub exclude_contentless: Option<bool>,
896 pub page_token: Option<String>,
897 pub limit: Option<u32>,
898}
899
900#[derive(Debug, Serialize, Deserialize)]
901pub struct NewsResponse {
902 pub news: Vec<NewsArticle>,
903 pub next_page_token: Option<String>,
904}
905
906#[derive(Debug, Serialize, Deserialize)]
907pub struct CryptoBarsParams {
908 pub start: Option<DateTime<Utc>>,
909 pub end: Option<DateTime<Utc>>,
910 pub timeframe: Option<String>,
911 pub page_token: Option<String>,
912 pub limit: Option<u32>,
913 pub sort: Option<String>,
914}
915
916#[derive(Debug, Serialize, Deserialize)]
917pub struct CryptoBarsResponse {
918 pub bars: Vec<Bar>,
919 pub symbol: String,
920 pub next_page_token: Option<String>,
921}
922
923#[derive(Debug, Serialize, Deserialize)]
924pub struct CryptoQuotesParams {
925 pub start: Option<DateTime<Utc>>,
926 pub end: Option<DateTime<Utc>>,
927 pub page_token: Option<String>,
928 pub limit: Option<u32>,
929 pub sort: Option<String>,
930}
931
932#[derive(Debug, Serialize, Deserialize)]
933pub struct CryptoQuotesResponse {
934 pub quotes: Vec<Quote>,
935 pub symbol: String,
936 pub next_page_token: Option<String>,
937}
938
939#[derive(Debug, Serialize, Deserialize)]
940pub struct CryptoTradesParams {
941 pub start: Option<DateTime<Utc>>,
942 pub end: Option<DateTime<Utc>>,
943 pub page_token: Option<String>,
944 pub limit: Option<u32>,
945 pub sort: Option<String>,
946}
947
948#[derive(Debug, Serialize, Deserialize)]
949pub struct CryptoTradesResponse {
950 pub trades: Vec<Trade>,
951 pub symbol: String,
952 pub next_page_token: Option<String>,
953}
954
955#[derive(Debug, Serialize, Deserialize)]
961pub struct OptionContractsResponse {
962 pub option_contracts: Vec<OptionContract>,
964 pub next_page_token: Option<String>,
966}
967
968#[derive(Debug, Serialize, Deserialize)]
970pub struct OptionBarsResponse {
971 pub bars: std::collections::HashMap<String, Vec<OptionBar>>,
973 pub next_page_token: Option<String>,
975}
976
977#[derive(Debug, Serialize, Deserialize)]
979pub struct OptionSnapshotsResponse {
980 pub snapshots: std::collections::HashMap<String, OptionSnapshot>,
982}
983
984impl AlpacaHttpClient {
985 pub async fn get_option_contracts(
997 &self,
998 params: &OptionContractParams,
999 ) -> Result<OptionContractsResponse> {
1000 self.get_with_params("/v2/options/contracts", params).await
1001 }
1002
1003 pub async fn get_option_contract(&self, symbol_or_id: &str) -> Result<OptionContract> {
1011 self.get(&format!("/v2/options/contracts/{}", symbol_or_id))
1012 .await
1013 }
1014
1015 pub async fn exercise_option(&self, request: &OptionExerciseRequest) -> Result<Order> {
1023 self.post("/v2/options/exercise", request).await
1024 }
1025
1026 pub async fn get_option_bars(&self, params: &OptionBarsParams) -> Result<OptionBarsResponse> {
1038 self.get_with_params("/v1beta1/options/bars", params).await
1039 }
1040
1041 pub async fn get_option_snapshots(&self, symbols: &str) -> Result<OptionSnapshotsResponse> {
1049 #[derive(Serialize)]
1050 struct Params<'a> {
1051 symbols: &'a str,
1052 }
1053 self.get_with_params("/v1beta1/options/snapshots", &Params { symbols })
1054 .await
1055 }
1056
1057 pub async fn get_option_chain(
1065 &self,
1066 underlying_symbol: &str,
1067 ) -> Result<OptionSnapshotsResponse> {
1068 #[derive(Serialize)]
1069 struct Params<'a> {
1070 underlying_symbol: &'a str,
1071 }
1072 self.get_with_params("/v1beta1/options/snapshots", &Params { underlying_symbol })
1073 .await
1074 }
1075}
1076
1077#[derive(Debug, Serialize, Deserialize)]
1083pub struct MultiBarsResponse {
1084 pub bars: std::collections::HashMap<String, Vec<Bar>>,
1086 pub next_page_token: Option<String>,
1088}
1089
1090#[derive(Debug, Serialize, Deserialize)]
1092pub struct MultiQuotesResponse {
1093 pub quotes: std::collections::HashMap<String, Vec<Quote>>,
1095 pub next_page_token: Option<String>,
1097}
1098
1099#[derive(Debug, Serialize, Deserialize)]
1101pub struct MultiTradesResponse {
1102 pub trades: std::collections::HashMap<String, Vec<Trade>>,
1104 pub next_page_token: Option<String>,
1106}
1107
1108#[derive(Debug, Serialize, Deserialize)]
1110pub struct StockSnapshotsResponse {
1111 #[serde(flatten)]
1113 pub snapshots: std::collections::HashMap<String, StockSnapshot>,
1114}
1115
1116#[derive(Debug, Serialize, Deserialize)]
1118pub struct CorporateActionsResponse {
1119 pub corporate_actions: Vec<CorporateAction>,
1121 pub next_page_token: Option<String>,
1123}
1124
1125#[derive(Debug, Serialize, Deserialize)]
1127pub struct LatestBarsResponse {
1128 pub bars: std::collections::HashMap<String, Bar>,
1130}
1131
1132#[derive(Debug, Serialize, Deserialize)]
1134pub struct LatestQuotesResponse {
1135 pub quotes: std::collections::HashMap<String, Quote>,
1137}
1138
1139#[derive(Debug, Serialize, Deserialize)]
1141pub struct LatestTradesResponse {
1142 pub trades: std::collections::HashMap<String, Trade>,
1144}
1145
1146impl AlpacaHttpClient {
1147 pub async fn get_stock_bars(&self, params: &MultiBarsParams) -> Result<MultiBarsResponse> {
1159 self.get_with_params("/v2/stocks/bars", params).await
1160 }
1161
1162 pub async fn get_stock_quotes(
1170 &self,
1171 params: &MultiQuotesParams,
1172 ) -> Result<MultiQuotesResponse> {
1173 self.get_with_params("/v2/stocks/quotes", params).await
1174 }
1175
1176 pub async fn get_stock_trades(
1184 &self,
1185 params: &MultiTradesParams,
1186 ) -> Result<MultiTradesResponse> {
1187 self.get_with_params("/v2/stocks/trades", params).await
1188 }
1189
1190 pub async fn get_stock_snapshots(&self, symbols: &str) -> Result<StockSnapshotsResponse> {
1198 #[derive(Serialize)]
1199 struct Params<'a> {
1200 symbols: &'a str,
1201 }
1202 self.get_with_params("/v2/stocks/snapshots", &Params { symbols })
1203 .await
1204 }
1205
1206 pub async fn get_latest_bars(&self, symbols: &str) -> Result<LatestBarsResponse> {
1218 #[derive(Serialize)]
1219 struct Params<'a> {
1220 symbols: &'a str,
1221 }
1222 self.get_with_params("/v2/stocks/bars/latest", &Params { symbols })
1223 .await
1224 }
1225
1226 pub async fn get_latest_quotes(&self, symbols: &str) -> Result<LatestQuotesResponse> {
1234 #[derive(Serialize)]
1235 struct Params<'a> {
1236 symbols: &'a str,
1237 }
1238 self.get_with_params("/v2/stocks/quotes/latest", &Params { symbols })
1239 .await
1240 }
1241
1242 pub async fn get_latest_trades(&self, symbols: &str) -> Result<LatestTradesResponse> {
1250 #[derive(Serialize)]
1251 struct Params<'a> {
1252 symbols: &'a str,
1253 }
1254 self.get_with_params("/v2/stocks/trades/latest", &Params { symbols })
1255 .await
1256 }
1257
1258 pub async fn get_corporate_actions(
1270 &self,
1271 params: &CorporateActionsParams,
1272 ) -> Result<CorporateActionsResponse> {
1273 self.get_with_params("/v1beta1/corporate-actions/announcements", params)
1274 .await
1275 }
1276}
1277
1278impl AlpacaHttpClient {
1283 pub async fn create_broker_account(
1295 &self,
1296 request: &CreateBrokerAccountRequest,
1297 ) -> Result<BrokerAccount> {
1298 self.post("/v1/accounts", request).await
1299 }
1300
1301 pub async fn list_broker_accounts(
1309 &self,
1310 params: &ListBrokerAccountsParams,
1311 ) -> Result<Vec<BrokerAccount>> {
1312 self.get_with_params("/v1/accounts", params).await
1313 }
1314
1315 pub async fn get_broker_account(&self, account_id: &str) -> Result<BrokerAccount> {
1323 self.get(&format!("/v1/accounts/{}", account_id)).await
1324 }
1325
1326 pub async fn update_broker_account(
1335 &self,
1336 account_id: &str,
1337 request: &UpdateBrokerAccountRequest,
1338 ) -> Result<BrokerAccount> {
1339 self.patch(&format!("/v1/accounts/{}", account_id), request)
1340 .await
1341 }
1342
1343 pub async fn close_broker_account(&self, account_id: &str) -> Result<()> {
1348 self.delete(&format!("/v1/accounts/{}", account_id)).await
1349 }
1350
1351 pub async fn get_broker_trading_account(&self, account_id: &str) -> Result<Account> {
1359 self.get(&format!("/v1/accounts/{}/trading", account_id))
1360 .await
1361 }
1362
1363 pub async fn submit_cip(&self, account_id: &str, cip_info: &CipInfo) -> Result<CipInfo> {
1376 self.post(&format!("/v1/accounts/{}/cip", account_id), cip_info)
1377 .await
1378 }
1379
1380 pub async fn get_cip(&self, account_id: &str) -> Result<CipInfo> {
1388 self.get(&format!("/v1/accounts/{}/cip", account_id)).await
1389 }
1390
1391 pub async fn upload_document(
1404 &self,
1405 account_id: &str,
1406 document: &Document,
1407 ) -> Result<DocumentUploadResponse> {
1408 self.post(
1409 &format!("/v1/accounts/{}/documents/upload", account_id),
1410 document,
1411 )
1412 .await
1413 }
1414
1415 pub async fn list_documents(&self, account_id: &str) -> Result<Vec<DocumentInfo>> {
1423 self.get(&format!("/v1/accounts/{}/documents", account_id))
1424 .await
1425 }
1426
1427 pub async fn get_document(&self, account_id: &str, document_id: &str) -> Result<DocumentInfo> {
1436 self.get(&format!(
1437 "/v1/accounts/{}/documents/{}",
1438 account_id, document_id
1439 ))
1440 .await
1441 }
1442
1443 pub async fn delete_document(&self, account_id: &str, document_id: &str) -> Result<()> {
1449 self.delete(&format!(
1450 "/v1/accounts/{}/documents/{}",
1451 account_id, document_id
1452 ))
1453 .await
1454 }
1455}
1456
1457#[derive(Debug, Serialize, Deserialize)]
1459pub struct DocumentUploadResponse {
1460 pub id: String,
1462 pub document_type: DocumentType,
1464 pub status: String,
1466}
1467
1468#[derive(Debug, Serialize, Deserialize)]
1470pub struct DocumentInfo {
1471 pub id: String,
1473 pub document_type: DocumentType,
1475 #[serde(skip_serializing_if = "Option::is_none")]
1477 pub document_sub_type: Option<String>,
1478 pub created_at: DateTime<Utc>,
1480}
1481
1482impl AlpacaHttpClient {
1487 pub async fn create_ach_relationship(
1500 &self,
1501 account_id: &str,
1502 request: &CreateAchRelationshipRequest,
1503 ) -> Result<AchRelationship> {
1504 self.post(
1505 &format!("/v1/accounts/{}/ach_relationships", account_id),
1506 request,
1507 )
1508 .await
1509 }
1510
1511 pub async fn list_ach_relationships(&self, account_id: &str) -> Result<Vec<AchRelationship>> {
1519 self.get(&format!("/v1/accounts/{}/ach_relationships", account_id))
1520 .await
1521 }
1522
1523 pub async fn delete_ach_relationship(
1529 &self,
1530 account_id: &str,
1531 relationship_id: &str,
1532 ) -> Result<()> {
1533 self.delete(&format!(
1534 "/v1/accounts/{}/ach_relationships/{}",
1535 account_id, relationship_id
1536 ))
1537 .await
1538 }
1539
1540 pub async fn create_transfer(
1553 &self,
1554 account_id: &str,
1555 request: &CreateTransferRequest,
1556 ) -> Result<Transfer> {
1557 self.post(&format!("/v1/accounts/{}/transfers", account_id), request)
1558 .await
1559 }
1560
1561 pub async fn list_transfers(
1570 &self,
1571 account_id: &str,
1572 params: &ListTransfersParams,
1573 ) -> Result<Vec<Transfer>> {
1574 self.get_with_params(&format!("/v1/accounts/{}/transfers", account_id), params)
1575 .await
1576 }
1577
1578 pub async fn get_transfer(&self, account_id: &str, transfer_id: &str) -> Result<Transfer> {
1587 self.get(&format!(
1588 "/v1/accounts/{}/transfers/{}",
1589 account_id, transfer_id
1590 ))
1591 .await
1592 }
1593
1594 pub async fn cancel_transfer(&self, account_id: &str, transfer_id: &str) -> Result<()> {
1600 self.delete(&format!(
1601 "/v1/accounts/{}/transfers/{}",
1602 account_id, transfer_id
1603 ))
1604 .await
1605 }
1606
1607 pub async fn list_wire_banks(&self, account_id: &str) -> Result<Vec<WireBank>> {
1619 self.get(&format!("/v1/accounts/{}/recipient_banks", account_id))
1620 .await
1621 }
1622
1623 pub async fn create_wire_bank(
1632 &self,
1633 account_id: &str,
1634 request: &CreateWireBankRequest,
1635 ) -> Result<WireBank> {
1636 self.post(
1637 &format!("/v1/accounts/{}/recipient_banks", account_id),
1638 request,
1639 )
1640 .await
1641 }
1642
1643 pub async fn delete_wire_bank(&self, account_id: &str, bank_id: &str) -> Result<()> {
1649 self.delete(&format!(
1650 "/v1/accounts/{}/recipient_banks/{}",
1651 account_id, bank_id
1652 ))
1653 .await
1654 }
1655
1656 pub async fn create_journal(&self, request: &CreateJournalRequest) -> Result<Journal> {
1668 self.post("/v1/journals", request).await
1669 }
1670
1671 pub async fn list_journals(&self, params: &ListJournalsParams) -> Result<Vec<Journal>> {
1679 self.get_with_params("/v1/journals", params).await
1680 }
1681
1682 pub async fn create_batch_journals(
1690 &self,
1691 request: &CreateBatchJournalRequest,
1692 ) -> Result<Vec<Journal>> {
1693 self.post("/v1/journals/batch", request).await
1694 }
1695
1696 pub async fn delete_journal(&self, journal_id: &str) -> Result<()> {
1701 self.delete(&format!("/v1/journals/{}", journal_id)).await
1702 }
1703}
1704
1705#[derive(Debug, Serialize, Deserialize)]
1711pub struct MultiCryptoSnapshotsResponse {
1712 pub snapshots: std::collections::HashMap<String, CryptoSnapshot>,
1714}
1715
1716#[derive(Debug, Serialize, Deserialize)]
1718pub struct MultiCryptoBarsResponse {
1719 pub bars: std::collections::HashMap<String, Vec<CryptoBar>>,
1721 pub next_page_token: Option<String>,
1723}
1724
1725#[derive(Debug, Serialize, Deserialize)]
1727pub struct LatestCryptoBarsResponse {
1728 pub bars: std::collections::HashMap<String, CryptoBar>,
1730}
1731
1732#[derive(Debug, Serialize, Deserialize)]
1734pub struct LatestCryptoQuotesResponse {
1735 pub quotes: std::collections::HashMap<String, CryptoQuote>,
1737}
1738
1739#[derive(Debug, Serialize, Deserialize)]
1741pub struct LatestCryptoTradesResponse {
1742 pub trades: std::collections::HashMap<String, CryptoTrade>,
1744}
1745
1746#[derive(Debug, Serialize, Deserialize)]
1748pub struct CryptoOrderbooksResponse {
1749 pub orderbooks: std::collections::HashMap<String, CryptoOrderbook>,
1751}
1752
1753impl AlpacaHttpClient {
1754 pub async fn list_crypto_wallets(&self, account_id: &str) -> Result<Vec<BrokerCryptoWallet>> {
1766 self.get(&format!("/v1/accounts/{}/wallets", account_id))
1767 .await
1768 }
1769
1770 pub async fn create_crypto_wallet(
1779 &self,
1780 account_id: &str,
1781 request: &CreateCryptoWalletRequest,
1782 ) -> Result<BrokerCryptoWallet> {
1783 self.post(&format!("/v1/accounts/{}/wallets", account_id), request)
1784 .await
1785 }
1786
1787 pub async fn get_crypto_wallet(
1796 &self,
1797 account_id: &str,
1798 asset: &str,
1799 ) -> Result<BrokerCryptoWallet> {
1800 self.get(&format!("/v1/accounts/{}/wallets/{}", account_id, asset))
1801 .await
1802 }
1803
1804 pub async fn list_crypto_transfers(&self, account_id: &str) -> Result<Vec<CryptoTransfer>> {
1812 self.get(&format!("/v1/accounts/{}/wallets/transfers", account_id))
1813 .await
1814 }
1815
1816 pub async fn create_crypto_transfer(
1826 &self,
1827 account_id: &str,
1828 asset: &str,
1829 request: &CreateCryptoTransferRequest,
1830 ) -> Result<CryptoTransfer> {
1831 self.post(
1832 &format!("/v1/accounts/{}/wallets/{}/transfers", account_id, asset),
1833 request,
1834 )
1835 .await
1836 }
1837
1838 pub async fn list_crypto_whitelists(
1846 &self,
1847 account_id: &str,
1848 ) -> Result<Vec<CryptoWhitelistAddress>> {
1849 self.get(&format!("/v1/accounts/{}/wallets/whitelists", account_id))
1850 .await
1851 }
1852
1853 pub async fn create_crypto_whitelist(
1862 &self,
1863 account_id: &str,
1864 request: &CreateCryptoWhitelistRequest,
1865 ) -> Result<CryptoWhitelistAddress> {
1866 self.post(
1867 &format!("/v1/accounts/{}/wallets/whitelists", account_id),
1868 request,
1869 )
1870 .await
1871 }
1872
1873 pub async fn get_multi_crypto_bars(
1885 &self,
1886 params: &CryptoBarsParams,
1887 ) -> Result<MultiCryptoBarsResponse> {
1888 self.get_with_params("/v1beta3/crypto/us/bars", params)
1889 .await
1890 }
1891
1892 pub async fn get_latest_crypto_bars(&self, symbols: &str) -> Result<LatestCryptoBarsResponse> {
1900 #[derive(Serialize)]
1901 struct Params<'a> {
1902 symbols: &'a str,
1903 }
1904 self.get_with_params("/v1beta3/crypto/us/latest/bars", &Params { symbols })
1905 .await
1906 }
1907
1908 pub async fn get_latest_crypto_quotes(
1916 &self,
1917 symbols: &str,
1918 ) -> Result<LatestCryptoQuotesResponse> {
1919 #[derive(Serialize)]
1920 struct Params<'a> {
1921 symbols: &'a str,
1922 }
1923 self.get_with_params("/v1beta3/crypto/us/latest/quotes", &Params { symbols })
1924 .await
1925 }
1926
1927 pub async fn get_latest_crypto_trades(
1935 &self,
1936 symbols: &str,
1937 ) -> Result<LatestCryptoTradesResponse> {
1938 #[derive(Serialize)]
1939 struct Params<'a> {
1940 symbols: &'a str,
1941 }
1942 self.get_with_params("/v1beta3/crypto/us/latest/trades", &Params { symbols })
1943 .await
1944 }
1945
1946 pub async fn get_multi_crypto_snapshots(
1954 &self,
1955 symbols: &str,
1956 ) -> Result<MultiCryptoSnapshotsResponse> {
1957 #[derive(Serialize)]
1958 struct Params<'a> {
1959 symbols: &'a str,
1960 }
1961 self.get_with_params("/v1beta3/crypto/us/snapshots", &Params { symbols })
1962 .await
1963 }
1964
1965 pub async fn get_crypto_orderbooks(&self, symbols: &str) -> Result<CryptoOrderbooksResponse> {
1973 #[derive(Serialize)]
1974 struct Params<'a> {
1975 symbols: &'a str,
1976 }
1977 self.get_with_params("/v1beta3/crypto/us/latest/orderbooks", &Params { symbols })
1978 .await
1979 }
1980}
1981
1982#[derive(Debug, Serialize, Deserialize)]
1988pub struct EnhancedNewsResponse {
1989 pub news: Vec<EnhancedNewsArticle>,
1991 pub next_page_token: Option<String>,
1993}
1994
1995impl AlpacaHttpClient {
1996 pub async fn get_enhanced_news(
2004 &self,
2005 params: &alpaca_base::NewsParams,
2006 ) -> Result<EnhancedNewsResponse> {
2007 self.get_with_params("/v1beta1/news", params).await
2008 }
2009
2010 pub async fn get_enhanced_news_for_symbols(
2019 &self,
2020 symbols: &str,
2021 limit: u32,
2022 ) -> Result<EnhancedNewsResponse> {
2023 let params = alpaca_base::NewsParams::new().symbols(symbols).limit(limit);
2024 self.get_enhanced_news(¶ms).await
2025 }
2026
2027 pub async fn get_latest_enhanced_news(&self, limit: u32) -> Result<EnhancedNewsResponse> {
2035 let params = alpaca_base::NewsParams::new().sort_desc().limit(limit);
2036 self.get_enhanced_news(¶ms).await
2037 }
2038}
2039
2040impl AlpacaHttpClient {
2045 pub async fn oauth_exchange_code(&self, request: &OAuthTokenRequest) -> Result<OAuthToken> {
2053 self.post("/oauth/token", request).await
2054 }
2055
2056 pub async fn oauth_refresh_token(&self, request: &OAuthTokenRequest) -> Result<OAuthToken> {
2064 self.post("/oauth/token", request).await
2065 }
2066
2067 pub async fn oauth_revoke_token(&self, request: &OAuthRevokeRequest) -> Result<()> {
2072 let _: serde_json::Value = self.post("/oauth/revoke", request).await?;
2073 Ok(())
2074 }
2075}
2076
2077impl AlpacaHttpClient {
2082 #[must_use]
2092 pub fn get_account_status_events_url(&self, params: &SseEventParams) -> String {
2093 let base = "/v1/events/accounts/status";
2094 self.build_sse_url(base, params)
2095 }
2096
2097 #[must_use]
2107 pub fn get_transfer_status_events_url(&self, params: &SseEventParams) -> String {
2108 let base = "/v1/events/transfers/status";
2109 self.build_sse_url(base, params)
2110 }
2111
2112 #[must_use]
2122 pub fn get_trade_events_url(&self, params: &SseEventParams) -> String {
2123 let base = "/v1/events/trades";
2124 self.build_sse_url(base, params)
2125 }
2126
2127 #[must_use]
2137 pub fn get_journal_status_events_url(&self, params: &SseEventParams) -> String {
2138 let base = "/v1/events/journals/status";
2139 self.build_sse_url(base, params)
2140 }
2141
2142 #[must_use]
2152 pub fn get_nta_events_url(&self, params: &SseEventParams) -> String {
2153 let base = "/v2beta1/events/nta";
2154 self.build_sse_url(base, params)
2155 }
2156
2157 fn build_sse_url(&self, base: &str, params: &SseEventParams) -> String {
2159 let mut url = base.to_string();
2160 let mut query_parts = Vec::new();
2161
2162 if let Some(ref account_id) = params.account_id {
2163 query_parts.push(format!("account_id={}", account_id));
2164 }
2165 if let Some(ref since) = params.since {
2166 query_parts.push(format!("since={}", since));
2167 }
2168 if let Some(ref until) = params.until {
2169 query_parts.push(format!("until={}", until));
2170 }
2171
2172 if !query_parts.is_empty() {
2173 url.push('?');
2174 url.push_str(&query_parts.join("&"));
2175 }
2176
2177 url
2178 }
2179}
2180
2181impl AlpacaHttpClient {
2186 pub async fn list_enhanced_assets(
2194 &self,
2195 params: &ListAssetsParams,
2196 ) -> Result<Vec<EnhancedAsset>> {
2197 self.get_with_params("/v2/assets", params).await
2198 }
2199
2200 pub async fn get_enhanced_asset(&self, symbol_or_id: &str) -> Result<EnhancedAsset> {
2208 self.get(&format!("/v2/assets/{}", symbol_or_id)).await
2209 }
2210
2211 pub async fn get_asset_options(&self, symbol: &str) -> Result<Vec<OptionContractAsset>> {
2219 self.get(&format!("/v2/assets/{}/options", symbol)).await
2220 }
2221
2222 pub async fn list_announcements(
2230 &self,
2231 params: &ListAnnouncementsParams,
2232 ) -> Result<Vec<CorporateActionAnnouncement>> {
2233 self.get_with_params("/v1beta1/corporate-actions/announcements", params)
2234 .await
2235 }
2236
2237 pub async fn get_announcement(
2245 &self,
2246 announcement_id: &str,
2247 ) -> Result<CorporateActionAnnouncement> {
2248 self.get(&format!(
2249 "/v1beta1/corporate-actions/announcements/{}",
2250 announcement_id
2251 ))
2252 .await
2253 }
2254}
2255
2256impl AlpacaHttpClient {
2261 pub async fn list_activities(
2269 &self,
2270 params: &ListActivitiesParams,
2271 ) -> Result<Vec<AccountActivity>> {
2272 self.get_with_params("/v2/account/activities", params).await
2273 }
2274
2275 pub async fn list_activities_by_type(
2284 &self,
2285 activity_type: &str,
2286 params: &ListActivitiesParams,
2287 ) -> Result<Vec<AccountActivity>> {
2288 self.get_with_params(&format!("/v2/account/activities/{}", activity_type), params)
2289 .await
2290 }
2291
2292 pub async fn list_broker_activities(
2300 &self,
2301 params: &ListActivitiesParams,
2302 ) -> Result<Vec<AccountActivity>> {
2303 self.get_with_params("/v1/accounts/activities", params)
2304 .await
2305 }
2306
2307 pub async fn list_broker_account_activities(
2316 &self,
2317 account_id: &str,
2318 params: &ListActivitiesParams,
2319 ) -> Result<Vec<AccountActivity>> {
2320 self.get_with_params(&format!("/v1/accounts/{}/activities", account_id), params)
2321 .await
2322 }
2323}
2324
2325impl AlpacaHttpClient {
2330 pub async fn create_rebalance_portfolio(
2338 &self,
2339 request: &RebalancePortfolioRequest,
2340 ) -> Result<RebalancePortfolio> {
2341 self.post("/v1/rebalancing/portfolios", request).await
2342 }
2343
2344 pub async fn list_rebalance_portfolios(&self) -> Result<Vec<RebalancePortfolio>> {
2349 self.get("/v1/rebalancing/portfolios").await
2350 }
2351
2352 pub async fn get_rebalance_portfolio(&self, portfolio_id: &str) -> Result<RebalancePortfolio> {
2360 self.get(&format!("/v1/rebalancing/portfolios/{}", portfolio_id))
2361 .await
2362 }
2363
2364 pub async fn delete_rebalance_portfolio(&self, portfolio_id: &str) -> Result<()> {
2369 let _: serde_json::Value = self
2370 .delete(&format!("/v1/rebalancing/portfolios/{}", portfolio_id))
2371 .await?;
2372 Ok(())
2373 }
2374
2375 pub async fn execute_rebalance(&self, request: &RebalanceRunRequest) -> Result<RebalanceRun> {
2383 self.post("/v1/rebalancing/runs", request).await
2384 }
2385
2386 pub async fn list_rebalance_runs(&self) -> Result<Vec<RebalanceRun>> {
2391 self.get("/v1/rebalancing/runs").await
2392 }
2393}
2394
2395impl AlpacaHttpClient {
2400 pub async fn get_locates(&self) -> Result<Vec<LocateResponse>> {
2405 self.get("/v1/locate/stocks").await
2406 }
2407
2408 pub async fn request_locate(&self, request: &LocateRequest) -> Result<LocateResponse> {
2416 self.post("/v1/locate/stocks", request).await
2417 }
2418}
2419
2420impl AlpacaHttpClient {
2425 pub async fn reset_paper_account(&self) -> Result<Account> {
2430 self.post("/v2/account/reset", &serde_json::json!({})).await
2431 }
2432}
2433
2434impl AlpacaHttpClient {
2439 pub async fn get_exchange_rates(&self) -> Result<Vec<ExchangeRate>> {
2444 self.get("/v1/fx/rates").await
2445 }
2446
2447 pub async fn get_exchange_rate(&self, currency_pair: &str) -> Result<ExchangeRate> {
2455 self.get(&format!("/v1/fx/rates/{}", currency_pair)).await
2456 }
2457}
2458
2459impl AlpacaHttpClient {
2464 pub async fn list_ira_contributions(&self, account_id: &str) -> Result<Vec<IraContribution>> {
2472 self.get(&format!("/v1/accounts/{}/ira/contributions", account_id))
2473 .await
2474 }
2475
2476 pub async fn create_ira_contribution(
2485 &self,
2486 account_id: &str,
2487 request: &CreateIraContributionRequest,
2488 ) -> Result<IraContribution> {
2489 self.post(
2490 &format!("/v1/accounts/{}/ira/contributions", account_id),
2491 request,
2492 )
2493 .await
2494 }
2495
2496 pub async fn list_ira_distributions(&self, account_id: &str) -> Result<Vec<IraDistribution>> {
2504 self.get(&format!("/v1/accounts/{}/ira/distributions", account_id))
2505 .await
2506 }
2507
2508 pub async fn list_ira_beneficiaries(&self, account_id: &str) -> Result<Vec<IraBeneficiary>> {
2516 self.get(&format!("/v1/accounts/{}/ira/beneficiaries", account_id))
2517 .await
2518 }
2519}
2520
2521#[cfg(test)]
2522mod tests {
2523 use super::*;
2524
2525 #[test]
2526 fn test_create_order_request_market() {
2527 let order = CreateOrderRequest::market("AAPL", OrderSide::Buy, "10");
2528 assert_eq!(order.symbol, "AAPL");
2529 assert_eq!(order.side, OrderSide::Buy);
2530 assert_eq!(order.qty, Some("10".to_string()));
2531 assert_eq!(order.order_type, OrderType::Market);
2532 assert_eq!(order.time_in_force, TimeInForce::Day);
2533 }
2534
2535 #[test]
2536 fn test_create_order_request_limit() {
2537 let order = CreateOrderRequest::limit("AAPL", OrderSide::Buy, "10", "150.00");
2538 assert_eq!(order.symbol, "AAPL");
2539 assert_eq!(order.limit_price, Some("150.00".to_string()));
2540 assert_eq!(order.order_type, OrderType::Limit);
2541 }
2542
2543 #[test]
2544 fn test_create_order_request_stop() {
2545 let order = CreateOrderRequest::stop("AAPL", OrderSide::Sell, "10", "145.00");
2546 assert_eq!(order.stop_price, Some("145.00".to_string()));
2547 assert_eq!(order.order_type, OrderType::Stop);
2548 }
2549
2550 #[test]
2551 fn test_create_order_request_stop_limit() {
2552 let order =
2553 CreateOrderRequest::stop_limit("AAPL", OrderSide::Sell, "10", "145.00", "144.50");
2554 assert_eq!(order.stop_price, Some("145.00".to_string()));
2555 assert_eq!(order.limit_price, Some("144.50".to_string()));
2556 assert_eq!(order.order_type, OrderType::StopLimit);
2557 }
2558
2559 #[test]
2560 fn test_create_order_request_trailing_stop_price() {
2561 let order = CreateOrderRequest::trailing_stop_price("AAPL", OrderSide::Sell, "10", "5.00");
2562 assert_eq!(order.trail_price, Some("5.00".to_string()));
2563 assert_eq!(order.order_type, OrderType::TrailingStop);
2564 }
2565
2566 #[test]
2567 fn test_create_order_request_trailing_stop_percent() {
2568 let order = CreateOrderRequest::trailing_stop_percent("AAPL", OrderSide::Sell, "10", "2.5");
2569 assert_eq!(order.trail_percent, Some("2.5".to_string()));
2570 assert_eq!(order.order_type, OrderType::TrailingStop);
2571 }
2572
2573 #[test]
2574 fn test_create_order_request_bracket() {
2575 let tp = TakeProfit::new("160.00");
2576 let sl = StopLoss::new("140.00");
2577 let order =
2578 CreateOrderRequest::bracket("AAPL", OrderSide::Buy, "10", OrderType::Market, tp, sl);
2579
2580 assert_eq!(order.order_class, Some(OrderClass::Bracket));
2581 assert!(order.take_profit.is_some());
2582 assert!(order.stop_loss.is_some());
2583 assert_eq!(order.take_profit.unwrap().limit_price, "160.00");
2584 assert_eq!(order.stop_loss.unwrap().stop_price, "140.00");
2585 }
2586
2587 #[test]
2588 fn test_create_order_request_oco() {
2589 let tp = TakeProfit::new("160.00");
2590 let sl = StopLoss::with_limit("140.00", "139.50");
2591 let order = CreateOrderRequest::oco("AAPL", OrderSide::Sell, "10", tp, sl);
2592
2593 assert_eq!(order.order_class, Some(OrderClass::Oco));
2594 assert!(order.take_profit.is_some());
2595 assert!(order.stop_loss.is_some());
2596 }
2597
2598 #[test]
2599 fn test_create_order_request_oto() {
2600 let sl = StopLoss::new("140.00");
2601 let order = CreateOrderRequest::oto("AAPL", OrderSide::Buy, "10", OrderType::Limit, sl);
2602
2603 assert_eq!(order.order_class, Some(OrderClass::Oto));
2604 assert!(order.stop_loss.is_some());
2605 }
2606
2607 #[test]
2608 fn test_create_order_request_builder_methods() {
2609 let order = CreateOrderRequest::market("AAPL", OrderSide::Buy, "10")
2610 .time_in_force(TimeInForce::Gtc)
2611 .extended_hours(true)
2612 .client_order_id("my-order-123");
2613
2614 assert_eq!(order.time_in_force, TimeInForce::Gtc);
2615 assert_eq!(order.extended_hours, Some(true));
2616 assert_eq!(order.client_order_id, Some("my-order-123".to_string()));
2617 }
2618
2619 #[test]
2620 fn test_create_order_request_position_intent() {
2621 let order = CreateOrderRequest::market("AAPL", OrderSide::Buy, "10")
2622 .position_intent(PositionIntent::BuyToOpen);
2623
2624 assert_eq!(order.position_intent, Some(PositionIntent::BuyToOpen));
2625 }
2626
2627 #[test]
2628 fn test_replace_order_request_builder() {
2629 let request = ReplaceOrderRequest::new()
2630 .qty("20")
2631 .limit_price("155.00")
2632 .time_in_force(TimeInForce::Gtc);
2633
2634 assert_eq!(request.qty, Some("20".to_string()));
2635 assert_eq!(request.limit_price, Some("155.00".to_string()));
2636 assert_eq!(request.time_in_force, Some(TimeInForce::Gtc));
2637 }
2638
2639 #[test]
2640 fn test_order_params_builder() {
2641 let params = OrderParams::new()
2642 .status(OrderQueryStatus::Open)
2643 .limit(100)
2644 .nested(true)
2645 .symbols("AAPL,GOOGL")
2646 .side(OrderSide::Buy)
2647 .direction(SortDirection::Desc);
2648
2649 assert_eq!(params.status, Some(OrderQueryStatus::Open));
2650 assert_eq!(params.limit, Some(100));
2651 assert_eq!(params.nested, Some(true));
2652 assert_eq!(params.symbols, Some("AAPL,GOOGL".to_string()));
2653 assert_eq!(params.side, Some(OrderSide::Buy));
2654 assert_eq!(params.direction, Some(SortDirection::Desc));
2655 }
2656
2657 #[test]
2658 fn test_create_order_request_serialization() {
2659 let order = CreateOrderRequest::limit("AAPL", OrderSide::Buy, "10", "150.00")
2660 .client_order_id("test-123");
2661
2662 let json = serde_json::to_string(&order).unwrap();
2663 assert!(json.contains("\"symbol\":\"AAPL\""));
2664 assert!(json.contains("\"side\":\"buy\""));
2665 assert!(json.contains("\"type\":\"limit\""));
2666 assert!(json.contains("\"limit_price\":\"150.00\""));
2667 }
2668
2669 #[test]
2670 fn test_bracket_order_serialization() {
2671 let tp = TakeProfit::new("160.00");
2672 let sl = StopLoss::with_limit("140.00", "139.50");
2673 let order =
2674 CreateOrderRequest::bracket("AAPL", OrderSide::Buy, "10", OrderType::Limit, tp, sl)
2675 .with_limit_price("150.00");
2676
2677 let json = serde_json::to_string(&order).unwrap();
2678 assert!(json.contains("\"order_class\":\"bracket\""));
2679 assert!(json.contains("\"take_profit\""));
2680 assert!(json.contains("\"stop_loss\""));
2681 }
2682}