#![allow(missing_docs)]
use serde::{Deserialize, Serialize};
use crate::types::enums::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[allow(non_camel_case_types)]
pub enum MultiOrderExchangeSegment {
NSE_EQ,
NSE_FNO,
NSE_COMM,
BSE_EQ,
BSE_FNO,
MCX_COMM,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[allow(non_camel_case_types)]
pub enum MultiOrderProductType {
CNC,
INTRADAY,
MARGIN,
MTF,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MultiOrderItemRequest {
pub sequence: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub correlation_id: Option<String>,
pub transaction_type: TransactionType,
pub exchange_segment: MultiOrderExchangeSegment,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_type: Option<MultiOrderProductType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_type: Option<OrderType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub validity: Option<Validity>,
#[serde(skip_serializing_if = "Option::is_none")]
pub security_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantity: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after_market_order: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amo_time: Option<AmoTime>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_price: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disclosed_quantity: Option<u32>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MultiOrderRequest {
pub dhan_client_id: String,
pub orders: Vec<MultiOrderItemRequest>,
}
impl MultiOrderRequest {
pub fn validate(&self) -> std::result::Result<(), &'static str> {
if self.dhan_client_id.trim().is_empty() {
return Err("multi order dhan_client_id cannot be empty");
}
if self.orders.is_empty() {
return Err("multi order orders cannot be empty");
}
if self.orders.iter().any(|order| {
order
.correlation_id
.as_ref()
.is_some_and(|value| value.chars().count() > 30)
}) {
return Err("multi order correlation_id cannot exceed 30 characters");
}
if self.orders.iter().any(|order| {
order.quantity.is_some_and(|value| value > i32::MAX as u32)
|| order
.disclosed_quantity
.is_some_and(|value| value > i32::MAX as u32)
}) {
return Err("multi order quantities cannot exceed the documented int32 range");
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MultiOrderItemResponse {
pub order_id: Option<String>,
pub sequence: Option<String>,
pub order_status: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MultiOrderResponse {
#[serde(default)]
pub orders: Vec<MultiOrderItemResponse>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AlertCondition {
pub comparison_type: String,
pub exchange_segment: ExchangeSegment,
pub security_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub indicator_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time_frame: Option<String>,
pub operator: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub comparing_value: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comparing_indicator_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exp_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frequency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_note: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AlertOrder {
pub transaction_type: TransactionType,
pub exchange_segment: ExchangeSegment,
pub product_type: ProductType,
pub order_type: OrderType,
pub security_id: String,
pub quantity: u64,
pub validity: Validity,
pub price: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub disc_quantity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_price: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ConditionalTriggerRequest {
pub dhan_client_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub alert_id: Option<String>,
pub condition: AlertCondition,
pub orders: Vec<AlertOrder>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConditionalTriggerResponse {
pub alert_id: String,
pub alert_status: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConditionalTriggerDetail {
pub alert_id: Option<String>,
pub alert_status: Option<String>,
pub created_time: Option<String>,
pub triggered_time: Option<String>,
#[serde(default)]
pub last_price: Option<serde_json::Value>,
pub condition: Option<AlertCondition>,
#[serde(default)]
pub orders: Vec<AlertOrder>,
}