1use super::triggers::{GTTCondition, GTTCreateParams, GTTOrderParams, GTTTriggerType};
2use crate::models::common::{Exchange, OrderType, Product, TransactionType};
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone)]
8pub struct GTTOrderBuilder {
9 exchange: Option<Exchange>,
10 trading_symbol: Option<String>,
11 transaction_type: Option<TransactionType>,
12 order_type: Option<OrderType>,
13 product: Option<Product>,
14 quantity: Option<u32>,
15 price: Option<f64>,
16}
17
18#[derive(Debug, Clone)]
20pub struct GTTBuilder {
21 gtt_type: Option<GTTTriggerType>,
22 condition: Option<GTTCondition>,
23 orders: Vec<GTTOrderParams>,
24 expires_at: Option<DateTime<Utc>>,
25}
26
27#[derive(Debug, Clone)]
29pub struct GTTConditionBuilder {
30 exchange: Option<Exchange>,
31 trading_symbol: Option<String>,
32 trigger_values: Vec<f64>,
33 last_price: Option<f64>,
34}
35
36#[derive(Debug, Clone)]
38pub struct StopLossGTTBuilder {
39 exchange: Option<Exchange>,
40 trading_symbol: Option<String>,
41 transaction_type: Option<TransactionType>,
42 product: Option<Product>,
43 quantity: Option<u32>,
44 trigger_price: Option<f64>,
45 limit_price: Option<f64>,
46 current_price: Option<f64>,
47}
48
49#[derive(Debug, Clone)]
51pub struct TargetGTTBuilder {
52 exchange: Option<Exchange>,
53 trading_symbol: Option<String>,
54 transaction_type: Option<TransactionType>,
55 product: Option<Product>,
56 quantity: Option<u32>,
57 target_price: Option<f64>,
58 current_price: Option<f64>,
59}
60
61#[derive(Debug, Clone)]
63pub struct BracketGTTBuilder {
64 exchange: Option<Exchange>,
65 trading_symbol: Option<String>,
66 transaction_type: Option<TransactionType>,
67 product: Option<Product>,
68 quantity: Option<u32>,
69 stop_loss_price: Option<f64>,
70 target_price: Option<f64>,
71 current_price: Option<f64>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct GTTTemplate {
77 pub name: String,
79
80 pub description: String,
82
83 pub gtt_type: GTTTriggerType,
85
86 pub template: GTTCreateParams,
88}
89
90impl GTTOrderBuilder {
91 pub fn new() -> Self {
93 Self {
94 exchange: None,
95 trading_symbol: None,
96 transaction_type: None,
97 order_type: None,
98 product: None,
99 quantity: None,
100 price: None,
101 }
102 }
103
104 pub fn exchange(mut self, exchange: Exchange) -> Self {
106 self.exchange = Some(exchange);
107 self
108 }
109
110 pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
112 self.trading_symbol = Some(symbol.into());
113 self
114 }
115
116 pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
118 self.transaction_type = Some(transaction_type);
119 self
120 }
121
122 pub fn order_type(mut self, order_type: OrderType) -> Self {
124 self.order_type = Some(order_type);
125 self
126 }
127
128 pub fn product(mut self, product: Product) -> Self {
130 self.product = Some(product);
131 self
132 }
133
134 pub fn quantity(mut self, quantity: u32) -> Self {
136 self.quantity = Some(quantity);
137 self
138 }
139
140 pub fn price(mut self, price: f64) -> Self {
142 self.price = Some(price);
143 self
144 }
145
146 pub fn build(self) -> Result<GTTOrderParams, String> {
148 Ok(GTTOrderParams {
149 exchange: self.exchange.ok_or("Exchange is required")?,
150 trading_symbol: self.trading_symbol.ok_or("Trading symbol is required")?,
151 transaction_type: self
152 .transaction_type
153 .ok_or("Transaction type is required")?,
154 order_type: self.order_type.ok_or("Order type is required")?,
155 product: self.product.ok_or("Product is required")?,
156 quantity: self.quantity.ok_or("Quantity is required")?,
157 price: self.price.unwrap_or(0.0),
158 result: None,
159 })
160 }
161}
162
163impl GTTConditionBuilder {
164 pub fn new() -> Self {
166 Self {
167 exchange: None,
168 trading_symbol: None,
169 trigger_values: Vec::new(),
170 last_price: None,
171 }
172 }
173
174 pub fn exchange(mut self, exchange: Exchange) -> Self {
176 self.exchange = Some(exchange);
177 self
178 }
179
180 pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
182 self.trading_symbol = Some(symbol.into());
183 self
184 }
185
186 pub fn trigger_value(mut self, value: f64) -> Self {
188 self.trigger_values.push(value);
189 self
190 }
191
192 pub fn trigger_values(mut self, values: Vec<f64>) -> Self {
194 self.trigger_values = values;
195 self
196 }
197
198 pub fn last_price(mut self, price: f64) -> Self {
200 self.last_price = Some(price);
201 self
202 }
203
204 pub fn build(self) -> Result<GTTCondition, String> {
206 if self.trigger_values.is_empty() {
207 return Err("At least one trigger value is required".to_string());
208 }
209
210 Ok(GTTCondition {
211 exchange: self.exchange.ok_or("Exchange is required")?,
212 trading_symbol: self.trading_symbol.ok_or("Trading symbol is required")?,
213 trigger_values: self.trigger_values,
214 last_price: self.last_price.ok_or("Last price is required")?,
215 })
216 }
217}
218
219impl GTTBuilder {
220 pub fn new() -> Self {
222 Self {
223 gtt_type: None,
224 condition: None,
225 orders: Vec::new(),
226 expires_at: None,
227 }
228 }
229
230 pub fn gtt_type(mut self, gtt_type: GTTTriggerType) -> Self {
232 self.gtt_type = Some(gtt_type);
233 self
234 }
235
236 pub fn condition(mut self, condition: GTTCondition) -> Self {
238 self.condition = Some(condition);
239 self
240 }
241
242 pub fn add_order(mut self, order: GTTOrderParams) -> Self {
244 self.orders.push(order);
245 self
246 }
247
248 pub fn orders(mut self, orders: Vec<GTTOrderParams>) -> Self {
250 self.orders = orders;
251 self
252 }
253
254 pub fn expires_at(mut self, expires_at: DateTime<Utc>) -> Self {
256 self.expires_at = Some(expires_at);
257 self
258 }
259
260 pub fn build(self) -> Result<GTTCreateParams, String> {
262 if self.orders.is_empty() {
263 return Err("At least one order is required".to_string());
264 }
265
266 let params = GTTCreateParams {
267 gtt_type: self.gtt_type.ok_or("GTT type is required")?,
268 condition: self.condition.ok_or("Condition is required")?,
269 orders: self.orders,
270 expires_at: self.expires_at,
271 };
272
273 params.validate()?;
274 Ok(params)
275 }
276}
277
278impl StopLossGTTBuilder {
279 pub fn new() -> Self {
281 Self {
282 exchange: None,
283 trading_symbol: None,
284 transaction_type: None,
285 product: None,
286 quantity: None,
287 trigger_price: None,
288 limit_price: None,
289 current_price: None,
290 }
291 }
292
293 pub fn exchange(mut self, exchange: Exchange) -> Self {
295 self.exchange = Some(exchange);
296 self
297 }
298
299 pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
301 self.trading_symbol = Some(symbol.into());
302 self
303 }
304
305 pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
307 self.transaction_type = Some(transaction_type);
308 self
309 }
310
311 pub fn product(mut self, product: Product) -> Self {
313 self.product = Some(product);
314 self
315 }
316
317 pub fn quantity(mut self, quantity: u32) -> Self {
319 self.quantity = Some(quantity);
320 self
321 }
322
323 pub fn trigger_price(mut self, price: f64) -> Self {
325 self.trigger_price = Some(price);
326 self
327 }
328
329 pub fn limit_price(mut self, price: f64) -> Self {
331 self.limit_price = Some(price);
332 self
333 }
334
335 pub fn current_price(mut self, price: f64) -> Self {
337 self.current_price = Some(price);
338 self
339 }
340
341 pub fn build_market(self) -> Result<GTTCreateParams, String> {
343 let condition = GTTConditionBuilder::new()
344 .exchange(self.exchange.ok_or("Exchange is required")?)
345 .trading_symbol(
346 self.trading_symbol
347 .clone()
348 .ok_or("Trading symbol is required")?,
349 )
350 .trigger_value(self.trigger_price.ok_or("Trigger price is required")?)
351 .last_price(self.current_price.ok_or("Current price is required")?)
352 .build()?;
353
354 let order = GTTOrderBuilder::new()
355 .exchange(self.exchange.ok_or("Exchange is required")?)
356 .trading_symbol(self.trading_symbol.ok_or("Trading symbol is required")?)
357 .transaction_type(
358 self.transaction_type
359 .ok_or("Transaction type is required")?,
360 )
361 .order_type(OrderType::MARKET)
362 .product(self.product.ok_or("Product is required")?)
363 .quantity(self.quantity.ok_or("Quantity is required")?)
364 .build()?;
365
366 GTTBuilder::new()
367 .gtt_type(GTTTriggerType::Single)
368 .condition(condition)
369 .add_order(order)
370 .build()
371 }
372
373 pub fn build_limit(self) -> Result<GTTCreateParams, String> {
375 let condition = GTTConditionBuilder::new()
376 .exchange(self.exchange.ok_or("Exchange is required")?)
377 .trading_symbol(
378 self.trading_symbol
379 .clone()
380 .ok_or("Trading symbol is required")?,
381 )
382 .trigger_value(self.trigger_price.ok_or("Trigger price is required")?)
383 .last_price(self.current_price.ok_or("Current price is required")?)
384 .build()?;
385
386 let order = GTTOrderBuilder::new()
387 .exchange(self.exchange.ok_or("Exchange is required")?)
388 .trading_symbol(self.trading_symbol.ok_or("Trading symbol is required")?)
389 .transaction_type(
390 self.transaction_type
391 .ok_or("Transaction type is required")?,
392 )
393 .order_type(OrderType::LIMIT)
394 .product(self.product.ok_or("Product is required")?)
395 .quantity(self.quantity.ok_or("Quantity is required")?)
396 .price(self.limit_price.ok_or("Limit price is required")?)
397 .build()?;
398
399 GTTBuilder::new()
400 .gtt_type(GTTTriggerType::Single)
401 .condition(condition)
402 .add_order(order)
403 .build()
404 }
405}
406
407impl TargetGTTBuilder {
408 pub fn new() -> Self {
410 Self {
411 exchange: None,
412 trading_symbol: None,
413 transaction_type: None,
414 product: None,
415 quantity: None,
416 target_price: None,
417 current_price: None,
418 }
419 }
420
421 pub fn exchange(mut self, exchange: Exchange) -> Self {
423 self.exchange = Some(exchange);
424 self
425 }
426
427 pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
429 self.trading_symbol = Some(symbol.into());
430 self
431 }
432
433 pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
435 self.transaction_type = Some(transaction_type);
436 self
437 }
438
439 pub fn product(mut self, product: Product) -> Self {
441 self.product = Some(product);
442 self
443 }
444
445 pub fn quantity(mut self, quantity: u32) -> Self {
447 self.quantity = Some(quantity);
448 self
449 }
450
451 pub fn target_price(mut self, price: f64) -> Self {
453 self.target_price = Some(price);
454 self
455 }
456
457 pub fn current_price(mut self, price: f64) -> Self {
459 self.current_price = Some(price);
460 self
461 }
462
463 pub fn build(self) -> Result<GTTCreateParams, String> {
465 let condition = GTTConditionBuilder::new()
466 .exchange(self.exchange.ok_or("Exchange is required")?)
467 .trading_symbol(
468 self.trading_symbol
469 .clone()
470 .ok_or("Trading symbol is required")?,
471 )
472 .trigger_value(self.target_price.ok_or("Target price is required")?)
473 .last_price(self.current_price.ok_or("Current price is required")?)
474 .build()?;
475
476 let order = GTTOrderBuilder::new()
477 .exchange(self.exchange.ok_or("Exchange is required")?)
478 .trading_symbol(self.trading_symbol.ok_or("Trading symbol is required")?)
479 .transaction_type(
480 self.transaction_type
481 .ok_or("Transaction type is required")?,
482 )
483 .order_type(OrderType::LIMIT)
484 .product(self.product.ok_or("Product is required")?)
485 .quantity(self.quantity.ok_or("Quantity is required")?)
486 .price(self.target_price.ok_or("Target price is required")?)
487 .build()?;
488
489 GTTBuilder::new()
490 .gtt_type(GTTTriggerType::Single)
491 .condition(condition)
492 .add_order(order)
493 .build()
494 }
495}
496
497impl BracketGTTBuilder {
498 pub fn new() -> Self {
500 Self {
501 exchange: None,
502 trading_symbol: None,
503 transaction_type: None,
504 product: None,
505 quantity: None,
506 stop_loss_price: None,
507 target_price: None,
508 current_price: None,
509 }
510 }
511
512 pub fn exchange(mut self, exchange: Exchange) -> Self {
514 self.exchange = Some(exchange);
515 self
516 }
517
518 pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
520 self.trading_symbol = Some(symbol.into());
521 self
522 }
523
524 pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
526 self.transaction_type = Some(transaction_type);
527 self
528 }
529
530 pub fn product(mut self, product: Product) -> Self {
532 self.product = Some(product);
533 self
534 }
535
536 pub fn quantity(mut self, quantity: u32) -> Self {
538 self.quantity = Some(quantity);
539 self
540 }
541
542 pub fn stop_loss_price(mut self, price: f64) -> Self {
544 self.stop_loss_price = Some(price);
545 self
546 }
547
548 pub fn target_price(mut self, price: f64) -> Self {
550 self.target_price = Some(price);
551 self
552 }
553
554 pub fn current_price(mut self, price: f64) -> Self {
556 self.current_price = Some(price);
557 self
558 }
559
560 pub fn build(self) -> Result<GTTCreateParams, String> {
562 let stop_loss_price = self.stop_loss_price.ok_or("Stop-loss price is required")?;
563 let target_price = self.target_price.ok_or("Target price is required")?;
564
565 let condition = GTTConditionBuilder::new()
566 .exchange(self.exchange.ok_or("Exchange is required")?)
567 .trading_symbol(
568 self.trading_symbol
569 .clone()
570 .ok_or("Trading symbol is required")?,
571 )
572 .trigger_values(vec![stop_loss_price, target_price])
573 .last_price(self.current_price.ok_or("Current price is required")?)
574 .build()?;
575
576 let stop_loss_order = GTTOrderBuilder::new()
578 .exchange(self.exchange.ok_or("Exchange is required")?)
579 .trading_symbol(
580 self.trading_symbol
581 .clone()
582 .ok_or("Trading symbol is required")?,
583 )
584 .transaction_type(
585 self.transaction_type
586 .ok_or("Transaction type is required")?,
587 )
588 .order_type(OrderType::MARKET)
589 .product(self.product.ok_or("Product is required")?)
590 .quantity(self.quantity.ok_or("Quantity is required")?)
591 .build()?;
592
593 let target_order = GTTOrderBuilder::new()
595 .exchange(self.exchange.ok_or("Exchange is required")?)
596 .trading_symbol(self.trading_symbol.ok_or("Trading symbol is required")?)
597 .transaction_type(
598 self.transaction_type
599 .ok_or("Transaction type is required")?,
600 )
601 .order_type(OrderType::LIMIT)
602 .product(self.product.ok_or("Product is required")?)
603 .quantity(self.quantity.ok_or("Quantity is required")?)
604 .price(target_price)
605 .build()?;
606
607 GTTBuilder::new()
608 .gtt_type(GTTTriggerType::TwoLeg)
609 .condition(condition)
610 .orders(vec![stop_loss_order, target_order])
611 .build()
612 }
613}
614
615impl Default for GTTOrderBuilder {
616 fn default() -> Self {
617 Self::new()
618 }
619}
620
621impl Default for GTTConditionBuilder {
622 fn default() -> Self {
623 Self::new()
624 }
625}
626
627impl Default for GTTBuilder {
628 fn default() -> Self {
629 Self::new()
630 }
631}
632
633impl Default for StopLossGTTBuilder {
634 fn default() -> Self {
635 Self::new()
636 }
637}
638
639impl Default for TargetGTTBuilder {
640 fn default() -> Self {
641 Self::new()
642 }
643}
644
645impl Default for BracketGTTBuilder {
646 fn default() -> Self {
647 Self::new()
648 }
649}
650
651impl GTTTemplate {
653 pub fn stop_loss_template() -> Self {
655 let condition = GTTCondition {
656 exchange: Exchange::NSE,
657 trading_symbol: "TEMPLATE".to_string(),
658 trigger_values: vec![0.0],
659 last_price: 0.0,
660 };
661
662 let order = GTTOrderParams {
663 exchange: Exchange::NSE,
664 trading_symbol: "TEMPLATE".to_string(),
665 transaction_type: TransactionType::SELL,
666 order_type: OrderType::MARKET,
667 product: Product::CNC,
668 quantity: 0,
669 price: 0.0,
670 result: None,
671 };
672
673 Self {
674 name: "Stop Loss".to_string(),
675 description: "Basic stop-loss GTT template".to_string(),
676 gtt_type: GTTTriggerType::Single,
677 template: GTTCreateParams {
678 gtt_type: GTTTriggerType::Single,
679 condition,
680 orders: vec![order],
681 expires_at: None,
682 },
683 }
684 }
685
686 pub fn target_template() -> Self {
688 let condition = GTTCondition {
689 exchange: Exchange::NSE,
690 trading_symbol: "TEMPLATE".to_string(),
691 trigger_values: vec![0.0],
692 last_price: 0.0,
693 };
694
695 let order = GTTOrderParams {
696 exchange: Exchange::NSE,
697 trading_symbol: "TEMPLATE".to_string(),
698 transaction_type: TransactionType::SELL,
699 order_type: OrderType::LIMIT,
700 product: Product::CNC,
701 quantity: 0,
702 price: 0.0,
703 result: None,
704 };
705
706 Self {
707 name: "Target".to_string(),
708 description: "Basic target GTT template".to_string(),
709 gtt_type: GTTTriggerType::Single,
710 template: GTTCreateParams {
711 gtt_type: GTTTriggerType::Single,
712 condition,
713 orders: vec![order],
714 expires_at: None,
715 },
716 }
717 }
718
719 pub fn bracket_template() -> Self {
721 let condition = GTTCondition {
722 exchange: Exchange::NSE,
723 trading_symbol: "TEMPLATE".to_string(),
724 trigger_values: vec![0.0, 0.0],
725 last_price: 0.0,
726 };
727
728 let stop_loss_order = GTTOrderParams {
729 exchange: Exchange::NSE,
730 trading_symbol: "TEMPLATE".to_string(),
731 transaction_type: TransactionType::SELL,
732 order_type: OrderType::MARKET,
733 product: Product::CNC,
734 quantity: 0,
735 price: 0.0,
736 result: None,
737 };
738
739 let target_order = GTTOrderParams {
740 exchange: Exchange::NSE,
741 trading_symbol: "TEMPLATE".to_string(),
742 transaction_type: TransactionType::SELL,
743 order_type: OrderType::LIMIT,
744 product: Product::CNC,
745 quantity: 0,
746 price: 0.0,
747 result: None,
748 };
749
750 Self {
751 name: "Bracket Order".to_string(),
752 description: "OCO bracket order with stop-loss and target".to_string(),
753 gtt_type: GTTTriggerType::TwoLeg,
754 template: GTTCreateParams {
755 gtt_type: GTTTriggerType::TwoLeg,
756 condition,
757 orders: vec![stop_loss_order, target_order],
758 expires_at: None,
759 },
760 }
761 }
762}
763
764#[cfg(test)]
765mod tests {
766 use super::*;
767 use crate::models::common::*;
768
769 #[test]
770 fn test_gtt_order_builder() {
771 let order = GTTOrderBuilder::new()
772 .exchange(Exchange::NSE)
773 .trading_symbol("RELIANCE")
774 .transaction_type(TransactionType::SELL)
775 .order_type(OrderType::MARKET)
776 .product(Product::CNC)
777 .quantity(10)
778 .build()
779 .unwrap();
780
781 assert_eq!(order.exchange, Exchange::NSE);
782 assert_eq!(order.trading_symbol, "RELIANCE");
783 assert_eq!(order.transaction_type, TransactionType::SELL);
784 assert_eq!(order.quantity, 10);
785 }
786
787 #[test]
788 fn test_stop_loss_gtt_builder() {
789 let gtt = StopLossGTTBuilder::new()
790 .exchange(Exchange::NSE)
791 .trading_symbol("RELIANCE")
792 .transaction_type(TransactionType::SELL)
793 .product(Product::CNC)
794 .quantity(10)
795 .trigger_price(2000.0)
796 .current_price(2100.0)
797 .build_market()
798 .unwrap();
799
800 assert_eq!(gtt.gtt_type, GTTTriggerType::Single);
801 assert_eq!(gtt.condition.trigger_values, vec![2000.0]);
802 assert_eq!(gtt.orders.len(), 1);
803 assert_eq!(gtt.orders[0].order_type, OrderType::MARKET);
804 }
805
806 #[test]
807 fn test_bracket_gtt_builder() {
808 let gtt = BracketGTTBuilder::new()
809 .exchange(Exchange::NSE)
810 .trading_symbol("RELIANCE")
811 .transaction_type(TransactionType::SELL)
812 .product(Product::CNC)
813 .quantity(10)
814 .stop_loss_price(2000.0)
815 .target_price(2200.0)
816 .current_price(2100.0)
817 .build()
818 .unwrap();
819
820 assert_eq!(gtt.gtt_type, GTTTriggerType::TwoLeg);
821 assert_eq!(gtt.condition.trigger_values, vec![2000.0, 2200.0]);
822 assert_eq!(gtt.orders.len(), 2);
823 }
824
825 #[test]
826 fn test_gtt_templates() {
827 let template = GTTTemplate::stop_loss_template();
828 assert_eq!(template.name, "Stop Loss");
829 assert_eq!(template.gtt_type, GTTTriggerType::Single);
830
831 let template = GTTTemplate::bracket_template();
832 assert_eq!(template.name, "Bracket Order");
833 assert_eq!(template.gtt_type, GTTTriggerType::TwoLeg);
834 }
835}