11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -1482,6 +1482,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "number_prefix"
|
name = "number_prefix"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -2394,7 +2403,9 @@ checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"libc",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
|
"num_threads",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
@@ -46,9 +46,11 @@ uuid = { version = "1.6.1", features = [
|
|||||||
] }
|
] }
|
||||||
time = { version = "0.3.31", features = [
|
time = { version = "0.3.31", features = [
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-well-known",
|
||||||
|
"serde-human-readable",
|
||||||
"formatting",
|
"formatting",
|
||||||
"macros",
|
"macros",
|
||||||
"serde-well-known",
|
"local-offset",
|
||||||
] }
|
] }
|
||||||
backoff = { version = "0.4.0", features = [
|
backoff = { version = "0.4.0", features = [
|
||||||
"tokio",
|
"tokio",
|
||||||
|
55
src/types/alpaca/api/incoming/calendar.rs
Normal file
55
src/types/alpaca/api/incoming/calendar.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use crate::{config::ALPACA_API_URL, types::alpaca::api::outgoing, utils::de};
|
||||||
|
use backoff::{future::retry_notify, ExponentialBackoff};
|
||||||
|
use governor::DefaultDirectRateLimiter;
|
||||||
|
use log::warn;
|
||||||
|
use reqwest::{Client, Error};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::time::Duration;
|
||||||
|
use time::{Date, Time};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Calendar {
|
||||||
|
pub date: Date,
|
||||||
|
#[serde(deserialize_with = "de::human_time_hh_mm")]
|
||||||
|
pub open: Time,
|
||||||
|
#[serde(deserialize_with = "de::human_time_hh_mm")]
|
||||||
|
pub close: Time,
|
||||||
|
pub settlement_date: Date,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get(
|
||||||
|
alpaca_client: &Client,
|
||||||
|
alpaca_rate_limiter: &DefaultDirectRateLimiter,
|
||||||
|
query: &outgoing::calendar::Calendar,
|
||||||
|
backoff: Option<ExponentialBackoff>,
|
||||||
|
) -> Result<Vec<Calendar>, Error> {
|
||||||
|
retry_notify(
|
||||||
|
backoff.unwrap_or_default(),
|
||||||
|
|| async {
|
||||||
|
alpaca_rate_limiter.until_ready().await;
|
||||||
|
alpaca_client
|
||||||
|
.get(&format!("{}/calendar", *ALPACA_API_URL))
|
||||||
|
.query(query)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()
|
||||||
|
.map_err(|e| match e.status() {
|
||||||
|
Some(reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::FORBIDDEN) => {
|
||||||
|
backoff::Error::Permanent(e)
|
||||||
|
}
|
||||||
|
_ => e.into(),
|
||||||
|
})?
|
||||||
|
.json::<Vec<Calendar>>()
|
||||||
|
.await
|
||||||
|
.map_err(backoff::Error::Permanent)
|
||||||
|
},
|
||||||
|
|e, duration: Duration| {
|
||||||
|
warn!(
|
||||||
|
"Failed to get calendar, will retry in {} seconds: {}",
|
||||||
|
duration.as_secs(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod asset;
|
pub mod asset;
|
||||||
pub mod bar;
|
pub mod bar;
|
||||||
|
pub mod calendar;
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod news;
|
pub mod news;
|
||||||
pub mod order;
|
pub mod order;
|
||||||
|
20
src/types/alpaca/api/outgoing/calendar.rs
Normal file
20
src/types/alpaca/api/outgoing/calendar.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum DateType {
|
||||||
|
Trading,
|
||||||
|
Settlement,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Calendar {
|
||||||
|
#[serde(with = "time::serde::rfc3339")]
|
||||||
|
pub start: OffsetDateTime,
|
||||||
|
#[serde(with = "time::serde::rfc3339")]
|
||||||
|
pub end: OffsetDateTime,
|
||||||
|
#[serde(rename = "date")]
|
||||||
|
pub date_type: DateType,
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
pub mod bar;
|
pub mod bar;
|
||||||
|
pub mod calendar;
|
||||||
pub mod news;
|
pub mod news;
|
||||||
pub mod order;
|
pub mod order;
|
||||||
|
@@ -5,9 +5,11 @@ use serde::{
|
|||||||
Deserializer,
|
Deserializer,
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use time::{format_description::OwnedFormatItem, macros::format_description, Time};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RE_SLASH: Regex = Regex::new(r"^(.+)(BTC|USD.?)$").unwrap();
|
static ref RE_SLASH: Regex = Regex::new(r"^(.+)(BTC|USD.?)$").unwrap();
|
||||||
|
static ref FMT_HH_MM: OwnedFormatItem = format_description!("[hour]:[minute]").into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_slash(pair: &str) -> String {
|
fn add_slash(pair: &str) -> String {
|
||||||
@@ -75,3 +77,27 @@ where
|
|||||||
|
|
||||||
deserializer.deserialize_seq(VecStringVisitor)
|
deserializer.deserialize_seq(VecStringVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn human_time_hh_mm<'de, D>(deserializer: D) -> Result<Time, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct TimeVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for TimeVisitor {
|
||||||
|
type Value = time::Time;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a string in the format HH:MM")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, time: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Time::parse(time, &FMT_HH_MM).map_err(|e| de::Error::custom(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(TimeVisitor)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user