use chrono::prelude::*;
use serde::{Deserialize, Serialize};
use crate::api::{GenericResponse, Requests};
use crate::client::TradingClient;
use crate::{api::Response, error::Error};
#[derive(Serialize, Deserialize, Debug)]
pub struct OrderPlacing {
pub isin: String,
pub expires_at: Option<String>,
pub side: OrderType,
pub quantity: i64,
pub venue: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum OrderType {
Buy,
Sell,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OrderPlacingResponse<T> {
pub time: String,
pub status: String,
pub mode: String,
pub results: Option<T>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OrderResults {
pub created_at: DateTime<Utc>,
pub id: String,
pub status: String,
pub regulatory_information: Option<RegulatoryInformation>,
pub isin: Option<String>,
pub expires_at: Option<String>,
pub side: Option<OrderType>,
pub quantity: Option<i64>,
pub stop_price: Option<String>,
pub limit_price: Option<String>,
pub venue: Option<String>,
pub estimated_price: Option<i64>,
pub notes: Option<String>,
pub idempotency: Option<String>,
pub charge: Option<i64>,
pub chargeable_at: Option<String>,
pub key_creation_id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RegulatoryInformation {
pub costs_entry: Option<i64>,
pub costs_entry_pct: Option<String>,
pub costs_running: Option<i64>,
pub costs_running_pct: Option<String>,
pub costs_product: Option<i64>,
pub costs_product_pct: Option<String>,
pub costs_exit: Option<i64>,
pub costs_exit_pct: Option<String>,
pub yield_reduction_year: Option<i64>,
pub yield_reduction_year_pct: Option<String>,
pub yield_reduction_year_following: Option<i64>,
pub yield_reduction_year_following_pct: Option<String>,
pub yield_reduction_year_exit: Option<i64>,
pub yield_reduction_year_exit_pct: Option<String>,
pub estimated_holding_duration_years: Option<String>,
pub estimated_yield_reduction_total: Option<i64>,
pub estimated_yield_reduction_total_pct: Option<String>,
#[serde(rename = "KIID")]
pub kiid: Option<String>,
pub legal_disclaimer: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ActivateOrder {
pub id: String,
pub pin: i64,
}
impl TradingClient {
pub fn get_order(&self, id: Option<String>) -> Result<GenericResponse<OrderResults>, Error> {
let url = format!("{}/orders/{}", self.base_url, id.unwrap_or_default());
let response = self.client.get(&url).send()?;
let body = response.text()?;
let order = serde_json::from_str(&body)?;
Ok(order)
}
pub fn post_order(&self, _body: OrderPlacing) -> Result<GenericResponse<OrderResults>, Error> {
const PATH: &str = "orders/";
let resp = self.post::<GenericResponse<OrderResults>, _>(PATH, _body);
match resp {
Ok(r) => Ok(r),
Err(e) => Err(e),
}
}
pub fn activate_order(&self, pin: i64, order_id: &str) -> Result<Response, Error> {
let url = format!("orders/{order_id}/activate");
let resp = self.post::<Response, ActivateOrder>(
url.as_str(),
ActivateOrder {
id: order_id.to_string(),
pin,
},
);
match resp {
Ok(r) => Ok(r),
Err(e) => Err(e),
}
}
pub fn delete_order(&self, order_id: &str) -> Result<Response, Error> {
const PATH: &str = "orders/{order_id}/";
let resp = self.delete::<Response>(PATH, order_id);
match resp {
Ok(r) => Ok(r),
Err(e) => Err(e),
}
}
}
#[cfg(test)]
mod test {
use chrono::prelude::*;
use std::env;
use crate::*;
#[test]
fn test_placing_and_activating_an_order() {
dotenv::dotenv().unwrap();
let local: DateTime<Local> = Local::now();
let api_key = env::var("LEMON_MARKET_TRADING_API_KEY").unwrap();
let client = client::TradingClient::paper_client(&api_key);
let body = super::OrderPlacing {
isin: "US0378331005".to_string(),
expires_at: Some(local.format("%Y-%m-%d").to_string()),
side: super::OrderType::Buy,
quantity: 1,
venue: Some("XMUN".to_string()),
};
let resp = client.post_order(body).unwrap();
assert_eq!(resp.status, "ok");
let resp = client
.activate_order(1234, resp.results.unwrap().id.as_str())
.unwrap();
assert_eq!(resp.status, "ok");
}
}