firstock 1.0.1 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +151 -1
- package/dist/Classes/Firstock.js +57 -3
- package/dist/test.js +48 -19
- package/dist/websockets/websocket_functions.js +668 -0
- package/dist/websockets/websockets.js +213 -0
- package/package.json +5 -2
- package/websockets/test_websockets.js +187 -0
- package/config.json +0 -3
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.Firstock = exports.FirstockWebSocket = void 0;
|
|
16
|
+
const ws_1 = __importDefault(require("ws"));
|
|
17
|
+
const websocket_functions_1 = require("./websocket_functions");
|
|
18
|
+
const logger = {
|
|
19
|
+
info: (msg) => console.info(`[INFO] ${new Date().toISOString()} - ${msg}`),
|
|
20
|
+
error: (msg, err) => {
|
|
21
|
+
console.error(`[ERROR] ${new Date().toISOString()} - ${msg}`);
|
|
22
|
+
if (err)
|
|
23
|
+
console.error(err);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
class FirstockWebSocket {
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
this.tokens = options.tokens || [];
|
|
29
|
+
this.option_greeks_tokens = options.option_greeks_tokens || [];
|
|
30
|
+
this.order_data = options.order_data;
|
|
31
|
+
this.position_data = options.position_data;
|
|
32
|
+
this.subscribe_feed_data = options.subscribe_feed_data;
|
|
33
|
+
this.subscribe_option_greeks_data = options.subscribe_option_greeks_data;
|
|
34
|
+
this.on_reconnect = options.on_reconnect;
|
|
35
|
+
}
|
|
36
|
+
toDict() {
|
|
37
|
+
return {
|
|
38
|
+
tokens: this.tokens,
|
|
39
|
+
option_greeks_tokens: this.option_greeks_tokens,
|
|
40
|
+
order_data: this.order_data,
|
|
41
|
+
position_data: this.position_data,
|
|
42
|
+
subscribe_feed_data: this.subscribe_feed_data,
|
|
43
|
+
subscribe_option_greeks_data: this.subscribe_option_greeks_data,
|
|
44
|
+
on_reconnect: this.on_reconnect
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.FirstockWebSocket = FirstockWebSocket;
|
|
49
|
+
class Firstock {
|
|
50
|
+
static initializeWebsockets(userId, model, config) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
const finalConfig = Object.assign({ scheme: 'wss', host: 'socket.firstock.in', path: '/ws', source: 'developer-api', accept_encoding: 'gzip, deflate, br', accept_language: 'en-US,en;q=0.9', origin: 'https://firstock.in', max_websocket_connection_retries: 3, time_interval: 5 }, config);
|
|
53
|
+
const [baseUrl, headers, err] = (0, websocket_functions_1.getUrlAndHeaderData)(userId, finalConfig);
|
|
54
|
+
if (err) {
|
|
55
|
+
return [null, { error: { message: err.message } }];
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const ws = new ws_1.default(baseUrl, { headers });
|
|
59
|
+
yield new Promise((resolve, reject) => {
|
|
60
|
+
const timeout = setTimeout(() => {
|
|
61
|
+
reject(new Error('Connection timeout'));
|
|
62
|
+
}, 10000);
|
|
63
|
+
ws.once('open', () => {
|
|
64
|
+
clearTimeout(timeout);
|
|
65
|
+
resolve();
|
|
66
|
+
});
|
|
67
|
+
ws.once('error', (error) => {
|
|
68
|
+
clearTimeout(timeout);
|
|
69
|
+
reject(error);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
logger.info("WebSocket connection created");
|
|
73
|
+
yield websocket_functions_1.connections.addConnection(ws);
|
|
74
|
+
const msg = yield new Promise((resolve, reject) => {
|
|
75
|
+
const timeout = setTimeout(() => {
|
|
76
|
+
reject(new Error('Authentication timeout'));
|
|
77
|
+
}, 5000);
|
|
78
|
+
ws.once('message', (data) => {
|
|
79
|
+
clearTimeout(timeout);
|
|
80
|
+
resolve(data.toString());
|
|
81
|
+
});
|
|
82
|
+
ws.once('error', (error) => {
|
|
83
|
+
clearTimeout(timeout);
|
|
84
|
+
reject(error);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
logger.info(`Initial message received: ${msg}`);
|
|
88
|
+
if (msg.includes("Authentication successful")) {
|
|
89
|
+
logger.info("Authentication successful, starting message reader");
|
|
90
|
+
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
91
|
+
const modelDict = model.toDict();
|
|
92
|
+
(0, websocket_functions_1.readMessage)(userId, ws, modelDict, finalConfig);
|
|
93
|
+
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
94
|
+
if (model.tokens && model.tokens.length > 0) {
|
|
95
|
+
logger.info(`Subscribing to initial tokens: ${model.tokens.join(', ')}`);
|
|
96
|
+
const subscribeErr = yield (0, websocket_functions_1.subscribe)(ws, model.tokens);
|
|
97
|
+
if (subscribeErr) {
|
|
98
|
+
logger.error(`Initial subscription error: ${JSON.stringify(subscribeErr)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (model.option_greeks_tokens && model.option_greeks_tokens.length > 0) {
|
|
102
|
+
logger.info(`Subscribing to option Greeks tokens: ${model.option_greeks_tokens.join(', ')}`);
|
|
103
|
+
const subscribeErr = yield (0, websocket_functions_1.subscribeOptionGreeks)(ws, model.option_greeks_tokens);
|
|
104
|
+
if (subscribeErr) {
|
|
105
|
+
logger.error(`Initial option Greeks subscription error: ${JSON.stringify(subscribeErr)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return [ws, null];
|
|
109
|
+
}
|
|
110
|
+
else if (msg.includes("Maximum sessions limit")) {
|
|
111
|
+
yield websocket_functions_1.connections.deleteConnection(ws);
|
|
112
|
+
return [null, { error: { message: msg } }];
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
yield websocket_functions_1.connections.deleteConnection(ws);
|
|
116
|
+
return [null, { error: { message: `Unexpected authentication response: ${msg}` } }];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
logger.error(`WebSocket initialization error: ${e.message}`, e);
|
|
121
|
+
return [null, { error: { message: e.message } }];
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
static closeWebsocket(ws) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
if (ws === null) {
|
|
128
|
+
return {
|
|
129
|
+
error: {
|
|
130
|
+
message: "Connection does not exist"
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (yield websocket_functions_1.connections.checkIfConnectionExists(ws)) {
|
|
135
|
+
try {
|
|
136
|
+
ws.close();
|
|
137
|
+
yield websocket_functions_1.connections.deleteConnection(ws);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
const errorMsg = e.message.toLowerCase();
|
|
142
|
+
if (!errorMsg.includes("closed")) {
|
|
143
|
+
return {
|
|
144
|
+
error: {
|
|
145
|
+
message: e.message
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
yield websocket_functions_1.connections.deleteConnection(ws);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
return {
|
|
157
|
+
error: {
|
|
158
|
+
message: "Connection does not exist"
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
static subscribe(ws, tokens) {
|
|
165
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
+
if (ws === null) {
|
|
167
|
+
return {
|
|
168
|
+
error: {
|
|
169
|
+
message: "Connection does not exist"
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return (0, websocket_functions_1.subscribe)(ws, tokens);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
static unsubscribe(ws, tokens) {
|
|
177
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
if (ws === null) {
|
|
179
|
+
return {
|
|
180
|
+
error: {
|
|
181
|
+
message: "Connection does not exist"
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return (0, websocket_functions_1.unsubscribe)(ws, tokens);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
static subscribeOptionGreeks(ws, tokens) {
|
|
189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
if (ws === null) {
|
|
191
|
+
return {
|
|
192
|
+
error: {
|
|
193
|
+
message: "Connection does not exist"
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return (0, websocket_functions_1.subscribeOptionGreeks)(ws, tokens);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
static unsubscribeOptionGreeks(ws, tokens) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
if (ws === null) {
|
|
203
|
+
return {
|
|
204
|
+
error: {
|
|
205
|
+
message: "Connection does not exist"
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return (0, websocket_functions_1.unsubscribeOptionGreeks)(ws, tokens);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.Firstock = Firstock;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firstock",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Node js package for using firstock developer apis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -23,10 +23,13 @@
|
|
|
23
23
|
"homepage": "https://github.com/the-firstock/firstock-developer-sdk-nodejs#readme",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"axios": "^1.10.0",
|
|
26
|
-
"sha256": "^0.2.0"
|
|
26
|
+
"sha256": "^0.2.0",
|
|
27
|
+
"util": "^0.12.5",
|
|
28
|
+
"ws": "^8.18.3"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"@types/sha256": "^0.2.2",
|
|
32
|
+
"@types/ws": "^8.18.1",
|
|
30
33
|
"typescript": "^5.8.3"
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
const { Firstock, FirstockWebSocket } = require('./websockets');
|
|
2
|
+
const { appendFileSync } = require('fs');
|
|
3
|
+
|
|
4
|
+
function subscribeFeedData(data) {
|
|
5
|
+
try {
|
|
6
|
+
appendFileSync('websocket.log', `${JSON.stringify(data)}\n`);
|
|
7
|
+
console.log(data);
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.error(`Error writing to log: ${e}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function subscribeOptionGreeksData(data) {
|
|
14
|
+
try {
|
|
15
|
+
const timestamp = new Date().toISOString();
|
|
16
|
+
appendFileSync('option_greeks.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.error(`Error writing option Greeks: ${e}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function orderBookData(data) {
|
|
23
|
+
try {
|
|
24
|
+
const timestamp = new Date().toISOString();
|
|
25
|
+
appendFileSync('order_detail.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.error(`Error opening log file: ${e}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function positionBookData(data) {
|
|
32
|
+
try {
|
|
33
|
+
const timestamp = new Date().toISOString();
|
|
34
|
+
appendFileSync('position_detail.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.error(`Error opening log file: ${e}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function subscribeFeedData2(data) {
|
|
41
|
+
try {
|
|
42
|
+
const timestamp = new Date().toISOString();
|
|
43
|
+
appendFileSync('websocket2.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.error(`Error opening log file: ${e}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function subscribeFeedData3(data) {
|
|
50
|
+
try {
|
|
51
|
+
const timestamp = new Date().toISOString();
|
|
52
|
+
appendFileSync('websocket3.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.error(`Error opening log file: ${e}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function subscribeFeedData4(data) {
|
|
59
|
+
try {
|
|
60
|
+
const timestamp = new Date().toISOString();
|
|
61
|
+
appendFileSync('websocket4.log', `${timestamp} - ${JSON.stringify(data)}\n`);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error(`Error opening log file: ${e}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function main() {
|
|
68
|
+
const userId = 'NP2997';
|
|
69
|
+
|
|
70
|
+
// Connection reference holder
|
|
71
|
+
const connectionRef = { conn: null };
|
|
72
|
+
|
|
73
|
+
// Reconnection callback
|
|
74
|
+
function onReconnectCallback(newWs) {
|
|
75
|
+
console.log("🔄 Connection reference updated");
|
|
76
|
+
connectionRef.conn = newWs;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Create WebSocket model
|
|
80
|
+
const model = new FirstockWebSocket({
|
|
81
|
+
tokens: [],
|
|
82
|
+
option_greeks_tokens: [],
|
|
83
|
+
order_data: orderBookData,
|
|
84
|
+
position_data: positionBookData,
|
|
85
|
+
subscribe_feed_data: subscribeFeedData,
|
|
86
|
+
subscribe_option_greeks_data: subscribeOptionGreeksData,
|
|
87
|
+
on_reconnect: onReconnectCallback
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Initialize WebSocket
|
|
91
|
+
const [conn, err] = await Firstock.initializeWebsockets(userId, model);
|
|
92
|
+
connectionRef.conn = conn;
|
|
93
|
+
|
|
94
|
+
console.log("Error:", err);
|
|
95
|
+
|
|
96
|
+
if (err) {
|
|
97
|
+
console.log(`Connection failed: ${JSON.stringify(err)}`);
|
|
98
|
+
return;
|
|
99
|
+
} else {
|
|
100
|
+
console.log("WebSocket connected successfully!");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Subscribe to tokens
|
|
104
|
+
const subscribeErr = await Firstock.subscribe(connectionRef.conn, ["BSE:500470|NSE:26000"]);
|
|
105
|
+
console.log("Subscribe Error:", subscribeErr);
|
|
106
|
+
|
|
107
|
+
// Subscribe to option Greeks (uncomment to use)
|
|
108
|
+
// const optionErr = await Firstock.subscribeOptionGreeks(connectionRef.conn, ["NFO:44297"]);
|
|
109
|
+
// console.log("Option Greeks Subscribe Error:", optionErr);
|
|
110
|
+
|
|
111
|
+
// // Later, unsubscribe (uncomment to use)
|
|
112
|
+
// await new Promise(resolve => setTimeout(resolve, 30000));
|
|
113
|
+
// const unsubErr = await Firstock.unsubscribeOptionGreeks(connectionRef.conn, ["NFO:44283"]);
|
|
114
|
+
// console.log("Option Greeks Unsubscribe Error:", unsubErr);
|
|
115
|
+
|
|
116
|
+
// Multiple connections example (uncomment to use)
|
|
117
|
+
|
|
118
|
+
// const model2 = new FirstockWebSocket({
|
|
119
|
+
// tokens: [],
|
|
120
|
+
// subscribe_feed_data: subscribeFeedData2
|
|
121
|
+
// });
|
|
122
|
+
// const [conn2, err2] = await Firstock.initializeWebsockets(userId, model2);
|
|
123
|
+
// console.log("Error:", err2);
|
|
124
|
+
|
|
125
|
+
// const subscribeErr2 = await Firstock.subscribe(conn2, ["BSE:1"]);
|
|
126
|
+
// console.log("Error:", subscribeErr2);
|
|
127
|
+
|
|
128
|
+
// const model3 = new FirstockWebSocket({
|
|
129
|
+
// tokens: [],
|
|
130
|
+
// subscribe_feed_data: subscribeFeedData3
|
|
131
|
+
// });
|
|
132
|
+
// const [conn3, err3] = await Firstock.initializeWebsockets(userId, model3);
|
|
133
|
+
// console.log("Error:", err3);
|
|
134
|
+
|
|
135
|
+
// const subscribeErr3 = await Firstock.subscribe(conn3, ["NSE:26000|BSE:1"]);
|
|
136
|
+
// console.log("Error:", subscribeErr3);
|
|
137
|
+
|
|
138
|
+
// const model4 = new FirstockWebSocket({
|
|
139
|
+
// tokens: [],
|
|
140
|
+
// subscribe_feed_data: subscribeFeedData4
|
|
141
|
+
// });
|
|
142
|
+
// const [conn4, err4] = await Firstock.initializeWebsockets(userId, model4);
|
|
143
|
+
// console.log("Error:", err4);
|
|
144
|
+
|
|
145
|
+
// const subscribeErr4 = await Firstock.subscribe(conn4, ["NSE:26000"]);
|
|
146
|
+
// console.log("Error:", subscribeErr4);
|
|
147
|
+
|
|
148
|
+
// Unsubscribe example
|
|
149
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
150
|
+
const unsubErr = await Firstock.unsubscribe(connectionRef.conn, ["BSE:500470|NSE:26000"]);
|
|
151
|
+
console.log("Unsubscribe Error:", unsubErr);
|
|
152
|
+
|
|
153
|
+
// Wait for 25 seconds
|
|
154
|
+
await new Promise(resolve => setTimeout(resolve, 200000));
|
|
155
|
+
|
|
156
|
+
// Close WebSocket connection
|
|
157
|
+
const closeErr = await Firstock.closeWebsocket(connectionRef.conn);
|
|
158
|
+
console.log("Close Error:", closeErr);
|
|
159
|
+
|
|
160
|
+
// Close additional connections (uncomment if using multiple connections)
|
|
161
|
+
// const closeErr2 = await Firstock.closeWebsocket(conn2);
|
|
162
|
+
// console.log("Close Error:", closeErr2);
|
|
163
|
+
|
|
164
|
+
// const closeErr3 = await Firstock.closeWebsocket(conn3);
|
|
165
|
+
// console.log("Close Error:", closeErr3);
|
|
166
|
+
|
|
167
|
+
// Keep program running
|
|
168
|
+
console.log("\nWebSocket test running. Press Ctrl+C to exit.");
|
|
169
|
+
|
|
170
|
+
// Handle graceful shutdown
|
|
171
|
+
process.on('SIGINT', async () => {
|
|
172
|
+
console.log("\nExiting...");
|
|
173
|
+
if (connectionRef.conn) {
|
|
174
|
+
await Firstock.closeWebsocket(connectionRef.conn);
|
|
175
|
+
}
|
|
176
|
+
process.exit(0);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Keep alive - never resolves, keeps running until SIGINT
|
|
180
|
+
await new Promise(() => {});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Run main function
|
|
184
|
+
main().catch(error => {
|
|
185
|
+
console.error("Fatal error:", error);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
});
|
package/config.json
DELETED