kiteconnect_async_wasm/connect/gtt.rs
1//! # GTT (Good Till Triggered) Module
2//!
3//! This module provides comprehensive GTT (Good Till Triggered) order management functionality
4//! for the KiteConnect API. GTT orders are advanced conditional orders that remain active until
5//! triggered by specific market conditions or manually cancelled.
6//!
7//! ## Overview
8//!
9//! GTT orders allow you to:
10//! - Set stop-loss orders that trigger when price moves against your position
11//! - Set target orders that trigger when price reaches your profit target
12//! - Create bracket orders (OCO - One Cancels Other) with both stop-loss and target
13//! - Monitor and manage conditional orders without constant market watching
14//!
15//! ## GTT Types
16//!
17//! ### Single Trigger GTT
18//! A single trigger GTT executes one order when a specific price level is reached.
19//!
20//! ### Two-Leg GTT (OCO - One Cancels Other)
21//! A two-leg GTT contains two orders where execution of one automatically cancels the other.
22//! This is commonly used for bracket orders with both stop-loss and target prices.
23//!
24//! ## Basic Usage
25//!
26//! ### Creating a Simple Stop-Loss GTT
27//!
28//! ```rust,no_run
29//! use kiteconnect_async_wasm::connect::KiteConnect;
30//! use serde_json::json;
31//!
32//! # #[tokio::main]
33//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
34//! let client = KiteConnect::new("api_key", "access_token");
35//!
36//! // Place a stop-loss GTT - sell 10 shares of RELIANCE when price drops to ₹2000
37//! let stop_loss_gtt = client.place_gtt(
38//! "single", // Single trigger type
39//! "RELIANCE", // Trading symbol
40//! "NSE", // Exchange
41//! &[2000.0], // Trigger price
42//! 2100.0, // Current market price
43//! &[json!({
44//! "transaction_type": "SELL",
45//! "quantity": 10,
46//! "order_type": "MARKET",
47//! "product": "CNC"
48//! })]
49//! ).await?;
50//!
51//! println!("Stop-loss GTT placed: {:?}", stop_loss_gtt);
52//! # Ok(())
53//! # }
54//! ```
55//!
56//! ### Creating a Target GTT
57//!
58//! ```rust,no_run
59//! use kiteconnect_async_wasm::connect::KiteConnect;
60//! use serde_json::json;
61//!
62//! # #[tokio::main]
63//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
64//! let client = KiteConnect::new("api_key", "access_token");
65//!
66//! // Place a target GTT - sell 10 shares of RELIANCE when price reaches ₹2200
67//! let target_gtt = client.place_gtt(
68//! "single", // Single trigger type
69//! "RELIANCE", // Trading symbol
70//! "NSE", // Exchange
71//! &[2200.0], // Target price
72//! 2100.0, // Current market price
73//! &[json!({
74//! "transaction_type": "SELL",
75//! "quantity": 10,
76//! "order_type": "LIMIT",
77//! "product": "CNC",
78//! "price": 2200.0
79//! })]
80//! ).await?;
81//!
82//! println!("Target GTT placed: {:?}", target_gtt);
83//! # Ok(())
84//! # }
85//! ```
86//!
87//! ### Creating a Bracket GTT (OCO - One Cancels Other)
88//!
89//! ```rust,no_run
90//! use kiteconnect_async_wasm::connect::KiteConnect;
91//! use serde_json::json;
92//!
93//! # #[tokio::main]
94//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
95//! let client = KiteConnect::new("api_key", "access_token");
96//!
97//! // Place a bracket GTT with both stop-loss and target
98//! let bracket_gtt = client.place_gtt(
99//! "two-leg", // Two-leg trigger type (OCO)
100//! "RELIANCE", // Trading symbol
101//! "NSE", // Exchange
102//! &[2000.0, 2200.0], // Stop-loss and target prices
103//! 2100.0, // Current market price
104//! &[
105//! // Stop-loss order (market order)
106//! json!({
107//! "transaction_type": "SELL",
108//! "quantity": 10,
109//! "order_type": "MARKET",
110//! "product": "CNC"
111//! }),
112//! // Target order (limit order)
113//! json!({
114//! "transaction_type": "SELL",
115//! "quantity": 10,
116//! "order_type": "LIMIT",
117//! "product": "CNC",
118//! "price": 2200.0
119//! })
120//! ]
121//! ).await?;
122//!
123//! println!("Bracket GTT placed: {:?}", bracket_gtt);
124//! # Ok(())
125//! # }
126//! ```
127//!
128//! ## Advanced Usage with Builder Patterns
129//!
130//! For more complex GTT orders, you can use the builder patterns provided in the models:
131//!
132//! ```rust,no_run
133//! use kiteconnect_async_wasm::models::gtt::{StopLossGTTBuilder, BracketGTTBuilder};
134//! use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, Product};
135//!
136//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
137//! // Create a stop-loss GTT using the builder pattern
138//! let stop_loss_gtt = StopLossGTTBuilder::new()
139//! .exchange(Exchange::NSE)
140//! .trading_symbol("RELIANCE")
141//! .transaction_type(TransactionType::SELL)
142//! .product(Product::CNC)
143//! .quantity(10)
144//! .trigger_price(2000.0)
145//! .current_price(2100.0)
146//! .build_market()?; // Creates market order on trigger
147//!
148//! // Create a bracket GTT using the builder pattern
149//! let bracket_gtt = BracketGTTBuilder::new()
150//! .exchange(Exchange::NSE)
151//! .trading_symbol("RELIANCE")
152//! .transaction_type(TransactionType::SELL)
153//! .product(Product::CNC)
154//! .quantity(10)
155//! .stop_loss_price(2000.0)
156//! .target_price(2200.0)
157//! .current_price(2100.0)
158//! .build()?;
159//!
160//! println!("GTT parameters ready for placement");
161//! # Ok(())
162//! # }
163//! ```
164//!
165//! ## GTT Management Operations
166//!
167//! ### Retrieving GTT Orders
168//!
169//! ```rust,no_run
170//! use kiteconnect_async_wasm::connect::KiteConnect;
171//!
172//! # #[tokio::main]
173//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
174//! let client = KiteConnect::new("api_key", "access_token");
175//!
176//! // Get all GTT orders
177//! let all_gtts = client.get_gtts(None).await?;
178//! println!("All GTT orders: {:?}", all_gtts);
179//!
180//! // Get specific GTT order details
181//! let gtt_details = client.get_gtts(Some("123456")).await?;
182//! println!("GTT 123456 details: {:?}", gtt_details);
183//! # Ok(())
184//! # }
185//! ```
186//!
187//! ### Modifying GTT Orders
188//!
189//! ```rust,no_run
190//! use kiteconnect_async_wasm::connect::KiteConnect;
191//! use serde_json::json;
192//!
193//! # #[tokio::main]
194//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
195//! let client = KiteConnect::new("api_key", "access_token");
196//!
197//! // Modify an existing GTT order
198//! let modified_gtt = client.modify_gtt(
199//! "123456", // GTT ID to modify
200//! "single", // Trigger type
201//! "RELIANCE", // Trading symbol
202//! "NSE", // Exchange
203//! &[1950.0], // New trigger price (lowered from 2000)
204//! 2100.0, // Current market price
205//! &[json!({
206//! "transaction_type": "SELL",
207//! "quantity": 15, // Increased quantity
208//! "order_type": "MARKET",
209//! "product": "CNC"
210//! })]
211//! ).await?;
212//!
213//! println!("GTT modified: {:?}", modified_gtt);
214//! # Ok(())
215//! # }
216//! ```
217//!
218//! ### Cancelling GTT Orders
219//!
220//! ```rust,no_run
221//! use kiteconnect_async_wasm::connect::KiteConnect;
222//!
223//! # #[tokio::main]
224//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
225//! let client = KiteConnect::new("api_key", "access_token");
226//!
227//! // Cancel a GTT order
228//! let cancellation_result = client.delete_gtt("123456").await?;
229//! println!("GTT cancelled: {:?}", cancellation_result);
230//! # Ok(())
231//! # }
232//! ```
233//!
234//! ## Best Practices
235//!
236//! ### 1. Risk Management
237//!
238//! - **Always set stop-losses**: Use GTT orders to automatically limit losses
239//! - **Position sizing**: Never risk more than 1-2% of your capital per trade
240//! - **Multiple GTTs**: Use bracket orders to capture profits and limit losses simultaneously
241//!
242//! ### 2. Price Setting Guidelines
243//!
244//! - **Stop-loss placement**: Set 3-5% below entry price for swing trades
245//! - **Target placement**: Use risk-reward ratio of at least 1:2 (target = 2x stop-loss distance)
246//! - **Market conditions**: Adjust trigger levels based on volatility and support/resistance levels
247//!
248//! ### 3. Order Types
249//!
250//! - **Market orders**: Use for stop-losses when quick execution is priority
251//! - **Limit orders**: Use for targets to ensure specific price execution
252//! - **Slippage consideration**: Account for potential slippage in volatile markets
253//!
254//! ### 4. Monitoring and Maintenance
255//!
256//! ```rust,no_run
257//! use kiteconnect_async_wasm::connect::KiteConnect;
258//! use std::time::Duration;
259//!
260//! # #[tokio::main]
261//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
262//! let client = KiteConnect::new("api_key", "access_token");
263//!
264//! // Regular GTT monitoring loop
265//! loop {
266//! let gtts = client.get_gtts(None).await?;
267//!
268//! // Process GTT status and take action if needed
269//! // - Check for triggered GTTs
270//! // - Update stop-losses based on favorable price movement
271//! // - Cancel outdated GTTs
272//!
273//! println!("GTT status check completed");
274//!
275//! // Wait before next check (respect rate limits)
276//! tokio::time::sleep(Duration::from_secs(300)).await; // Check every 5 minutes
277//! }
278//! # }
279//! ```
280//!
281//! ## Error Handling
282//!
283//! GTT operations can fail for various reasons. Always implement proper error handling:
284//!
285//! ```rust,no_run
286//! use kiteconnect_async_wasm::connect::KiteConnect;
287//! use serde_json::json;
288//!
289//! # #[tokio::main]
290//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
291//! let client = KiteConnect::new("api_key", "access_token");
292//!
293//! match client.place_gtt(
294//! "single",
295//! "RELIANCE",
296//! "NSE",
297//! &[2000.0],
298//! 2100.0,
299//! &[json!({
300//! "transaction_type": "SELL",
301//! "quantity": 10,
302//! "order_type": "MARKET",
303//! "product": "CNC"
304//! })]
305//! ).await {
306//! Ok(response) => {
307//! println!("✅ GTT placed successfully: {:?}", response);
308//! },
309//! Err(e) => {
310//! eprintln!("❌ GTT placement failed: {}", e);
311//! // Handle specific error cases:
312//! // - Invalid price levels
313//! // - Insufficient margin
314//! // - Invalid instrument
315//! // - Rate limiting
316//! }
317//! }
318//! # Ok(())
319//! # }
320//! ```
321//!
322//! ## Platform Compatibility
323//!
324//! This GTT module works seamlessly across platforms:
325//! - **Native (Desktop/Server)**: Full functionality with optimal performance
326//! - **WASM (Browser)**: Complete GTT management in web applications
327//! - **Cross-platform**: Identical API surface and behavior
328//!
329//! ## Rate Limiting
330//!
331//! GTT operations are subject to API rate limits:
332//! - **Standard category**: 10 requests per second
333//! - **Automatic handling**: Built-in rate limiting with retry logic
334//! - **Best practice**: Batch multiple operations when possible
335//!
336//! For high-frequency GTT management, consider implementing local caching and
337//! batching strategies to minimize API calls.
338
339use crate::connect::endpoints::KiteEndpoint;
340use crate::connect::KiteConnect;
341use anyhow::Result;
342use serde_json::Value as JsonValue;
343use std::collections::HashMap;
344
345impl KiteConnect {
346 /// Get all GTT orders or details of a specific GTT
347 ///
348 /// Retrieves all Good Till Triggered (GTT) orders or details of a specific GTT order.
349 /// GTT orders are conditional orders that get executed when certain trigger conditions are met.
350 ///
351 /// # Arguments
352 ///
353 /// * `gtt_id` - Optional GTT ID. If None, returns all GTT orders
354 ///
355 /// # Returns
356 ///
357 /// A `Result<JsonValue>` containing GTT orders data
358 ///
359 /// # Errors
360 ///
361 /// Returns an error if the API request fails or the user is not authenticated.
362 ///
363 /// # Example
364 ///
365 /// ```rust,no_run
366 /// use kiteconnect_async_wasm::connect::KiteConnect;
367 ///
368 /// # #[tokio::main]
369 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
370 /// let client = KiteConnect::new("api_key", "access_token");
371 ///
372 /// // Get all GTT orders
373 /// let all_gtts = client.get_gtts(None).await?;
374 /// println!("All GTTs: {:?}", all_gtts);
375 ///
376 /// // Get specific GTT
377 /// let gtt_details = client.get_gtts(Some("123456")).await?;
378 /// println!("GTT details: {:?}", gtt_details);
379 /// # Ok(())
380 /// # }
381 /// ```
382 pub async fn get_gtts(&self, gtt_id: Option<&str>) -> Result<JsonValue> {
383 let resp = if let Some(id) = gtt_id {
384 self.send_request_with_rate_limiting_and_retry(KiteEndpoint::GTTInfo, &[id], None, None)
385 .await
386 .map_err(|e| anyhow::anyhow!("Failed to get GTT info: {}", e))?
387 } else {
388 self.send_request_with_rate_limiting_and_retry(KiteEndpoint::GTTs, &[], None, None)
389 .await
390 .map_err(|e| anyhow::anyhow!("Failed to get GTTs: {}", e))?
391 };
392
393 self.raise_or_return_json(resp).await
394 }
395
396 /// Place a GTT order
397 ///
398 /// Creates a new Good Till Triggered order that will be executed when
399 /// the specified trigger conditions are met.
400 ///
401 /// # Arguments
402 ///
403 /// * `trigger_type` - Type of trigger ("single" or "two-leg")
404 /// * `tradingsymbol` - Trading symbol of the instrument
405 /// * `exchange` - Exchange where the instrument is traded
406 /// * `trigger_values` - Trigger price values
407 /// * `last_price` - Current market price of the instrument
408 /// * `orders` - List of orders to be placed when triggered
409 ///
410 /// # Returns
411 ///
412 /// A `Result<JsonValue>` containing GTT order creation response
413 ///
414 /// # Errors
415 ///
416 /// Returns an error if the GTT placement fails or parameters are invalid
417 ///
418 /// # Example
419 ///
420 /// ```rust,no_run
421 /// use kiteconnect_async_wasm::connect::KiteConnect;
422 ///
423 /// # #[tokio::main]
424 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
425 /// let client = KiteConnect::new("api_key", "access_token");
426 ///
427 /// let gtt = client.place_gtt(
428 /// "single",
429 /// "RELIANCE",
430 /// "NSE",
431 /// &[2500.0], // Trigger when price hits 2500
432 /// 2450.0, // Current price
433 /// &[serde_json::json!({
434 /// "transaction_type": "SELL",
435 /// "quantity": 10,
436 /// "order_type": "LIMIT",
437 /// "product": "CNC",
438 /// "price": 2500.0
439 /// })]
440 /// ).await?;
441 ///
442 /// println!("GTT placed: {:?}", gtt);
443 /// # Ok(())
444 /// # }
445 /// ```
446 pub async fn place_gtt(
447 &self,
448 trigger_type: &str,
449 tradingsymbol: &str,
450 exchange: &str,
451 trigger_values: &[f64],
452 last_price: f64,
453 orders: &[JsonValue],
454 ) -> Result<JsonValue> {
455 let mut params = HashMap::new();
456 params.insert("type", trigger_type);
457 params.insert("tradingsymbol", tradingsymbol);
458 params.insert("exchange", exchange);
459
460 // Convert trigger values to comma-separated string
461 let trigger_values_str = trigger_values
462 .iter()
463 .map(|v| v.to_string())
464 .collect::<Vec<_>>()
465 .join(",");
466 params.insert("trigger_values", &trigger_values_str);
467
468 let last_price_str = last_price.to_string();
469 params.insert("last_price", &last_price_str);
470
471 // Convert orders to JSON string
472 let orders_json = serde_json::to_string(orders)?;
473 params.insert("orders", &orders_json);
474
475 let resp = self
476 .send_request_with_rate_limiting_and_retry(
477 KiteEndpoint::PlaceGTT,
478 &[],
479 None,
480 Some(params),
481 )
482 .await
483 .map_err(|e| anyhow::anyhow!("Failed to place GTT: {}", e))?;
484
485 self.raise_or_return_json(resp).await
486 }
487
488 /// Modify a GTT order
489 ///
490 /// Updates an existing GTT order with new trigger conditions or orders.
491 ///
492 /// # Arguments
493 ///
494 /// * `gtt_id` - GTT order ID to modify
495 /// * `trigger_type` - Type of trigger ("single" or "two-leg")
496 /// * `tradingsymbol` - Trading symbol of the instrument
497 /// * `exchange` - Exchange where the instrument is traded
498 /// * `trigger_values` - New trigger price values
499 /// * `last_price` - Current market price of the instrument
500 /// * `orders` - Updated list of orders to be placed when triggered
501 ///
502 /// # Returns
503 ///
504 /// A `Result<JsonValue>` containing GTT order modification response
505 ///
506 /// # Example
507 ///
508 /// ```rust,no_run
509 /// use kiteconnect_async_wasm::connect::KiteConnect;
510 ///
511 /// # #[tokio::main]
512 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
513 /// let client = KiteConnect::new("api_key", "access_token");
514 ///
515 /// let result = client.modify_gtt(
516 /// "123456", // GTT ID
517 /// "single",
518 /// "RELIANCE",
519 /// "NSE",
520 /// &[2600.0], // New trigger price
521 /// 2450.0, // Current price
522 /// &[serde_json::json!({
523 /// "transaction_type": "SELL",
524 /// "quantity": 20, // Updated quantity
525 /// "order_type": "LIMIT",
526 /// "product": "CNC",
527 /// "price": 2600.0
528 /// })]
529 /// ).await?;
530 ///
531 /// println!("GTT modified: {:?}", result);
532 /// # Ok(())
533 /// # }
534 /// ```
535 #[allow(clippy::too_many_arguments)]
536 pub async fn modify_gtt(
537 &self,
538 gtt_id: &str,
539 trigger_type: &str,
540 tradingsymbol: &str,
541 exchange: &str,
542 trigger_values: &[f64],
543 last_price: f64,
544 orders: &[JsonValue],
545 ) -> Result<JsonValue> {
546 let mut params = HashMap::new();
547 params.insert("type", trigger_type);
548 params.insert("tradingsymbol", tradingsymbol);
549 params.insert("exchange", exchange);
550
551 // Convert trigger values to comma-separated string
552 let trigger_values_str = trigger_values
553 .iter()
554 .map(|v| v.to_string())
555 .collect::<Vec<_>>()
556 .join(",");
557 params.insert("trigger_values", &trigger_values_str);
558
559 let last_price_str = last_price.to_string();
560 params.insert("last_price", &last_price_str);
561
562 // Convert orders to JSON string
563 let orders_json = serde_json::to_string(orders)?;
564 params.insert("orders", &orders_json);
565
566 let resp = self
567 .send_request_with_rate_limiting_and_retry(
568 KiteEndpoint::ModifyGTT,
569 &[gtt_id],
570 None,
571 Some(params),
572 )
573 .await
574 .map_err(|e| anyhow::anyhow!("Failed to modify GTT: {}", e))?;
575
576 self.raise_or_return_json(resp).await
577 }
578
579 /// Delete a GTT order
580 ///
581 /// Cancels an existing GTT order. Once deleted, the GTT will no longer
582 /// monitor for trigger conditions.
583 ///
584 /// # Arguments
585 ///
586 /// * `gtt_id` - GTT order ID to delete
587 ///
588 /// # Returns
589 ///
590 /// A `Result<JsonValue>` containing deletion confirmation
591 ///
592 /// # Example
593 ///
594 /// ```rust,no_run
595 /// use kiteconnect_async_wasm::connect::KiteConnect;
596 ///
597 /// # #[tokio::main]
598 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
599 /// let client = KiteConnect::new("api_key", "access_token");
600 ///
601 /// let result = client.delete_gtt("123456").await?;
602 /// println!("GTT deleted: {:?}", result);
603 /// # Ok(())
604 /// # }
605 /// ```
606 pub async fn delete_gtt(&self, gtt_id: &str) -> Result<JsonValue> {
607 let resp = self
608 .send_request_with_rate_limiting_and_retry(
609 KiteEndpoint::CancelGTT,
610 &[gtt_id],
611 None,
612 None,
613 )
614 .await
615 .map_err(|e| anyhow::anyhow!("Failed to delete GTT: {}", e))?;
616
617 self.raise_or_return_json(resp).await
618 }
619}