kiteconnect_async_wasm/models/gtt/
orders.rs

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/// GTT order builder for creating complex GTT orders
7#[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/// GTT builder for creating complete GTT triggers with orders
19#[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/// GTT condition builder
28#[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/// Stop-loss GTT builder
37#[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/// Target GTT builder
50#[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/// Bracket GTT builder (combines stop-loss and target)
62#[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/// GTT template for common patterns
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct GTTTemplate {
77    /// Template name
78    pub name: String,
79
80    /// Template description
81    pub description: String,
82
83    /// GTT type
84    pub gtt_type: GTTTriggerType,
85
86    /// Template parameters
87    pub template: GTTCreateParams,
88}
89
90impl GTTOrderBuilder {
91    /// Create a new GTT order builder
92    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    /// Set exchange
105    pub fn exchange(mut self, exchange: Exchange) -> Self {
106        self.exchange = Some(exchange);
107        self
108    }
109
110    /// Set trading symbol
111    pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
112        self.trading_symbol = Some(symbol.into());
113        self
114    }
115
116    /// Set transaction type
117    pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
118        self.transaction_type = Some(transaction_type);
119        self
120    }
121
122    /// Set order type
123    pub fn order_type(mut self, order_type: OrderType) -> Self {
124        self.order_type = Some(order_type);
125        self
126    }
127
128    /// Set product type
129    pub fn product(mut self, product: Product) -> Self {
130        self.product = Some(product);
131        self
132    }
133
134    /// Set quantity
135    pub fn quantity(mut self, quantity: u32) -> Self {
136        self.quantity = Some(quantity);
137        self
138    }
139
140    /// Set price
141    pub fn price(mut self, price: f64) -> Self {
142        self.price = Some(price);
143        self
144    }
145
146    /// Build the GTT order parameters
147    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    /// Create a new GTT condition builder
165    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    /// Set exchange
175    pub fn exchange(mut self, exchange: Exchange) -> Self {
176        self.exchange = Some(exchange);
177        self
178    }
179
180    /// Set trading symbol
181    pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
182        self.trading_symbol = Some(symbol.into());
183        self
184    }
185
186    /// Add a trigger value
187    pub fn trigger_value(mut self, value: f64) -> Self {
188        self.trigger_values.push(value);
189        self
190    }
191
192    /// Set multiple trigger values
193    pub fn trigger_values(mut self, values: Vec<f64>) -> Self {
194        self.trigger_values = values;
195        self
196    }
197
198    /// Set last price
199    pub fn last_price(mut self, price: f64) -> Self {
200        self.last_price = Some(price);
201        self
202    }
203
204    /// Build the GTT condition
205    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    /// Create a new GTT builder
221    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    /// Set GTT type
231    pub fn gtt_type(mut self, gtt_type: GTTTriggerType) -> Self {
232        self.gtt_type = Some(gtt_type);
233        self
234    }
235
236    /// Set condition
237    pub fn condition(mut self, condition: GTTCondition) -> Self {
238        self.condition = Some(condition);
239        self
240    }
241
242    /// Add an order
243    pub fn add_order(mut self, order: GTTOrderParams) -> Self {
244        self.orders.push(order);
245        self
246    }
247
248    /// Set orders
249    pub fn orders(mut self, orders: Vec<GTTOrderParams>) -> Self {
250        self.orders = orders;
251        self
252    }
253
254    /// Set expiry time
255    pub fn expires_at(mut self, expires_at: DateTime<Utc>) -> Self {
256        self.expires_at = Some(expires_at);
257        self
258    }
259
260    /// Build the GTT create parameters
261    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    /// Create a new stop-loss GTT builder
280    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    /// Set exchange
294    pub fn exchange(mut self, exchange: Exchange) -> Self {
295        self.exchange = Some(exchange);
296        self
297    }
298
299    /// Set trading symbol
300    pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
301        self.trading_symbol = Some(symbol.into());
302        self
303    }
304
305    /// Set transaction type (usually SELL for long positions, BUY for short positions)
306    pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
307        self.transaction_type = Some(transaction_type);
308        self
309    }
310
311    /// Set product type
312    pub fn product(mut self, product: Product) -> Self {
313        self.product = Some(product);
314        self
315    }
316
317    /// Set quantity
318    pub fn quantity(mut self, quantity: u32) -> Self {
319        self.quantity = Some(quantity);
320        self
321    }
322
323    /// Set trigger price (stop-loss level)
324    pub fn trigger_price(mut self, price: f64) -> Self {
325        self.trigger_price = Some(price);
326        self
327    }
328
329    /// Set limit price (for SL-L orders)
330    pub fn limit_price(mut self, price: f64) -> Self {
331        self.limit_price = Some(price);
332        self
333    }
334
335    /// Set current market price
336    pub fn current_price(mut self, price: f64) -> Self {
337        self.current_price = Some(price);
338        self
339    }
340
341    /// Build stop-loss GTT with market order
342    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    /// Build stop-loss GTT with limit order
374    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    /// Create a new target GTT builder
409    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    /// Set exchange
422    pub fn exchange(mut self, exchange: Exchange) -> Self {
423        self.exchange = Some(exchange);
424        self
425    }
426
427    /// Set trading symbol
428    pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
429        self.trading_symbol = Some(symbol.into());
430        self
431    }
432
433    /// Set transaction type (usually SELL for long positions, BUY for short positions)
434    pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
435        self.transaction_type = Some(transaction_type);
436        self
437    }
438
439    /// Set product type
440    pub fn product(mut self, product: Product) -> Self {
441        self.product = Some(product);
442        self
443    }
444
445    /// Set quantity
446    pub fn quantity(mut self, quantity: u32) -> Self {
447        self.quantity = Some(quantity);
448        self
449    }
450
451    /// Set target price
452    pub fn target_price(mut self, price: f64) -> Self {
453        self.target_price = Some(price);
454        self
455    }
456
457    /// Set current market price
458    pub fn current_price(mut self, price: f64) -> Self {
459        self.current_price = Some(price);
460        self
461    }
462
463    /// Build target GTT
464    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    /// Create a new bracket GTT builder
499    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    /// Set exchange
513    pub fn exchange(mut self, exchange: Exchange) -> Self {
514        self.exchange = Some(exchange);
515        self
516    }
517
518    /// Set trading symbol
519    pub fn trading_symbol<S: Into<String>>(mut self, symbol: S) -> Self {
520        self.trading_symbol = Some(symbol.into());
521        self
522    }
523
524    /// Set transaction type (usually SELL for long positions, BUY for short positions)
525    pub fn transaction_type(mut self, transaction_type: TransactionType) -> Self {
526        self.transaction_type = Some(transaction_type);
527        self
528    }
529
530    /// Set product type
531    pub fn product(mut self, product: Product) -> Self {
532        self.product = Some(product);
533        self
534    }
535
536    /// Set quantity
537    pub fn quantity(mut self, quantity: u32) -> Self {
538        self.quantity = Some(quantity);
539        self
540    }
541
542    /// Set stop-loss price
543    pub fn stop_loss_price(mut self, price: f64) -> Self {
544        self.stop_loss_price = Some(price);
545        self
546    }
547
548    /// Set target price
549    pub fn target_price(mut self, price: f64) -> Self {
550        self.target_price = Some(price);
551        self
552    }
553
554    /// Set current market price
555    pub fn current_price(mut self, price: f64) -> Self {
556        self.current_price = Some(price);
557        self
558    }
559
560    /// Build bracket GTT (OCO - One Cancels Other)
561    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        // Stop-loss order (market order)
577        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        // Target order (limit order)
594        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
651// Common GTT patterns and utilities
652impl GTTTemplate {
653    /// Create a stop-loss template
654    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    /// Create a target template
687    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    /// Create a bracket (OCO) template
720    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}