From 8edc71e6a743dc0adb488c9849b804e071c1f9a3 Mon Sep 17 00:00:00 2001 From: KETAN GUPTA Date: Wed, 11 Mar 2026 15:19:01 +0530 Subject: [PATCH 1/4] Bump version to 2.22.0 and add market protection support in order APIs --- package.json | 2 +- src/ApiClient.js | 2 +- src/api/OrderApi.js | 2 + src/api/OrderControllerV3Api.js | 8 +- src/model/GttRule.js | 10 ++ src/model/MultiOrderRequest.js | 10 ++ test/sdk/MarketProtection.js | 170 ++++++++++++++++++++++++++++++++ 7 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 test/sdk/MarketProtection.js diff --git a/package.json b/package.json index 846efb6..83179c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "upstox-js-sdk", - "version": "2.21.0", + "version": "2.22.0", "description": "The official Node Js client for communicating with the Upstox API", "license": "MIT", "main": "dist/index.js", diff --git a/src/ApiClient.js b/src/ApiClient.js index 2f4d54d..ceb1752 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -68,7 +68,7 @@ export class ApiClient { */ this.defaultHeaders = { 'X-Upstox-SDK-Language': 'nodejs', - 'X-Upstox-SDK-Version': '2.21.0' + 'X-Upstox-SDK-Version': '2.22.0' }; /** diff --git a/src/api/OrderApi.js b/src/api/OrderApi.js index bbddb49..c9c0481 100644 --- a/src/api/OrderApi.js +++ b/src/api/OrderApi.js @@ -522,6 +522,8 @@ export class OrderApi { obj.disclosed_quantity = ApiClient.convertToType(data['disclosedQuantity'], 'Number'); if (data.hasOwnProperty('triggerPrice')) obj.trigger_price = ApiClient.convertToType(data['triggerPrice'], 'Number'); + if (data.hasOwnProperty('marketProtection')) + obj.market_protection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } diff --git a/src/api/OrderControllerV3Api.js b/src/api/OrderControllerV3Api.js index 3ec126c..cb8a576 100644 --- a/src/api/OrderControllerV3Api.js +++ b/src/api/OrderControllerV3Api.js @@ -65,6 +65,8 @@ export class OrderApiV3 { rule.trigger_price = ApiClient.convertToType(userRule['triggerPrice'], 'Number'); if(userRule.hasOwnProperty('trailingGap')) rule.trailing_gap = ApiClient.convertToType(userRule['trailingGap'], 'Number'); + if(userRule.hasOwnProperty('marketProtection')) + rule.market_protection = ApiClient.convertToType(userRule['marketProtection'], 'Number'); obj.rules.push(rule); }); } @@ -301,6 +303,8 @@ export class OrderApiV3 { obj.disclosed_quantity = ApiClient.convertToType(data['disclosedQuantity'], 'Number'); if (data.hasOwnProperty('triggerPrice')) obj.trigger_price = ApiClient.convertToType(data['triggerPrice'], 'Number'); + if (data.hasOwnProperty('marketProtection')) + obj.market_protection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } @@ -382,7 +386,9 @@ export class OrderApiV3 { if (data.hasOwnProperty('isAmo')) obj.is_amo = ApiClient.convertToType(data['isAmo'], 'Boolean'); if (data.hasOwnProperty('slice')) - obj.is_amo = ApiClient.convertToType(data['slice'], 'Boolean'); + obj.slice = ApiClient.convertToType(data['slice'], 'Boolean'); + if (data.hasOwnProperty('marketProtection')) + obj.market_protection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } diff --git a/src/model/GttRule.js b/src/model/GttRule.js index 2b8fd19..750eec2 100644 --- a/src/model/GttRule.js +++ b/src/model/GttRule.js @@ -53,6 +53,10 @@ export class GttRule { obj.triggerPrice = ApiClient.convertToType(data['trigger_price'], 'Number'); if (data.hasOwnProperty('trailing_gap')) obj.trailingGap = ApiClient.convertToType(data['trailing_gap'], 'Number'); + if (data.hasOwnProperty('market_protection')) + obj.marketProtection = ApiClient.convertToType(data['market_protection'], 'Number'); + if (data.hasOwnProperty('marketProtection')) + obj.marketProtection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } @@ -130,3 +134,9 @@ GttRule.prototype.triggerPrice = undefined; */ GttRule.prototype.trailingGap = undefined; +/** + * Optional market price protection for the GTT order rule + * @member {Number} marketProtection + */ +GttRule.prototype.marketProtection = undefined; + diff --git a/src/model/MultiOrderRequest.js b/src/model/MultiOrderRequest.js index d15a60d..7c91137 100644 --- a/src/model/MultiOrderRequest.js +++ b/src/model/MultiOrderRequest.js @@ -88,6 +88,10 @@ export class MultiOrderRequest { obj.is_amo = ApiClient.convertToType(data['is_amo'], 'Boolean'); if (data.hasOwnProperty('correlation_id')) obj.correlation_id = ApiClient.convertToType(data['correlation_id'], 'String'); + if (data.hasOwnProperty('market_protection')) + obj.market_protection = ApiClient.convertToType(data['market_protection'], 'Number'); + if (data.hasOwnProperty('marketProtection')) + obj.market_protection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } @@ -254,3 +258,9 @@ MultiOrderRequest.prototype.is_amo = undefined; */ MultiOrderRequest.prototype.correlation_id = undefined; +/** + * Market price protection (optional). Numeric value. + * @member {Number} market_protection + */ +MultiOrderRequest.prototype.market_protection = undefined; + diff --git a/test/sdk/MarketProtection.js b/test/sdk/MarketProtection.js new file mode 100644 index 0000000..91c37b7 --- /dev/null +++ b/test/sdk/MarketProtection.js @@ -0,0 +1,170 @@ +/** + * Script-style tests for market_protection support on order APIs. + * Run with: node test/sdk/MarketProtection.js + * Requires a valid access token in test/sdk/DataToken.js. + */ +let UpstoxClient = require('upstox-js-sdk'); +const { accessToken } = require('./DataToken'); +let defaultClient = UpstoxClient.ApiClient.instance; +let OAUTH2 = defaultClient.authentications['OAUTH2']; +OAUTH2.accessToken = accessToken; + +let X_Algo_Name = 'MarketProtectionTest'; + +// --------------------------------------------------------------------------- +// 1. V3 placeOrder with marketProtection +// --------------------------------------------------------------------------- +function testV3PlaceOrderWithMarketProtection() { + let apiInstance = new UpstoxClient.OrderApiV3(); + let body = new UpstoxClient.PlaceOrderV3Request( + 1, + UpstoxClient.PlaceOrderV3Request.ProductEnum.D, + UpstoxClient.PlaceOrderV3Request.ValidityEnum.DAY, + 0, + 'NSE_EQ|INE669E01016', + UpstoxClient.PlaceOrderV3Request.OrderTypeEnum.MARKET, + UpstoxClient.PlaceOrderV3Request.TransactionTypeEnum.BUY, + 0, + 0, + false + ); + body.slice = false; + body.marketProtection = 0; + + apiInstance.placeOrder(body, {}, (error, data, response) => { + if (error) { + console.log('V3 placeOrder with marketProtection: error (may be expected if market closed) –', error.response?.text || error.message); + } else { + console.log('V3 placeOrder with marketProtection: success –', JSON.stringify(data)); + } + }, X_Algo_Name); +} + +// --------------------------------------------------------------------------- +// 2. V3 modifyOrder with marketProtection +// --------------------------------------------------------------------------- +function testV3ModifyOrderWithMarketProtection() { + let apiInstance = new UpstoxClient.OrderApiV3(); + let body = new UpstoxClient.ModifyOrderRequest( + UpstoxClient.ModifyOrderRequest.ValidityEnum.DAY, + 0, + 'REPLACE_WITH_VALID_ORDER_ID', + UpstoxClient.ModifyOrderRequest.OrderTypeEnum.MARKET, + 0 + ); + body.quantity = 1; + body.marketProtection = 0; + + apiInstance.modifyOrder(body, (error, data, response) => { + if (error) { + console.log('V3 modifyOrder with marketProtection: error (expected if order_id invalid) –', error.response?.text || error.message); + } else { + console.log('V3 modifyOrder with marketProtection: success –', JSON.stringify(data)); + } + }, X_Algo_Name); +} + +// --------------------------------------------------------------------------- +// 3. V2 placeMultiOrder with market_protection on orders +// --------------------------------------------------------------------------- +function testV2PlaceMultiOrderWithMarketProtection() { + let apiInstance = new UpstoxClient.OrderApi(); + let order1 = new UpstoxClient.MultiOrderRequest(1, 'D', 'DAY', 8.9, true, 'NSE_EQ|INE669E01016', 'LIMIT', 'BUY', 0, 9, true, 'mp_cid1'); + order1.tag = 'mp_tg1'; + order1.market_protection = 0; + + let order2 = new UpstoxClient.MultiOrderRequest(1, 'D', 'DAY', 8.9, true, 'NSE_EQ|INE669E01016', 'LIMIT', 'BUY', 0, 9.0, true, 'mp_cid2'); + order2.market_protection = 2; + + let body = [order1, order2]; + + apiInstance.placeMultiOrder(body, (error, data, response) => { + if (error) { + console.log('V2 placeMultiOrder with market_protection: error (may be expected if market closed) –', error.response?.text || error.message); + } else { + console.log('V2 placeMultiOrder with market_protection: success –', JSON.stringify(data)); + } + }, X_Algo_Name); +} + +// --------------------------------------------------------------------------- +// 4. V3 placeGTTOrder with marketProtection on rule +// --------------------------------------------------------------------------- +function testV3PlaceGTTOrderWithMarketProtection() { + let apiInstance = new UpstoxClient.OrderApiV3(); + let entryRule = new UpstoxClient.GttRule( + UpstoxClient.GttRule.StrategyEnum.ENTRY, + UpstoxClient.GttRule.TriggerTypeEnum.ABOVE, + 100 + ); + entryRule.marketProtection = 0; + + let body = new UpstoxClient.GttPlaceOrderRequest( + UpstoxClient.GttPlaceOrderRequest.TypeEnum.SINGLE, + 1, + UpstoxClient.GttPlaceOrderRequest.ProductEnum.D, + [entryRule], + 'NSE_EQ|INE669E01016', + UpstoxClient.GttPlaceOrderRequest.TransactionTypeEnum.BUY + ); + + apiInstance.placeGTTOrder(body, (error, data, response) => { + if (error) { + console.log('V3 placeGTTOrder with marketProtection: error (may be expected) –', error.response?.text || error.message); + } else { + console.log('V3 placeGTTOrder with marketProtection: success –', JSON.stringify(data)); + } + }, X_Algo_Name); +} + +// --------------------------------------------------------------------------- +// 5. V3 modifyGTTOrder with marketProtection on rule +// --------------------------------------------------------------------------- +function testV3ModifyGTTOrderWithMarketProtection() { + let apiInstance = new UpstoxClient.OrderApiV3(); + let entryRule = new UpstoxClient.GttRule( + UpstoxClient.GttRule.StrategyEnum.ENTRY, + UpstoxClient.GttRule.TriggerTypeEnum.ABOVE, + 100 + ); + entryRule.marketProtection = 0; + + let body = new UpstoxClient.GttModifyOrderRequest( + UpstoxClient.GttModifyOrderRequest.TypeEnum.SINGLE, + 1, + [entryRule], + 'REPLACE_WITH_VALID_GTT_ORDER_ID' + ); + body.quantity = 1; + + apiInstance.modifyGTTOrder(body, (error, data, response) => { + if (error) { + console.log('V3 modifyGTTOrder with marketProtection: error (expected if gtt_order_id invalid) –', error.response?.text || error.message); + } else { + console.log('V3 modifyGTTOrder with marketProtection: success –', JSON.stringify(data)); + } + }, X_Algo_Name); +} + +// --------------------------------------------------------------------------- +// Run tests (staggered to avoid rate limits; some calls may fail without live orders) +// --------------------------------------------------------------------------- +console.log('Market protection SDK tests (script-style). Some calls may fail without valid orders/tokens.\n'); + +testV3PlaceOrderWithMarketProtection(); + +setTimeout(() => { + testV3ModifyOrderWithMarketProtection(); +}, 500); + +setTimeout(() => { + testV2PlaceMultiOrderWithMarketProtection(); +}, 1000); + +setTimeout(() => { + testV3PlaceGTTOrderWithMarketProtection(); +}, 1500); + +setTimeout(() => { + testV3ModifyGTTOrderWithMarketProtection(); +}, 2000); From 5f41c46cfd512cdb407736ac771333707ee509d1 Mon Sep 17 00:00:00 2001 From: KETAN GUPTA Date: Wed, 11 Mar 2026 16:44:42 +0530 Subject: [PATCH 2/4] Add refreshExtendedToken property to TokenRequest model --- src/model/TokenRequest.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/model/TokenRequest.js b/src/model/TokenRequest.js index 5eab300..e53c7f3 100644 --- a/src/model/TokenRequest.js +++ b/src/model/TokenRequest.js @@ -58,6 +58,8 @@ export class TokenRequest { obj.redirectUri = ApiClient.convertToType(data['redirect_uri'], 'String'); if (data.hasOwnProperty('grant_type')) obj.grantType = ApiClient.convertToType(data['grant_type'], 'String'); + if (data.hasOwnProperty('refresh_extended_token')) + obj.refreshExtendedToken = ApiClient.convertToType(data['refresh_extended_token'], 'Boolean'); } return obj; } @@ -92,3 +94,8 @@ TokenRequest.prototype.redirectUri = undefined; */ TokenRequest.prototype.grantType = undefined; +/** + * @member {Boolean} refreshExtendedToken + */ +TokenRequest.prototype.refreshExtendedToken = undefined; + From 1afe26d092edccc6c522c5bbc38540d490cd23fd Mon Sep 17 00:00:00 2001 From: KETAN GUPTA Date: Wed, 11 Mar 2026 18:46:38 +0530 Subject: [PATCH 3/4] Add refreshExtendedToken parameter to LoginApi for extended token support --- src/api/LoginApi.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/LoginApi.js b/src/api/LoginApi.js index e7f97b7..f291299 100644 --- a/src/api/LoginApi.js +++ b/src/api/LoginApi.js @@ -223,7 +223,8 @@ export class LoginApi { * @param {String} opts.clientId * @param {String} opts.clientSecret * @param {String} opts.redirectUri - * @param {String} opts.grantType + * @param {String} opts.grantType + * @param {Boolean} opts.refreshExtendedToken * @param {module:api/LoginApi~tokenCallback} callback The callback function, accepting three arguments: error, data, response * data is of type: {@link <&vendorExtensions.x-jsdoc-type>} */ @@ -245,7 +246,7 @@ export class LoginApi { 'Api-Version': apiVersion }; let formParams = { - 'code': opts['code'],'client_id': opts['clientId'],'client_secret': opts['clientSecret'],'redirect_uri': opts['redirectUri'],'grant_type': opts['grantType'] + 'code': opts['code'],'client_id': opts['clientId'],'client_secret': opts['clientSecret'],'redirect_uri': opts['redirectUri'],'grant_type': opts['grantType'],'refresh_extended_token': opts['refreshExtendedToken'] }; let authNames = []; From e9c100f64cb6f89e352db76879a677951246de4d Mon Sep 17 00:00:00 2001 From: KETAN GUPTA Date: Wed, 11 Mar 2026 19:32:14 +0530 Subject: [PATCH 4/4] Remove redundant marketProtection property handling in GttRule and MultiOrderRequest models --- src/model/GttRule.js | 2 -- src/model/MultiOrderRequest.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/model/GttRule.js b/src/model/GttRule.js index 750eec2..58a21ab 100644 --- a/src/model/GttRule.js +++ b/src/model/GttRule.js @@ -55,8 +55,6 @@ export class GttRule { obj.trailingGap = ApiClient.convertToType(data['trailing_gap'], 'Number'); if (data.hasOwnProperty('market_protection')) obj.marketProtection = ApiClient.convertToType(data['market_protection'], 'Number'); - if (data.hasOwnProperty('marketProtection')) - obj.marketProtection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; } diff --git a/src/model/MultiOrderRequest.js b/src/model/MultiOrderRequest.js index 7c91137..210db2a 100644 --- a/src/model/MultiOrderRequest.js +++ b/src/model/MultiOrderRequest.js @@ -90,8 +90,6 @@ export class MultiOrderRequest { obj.correlation_id = ApiClient.convertToType(data['correlation_id'], 'String'); if (data.hasOwnProperty('market_protection')) obj.market_protection = ApiClient.convertToType(data['market_protection'], 'Number'); - if (data.hasOwnProperty('marketProtection')) - obj.market_protection = ApiClient.convertToType(data['marketProtection'], 'Number'); } return obj; }