use serde::Serialize;
use crate::{OrderType, ProductType, Side, Validity};
#[cfg(doc)]
use crate::Fyers;
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OrderRequest {
symbol: String,
qty: u32,
r#type: OrderType,
side: Side,
product_type: ProductType,
limit_price: f64,
stop_price: f64,
disclosed_qty: u32,
validity: Validity,
offline_order: bool,
stop_loss: f64,
take_profit: f64,
order_tag: Option<String>,
is_slice_order: bool,
}
#[must_use = "builders must be finalized with .build()"]
#[derive(Debug)]
pub struct OrderBuilder {
symbol: String,
qty: u32,
r#type: OrderType,
side: Side,
product_type: ProductType,
limit_price: f64,
stop_price: f64,
disclosed_qty: u32,
validity: Validity,
offline_order: bool,
stop_loss: f64,
take_profit: f64,
order_tag: Option<String>,
is_slice_order: bool,
}
impl OrderBuilder {
pub fn new(
symbol: impl Into<String>,
qty: u32,
order_type: OrderType,
side: Side,
product_type: ProductType,
validity: Validity,
) -> Self {
Self {
symbol: symbol.into(),
qty,
r#type: order_type,
side,
product_type,
validity,
limit_price: 0.0,
stop_price: 0.0,
disclosed_qty: 0,
offline_order: false,
stop_loss: 0.0,
take_profit: 0.0,
order_tag: None,
is_slice_order: false,
}
}
pub fn limit_price(mut self, price: f64) -> Self {
self.limit_price = price;
self
}
pub fn stop_price(mut self, price: f64) -> Self {
self.stop_price = price;
self
}
pub fn disclosed_qty(mut self, qty: u32) -> Self {
self.disclosed_qty = qty;
self
}
pub fn offline_order(mut self, value: bool) -> Self {
self.offline_order = value;
self
}
pub fn stop_loss(mut self, price: f64) -> Self {
self.stop_loss = price;
self
}
pub fn take_profit(mut self, price: f64) -> Self {
self.take_profit = price;
self
}
pub fn order_tag(mut self, tag: impl Into<String>) -> Self {
self.order_tag = Some(tag.into());
self
}
pub fn slice_order(mut self, value: bool) -> Self {
self.is_slice_order = value;
self
}
pub fn build(self) -> OrderRequest {
OrderRequest {
symbol: self.symbol,
qty: self.qty,
r#type: self.r#type,
side: self.side,
product_type: self.product_type,
limit_price: self.limit_price,
stop_price: self.stop_price,
disclosed_qty: self.disclosed_qty,
validity: self.validity,
offline_order: self.offline_order,
stop_loss: self.stop_loss,
take_profit: self.take_profit,
order_tag: self.order_tag,
is_slice_order: self.is_slice_order,
}
}
}
impl OrderRequest {
pub fn builder(
symbol: impl Into<String>,
qty: u32,
order_type: OrderType,
side: Side,
product_type: ProductType,
validity: Validity,
) -> OrderBuilder {
OrderBuilder::new(symbol, qty, order_type, side, product_type, validity)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn order_serializes_correctly() {
let order = OrderRequest::builder(
"NSE:IDEA-EQ",
1,
OrderType::Market,
Side::Buy,
ProductType::Intraday,
Validity::Day,
)
.order_tag("tag1")
.build();
let json = serde_json::to_value(&order).unwrap();
let expected = serde_json::json!({
"symbol":"NSE:IDEA-EQ",
"qty":1,
"type":2,
"side":1,
"productType":"INTRADAY",
"limitPrice":0.0,
"stopPrice":0.0,
"stopLoss": 0.0,
"takeProfit": 0.0,
"validity":"DAY",
"disclosedQty":0,
"offlineOrder":false,
"orderTag":"tag1",
"isSliceOrder":false,
});
assert_eq!(json, expected);
}
}