@tigeropenapi/tigeropen 0.5.3 → 0.5.4
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/dist/cjs/client/token-methods.js +42 -0
- package/dist/cjs/config/client-config.js +13 -3
- package/dist/cjs/model/order-helpers.js +126 -21
- package/dist/cjs/quote/quote-client.js +53 -0
- package/dist/cjs/trade/trade-client.js +59 -0
- package/dist/esm/client/token-methods.js +37 -0
- package/dist/esm/config/client-config.js +14 -4
- package/dist/esm/model/order-helpers.js +119 -20
- package/dist/esm/quote/quote-client.js +20 -0
- package/dist/esm/trade/trade-client.js +26 -0
- package/dist/types/client/token-methods.d.ts +34 -0
- package/dist/types/model/order-helpers.d.ts +48 -8
- package/dist/types/model/order.d.ts +8 -1
- package/dist/types/quote/quote-client.d.ts +13 -0
- package/dist/types/trade/trade-client.d.ts +19 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryToken = queryToken;
|
|
4
|
+
exports.refreshToken = refreshToken;
|
|
5
|
+
exports.startTokenAutoRefresh = startTokenAutoRefresh;
|
|
6
|
+
/**
|
|
7
|
+
* Call the `user_token_refresh` API and return the new token string.
|
|
8
|
+
* Read-only: does NOT update the stored token.
|
|
9
|
+
* Use `refreshToken()` to also update the in-memory config and optionally persist.
|
|
10
|
+
*/
|
|
11
|
+
async function queryToken(httpClient) {
|
|
12
|
+
return httpClient.queryToken();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
16
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
17
|
+
*
|
|
18
|
+
* @param httpClient - The underlying HTTP client
|
|
19
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
20
|
+
*/
|
|
21
|
+
async function refreshToken(httpClient, tokenManager) {
|
|
22
|
+
return httpClient.refreshToken(tokenManager);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
26
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
27
|
+
*
|
|
28
|
+
* @param httpClient - The underlying HTTP client
|
|
29
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
30
|
+
* When the token age exceeds this value the refresh is triggered.
|
|
31
|
+
* @param checkIntervalMs - How often to check whether a refresh is needed,
|
|
32
|
+
* in milliseconds. Defaults to 300 000 ms (5 minutes).
|
|
33
|
+
* @param tokenWriter - Optional callback invoked with the new token string
|
|
34
|
+
* after each successful refresh.
|
|
35
|
+
*/
|
|
36
|
+
function startTokenAutoRefresh(httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
37
|
+
return httpClient.startTokenAutoRefresh(null, {
|
|
38
|
+
refreshDuration: refreshDurationSecs,
|
|
39
|
+
refreshInterval: checkIntervalMs,
|
|
40
|
+
tokenWriter,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -113,23 +113,32 @@ function createClientConfig(options) {
|
|
|
113
113
|
const opts = options ?? {};
|
|
114
114
|
// Load properties: explicit path > auto-discovery
|
|
115
115
|
let fileProps = {};
|
|
116
|
+
let configFileDir;
|
|
116
117
|
if (opts.propertiesFilePath) {
|
|
117
118
|
// Support both directory path and full file path
|
|
118
119
|
let filePath = opts.propertiesFilePath;
|
|
119
120
|
if ((0, fs_1.existsSync)(filePath) && (0, fs_1.statSync)(filePath).isDirectory()) {
|
|
121
|
+
configFileDir = filePath;
|
|
120
122
|
filePath = (0, path_1.join)(filePath, CONFIG_FILE_NAME);
|
|
121
123
|
}
|
|
122
124
|
else if (!(0, fs_1.existsSync)(filePath) && !filePath.endsWith('.properties')) {
|
|
123
125
|
// Path doesn't exist as-is; try treating it as a directory
|
|
124
126
|
const asDir = (0, path_1.join)(filePath, CONFIG_FILE_NAME);
|
|
125
|
-
if ((0, fs_1.existsSync)(asDir))
|
|
127
|
+
if ((0, fs_1.existsSync)(asDir)) {
|
|
128
|
+
configFileDir = filePath;
|
|
126
129
|
filePath = asDir;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// It's a file path: derive directory from it
|
|
134
|
+
configFileDir = (0, path_1.dirname)(filePath);
|
|
127
135
|
}
|
|
128
136
|
fileProps = loadPropertiesFile(filePath);
|
|
129
137
|
}
|
|
130
138
|
else {
|
|
131
139
|
const discovered = discoverConfigFile();
|
|
132
140
|
if (discovered) {
|
|
141
|
+
configFileDir = (0, path_1.dirname)(discovered);
|
|
133
142
|
fileProps = loadPropertiesFile(discovered);
|
|
134
143
|
}
|
|
135
144
|
}
|
|
@@ -189,8 +198,9 @@ function createClientConfig(options) {
|
|
|
189
198
|
}
|
|
190
199
|
}
|
|
191
200
|
else {
|
|
192
|
-
// Load from token file: TIGEROPEN_TOKEN_FILE env var > default
|
|
193
|
-
const tokenFilePath = process.env[ENV_TOKEN_FILE]
|
|
201
|
+
// Load from token file: TIGEROPEN_TOKEN_FILE env var > config dir > default
|
|
202
|
+
const tokenFilePath = process.env[ENV_TOKEN_FILE]
|
|
203
|
+
|| (configFileDir ? (0, path_1.join)(configFileDir, 'tiger_openapi_token.properties') : 'tiger_openapi_token.properties');
|
|
194
204
|
const tm = new token_manager_1.TokenManager({ filePath: tokenFilePath });
|
|
195
205
|
try {
|
|
196
206
|
token = tm.loadTokenSync();
|
|
@@ -9,8 +9,14 @@ exports.auctionLimitOrder = auctionLimitOrder;
|
|
|
9
9
|
exports.auctionMarketOrder = auctionMarketOrder;
|
|
10
10
|
exports.algoOrder = algoOrder;
|
|
11
11
|
exports.icebergOrder = icebergOrder;
|
|
12
|
-
exports.icebergOrderFull = icebergOrderFull;
|
|
13
12
|
exports.orderLeg = orderLeg;
|
|
13
|
+
exports.marketOrderByAmount = marketOrderByAmount;
|
|
14
|
+
exports.limitOrderByAmount = limitOrderByAmount;
|
|
15
|
+
exports.trailOrderByPrice = trailOrderByPrice;
|
|
16
|
+
exports.limitOrderWithLegs = limitOrderWithLegs;
|
|
17
|
+
exports.comboOrder = comboOrder;
|
|
18
|
+
exports.ocaOrder = ocaOrder;
|
|
19
|
+
exports.contractLeg = contractLeg;
|
|
14
20
|
const enums_1 = require("./enums");
|
|
15
21
|
/** Market order */
|
|
16
22
|
function marketOrder(account, symbol, secType, action, quantity) {
|
|
@@ -101,26 +107,11 @@ function algoOrder(account, symbol, secType, action, quantity, limitPrice, algoT
|
|
|
101
107
|
};
|
|
102
108
|
}
|
|
103
109
|
/**
|
|
104
|
-
* Iceberg order
|
|
105
|
-
|
|
106
|
-
function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize) {
|
|
107
|
-
return {
|
|
108
|
-
account, symbol, secType, action,
|
|
109
|
-
orderType: enums_1.OrderType.ICEBERG,
|
|
110
|
-
totalQuantity: quantity,
|
|
111
|
-
limitPrice,
|
|
112
|
-
timeInForce: enums_1.TimeInForce.DAY,
|
|
113
|
-
outsideRth: false,
|
|
114
|
-
displaySize,
|
|
115
|
-
priceType: enums_1.PriceType.LIMIT_PRICE,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Iceberg order (full params).
|
|
120
|
-
* Pass `priceType` as empty string to use server default (LIMIT_PRICE).
|
|
110
|
+
* Iceberg order. `displaySize` is required; all other parameters are optional.
|
|
111
|
+
* Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
|
|
121
112
|
* Pass `startTime` / `endTime` as 0 to omit the time window.
|
|
122
113
|
*/
|
|
123
|
-
function
|
|
114
|
+
function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
|
|
124
115
|
const req = {
|
|
125
116
|
account, symbol, secType, action,
|
|
126
117
|
orderType: enums_1.OrderType.ICEBERG,
|
|
@@ -129,13 +120,12 @@ function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice
|
|
|
129
120
|
timeInForce: enums_1.TimeInForce.DAY,
|
|
130
121
|
outsideRth: false,
|
|
131
122
|
displaySize,
|
|
123
|
+
priceType: priceType || enums_1.PriceType.LIMIT_PRICE,
|
|
132
124
|
};
|
|
133
125
|
if (minDisplaySize !== undefined && minDisplaySize > 0)
|
|
134
126
|
req.minDisplaySize = minDisplaySize;
|
|
135
127
|
if (checkIntervals !== undefined && checkIntervals > 0)
|
|
136
128
|
req.checkIntervals = checkIntervals;
|
|
137
|
-
if (priceType)
|
|
138
|
-
req.priceType = priceType;
|
|
139
129
|
if (startTime && startTime > 0)
|
|
140
130
|
req.startTime = startTime;
|
|
141
131
|
if (endTime && endTime > 0)
|
|
@@ -146,3 +136,118 @@ function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice
|
|
|
146
136
|
function orderLeg(legType, price, timeInForce) {
|
|
147
137
|
return { legType, price, timeInForce };
|
|
148
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Market order by cash amount (instead of quantity).
|
|
141
|
+
* Server uses `isQuantityByAmount=true` + `amount` field.
|
|
142
|
+
*/
|
|
143
|
+
function marketOrderByAmount(account, symbol, secType, action, amount) {
|
|
144
|
+
return {
|
|
145
|
+
account, symbol, secType, action,
|
|
146
|
+
orderType: enums_1.OrderType.MKT,
|
|
147
|
+
totalQuantity: 0,
|
|
148
|
+
cashAmount: amount,
|
|
149
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
150
|
+
outsideRth: false,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Limit order by cash amount (instead of quantity).
|
|
155
|
+
*/
|
|
156
|
+
function limitOrderByAmount(account, symbol, secType, action, amount, limitPrice) {
|
|
157
|
+
return {
|
|
158
|
+
account, symbol, secType, action,
|
|
159
|
+
orderType: enums_1.OrderType.LMT,
|
|
160
|
+
totalQuantity: 0,
|
|
161
|
+
cashAmount: amount,
|
|
162
|
+
limitPrice,
|
|
163
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
164
|
+
outsideRth: false,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
|
|
169
|
+
* Use `trailOrder()` for percentage-based trailing stops.
|
|
170
|
+
*/
|
|
171
|
+
function trailOrderByPrice(account, symbol, secType, action, quantity, auxPrice) {
|
|
172
|
+
return {
|
|
173
|
+
account, symbol, secType, action,
|
|
174
|
+
orderType: enums_1.OrderType.TRAIL,
|
|
175
|
+
totalQuantity: quantity,
|
|
176
|
+
auxPrice,
|
|
177
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
178
|
+
outsideRth: false,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Limit order with attached profit/loss legs (bracket order).
|
|
183
|
+
* At most 2 legs are supported.
|
|
184
|
+
*
|
|
185
|
+
* @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
|
|
186
|
+
*/
|
|
187
|
+
function limitOrderWithLegs(account, symbol, secType, action, quantity, limitPrice, orderLegs) {
|
|
188
|
+
if (orderLegs.length === 0) {
|
|
189
|
+
throw new Error('At least 1 order leg is required for a bracket order');
|
|
190
|
+
}
|
|
191
|
+
if (orderLegs.length > 2) {
|
|
192
|
+
throw new Error('At most 2 order legs are supported');
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
account, symbol, secType, action,
|
|
196
|
+
orderType: enums_1.OrderType.LMT,
|
|
197
|
+
totalQuantity: quantity,
|
|
198
|
+
limitPrice,
|
|
199
|
+
orderLegs,
|
|
200
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
201
|
+
outsideRth: false,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Multi-leg (combo/MLEG) order for options combos.
|
|
206
|
+
*
|
|
207
|
+
* @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
|
|
208
|
+
* @param comboType - e.g. `'MLEG'`
|
|
209
|
+
*/
|
|
210
|
+
function comboOrder(account, action, quantity, orderType, contractLegs, comboType = 'MLEG', limitPrice, auxPrice, trailingPercent) {
|
|
211
|
+
return {
|
|
212
|
+
account,
|
|
213
|
+
symbol: '', // not used for combo orders
|
|
214
|
+
secType: 'MLEG',
|
|
215
|
+
action,
|
|
216
|
+
orderType,
|
|
217
|
+
totalQuantity: quantity,
|
|
218
|
+
limitPrice,
|
|
219
|
+
auxPrice,
|
|
220
|
+
trailingPercent,
|
|
221
|
+
contractLegs,
|
|
222
|
+
comboType,
|
|
223
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
224
|
+
outsideRth: false,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* OCA (One-Cancels-All) order.
|
|
229
|
+
* Server expects `orderType: 'OCA'` and an `ocaOrders` list.
|
|
230
|
+
*
|
|
231
|
+
* @param ocaOrders - The contained orders (use any order helper to build each)
|
|
232
|
+
*/
|
|
233
|
+
function ocaOrder(account, symbol, secType, action, quantity, ocaOrders) {
|
|
234
|
+
return {
|
|
235
|
+
account, symbol, secType, action,
|
|
236
|
+
orderType: enums_1.OrderType.OCA,
|
|
237
|
+
totalQuantity: quantity,
|
|
238
|
+
ocaOrders,
|
|
239
|
+
timeInForce: enums_1.TimeInForce.DAY,
|
|
240
|
+
outsideRth: false,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Build a single leg for a multi-leg (MLEG / combo) order.
|
|
245
|
+
*
|
|
246
|
+
* @param symbol - Underlying symbol
|
|
247
|
+
* @param secType - Security type (e.g. `'OPT'`)
|
|
248
|
+
* @param action - `'BUY'` or `'SELL'`
|
|
249
|
+
* @param ratio - Number of contracts for this leg
|
|
250
|
+
*/
|
|
251
|
+
function contractLeg(symbol, secType, action, ratio, expiry, strike, right) {
|
|
252
|
+
return { symbol, secType, action, ratio, expiry, strike, right };
|
|
253
|
+
}
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.QuoteClient = void 0;
|
|
4
37
|
exports.parseOptionIdentifier = parseOptionIdentifier;
|
|
@@ -12,6 +45,7 @@ exports.parseOptionIdentifier = parseOptionIdentifier;
|
|
|
12
45
|
const http_client_1 = require("../client/http-client");
|
|
13
46
|
const api_request_1 = require("../client/api-request");
|
|
14
47
|
const api_response_1 = require("../client/api-response");
|
|
48
|
+
const tokenMethods = __importStar(require("../client/token-methods"));
|
|
15
49
|
/**
|
|
16
50
|
* resolveOptionTimezone returns the timezone string to use for expiry conversion.
|
|
17
51
|
* Explicit tz takes precedence; otherwise infer from symbol (.HK suffix → Asia/Hong_Kong, else America/New_York).
|
|
@@ -94,6 +128,25 @@ class QuoteClient {
|
|
|
94
128
|
static fromConfig(config) {
|
|
95
129
|
return new QuoteClient(new http_client_1.HttpClient(config, undefined, { useQuoteServerUrl: true }));
|
|
96
130
|
}
|
|
131
|
+
// ── Token management ──────────────────────────────────────────────────────
|
|
132
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
133
|
+
async queryToken() {
|
|
134
|
+
return tokenMethods.queryToken(this.httpClient);
|
|
135
|
+
}
|
|
136
|
+
/** Refresh the token and update the in-memory config token. */
|
|
137
|
+
async refreshToken(tokenManager) {
|
|
138
|
+
return tokenMethods.refreshToken(this.httpClient, tokenManager);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
|
|
142
|
+
*
|
|
143
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
144
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
145
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
146
|
+
*/
|
|
147
|
+
startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
148
|
+
return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
|
|
149
|
+
}
|
|
97
150
|
async callInto(method, bizParams, version) {
|
|
98
151
|
const request = (0, api_request_1.createApiRequest)(method, bizParams, version);
|
|
99
152
|
const response = await this.httpClient.executeRequest(request);
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.TradeClient = void 0;
|
|
4
37
|
/**
|
|
@@ -13,6 +46,7 @@ exports.TradeClient = void 0;
|
|
|
13
46
|
const http_client_1 = require("../client/http-client");
|
|
14
47
|
const api_request_1 = require("../client/api-request");
|
|
15
48
|
const api_response_1 = require("../client/api-response");
|
|
49
|
+
const tokenMethods = __importStar(require("../client/token-methods"));
|
|
16
50
|
const order_status_1 = require("../model/order-status");
|
|
17
51
|
/** Normalize `Order.status` field in-place (handles int → string). */
|
|
18
52
|
function normalizeOrderInPlace(o) {
|
|
@@ -44,6 +78,31 @@ class TradeClient {
|
|
|
44
78
|
static fromConfig(config, account, secretKey) {
|
|
45
79
|
return new TradeClient(new http_client_1.HttpClient(config), account, secretKey);
|
|
46
80
|
}
|
|
81
|
+
// ── Token management ──────────────────────────────────────────────────────
|
|
82
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
83
|
+
async queryToken() {
|
|
84
|
+
return tokenMethods.queryToken(this.httpClient);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
88
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
89
|
+
*
|
|
90
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
91
|
+
*/
|
|
92
|
+
async refreshToken(tokenManager) {
|
|
93
|
+
return tokenMethods.refreshToken(this.httpClient, tokenManager);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
97
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
98
|
+
*
|
|
99
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
100
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
101
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
102
|
+
*/
|
|
103
|
+
startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
104
|
+
return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
|
|
105
|
+
}
|
|
47
106
|
async callInto(method, bizParams) {
|
|
48
107
|
// Inject secretKey into every request when available (institution accounts require it).
|
|
49
108
|
// Individual methods that already set secretKey will not be overwritten (|| not &&).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call the `user_token_refresh` API and return the new token string.
|
|
3
|
+
* Read-only: does NOT update the stored token.
|
|
4
|
+
* Use `refreshToken()` to also update the in-memory config and optionally persist.
|
|
5
|
+
*/
|
|
6
|
+
export async function queryToken(httpClient) {
|
|
7
|
+
return httpClient.queryToken();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
11
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
12
|
+
*
|
|
13
|
+
* @param httpClient - The underlying HTTP client
|
|
14
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
15
|
+
*/
|
|
16
|
+
export async function refreshToken(httpClient, tokenManager) {
|
|
17
|
+
return httpClient.refreshToken(tokenManager);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
21
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
22
|
+
*
|
|
23
|
+
* @param httpClient - The underlying HTTP client
|
|
24
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
25
|
+
* When the token age exceeds this value the refresh is triggered.
|
|
26
|
+
* @param checkIntervalMs - How often to check whether a refresh is needed,
|
|
27
|
+
* in milliseconds. Defaults to 300 000 ms (5 minutes).
|
|
28
|
+
* @param tokenWriter - Optional callback invoked with the new token string
|
|
29
|
+
* after each successful refresh.
|
|
30
|
+
*/
|
|
31
|
+
export function startTokenAutoRefresh(httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
32
|
+
return httpClient.startTokenAutoRefresh(null, {
|
|
33
|
+
refreshDuration: refreshDurationSecs,
|
|
34
|
+
refreshInterval: checkIntervalMs,
|
|
35
|
+
tokenWriter,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Priority: environment variables > code options (incl. config file) > defaults
|
|
10
10
|
*/
|
|
11
11
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
12
|
-
import { join } from 'path';
|
|
12
|
+
import { join, dirname } from 'path';
|
|
13
13
|
import { homedir, networkInterfaces } from 'os';
|
|
14
14
|
import { parsePropertiesString } from './config-parser.js';
|
|
15
15
|
import { queryDomains, resolveDynamicServerUrl, resolveDynamicQuoteServerUrl } from './domain.js';
|
|
@@ -108,23 +108,32 @@ export function createClientConfig(options) {
|
|
|
108
108
|
const opts = options ?? {};
|
|
109
109
|
// Load properties: explicit path > auto-discovery
|
|
110
110
|
let fileProps = {};
|
|
111
|
+
let configFileDir;
|
|
111
112
|
if (opts.propertiesFilePath) {
|
|
112
113
|
// Support both directory path and full file path
|
|
113
114
|
let filePath = opts.propertiesFilePath;
|
|
114
115
|
if (existsSync(filePath) && statSync(filePath).isDirectory()) {
|
|
116
|
+
configFileDir = filePath;
|
|
115
117
|
filePath = join(filePath, CONFIG_FILE_NAME);
|
|
116
118
|
}
|
|
117
119
|
else if (!existsSync(filePath) && !filePath.endsWith('.properties')) {
|
|
118
120
|
// Path doesn't exist as-is; try treating it as a directory
|
|
119
121
|
const asDir = join(filePath, CONFIG_FILE_NAME);
|
|
120
|
-
if (existsSync(asDir))
|
|
122
|
+
if (existsSync(asDir)) {
|
|
123
|
+
configFileDir = filePath;
|
|
121
124
|
filePath = asDir;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// It's a file path: derive directory from it
|
|
129
|
+
configFileDir = dirname(filePath);
|
|
122
130
|
}
|
|
123
131
|
fileProps = loadPropertiesFile(filePath);
|
|
124
132
|
}
|
|
125
133
|
else {
|
|
126
134
|
const discovered = discoverConfigFile();
|
|
127
135
|
if (discovered) {
|
|
136
|
+
configFileDir = dirname(discovered);
|
|
128
137
|
fileProps = loadPropertiesFile(discovered);
|
|
129
138
|
}
|
|
130
139
|
}
|
|
@@ -184,8 +193,9 @@ export function createClientConfig(options) {
|
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
else {
|
|
187
|
-
// Load from token file: TIGEROPEN_TOKEN_FILE env var > default
|
|
188
|
-
const tokenFilePath = process.env[ENV_TOKEN_FILE]
|
|
196
|
+
// Load from token file: TIGEROPEN_TOKEN_FILE env var > config dir > default
|
|
197
|
+
const tokenFilePath = process.env[ENV_TOKEN_FILE]
|
|
198
|
+
|| (configFileDir ? join(configFileDir, 'tiger_openapi_token.properties') : 'tiger_openapi_token.properties');
|
|
189
199
|
const tm = new TokenManager({ filePath: tokenFilePath });
|
|
190
200
|
try {
|
|
191
201
|
token = tm.loadTokenSync();
|
|
@@ -88,26 +88,11 @@ export function algoOrder(account, symbol, secType, action, quantity, limitPrice
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
|
-
* Iceberg order
|
|
92
|
-
|
|
93
|
-
export function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize) {
|
|
94
|
-
return {
|
|
95
|
-
account, symbol, secType, action,
|
|
96
|
-
orderType: OrderType.ICEBERG,
|
|
97
|
-
totalQuantity: quantity,
|
|
98
|
-
limitPrice,
|
|
99
|
-
timeInForce: TimeInForce.DAY,
|
|
100
|
-
outsideRth: false,
|
|
101
|
-
displaySize,
|
|
102
|
-
priceType: PriceType.LIMIT_PRICE,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Iceberg order (full params).
|
|
107
|
-
* Pass `priceType` as empty string to use server default (LIMIT_PRICE).
|
|
91
|
+
* Iceberg order. `displaySize` is required; all other parameters are optional.
|
|
92
|
+
* Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
|
|
108
93
|
* Pass `startTime` / `endTime` as 0 to omit the time window.
|
|
109
94
|
*/
|
|
110
|
-
export function
|
|
95
|
+
export function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
|
|
111
96
|
const req = {
|
|
112
97
|
account, symbol, secType, action,
|
|
113
98
|
orderType: OrderType.ICEBERG,
|
|
@@ -116,13 +101,12 @@ export function icebergOrderFull(account, symbol, secType, action, quantity, lim
|
|
|
116
101
|
timeInForce: TimeInForce.DAY,
|
|
117
102
|
outsideRth: false,
|
|
118
103
|
displaySize,
|
|
104
|
+
priceType: priceType || PriceType.LIMIT_PRICE,
|
|
119
105
|
};
|
|
120
106
|
if (minDisplaySize !== undefined && minDisplaySize > 0)
|
|
121
107
|
req.minDisplaySize = minDisplaySize;
|
|
122
108
|
if (checkIntervals !== undefined && checkIntervals > 0)
|
|
123
109
|
req.checkIntervals = checkIntervals;
|
|
124
|
-
if (priceType)
|
|
125
|
-
req.priceType = priceType;
|
|
126
110
|
if (startTime && startTime > 0)
|
|
127
111
|
req.startTime = startTime;
|
|
128
112
|
if (endTime && endTime > 0)
|
|
@@ -133,3 +117,118 @@ export function icebergOrderFull(account, symbol, secType, action, quantity, lim
|
|
|
133
117
|
export function orderLeg(legType, price, timeInForce) {
|
|
134
118
|
return { legType, price, timeInForce };
|
|
135
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Market order by cash amount (instead of quantity).
|
|
122
|
+
* Server uses `isQuantityByAmount=true` + `amount` field.
|
|
123
|
+
*/
|
|
124
|
+
export function marketOrderByAmount(account, symbol, secType, action, amount) {
|
|
125
|
+
return {
|
|
126
|
+
account, symbol, secType, action,
|
|
127
|
+
orderType: OrderType.MKT,
|
|
128
|
+
totalQuantity: 0,
|
|
129
|
+
cashAmount: amount,
|
|
130
|
+
timeInForce: TimeInForce.DAY,
|
|
131
|
+
outsideRth: false,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Limit order by cash amount (instead of quantity).
|
|
136
|
+
*/
|
|
137
|
+
export function limitOrderByAmount(account, symbol, secType, action, amount, limitPrice) {
|
|
138
|
+
return {
|
|
139
|
+
account, symbol, secType, action,
|
|
140
|
+
orderType: OrderType.LMT,
|
|
141
|
+
totalQuantity: 0,
|
|
142
|
+
cashAmount: amount,
|
|
143
|
+
limitPrice,
|
|
144
|
+
timeInForce: TimeInForce.DAY,
|
|
145
|
+
outsideRth: false,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
|
|
150
|
+
* Use `trailOrder()` for percentage-based trailing stops.
|
|
151
|
+
*/
|
|
152
|
+
export function trailOrderByPrice(account, symbol, secType, action, quantity, auxPrice) {
|
|
153
|
+
return {
|
|
154
|
+
account, symbol, secType, action,
|
|
155
|
+
orderType: OrderType.TRAIL,
|
|
156
|
+
totalQuantity: quantity,
|
|
157
|
+
auxPrice,
|
|
158
|
+
timeInForce: TimeInForce.DAY,
|
|
159
|
+
outsideRth: false,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Limit order with attached profit/loss legs (bracket order).
|
|
164
|
+
* At most 2 legs are supported.
|
|
165
|
+
*
|
|
166
|
+
* @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
|
|
167
|
+
*/
|
|
168
|
+
export function limitOrderWithLegs(account, symbol, secType, action, quantity, limitPrice, orderLegs) {
|
|
169
|
+
if (orderLegs.length === 0) {
|
|
170
|
+
throw new Error('At least 1 order leg is required for a bracket order');
|
|
171
|
+
}
|
|
172
|
+
if (orderLegs.length > 2) {
|
|
173
|
+
throw new Error('At most 2 order legs are supported');
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
account, symbol, secType, action,
|
|
177
|
+
orderType: OrderType.LMT,
|
|
178
|
+
totalQuantity: quantity,
|
|
179
|
+
limitPrice,
|
|
180
|
+
orderLegs,
|
|
181
|
+
timeInForce: TimeInForce.DAY,
|
|
182
|
+
outsideRth: false,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Multi-leg (combo/MLEG) order for options combos.
|
|
187
|
+
*
|
|
188
|
+
* @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
|
|
189
|
+
* @param comboType - e.g. `'MLEG'`
|
|
190
|
+
*/
|
|
191
|
+
export function comboOrder(account, action, quantity, orderType, contractLegs, comboType = 'MLEG', limitPrice, auxPrice, trailingPercent) {
|
|
192
|
+
return {
|
|
193
|
+
account,
|
|
194
|
+
symbol: '', // not used for combo orders
|
|
195
|
+
secType: 'MLEG',
|
|
196
|
+
action,
|
|
197
|
+
orderType,
|
|
198
|
+
totalQuantity: quantity,
|
|
199
|
+
limitPrice,
|
|
200
|
+
auxPrice,
|
|
201
|
+
trailingPercent,
|
|
202
|
+
contractLegs,
|
|
203
|
+
comboType,
|
|
204
|
+
timeInForce: TimeInForce.DAY,
|
|
205
|
+
outsideRth: false,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* OCA (One-Cancels-All) order.
|
|
210
|
+
* Server expects `orderType: 'OCA'` and an `ocaOrders` list.
|
|
211
|
+
*
|
|
212
|
+
* @param ocaOrders - The contained orders (use any order helper to build each)
|
|
213
|
+
*/
|
|
214
|
+
export function ocaOrder(account, symbol, secType, action, quantity, ocaOrders) {
|
|
215
|
+
return {
|
|
216
|
+
account, symbol, secType, action,
|
|
217
|
+
orderType: OrderType.OCA,
|
|
218
|
+
totalQuantity: quantity,
|
|
219
|
+
ocaOrders,
|
|
220
|
+
timeInForce: TimeInForce.DAY,
|
|
221
|
+
outsideRth: false,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Build a single leg for a multi-leg (MLEG / combo) order.
|
|
226
|
+
*
|
|
227
|
+
* @param symbol - Underlying symbol
|
|
228
|
+
* @param secType - Security type (e.g. `'OPT'`)
|
|
229
|
+
* @param action - `'BUY'` or `'SELL'`
|
|
230
|
+
* @param ratio - Number of contracts for this leg
|
|
231
|
+
*/
|
|
232
|
+
export function contractLeg(symbol, secType, action, ratio, expiry, strike, right) {
|
|
233
|
+
return { symbol, secType, action, ratio, expiry, strike, right };
|
|
234
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { HttpClient } from '../client/http-client.js';
|
|
9
9
|
import { createApiRequest } from '../client/api-request.js';
|
|
10
10
|
import { unmarshalData } from '../client/api-response.js';
|
|
11
|
+
import * as tokenMethods from '../client/token-methods.js';
|
|
11
12
|
/**
|
|
12
13
|
* resolveOptionTimezone returns the timezone string to use for expiry conversion.
|
|
13
14
|
* Explicit tz takes precedence; otherwise infer from symbol (.HK suffix → Asia/Hong_Kong, else America/New_York).
|
|
@@ -90,6 +91,25 @@ export class QuoteClient {
|
|
|
90
91
|
static fromConfig(config) {
|
|
91
92
|
return new QuoteClient(new HttpClient(config, undefined, { useQuoteServerUrl: true }));
|
|
92
93
|
}
|
|
94
|
+
// ── Token management ──────────────────────────────────────────────────────
|
|
95
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
96
|
+
async queryToken() {
|
|
97
|
+
return tokenMethods.queryToken(this.httpClient);
|
|
98
|
+
}
|
|
99
|
+
/** Refresh the token and update the in-memory config token. */
|
|
100
|
+
async refreshToken(tokenManager) {
|
|
101
|
+
return tokenMethods.refreshToken(this.httpClient, tokenManager);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
|
|
105
|
+
*
|
|
106
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
107
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
108
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
109
|
+
*/
|
|
110
|
+
startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
111
|
+
return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
|
|
112
|
+
}
|
|
93
113
|
async callInto(method, bizParams, version) {
|
|
94
114
|
const request = createApiRequest(method, bizParams, version);
|
|
95
115
|
const response = await this.httpClient.executeRequest(request);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { HttpClient } from '../client/http-client.js';
|
|
11
11
|
import { createApiRequest } from '../client/api-request.js';
|
|
12
12
|
import { unmarshalData } from '../client/api-response.js';
|
|
13
|
+
import * as tokenMethods from '../client/token-methods.js';
|
|
13
14
|
import { normalizeOrderStatus } from '../model/order-status.js';
|
|
14
15
|
/** Normalize `Order.status` field in-place (handles int → string). */
|
|
15
16
|
function normalizeOrderInPlace(o) {
|
|
@@ -41,6 +42,31 @@ export class TradeClient {
|
|
|
41
42
|
static fromConfig(config, account, secretKey) {
|
|
42
43
|
return new TradeClient(new HttpClient(config), account, secretKey);
|
|
43
44
|
}
|
|
45
|
+
// ── Token management ──────────────────────────────────────────────────────
|
|
46
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
47
|
+
async queryToken() {
|
|
48
|
+
return tokenMethods.queryToken(this.httpClient);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
52
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
53
|
+
*
|
|
54
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
55
|
+
*/
|
|
56
|
+
async refreshToken(tokenManager) {
|
|
57
|
+
return tokenMethods.refreshToken(this.httpClient, tokenManager);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
61
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
62
|
+
*
|
|
63
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
64
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
65
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
66
|
+
*/
|
|
67
|
+
startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
|
|
68
|
+
return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
|
|
69
|
+
}
|
|
44
70
|
async callInto(method, bizParams) {
|
|
45
71
|
// Inject secretKey into every request when available (institution accounts require it).
|
|
46
72
|
// Individual methods that already set secretKey will not be overwritten (|| not &&).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared token management methods for TradeClient and QuoteClient.
|
|
3
|
+
* Both clients delegate to the underlying HttpClient; this module
|
|
4
|
+
* centralises the JSDoc so each client stays in sync automatically.
|
|
5
|
+
*/
|
|
6
|
+
import type { HttpClient } from './http-client';
|
|
7
|
+
import type { TokenManager } from '../config/token-manager';
|
|
8
|
+
/**
|
|
9
|
+
* Call the `user_token_refresh` API and return the new token string.
|
|
10
|
+
* Read-only: does NOT update the stored token.
|
|
11
|
+
* Use `refreshToken()` to also update the in-memory config and optionally persist.
|
|
12
|
+
*/
|
|
13
|
+
export declare function queryToken(httpClient: HttpClient): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
16
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
17
|
+
*
|
|
18
|
+
* @param httpClient - The underlying HTTP client
|
|
19
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
20
|
+
*/
|
|
21
|
+
export declare function refreshToken(httpClient: HttpClient, tokenManager?: TokenManager | null): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
24
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
25
|
+
*
|
|
26
|
+
* @param httpClient - The underlying HTTP client
|
|
27
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
28
|
+
* When the token age exceeds this value the refresh is triggered.
|
|
29
|
+
* @param checkIntervalMs - How often to check whether a refresh is needed,
|
|
30
|
+
* in milliseconds. Defaults to 300 000 ms (5 minutes).
|
|
31
|
+
* @param tokenWriter - Optional callback invoked with the new token string
|
|
32
|
+
* after each successful refresh.
|
|
33
|
+
*/
|
|
34
|
+
export declare function startTokenAutoRefresh(httpClient: HttpClient, refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Order construction helpers.
|
|
3
3
|
* All helpers return an `OrderRequest` with sensible defaults.
|
|
4
4
|
*/
|
|
5
|
-
import type { OrderRequest, OrderLegRequest, AlgoParamsRequest } from './order';
|
|
5
|
+
import type { OrderRequest, OrderLegRequest, AlgoParamsRequest, ContractLegRequest } from './order';
|
|
6
6
|
import { PriceType } from './enums';
|
|
7
7
|
/** Market order */
|
|
8
8
|
export declare function marketOrder(account: string, symbol: string, secType: string, action: string, quantity: number): OrderRequest;
|
|
@@ -21,14 +21,54 @@ export declare function auctionMarketOrder(account: string, symbol: string, secT
|
|
|
21
21
|
/** Algo order (TWAP / VWAP) */
|
|
22
22
|
export declare function algoOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, algoType: string, params: AlgoParamsRequest): OrderRequest;
|
|
23
23
|
/**
|
|
24
|
-
* Iceberg order
|
|
25
|
-
|
|
26
|
-
export declare function icebergOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, displaySize: number): OrderRequest;
|
|
27
|
-
/**
|
|
28
|
-
* Iceberg order (full params).
|
|
29
|
-
* Pass `priceType` as empty string to use server default (LIMIT_PRICE).
|
|
24
|
+
* Iceberg order. `displaySize` is required; all other parameters are optional.
|
|
25
|
+
* Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
|
|
30
26
|
* Pass `startTime` / `endTime` as 0 to omit the time window.
|
|
31
27
|
*/
|
|
32
|
-
export declare function
|
|
28
|
+
export declare function icebergOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, displaySize: number, minDisplaySize?: number, checkIntervals?: number, priceType?: PriceType | string, startTime?: number, endTime?: number): OrderRequest;
|
|
33
29
|
/** Attached profit / loss leg */
|
|
34
30
|
export declare function orderLeg(legType: string, price: number, timeInForce: string): OrderLegRequest;
|
|
31
|
+
/**
|
|
32
|
+
* Market order by cash amount (instead of quantity).
|
|
33
|
+
* Server uses `isQuantityByAmount=true` + `amount` field.
|
|
34
|
+
*/
|
|
35
|
+
export declare function marketOrderByAmount(account: string, symbol: string, secType: string, action: string, amount: number): OrderRequest;
|
|
36
|
+
/**
|
|
37
|
+
* Limit order by cash amount (instead of quantity).
|
|
38
|
+
*/
|
|
39
|
+
export declare function limitOrderByAmount(account: string, symbol: string, secType: string, action: string, amount: number, limitPrice: number): OrderRequest;
|
|
40
|
+
/**
|
|
41
|
+
* Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
|
|
42
|
+
* Use `trailOrder()` for percentage-based trailing stops.
|
|
43
|
+
*/
|
|
44
|
+
export declare function trailOrderByPrice(account: string, symbol: string, secType: string, action: string, quantity: number, auxPrice: number): OrderRequest;
|
|
45
|
+
/**
|
|
46
|
+
* Limit order with attached profit/loss legs (bracket order).
|
|
47
|
+
* At most 2 legs are supported.
|
|
48
|
+
*
|
|
49
|
+
* @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
|
|
50
|
+
*/
|
|
51
|
+
export declare function limitOrderWithLegs(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, orderLegs: OrderLegRequest[]): OrderRequest;
|
|
52
|
+
/**
|
|
53
|
+
* Multi-leg (combo/MLEG) order for options combos.
|
|
54
|
+
*
|
|
55
|
+
* @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
|
|
56
|
+
* @param comboType - e.g. `'MLEG'`
|
|
57
|
+
*/
|
|
58
|
+
export declare function comboOrder(account: string, action: string, quantity: number, orderType: string, contractLegs: ContractLegRequest[], comboType?: string, limitPrice?: number, auxPrice?: number, trailingPercent?: number): OrderRequest;
|
|
59
|
+
/**
|
|
60
|
+
* OCA (One-Cancels-All) order.
|
|
61
|
+
* Server expects `orderType: 'OCA'` and an `ocaOrders` list.
|
|
62
|
+
*
|
|
63
|
+
* @param ocaOrders - The contained orders (use any order helper to build each)
|
|
64
|
+
*/
|
|
65
|
+
export declare function ocaOrder(account: string, symbol: string, secType: string, action: string, quantity: number, ocaOrders: OrderRequest[]): OrderRequest;
|
|
66
|
+
/**
|
|
67
|
+
* Build a single leg for a multi-leg (MLEG / combo) order.
|
|
68
|
+
*
|
|
69
|
+
* @param symbol - Underlying symbol
|
|
70
|
+
* @param secType - Security type (e.g. `'OPT'`)
|
|
71
|
+
* @param action - `'BUY'` or `'SELL'`
|
|
72
|
+
* @param ratio - Number of contracts for this leg
|
|
73
|
+
*/
|
|
74
|
+
export declare function contractLeg(symbol: string, secType: string, action: string, ratio: number, expiry?: string, strike?: string, right?: string): ContractLegRequest;
|
|
@@ -149,7 +149,12 @@ export interface OrderRequest {
|
|
|
149
149
|
segType?: string;
|
|
150
150
|
/** 按金额下单:委托金额 */
|
|
151
151
|
amount?: number;
|
|
152
|
-
/**
|
|
152
|
+
/** 按金额下单:现金金额(wire: cash_amount,与 amount 二选一) */
|
|
153
|
+
cashAmount?: number;
|
|
154
|
+
/**
|
|
155
|
+
* @deprecated 服务端不再需要此字段,by-amount 订单直接设置 `cashAmount`。
|
|
156
|
+
* 保留仅为向前兼容,新代码勿使用。
|
|
157
|
+
*/
|
|
153
158
|
isQuantityByAmount?: boolean;
|
|
154
159
|
/** 账户分配列表(机构账户) */
|
|
155
160
|
allocAccounts?: string[];
|
|
@@ -173,6 +178,8 @@ export interface OrderRequest {
|
|
|
173
178
|
ocaOrders?: OrderRequest[];
|
|
174
179
|
/** 多腿期权各腿(MLEG) */
|
|
175
180
|
contractLegs?: ContractLegRequest[];
|
|
181
|
+
/** 组合单类型(如 MLEG) */
|
|
182
|
+
comboType?: string;
|
|
176
183
|
}
|
|
177
184
|
/** Single leg of a multi-leg option order (MLEG) */
|
|
178
185
|
export interface ContractLegRequest {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { HttpClient } from '../client/http-client';
|
|
9
9
|
import type { ClientConfig } from '../config/client-config';
|
|
10
|
+
import type { TokenManager } from '../config/token-manager';
|
|
10
11
|
import type { MarketState, Brief, Kline, KlineItem, Timeline, TradeTick, Depth, OptionExpiration, OptionChain, OptionChainFilter, FutureExchange, FutureContractInfo, FutureQuote, FutureKline, FutureKlineItem, FinancialDailyItem, FinancialReportItem, CorporateAction, CorporateSymbolChange, CorporateDelisting, CorporateIPO, CapitalFlow, CapitalDistribution, ScannerResult, QuotePermission, MarketScannerRequest, SymbolName, TradeMeta, StockDetail, StockBroker, StockIndustry, TradeRankItem, ShortInterest, KlineQuota, OptionAnalysis, OptionSymbol, FutureMainContractHistory, FutureTradingTime, FutureTradeTickItem, FutureDepth, WarrantBrief, WarrantFilterResult, IndustryItem, IndustryStock, TradingCalendarItem, ExchangeRate, FinancialCurrency, QuoteOvernight, MarketScannerTagGroup, FundContractInfo, FundQuote, FundHistoryQuote, FinancialDailyRequest, FinancialReportRequest, CorporateActionRequest } from '../model/quote';
|
|
11
12
|
import type { BriefRequest, DepthQuoteRequest, TradeTickRequest, FutureBriefRequest, SymbolsRequest, TradeMetasRequest, StockDetailsRequest, StockDelayBriefsRequest, KlineRequest, KlineByPageRequest, TimelineHistoryRequest, TradeRankRequest, ShortInterestRequest, StockBrokerRequest, StockFundamentalRequest, StockIndustryRequest, KlineQuotaRequest, QuotePermissionRequest, OptionTradeTicksRequest, OptionTimelineRequest, OptionDepthRequest, OptionSymbolsRequest, OptionAnalysisRequest, FutureContractSingleRequest, AllFutureContractsRequest, FutureContinuousContractsRequest, FutureHistoryMainContractRequest, FutureKlineRequest, FutureKlineByPageRequest, FutureTradeTicksRequest, FutureDepthRequest, FutureTradingTimesRequest, FundSymbolsRequest, FundContractsRequest, FundQuoteRequest, FundHistoryQuoteRequest, WarrantBriefsRequest, WarrantFilterRequest, IndustryListRequest, IndustryStocksRequest, TradingCalendarRequest, FinancialExchangeRateRequest, FinancialCurrencyRequest, MarketScannerTagsRequest, QuoteOvernightRequest } from '../model/quote-requests';
|
|
12
13
|
/**
|
|
@@ -28,6 +29,18 @@ export declare class QuoteClient {
|
|
|
28
29
|
constructor(httpClient: HttpClient);
|
|
29
30
|
/** Create a QuoteClient directly from a ClientConfig — no need to construct HttpClient manually. */
|
|
30
31
|
static fromConfig(config: ClientConfig): QuoteClient;
|
|
32
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
33
|
+
queryToken(): Promise<string>;
|
|
34
|
+
/** Refresh the token and update the in-memory config token. */
|
|
35
|
+
refreshToken(tokenManager?: TokenManager | null): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
|
|
38
|
+
*
|
|
39
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
40
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
41
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
42
|
+
*/
|
|
43
|
+
startTokenAutoRefresh(refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
|
|
31
44
|
private callInto;
|
|
32
45
|
/**
|
|
33
46
|
* Some endpoints return either a list or a single object depending on the
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { HttpClient } from '../client/http-client';
|
|
11
11
|
import type { ClientConfig } from '../config/client-config';
|
|
12
|
+
import type { TokenManager } from '../config/token-manager';
|
|
12
13
|
import type { OrderRequest, Order } from '../model/order';
|
|
13
14
|
import type { Contract } from '../model/contract';
|
|
14
15
|
import type { Position } from '../model/position';
|
|
@@ -22,6 +23,24 @@ export declare class TradeClient {
|
|
|
22
23
|
constructor(httpClient: HttpClient, account: string, secretKey?: string);
|
|
23
24
|
/** Create a TradeClient directly from a ClientConfig — no need to construct HttpClient manually. */
|
|
24
25
|
static fromConfig(config: ClientConfig, account: string, secretKey?: string): TradeClient;
|
|
26
|
+
/** Call the `user_token_refresh` API and return the new token. Read-only. */
|
|
27
|
+
queryToken(): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Refresh the token: call the API, update the in-memory config token, and
|
|
30
|
+
* optionally persist via the provided TokenManager (file + writer callback).
|
|
31
|
+
*
|
|
32
|
+
* @param tokenManager - optional TokenManager for file persistence and writer callback
|
|
33
|
+
*/
|
|
34
|
+
refreshToken(tokenManager?: TokenManager | null): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Start background token auto-refresh. Returns a TokenManager that can be
|
|
37
|
+
* used to stop the background task via `tm.stopAutoRefresh()`.
|
|
38
|
+
*
|
|
39
|
+
* @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
|
|
40
|
+
* @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
|
|
41
|
+
* @param tokenWriter - Optional callback invoked after each successful refresh.
|
|
42
|
+
*/
|
|
43
|
+
startTokenAutoRefresh(refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
|
|
25
44
|
private callInto;
|
|
26
45
|
/** Strip `{items: [...]}` envelope used by most trade read endpoints. */
|
|
27
46
|
private callIntoItems;
|
package/package.json
CHANGED