smartapi-typescript
Version:
TypeScript library for Angel One SmartAPI broker API
677 lines • 29.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MarketData = void 0;
const apiUrls_1 = require("../../constants/apiUrls");
const types_1 = require("../../types");
const http = __importStar(require("../../utils/http"));
/**
* Miscellaneous market data module for SmartAPI
* Handles data operations like historical candles, LTP, quotes, etc.
*/
class MarketData {
/**
* Initialize market data module
*/
constructor(auth, httpClient, debug = false) {
this.auth = auth;
this.httpClient = httpClient;
this.debug = debug;
}
/**
* Log debug messages if debug mode is enabled
*/
log(message, data) {
if (this.debug) {
console.log(`[SmartAPI:MarketData] ${message}`);
if (data) {
console.log(data);
}
}
}
/**
* Get market quotes using the new Live Market Data API
* Supports three modes: LTP, OHLC, FULL
* Supports up to 50 symbols in a single request
*
* @param request Market quote request with mode and exchangeTokens
* @param options Network configuration options
* @returns Market quote data
*/
getMarketQuote(request, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Validate request
if (!request.mode || !Object.values(types_1.MarketDataMode).includes(request.mode)) {
return {
status: false,
message: 'Invalid mode. Must be one of LTP, OHLC, FULL.'
};
}
if (!request.exchangeTokens || Object.keys(request.exchangeTokens).length === 0) {
return {
status: false,
message: 'exchangeTokens cannot be empty'
};
}
// Check if total symbols across all exchanges exceeds the limit (50)
const totalSymbols = Object.values(request.exchangeTokens)
.reduce((sum, tokens) => sum + tokens.length, 0);
if (totalSymbols > 50) {
return {
status: false,
message: 'Maximum 50 symbols allowed in a single request'
};
}
this.log('Fetching market quote data', request);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.MARKET_QUOTE}`, request, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get market quote failed', error);
const retryOperation = () => this.getMarketQuote(request, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get LTP data using the new Live Market Data API
* Convenience method that uses the getMarketQuote with LTP mode
*
* @param exchangeTokenMap Map of exchange to tokens (e.g., {"NSE": ["3045"], "BSE": ["500112"]})
* @param options Network configuration options
* @returns LTP data
*/
getLTPData(exchangeTokenMap, options) {
return __awaiter(this, void 0, void 0, function* () {
const request = {
mode: types_1.MarketDataMode.LTP,
exchangeTokens: exchangeTokenMap
};
return this.getMarketQuote(request, options);
});
}
/**
* Get OHLC data using the new Live Market Data API
* Convenience method that uses the getMarketQuote with OHLC mode
*
* @param exchangeTokenMap Map of exchange to tokens (e.g., {"NSE": ["3045"], "BSE": ["500112"]})
* @param options Network configuration options
* @returns OHLC data
*/
getOHLCData(exchangeTokenMap, options) {
return __awaiter(this, void 0, void 0, function* () {
const request = {
mode: types_1.MarketDataMode.OHLC,
exchangeTokens: exchangeTokenMap
};
return this.getMarketQuote(request, options);
});
}
/**
* Get full market data using the new Live Market Data API
* Convenience method that uses the getMarketQuote with FULL mode
*
* @param exchangeTokenMap Map of exchange to tokens (e.g., {"NSE": ["3045"], "BSE": ["500112"]})
* @param options Network configuration options
* @returns Full market data including depth
*/
getFullQuote(exchangeTokenMap, options) {
return __awaiter(this, void 0, void 0, function* () {
const request = {
mode: types_1.MarketDataMode.FULL,
exchangeTokens: exchangeTokenMap
};
return this.getMarketQuote(request, options);
});
}
/**
* Get last traded price for a symbol (Legacy method)
* @deprecated Use getLTPData() instead which supports multiple symbols
* @param exchange Exchange name (e.g., NSE, BSE)
* @param symbolToken Symbol token
* @param tradingSymbol Trading symbol
* @param options Network configuration options
* @returns LTP data
*/
getLTP(exchange, symbolToken, tradingSymbol, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
const params = {
exchange,
symboltoken: symbolToken,
tradingsymbol: tradingSymbol
};
this.log('Fetching LTP (Legacy)', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.LTP_DATA}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get LTP failed', error);
const retryOperation = () => this.getLTP(exchange, symbolToken, tradingSymbol, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get last traded price for multiple symbols (Legacy method)
* @deprecated Use getLTPData() instead which has better batching support
* @param instruments Array of instruments (exchange, symboltoken, tradingsymbol)
* @param options Network configuration options
* @returns LTP data for multiple symbols
*/
getMultiLTP(instruments, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
this.log('Fetching multiple LTPs (Legacy)', instruments);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}/rest/secure/angelbroking/market/v1/getMultiLTP`, { instruments }, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get multiple LTPs failed', error);
const retryOperation = () => this.getMultiLTP(instruments, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get comprehensive quote for symbols (Legacy method)
* @deprecated Use getFullQuote() instead which supports multiple symbols
* @param exchange Exchange name (e.g., NSE, BSE)
* @param symbolToken Symbol token
* @param tradingSymbol Trading symbol
* @param options Network configuration options
* @returns Quote data
*/
getQuote(exchange, symbolToken, tradingSymbol, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
const params = {
exchange,
symboltoken: symbolToken,
tradingsymbol: tradingSymbol
};
this.log('Fetching quote (Legacy)', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.QUOTE}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get quote failed', error);
const retryOperation = () => this.getQuote(exchange, symbolToken, tradingSymbol, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get market quotes for multiple symbols (Legacy method)
* @deprecated Use getFullQuote() instead which has better batching support
* @param instruments Array of instruments (exchange, token)
* @param options Network configuration options
* @returns Market quotes for multiple symbols
*/
getMultiQuotes(instruments, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
this.log('Fetching multiple quotes (Legacy)', instruments);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}/rest/secure/angelbroking/market/v1/getMultiQuotes`, { instruments }, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get multiple quotes failed', error);
const retryOperation = () => this.getMultiQuotes(instruments, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get historical candle data
* @param params Historical data parameters
* @param options Network configuration options
* @returns Historical candle data
*/
getHistoricalData(params, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
this.log('Fetching historical data', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.HISTORICAL_CANDLES}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get historical data failed', error);
const retryOperation = () => this.getHistoricalData(params, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get historical candle data with automatic pagination
* Handles large date ranges by splitting into smaller chunks
* @param params Historical data parameters
* @param maxCandlesPerRequest Maximum number of candles per request (default: 2000)
* @param options Network configuration options
* @returns Consolidated historical candle data
*/
getHistoricalDataPaginated(params_1) {
return __awaiter(this, arguments, void 0, function* (params, maxCandlesPerRequest = 2000, options) {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Parse input dates
const fromDate = new Date(params.fromdate);
const toDate = new Date(params.todate);
// Calculate appropriate chunk size based on interval
let chunkSizeMs = 0;
switch (params.interval) {
case types_1.HistoricalInterval.ONE_MINUTE:
chunkSizeMs = maxCandlesPerRequest * 60 * 1000; // 1 minute in ms
break;
case types_1.HistoricalInterval.FIVE_MINUTE:
chunkSizeMs = maxCandlesPerRequest * 5 * 60 * 1000;
break;
case types_1.HistoricalInterval.FIFTEEN_MINUTE:
chunkSizeMs = maxCandlesPerRequest * 15 * 60 * 1000;
break;
case types_1.HistoricalInterval.THIRTY_MINUTE:
chunkSizeMs = maxCandlesPerRequest * 30 * 60 * 1000;
break;
case types_1.HistoricalInterval.ONE_HOUR:
chunkSizeMs = maxCandlesPerRequest * 60 * 60 * 1000;
break;
case types_1.HistoricalInterval.ONE_DAY:
chunkSizeMs = maxCandlesPerRequest * 24 * 60 * 60 * 1000;
break;
default:
chunkSizeMs = 30 * 24 * 60 * 60 * 1000; // 30 days for larger intervals
}
// Create chunks of date ranges
const dateRanges = [];
let currentStart = new Date(fromDate);
while (currentStart < toDate) {
const chunkEnd = new Date(currentStart.getTime() + chunkSizeMs);
const actualEnd = chunkEnd < toDate ? chunkEnd : toDate;
dateRanges.push({
start: new Date(currentStart),
end: new Date(actualEnd)
});
currentStart = new Date(actualEnd.getTime() + 1); // Start next chunk 1ms after end of current
}
// Format date as YYYY-MM-DD HH:mm
const formatDate = (date) => {
return date.toISOString().replace('T', ' ').substring(0, 16);
};
try {
// Fetch data for each chunk
const allResults = [];
for (const range of dateRanges) {
const chunkParams = Object.assign(Object.assign({}, params), { fromdate: formatDate(range.start), todate: formatDate(range.end) });
this.log('Fetching historical data chunk', chunkParams);
const response = yield this.getHistoricalData(chunkParams, options);
if (response.status && response.data) {
allResults.push(...response.data);
}
else {
// Return error if any chunk fails
return response;
}
}
// Return consolidated results
return {
status: true,
message: 'Historical data retrieved successfully',
data: allResults
};
}
catch (error) {
this.log('Paginated historical data request failed', error);
return http.handleApiError(error);
}
});
}
/**
* Get historical Open Interest data for F&O contracts
* Provides historical OI data for live F&O contracts
*
* @param params Historical data parameters (same as for getHistoricalData)
* @param options Network configuration options
* @returns Historical OI data
*/
getHistoricalOIData(params, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Validate input parameters
if (params.exchange !== 'NFO' && params.exchange !== 'BFO') {
return {
status: false,
message: 'OI data is only available for derivatives segments (NFO, BFO)'
};
}
this.log('Fetching historical OI data', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.HISTORICAL_OI}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get historical OI data failed', error);
const retryOperation = () => this.getHistoricalOIData(params, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get historical Open Interest data with automatic pagination
* Handles large date ranges by splitting into smaller chunks
*
* @param params Historical data parameters
* @param maxEntriesPerRequest Maximum number of entries per request based on interval
* @param options Network configuration options
* @returns Consolidated historical OI data
*/
getHistoricalOIDataPaginated(params, maxEntriesPerRequest, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Determine max entries based on interval if not provided
if (maxEntriesPerRequest === undefined) {
switch (params.interval) {
case types_1.HistoricalInterval.ONE_MINUTE:
maxEntriesPerRequest = 30 * 375; // 30 days of market hours
break;
case types_1.HistoricalInterval.THREE_MINUTE:
maxEntriesPerRequest = 60 * 125; // 60 days of market hours
break;
case types_1.HistoricalInterval.FIVE_MINUTE:
maxEntriesPerRequest = 100 * 75; // 100 days of market hours
break;
case types_1.HistoricalInterval.TEN_MINUTE:
maxEntriesPerRequest = 100 * 38; // 100 days of market hours
break;
case types_1.HistoricalInterval.FIFTEEN_MINUTE:
maxEntriesPerRequest = 200 * 25; // 200 days of market hours
break;
case types_1.HistoricalInterval.THIRTY_MINUTE:
maxEntriesPerRequest = 200 * 13; // 200 days of market hours
break;
case types_1.HistoricalInterval.ONE_HOUR:
maxEntriesPerRequest = 400 * 7; // 400 days of market hours
break;
case types_1.HistoricalInterval.ONE_DAY:
maxEntriesPerRequest = 2000; // 2000 days per API doc
break;
default:
maxEntriesPerRequest = 1000; // Default value
}
}
// Parse input dates
const fromDate = new Date(params.fromdate);
const toDate = new Date(params.todate);
// Calculate appropriate chunk size based on interval
let chunkSizeMs = 0;
switch (params.interval) {
case types_1.HistoricalInterval.ONE_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 60 * 1000; // 1 minute in ms
break;
case types_1.HistoricalInterval.THREE_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 3 * 60 * 1000;
break;
case types_1.HistoricalInterval.FIVE_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 5 * 60 * 1000;
break;
case types_1.HistoricalInterval.TEN_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 10 * 60 * 1000;
break;
case types_1.HistoricalInterval.FIFTEEN_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 15 * 60 * 1000;
break;
case types_1.HistoricalInterval.THIRTY_MINUTE:
chunkSizeMs = maxEntriesPerRequest * 30 * 60 * 1000;
break;
case types_1.HistoricalInterval.ONE_HOUR:
chunkSizeMs = maxEntriesPerRequest * 60 * 60 * 1000;
break;
case types_1.HistoricalInterval.ONE_DAY:
chunkSizeMs = maxEntriesPerRequest * 24 * 60 * 60 * 1000;
break;
default:
chunkSizeMs = 30 * 24 * 60 * 60 * 1000; // 30 days for larger intervals
}
// Create chunks of date ranges
const dateRanges = [];
let currentStart = new Date(fromDate);
while (currentStart < toDate) {
const chunkEnd = new Date(currentStart.getTime() + chunkSizeMs);
const actualEnd = chunkEnd < toDate ? chunkEnd : toDate;
dateRanges.push({
start: new Date(currentStart),
end: new Date(actualEnd)
});
currentStart = new Date(actualEnd.getTime() + 1); // Start next chunk 1ms after end of current
}
// Format date as YYYY-MM-DD HH:mm
const formatDate = (date) => {
return date.toISOString().replace('T', ' ').substring(0, 16);
};
try {
// Fetch data for each chunk
const allResults = [];
for (const range of dateRanges) {
const chunkParams = Object.assign(Object.assign({}, params), { fromdate: formatDate(range.start), todate: formatDate(range.end) });
this.log('Fetching historical OI data chunk', chunkParams);
const response = yield this.getHistoricalOIData(chunkParams, options);
if (response.status && response.data) {
allResults.push(...response.data);
}
else {
// Return error if any chunk fails
return response;
}
}
// Return consolidated results
return {
status: true,
message: 'Historical OI data retrieved successfully',
data: allResults
};
}
catch (error) {
this.log('Paginated historical OI data request failed', error);
return http.handleApiError(error);
}
});
}
/**
* Set up webhook configuration for real-time order updates
*
* Note: The actual webhook URL must be registered when creating your API key in the Angel One dashboard.
* This method provides information about webhook behavior and requirements.
*
* @returns Object with webhook information and requirements
*/
getWebhookInfo() {
// This only provides information about webhook settings
// The webhook URL must be configured in the Angel One dashboard
return {
status: true,
message: "Webhook information retrieved",
data: {
url: null,
}
};
}
/**
* Parse webhook data received from Angel One postback
* This is meant to be used in your webhook endpoint implementation
*
* @param data Raw webhook payload as received from Angel One
* @returns Parsed PostbackData object
*/
static parseWebhookData(data) {
try {
if (typeof data === 'string') {
return JSON.parse(data);
}
return data;
}
catch (error) {
throw new Error('Invalid webhook data format');
}
}
/**
* Get Option Greeks (Delta, Gamma, Theta, Vega) and Implied Volatility
* for specified underlying and expiry date
*
* @param params Parameters containing the underlying name and expiry date
* @param options Network configuration options
* @returns Option greeks data for multiple strike prices
*/
getOptionGreeks(params, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Validate request parameters
if (!params.name || !params.expirydate) {
return {
status: false,
message: 'Both name (underlying) and expirydate are required'
};
}
this.log('Fetching option greeks data', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.OPTION_GREEKS}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get option greeks failed', error);
const retryOperation = () => this.getOptionGreeks(params, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
/**
* Get Top Gainers/Losers in derivatives segment
* Provides data about top gainers and losers in derivatives segment based on price change or open interest.
*
* @param params Parameters containing datatype and expirytype
* @param options Network configuration options
* @returns Top gainers or losers data based on the specified parameters
*/
getGainersLosers(params, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.auth.isAuthenticated()) {
return {
status: false,
message: 'Not authenticated. Please login first.'
};
}
// Validate datatype parameter
if (!params.datatype || !Object.values(types_1.GainersLosersDataType).includes(params.datatype)) {
return {
status: false,
message: 'Invalid datatype. Must be one of PercPriceGainers, PercPriceLosers, PercOIGainers, or PercOILosers.'
};
}
// Validate expirytype parameter
if (!params.expirytype || !Object.values(types_1.ExpiryType).includes(params.expirytype)) {
return {
status: false,
message: 'Invalid expirytype. Must be one of NEAR, NEXT, or FAR.'
};
}
this.log('Fetching gainers/losers data', params);
try {
return yield http.post(`${apiUrls_1.API_URLS.BASE_URL}${apiUrls_1.API_URLS.GAINERS_LOSERS}`, params, this.auth.getHeaders(options));
}
catch (error) {
this.log('Get gainers/losers data failed', error);
const retryOperation = () => this.getGainersLosers(params, options);
return this.auth.handleApiError(error, retryOperation);
}
});
}
}
exports.MarketData = MarketData;
//# sourceMappingURL=index.js.map