hedgequantx 1.3.0 → 1.3.1

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.
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Rithmic Orders Module
3
+ * Order placement, cancellation, and history
4
+ */
5
+
6
+ const { REQ } = require('./constants');
7
+
8
+ /**
9
+ * Place order via ORDER_PLANT
10
+ * @param {RithmicService} service - The Rithmic service instance
11
+ * @param {Object} orderData - Order parameters
12
+ */
13
+ const placeOrder = async (service, orderData) => {
14
+ if (!service.orderConn || !service.loginInfo) {
15
+ return { success: false, error: 'Not connected' };
16
+ }
17
+
18
+ try {
19
+ service.orderConn.send('RequestNewOrder', {
20
+ templateId: REQ.NEW_ORDER,
21
+ userMsg: ['HQX'],
22
+ fcmId: service.loginInfo.fcmId,
23
+ ibId: service.loginInfo.ibId,
24
+ accountId: orderData.accountId,
25
+ symbol: orderData.symbol,
26
+ exchange: orderData.exchange || 'CME',
27
+ quantity: orderData.size,
28
+ transactionType: orderData.side === 0 ? 1 : 2, // 1=Buy, 2=Sell
29
+ duration: 1, // DAY
30
+ orderType: orderData.type === 2 ? 1 : 2, // 1=Market, 2=Limit
31
+ price: orderData.price || 0,
32
+ });
33
+
34
+ return { success: true, message: 'Order submitted' };
35
+ } catch (error) {
36
+ return { success: false, error: error.message };
37
+ }
38
+ };
39
+
40
+ /**
41
+ * Cancel order
42
+ * @param {RithmicService} service - The Rithmic service instance
43
+ * @param {string} orderId - Order ID to cancel
44
+ */
45
+ const cancelOrder = async (service, orderId) => {
46
+ if (!service.orderConn || !service.loginInfo) {
47
+ return { success: false, error: 'Not connected' };
48
+ }
49
+
50
+ try {
51
+ service.orderConn.send('RequestCancelOrder', {
52
+ templateId: REQ.CANCEL_ORDER,
53
+ userMsg: ['HQX'],
54
+ fcmId: service.loginInfo.fcmId,
55
+ ibId: service.loginInfo.ibId,
56
+ orderId: orderId,
57
+ });
58
+
59
+ return { success: true };
60
+ } catch (error) {
61
+ return { success: false, error: error.message };
62
+ }
63
+ };
64
+
65
+ /**
66
+ * Get active orders
67
+ * @param {RithmicService} service - The Rithmic service instance
68
+ */
69
+ const getOrders = async (service) => {
70
+ if (!service.orderConn || !service.loginInfo) {
71
+ return { success: true, orders: [] };
72
+ }
73
+
74
+ return new Promise((resolve) => {
75
+ const orders = [];
76
+ const timeout = setTimeout(() => {
77
+ resolve({ success: true, orders });
78
+ }, 3000);
79
+
80
+ const orderHandler = (notification) => {
81
+ if (notification.orderId) {
82
+ orders.push({
83
+ orderId: notification.orderId,
84
+ symbol: notification.symbol,
85
+ exchange: notification.exchange,
86
+ side: notification.transactionType === 1 ? 'BUY' : 'SELL',
87
+ quantity: notification.quantity,
88
+ filledQuantity: notification.filledQuantity || 0,
89
+ price: notification.price,
90
+ orderType: notification.orderType,
91
+ status: notification.status,
92
+ });
93
+ }
94
+ };
95
+
96
+ service.once('ordersReceived', () => {
97
+ clearTimeout(timeout);
98
+ service.removeListener('orderNotification', orderHandler);
99
+ resolve({ success: true, orders });
100
+ });
101
+
102
+ service.on('orderNotification', orderHandler);
103
+
104
+ try {
105
+ for (const acc of service.accounts) {
106
+ service.orderConn.send('RequestShowOrders', {
107
+ templateId: REQ.SHOW_ORDERS,
108
+ userMsg: ['HQX'],
109
+ fcmId: acc.fcmId || service.loginInfo.fcmId,
110
+ ibId: acc.ibId || service.loginInfo.ibId,
111
+ accountId: acc.accountId,
112
+ });
113
+ }
114
+ } catch (e) {
115
+ clearTimeout(timeout);
116
+ resolve({ success: false, error: e.message, orders: [] });
117
+ }
118
+ });
119
+ };
120
+
121
+ /**
122
+ * Get order history
123
+ * @param {RithmicService} service - The Rithmic service instance
124
+ * @param {string} date - Date in YYYYMMDD format
125
+ */
126
+ const getOrderHistory = async (service, date) => {
127
+ if (!service.orderConn || !service.loginInfo) {
128
+ return { success: true, orders: [] };
129
+ }
130
+
131
+ const dateStr = date || new Date().toISOString().slice(0, 10).replace(/-/g, '');
132
+
133
+ return new Promise((resolve) => {
134
+ const orders = [];
135
+ const timeout = setTimeout(() => {
136
+ resolve({ success: true, orders });
137
+ }, 3000);
138
+
139
+ try {
140
+ for (const acc of service.accounts) {
141
+ service.orderConn.send('RequestShowOrderHistorySummary', {
142
+ templateId: REQ.SHOW_ORDER_HISTORY,
143
+ userMsg: ['HQX'],
144
+ fcmId: acc.fcmId || service.loginInfo.fcmId,
145
+ ibId: acc.ibId || service.loginInfo.ibId,
146
+ accountId: acc.accountId,
147
+ date: dateStr,
148
+ });
149
+ }
150
+
151
+ setTimeout(() => {
152
+ clearTimeout(timeout);
153
+ resolve({ success: true, orders });
154
+ }, 2000);
155
+ } catch (e) {
156
+ clearTimeout(timeout);
157
+ resolve({ success: false, error: e.message, orders: [] });
158
+ }
159
+ });
160
+ };
161
+
162
+ /**
163
+ * Close position (market order to flatten)
164
+ * @param {RithmicService} service - The Rithmic service instance
165
+ * @param {string} accountId - Account ID
166
+ * @param {string} symbol - Symbol to close
167
+ */
168
+ const closePosition = async (service, accountId, symbol) => {
169
+ const positions = Array.from(service.positions.values());
170
+ const position = positions.find(p => p.accountId === accountId && p.symbol === symbol);
171
+
172
+ if (!position) {
173
+ return { success: false, error: 'Position not found' };
174
+ }
175
+
176
+ return placeOrder(service, {
177
+ accountId,
178
+ symbol,
179
+ exchange: position.exchange,
180
+ size: Math.abs(position.quantity),
181
+ side: position.quantity > 0 ? 1 : 0, // Sell if long, Buy if short
182
+ type: 2, // Market
183
+ });
184
+ };
185
+
186
+ module.exports = {
187
+ placeOrder,
188
+ cancelOrder,
189
+ getOrders,
190
+ getOrderHistory,
191
+ closePosition
192
+ };