@discomedia/utils 1.0.63 → 1.0.65
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/index-frontend.cjs +41 -5
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +41 -5
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +320 -208
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +320 -208
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +2 -2
- package/dist/test.js +364 -210
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types/alpaca-trading-api.d.ts +8 -1
- package/dist/types/alpaca-trading-api.d.ts.map +1 -1
- package/dist/types/llm-config.d.ts.map +1 -1
- package/dist/types/llm-images.d.ts.map +1 -1
- package/dist/types/llm-openai.d.ts.map +1 -1
- package/dist/types/types/alpaca-types.d.ts +29 -0
- package/dist/types/types/alpaca-types.d.ts.map +1 -1
- package/dist/types/types/llm-types.d.ts +2 -2
- package/dist/types/types/llm-types.d.ts.map +1 -1
- package/dist/types-frontend/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types-frontend/alpaca-trading-api.d.ts +8 -1
- package/dist/types-frontend/alpaca-trading-api.d.ts.map +1 -1
- package/dist/types-frontend/llm-config.d.ts.map +1 -1
- package/dist/types-frontend/llm-images.d.ts.map +1 -1
- package/dist/types-frontend/llm-openai.d.ts.map +1 -1
- package/dist/types-frontend/types/alpaca-types.d.ts +29 -0
- package/dist/types-frontend/types/alpaca-types.d.ts.map +1 -1
- package/dist/types-frontend/types/llm-types.d.ts +2 -2
- package/dist/types-frontend/types/llm-types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/test.js
CHANGED
|
@@ -1146,6 +1146,7 @@ function isOpenRouterModel(model) {
|
|
|
1146
1146
|
const openRouterModels = [
|
|
1147
1147
|
'openai/gpt-5',
|
|
1148
1148
|
'openai/gpt-5-mini',
|
|
1149
|
+
'openai/gpt-5.4-mini',
|
|
1149
1150
|
'openai/gpt-5-nano',
|
|
1150
1151
|
'openai/gpt-5.1',
|
|
1151
1152
|
'openai/gpt-5.4',
|
|
@@ -1614,7 +1615,7 @@ const safeJSON = (text) => {
|
|
|
1614
1615
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1615
1616
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1616
1617
|
|
|
1617
|
-
const VERSION = '6.
|
|
1618
|
+
const VERSION = '6.32.0'; // x-release-please-version
|
|
1618
1619
|
|
|
1619
1620
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1620
1621
|
const isRunningInBrowser = () => {
|
|
@@ -4858,7 +4859,7 @@ class Speech extends APIResource {
|
|
|
4858
4859
|
* const speech = await client.audio.speech.create({
|
|
4859
4860
|
* input: 'input',
|
|
4860
4861
|
* model: 'string',
|
|
4861
|
-
* voice: '
|
|
4862
|
+
* voice: 'string',
|
|
4862
4863
|
* });
|
|
4863
4864
|
*
|
|
4864
4865
|
* const content = await speech.blob();
|
|
@@ -8139,7 +8140,7 @@ class Videos extends APIResource {
|
|
|
8139
8140
|
* Create a new video generation job from a prompt and optional reference assets.
|
|
8140
8141
|
*/
|
|
8141
8142
|
create(body, options) {
|
|
8142
|
-
return this._client.post('/videos',
|
|
8143
|
+
return this._client.post('/videos', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8143
8144
|
}
|
|
8144
8145
|
/**
|
|
8145
8146
|
* Fetch the latest metadata for a generated video.
|
|
@@ -8159,6 +8160,12 @@ class Videos extends APIResource {
|
|
|
8159
8160
|
delete(videoID, options) {
|
|
8160
8161
|
return this._client.delete(path `/videos/${videoID}`, options);
|
|
8161
8162
|
}
|
|
8163
|
+
/**
|
|
8164
|
+
* Create a character from an uploaded video.
|
|
8165
|
+
*/
|
|
8166
|
+
createCharacter(body, options) {
|
|
8167
|
+
return this._client.post('/videos/characters', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8168
|
+
}
|
|
8162
8169
|
/**
|
|
8163
8170
|
* Download the generated video bytes or a derived preview asset.
|
|
8164
8171
|
*
|
|
@@ -8172,6 +8179,25 @@ class Videos extends APIResource {
|
|
|
8172
8179
|
__binaryResponse: true,
|
|
8173
8180
|
});
|
|
8174
8181
|
}
|
|
8182
|
+
/**
|
|
8183
|
+
* Create a new video generation job by editing a source video or existing
|
|
8184
|
+
* generated video.
|
|
8185
|
+
*/
|
|
8186
|
+
edit(body, options) {
|
|
8187
|
+
return this._client.post('/videos/edits', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8188
|
+
}
|
|
8189
|
+
/**
|
|
8190
|
+
* Create an extension of a completed video.
|
|
8191
|
+
*/
|
|
8192
|
+
extend(body, options) {
|
|
8193
|
+
return this._client.post('/videos/extensions', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8194
|
+
}
|
|
8195
|
+
/**
|
|
8196
|
+
* Fetch a character.
|
|
8197
|
+
*/
|
|
8198
|
+
getCharacter(characterID, options) {
|
|
8199
|
+
return this._client.get(path `/videos/characters/${characterID}`, options);
|
|
8200
|
+
}
|
|
8175
8201
|
/**
|
|
8176
8202
|
* Create a remix of a completed video using a refreshed prompt.
|
|
8177
8203
|
*/
|
|
@@ -8453,8 +8479,9 @@ class OpenAI {
|
|
|
8453
8479
|
new URL(path)
|
|
8454
8480
|
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
|
|
8455
8481
|
const defaultQuery = this.defaultQuery();
|
|
8456
|
-
|
|
8457
|
-
|
|
8482
|
+
const pathQuery = Object.fromEntries(url.searchParams);
|
|
8483
|
+
if (!isEmptyObj$1(defaultQuery) || !isEmptyObj$1(pathQuery)) {
|
|
8484
|
+
query = { ...pathQuery, ...defaultQuery, ...query };
|
|
8458
8485
|
}
|
|
8459
8486
|
if (typeof query === 'object' && query && !Array.isArray(query)) {
|
|
8460
8487
|
url.search = this.stringifyQuery(query);
|
|
@@ -14934,6 +14961,11 @@ const openAiModelCosts = {
|
|
|
14934
14961
|
cacheHitCost: 0.025 / 1_000_000,
|
|
14935
14962
|
outputCost: 2 / 1_000_000,
|
|
14936
14963
|
},
|
|
14964
|
+
'gpt-5.4-mini': {
|
|
14965
|
+
inputCost: 0.25 / 1_000_000,
|
|
14966
|
+
cacheHitCost: 0.025 / 1_000_000,
|
|
14967
|
+
outputCost: 2 / 1_000_000,
|
|
14968
|
+
},
|
|
14937
14969
|
'gpt-5-nano': {
|
|
14938
14970
|
inputCost: 0.05 / 1_000_000,
|
|
14939
14971
|
cacheHitCost: 0.005 / 1_000_000,
|
|
@@ -15444,6 +15476,7 @@ const isSupportedModel = (model) => {
|
|
|
15444
15476
|
'gpt-4.1-nano',
|
|
15445
15477
|
'gpt-5',
|
|
15446
15478
|
'gpt-5-mini',
|
|
15479
|
+
'gpt-5.4-mini',
|
|
15447
15480
|
'gpt-5-nano',
|
|
15448
15481
|
'gpt-5.1',
|
|
15449
15482
|
'gpt-5.4',
|
|
@@ -15472,6 +15505,7 @@ function supportsTemperature(model) {
|
|
|
15472
15505
|
'o3',
|
|
15473
15506
|
'gpt-5',
|
|
15474
15507
|
'gpt-5-mini',
|
|
15508
|
+
'gpt-5.4-mini',
|
|
15475
15509
|
'gpt-5-nano',
|
|
15476
15510
|
'gpt-5.1',
|
|
15477
15511
|
'gpt-5.4',
|
|
@@ -15501,6 +15535,7 @@ function isGPT5Model(model) {
|
|
|
15501
15535
|
const gpt5Models = [
|
|
15502
15536
|
'gpt-5',
|
|
15503
15537
|
'gpt-5-mini',
|
|
15538
|
+
'gpt-5.4-mini',
|
|
15504
15539
|
'gpt-5-nano',
|
|
15505
15540
|
'gpt-5.1',
|
|
15506
15541
|
'gpt-5.4',
|
|
@@ -15810,6 +15845,7 @@ const MULTIMODAL_VISION_MODELS = new Set([
|
|
|
15810
15845
|
'gpt-4o',
|
|
15811
15846
|
'gpt-5',
|
|
15812
15847
|
'gpt-5-mini',
|
|
15848
|
+
'gpt-5.4-mini',
|
|
15813
15849
|
'gpt-5-nano',
|
|
15814
15850
|
'gpt-5.1',
|
|
15815
15851
|
'gpt-5.4',
|
|
@@ -22297,7 +22333,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22297
22333
|
*/
|
|
22298
22334
|
async getHistoricalBars(params) {
|
|
22299
22335
|
const symbols = params.symbols;
|
|
22300
|
-
symbols.join(',');
|
|
22336
|
+
const symbolsStr = symbols.join(',');
|
|
22301
22337
|
let allBars = {};
|
|
22302
22338
|
let pageToken = null;
|
|
22303
22339
|
let hasMorePages = true;
|
|
@@ -22308,7 +22344,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22308
22344
|
symbols.forEach((symbol) => {
|
|
22309
22345
|
allBars[symbol] = [];
|
|
22310
22346
|
});
|
|
22311
|
-
log(`Starting
|
|
22347
|
+
log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
|
|
22312
22348
|
while (hasMorePages) {
|
|
22313
22349
|
pageCount++;
|
|
22314
22350
|
const requestParams = {
|
|
@@ -22319,7 +22355,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22319
22355
|
};
|
|
22320
22356
|
const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
|
|
22321
22357
|
if (!response.bars) {
|
|
22322
|
-
log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
22358
|
+
log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
|
|
22323
22359
|
break;
|
|
22324
22360
|
}
|
|
22325
22361
|
// Track currency from first response
|
|
@@ -22353,7 +22389,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22353
22389
|
const dateRangeStr = earliestTimestamp && latestTimestamp
|
|
22354
22390
|
? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
|
|
22355
22391
|
: 'unknown range';
|
|
22356
|
-
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
|
|
22392
|
+
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { symbol: symbolsStr, type: 'debug' });
|
|
22357
22393
|
// Prevent infinite loops
|
|
22358
22394
|
if (pageCount > 1000) {
|
|
22359
22395
|
log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
@@ -22364,7 +22400,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22364
22400
|
const symbolCounts = Object.entries(allBars)
|
|
22365
22401
|
.map(([symbol, bars]) => `${symbol}: ${bars.length}`)
|
|
22366
22402
|
.join(', ');
|
|
22367
|
-
log(
|
|
22403
|
+
log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
|
|
22368
22404
|
return {
|
|
22369
22405
|
bars: allBars,
|
|
22370
22406
|
next_page_token: null, // Always null since we fetch all pages
|
|
@@ -23216,6 +23252,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
23216
23252
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|
|
23217
23253
|
|
|
23218
23254
|
const limitPriceSlippagePercent100 = 0.1; // 0.1%
|
|
23255
|
+
class AlpacaRequestError extends Error {
|
|
23256
|
+
method;
|
|
23257
|
+
status;
|
|
23258
|
+
url;
|
|
23259
|
+
responseCode;
|
|
23260
|
+
responseDetails;
|
|
23261
|
+
rawResponse;
|
|
23262
|
+
symbol;
|
|
23263
|
+
constructor(params) {
|
|
23264
|
+
super(params.message);
|
|
23265
|
+
this.name = 'AlpacaRequestError';
|
|
23266
|
+
this.method = params.method;
|
|
23267
|
+
this.status = params.status ?? null;
|
|
23268
|
+
this.url = params.url;
|
|
23269
|
+
this.responseCode = params.responseCode ?? null;
|
|
23270
|
+
this.responseDetails = params.responseDetails ?? null;
|
|
23271
|
+
this.rawResponse = params.rawResponse ?? null;
|
|
23272
|
+
this.symbol = params.symbol;
|
|
23273
|
+
}
|
|
23274
|
+
}
|
|
23219
23275
|
/**
|
|
23220
23276
|
Websocket example
|
|
23221
23277
|
const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
|
|
@@ -23299,6 +23355,75 @@ class AlpacaTradingAPI {
|
|
|
23299
23355
|
roundPriceForAlpaca = (price) => {
|
|
23300
23356
|
return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
|
|
23301
23357
|
};
|
|
23358
|
+
isJsonObject(value) {
|
|
23359
|
+
return value !== null && !Array.isArray(value) && typeof value === 'object';
|
|
23360
|
+
}
|
|
23361
|
+
parseAlpacaAPIErrorResponse(rawResponse) {
|
|
23362
|
+
if (rawResponse.trim() === '') {
|
|
23363
|
+
return null;
|
|
23364
|
+
}
|
|
23365
|
+
try {
|
|
23366
|
+
const parsedValue = JSON.parse(rawResponse);
|
|
23367
|
+
if (!this.isJsonObject(parsedValue)) {
|
|
23368
|
+
return null;
|
|
23369
|
+
}
|
|
23370
|
+
const code = parsedValue['code'];
|
|
23371
|
+
const message = parsedValue['message'];
|
|
23372
|
+
const symbol = parsedValue['symbol'];
|
|
23373
|
+
if (typeof code !== 'number' || typeof message !== 'string') {
|
|
23374
|
+
return null;
|
|
23375
|
+
}
|
|
23376
|
+
if (symbol !== undefined && typeof symbol !== 'string') {
|
|
23377
|
+
return null;
|
|
23378
|
+
}
|
|
23379
|
+
return parsedValue;
|
|
23380
|
+
}
|
|
23381
|
+
catch {
|
|
23382
|
+
return null;
|
|
23383
|
+
}
|
|
23384
|
+
}
|
|
23385
|
+
formatJsonValueForLog(value) {
|
|
23386
|
+
if (value === undefined) {
|
|
23387
|
+
return 'undefined';
|
|
23388
|
+
}
|
|
23389
|
+
if (Array.isArray(value)) {
|
|
23390
|
+
return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
|
|
23391
|
+
}
|
|
23392
|
+
if (value === null) {
|
|
23393
|
+
return 'null';
|
|
23394
|
+
}
|
|
23395
|
+
if (typeof value === 'object') {
|
|
23396
|
+
return JSON.stringify(value);
|
|
23397
|
+
}
|
|
23398
|
+
return `${value}`;
|
|
23399
|
+
}
|
|
23400
|
+
formatAlpacaAPIErrorDetails(errorResponse) {
|
|
23401
|
+
return Object.entries(errorResponse)
|
|
23402
|
+
.filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
|
|
23403
|
+
.map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
|
|
23404
|
+
.join(', ');
|
|
23405
|
+
}
|
|
23406
|
+
formatRequestAction(requestContext) {
|
|
23407
|
+
return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
|
|
23408
|
+
}
|
|
23409
|
+
buildAlpacaAPIErrorMessage(params) {
|
|
23410
|
+
const { requestContext, status, url, errorResponse, rawResponse } = params;
|
|
23411
|
+
const action = this.formatRequestAction(requestContext);
|
|
23412
|
+
const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
|
|
23413
|
+
const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
|
|
23414
|
+
const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
|
|
23415
|
+
const detailText = detailSummary !== ''
|
|
23416
|
+
? ` Details: ${detailSummary}.`
|
|
23417
|
+
: rawResponse.trim() !== '' && errorResponse === null
|
|
23418
|
+
? ` Response: ${rawResponse}.`
|
|
23419
|
+
: '';
|
|
23420
|
+
return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
|
|
23421
|
+
}
|
|
23422
|
+
buildRequestExecutionErrorMessage(params) {
|
|
23423
|
+
const { requestContext, url, errorMessage } = params;
|
|
23424
|
+
const action = this.formatRequestAction(requestContext);
|
|
23425
|
+
return `${action}: ${errorMessage}. Url: ${url}`;
|
|
23426
|
+
}
|
|
23302
23427
|
handleAuthMessage(data) {
|
|
23303
23428
|
if (data.status === 'authorized') {
|
|
23304
23429
|
this.authenticated = true;
|
|
@@ -23526,7 +23651,7 @@ class AlpacaTradingAPI {
|
|
|
23526
23651
|
this.ws?.on('message', handleListenResponse);
|
|
23527
23652
|
});
|
|
23528
23653
|
}
|
|
23529
|
-
async makeRequest(endpoint, method = 'GET', body, queryString = '') {
|
|
23654
|
+
async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
|
|
23530
23655
|
const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
|
|
23531
23656
|
try {
|
|
23532
23657
|
const response = await fetch(url, {
|
|
@@ -23535,9 +23660,27 @@ class AlpacaTradingAPI {
|
|
|
23535
23660
|
body: body ? JSON.stringify(body) : undefined,
|
|
23536
23661
|
});
|
|
23537
23662
|
if (!response.ok) {
|
|
23538
|
-
const
|
|
23539
|
-
|
|
23540
|
-
|
|
23663
|
+
const rawResponse = await response.text();
|
|
23664
|
+
const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
|
|
23665
|
+
const symbol = requestContext?.symbol ?? errorResponse?.symbol;
|
|
23666
|
+
const error = new AlpacaRequestError({
|
|
23667
|
+
message: this.buildAlpacaAPIErrorMessage({
|
|
23668
|
+
requestContext,
|
|
23669
|
+
status: response.status,
|
|
23670
|
+
url,
|
|
23671
|
+
errorResponse,
|
|
23672
|
+
rawResponse,
|
|
23673
|
+
}),
|
|
23674
|
+
method,
|
|
23675
|
+
status: response.status,
|
|
23676
|
+
url,
|
|
23677
|
+
responseCode: errorResponse?.code ?? null,
|
|
23678
|
+
responseDetails: errorResponse,
|
|
23679
|
+
rawResponse,
|
|
23680
|
+
symbol,
|
|
23681
|
+
});
|
|
23682
|
+
this.log(error.message, { symbol, type: 'error' });
|
|
23683
|
+
throw error;
|
|
23541
23684
|
}
|
|
23542
23685
|
// Handle responses with no content (e.g., 204 No Content)
|
|
23543
23686
|
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
@@ -23545,23 +23688,37 @@ class AlpacaTradingAPI {
|
|
|
23545
23688
|
}
|
|
23546
23689
|
const contentType = response.headers.get('content-type');
|
|
23547
23690
|
if (contentType && contentType.includes('application/json')) {
|
|
23548
|
-
return await response.json();
|
|
23691
|
+
return (await response.json());
|
|
23549
23692
|
}
|
|
23550
23693
|
// For non-JSON responses, return the text content
|
|
23551
23694
|
const textContent = await response.text();
|
|
23552
|
-
return textContent || null;
|
|
23695
|
+
return (textContent || null);
|
|
23553
23696
|
}
|
|
23554
|
-
catch (
|
|
23555
|
-
|
|
23556
|
-
|
|
23557
|
-
|
|
23558
|
-
|
|
23697
|
+
catch (error) {
|
|
23698
|
+
if (error instanceof AlpacaRequestError) {
|
|
23699
|
+
throw error;
|
|
23700
|
+
}
|
|
23701
|
+
const normalizedError = error instanceof Error ? error : new Error(`${error}`);
|
|
23702
|
+
const symbol = requestContext?.symbol;
|
|
23703
|
+
const requestError = new AlpacaRequestError({
|
|
23704
|
+
message: this.buildRequestExecutionErrorMessage({
|
|
23705
|
+
requestContext,
|
|
23706
|
+
url,
|
|
23707
|
+
errorMessage: normalizedError.message,
|
|
23708
|
+
}),
|
|
23709
|
+
method,
|
|
23710
|
+
url,
|
|
23711
|
+
rawResponse: null,
|
|
23712
|
+
symbol,
|
|
23559
23713
|
});
|
|
23560
|
-
|
|
23714
|
+
this.log(requestError.message, { symbol, type: 'error' });
|
|
23715
|
+
throw requestError;
|
|
23561
23716
|
}
|
|
23562
23717
|
}
|
|
23563
23718
|
async getPositions(assetClass) {
|
|
23564
|
-
const positions =
|
|
23719
|
+
const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
|
|
23720
|
+
action: 'Get positions',
|
|
23721
|
+
});
|
|
23565
23722
|
if (assetClass) {
|
|
23566
23723
|
return positions.filter((position) => position.asset_class === assetClass);
|
|
23567
23724
|
}
|
|
@@ -23599,22 +23756,15 @@ class AlpacaTradingAPI {
|
|
|
23599
23756
|
if (params.side)
|
|
23600
23757
|
queryParams.append('side', params.side);
|
|
23601
23758
|
const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
23602
|
-
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
this.log(`Error getting orders: ${error}`, { type: 'error' });
|
|
23607
|
-
throw error;
|
|
23608
|
-
}
|
|
23759
|
+
return this.makeRequest(endpoint, 'GET', undefined, '', {
|
|
23760
|
+
action: 'Get orders',
|
|
23761
|
+
symbol: params.symbols?.join(','),
|
|
23762
|
+
});
|
|
23609
23763
|
}
|
|
23610
23764
|
async getAccountDetails() {
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
}
|
|
23614
|
-
catch (error) {
|
|
23615
|
-
this.log(`Error getting account details: ${error}`, { type: 'error' });
|
|
23616
|
-
throw error;
|
|
23617
|
-
}
|
|
23765
|
+
return this.makeRequest('/account', 'GET', undefined, '', {
|
|
23766
|
+
action: 'Get account details',
|
|
23767
|
+
});
|
|
23618
23768
|
}
|
|
23619
23769
|
/**
|
|
23620
23770
|
* Create a trailing stop order
|
|
@@ -23632,27 +23782,21 @@ class AlpacaTradingAPI {
|
|
|
23632
23782
|
});
|
|
23633
23783
|
const body = {
|
|
23634
23784
|
symbol,
|
|
23635
|
-
qty: Math.abs(qty),
|
|
23785
|
+
qty: Math.abs(qty).toString(),
|
|
23636
23786
|
side,
|
|
23637
23787
|
position_intent,
|
|
23638
23788
|
order_class: 'simple',
|
|
23639
23789
|
type: 'trailing_stop',
|
|
23640
|
-
trail_percent: trailPercent100
|
|
23790
|
+
trail_percent: trailPercent100.toString(),
|
|
23641
23791
|
time_in_force: 'gtc',
|
|
23642
23792
|
};
|
|
23643
23793
|
if (client_order_id !== undefined) {
|
|
23644
23794
|
body.client_order_id = client_order_id;
|
|
23645
23795
|
}
|
|
23646
|
-
|
|
23647
|
-
|
|
23648
|
-
|
|
23649
|
-
|
|
23650
|
-
this.log(`Error creating trailing stop: ${error}`, {
|
|
23651
|
-
symbol,
|
|
23652
|
-
type: 'error',
|
|
23653
|
-
});
|
|
23654
|
-
throw error;
|
|
23655
|
-
}
|
|
23796
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23797
|
+
action: 'Create trailing stop order',
|
|
23798
|
+
symbol,
|
|
23799
|
+
});
|
|
23656
23800
|
}
|
|
23657
23801
|
/**
|
|
23658
23802
|
* Create a stop order (stop or stop-limit)
|
|
@@ -23678,25 +23822,19 @@ class AlpacaTradingAPI {
|
|
|
23678
23822
|
position_intent,
|
|
23679
23823
|
order_class: 'simple',
|
|
23680
23824
|
type: isStopLimit ? 'stop_limit' : 'stop',
|
|
23681
|
-
stop_price: this.roundPriceForAlpaca(stopPrice),
|
|
23825
|
+
stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
|
|
23682
23826
|
time_in_force: 'gtc',
|
|
23683
23827
|
};
|
|
23684
|
-
if (
|
|
23685
|
-
body.limit_price = this.roundPriceForAlpaca(limitPrice);
|
|
23828
|
+
if (limitPrice !== undefined) {
|
|
23829
|
+
body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
23686
23830
|
}
|
|
23687
23831
|
if (client_order_id !== undefined) {
|
|
23688
23832
|
body.client_order_id = client_order_id;
|
|
23689
23833
|
}
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
|
|
23694
|
-
this.log(`Error creating ${orderType} order: ${error}`, {
|
|
23695
|
-
symbol,
|
|
23696
|
-
type: 'error',
|
|
23697
|
-
});
|
|
23698
|
-
throw error;
|
|
23699
|
-
}
|
|
23834
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23835
|
+
action: `Create ${orderType} order`,
|
|
23836
|
+
symbol,
|
|
23837
|
+
});
|
|
23700
23838
|
}
|
|
23701
23839
|
/**
|
|
23702
23840
|
* Create a market order
|
|
@@ -23722,13 +23860,10 @@ class AlpacaTradingAPI {
|
|
|
23722
23860
|
if (client_order_id !== undefined) {
|
|
23723
23861
|
body.client_order_id = client_order_id;
|
|
23724
23862
|
}
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
this.log(`Error creating market order: ${error}`, { type: 'error' });
|
|
23730
|
-
throw error;
|
|
23731
|
-
}
|
|
23863
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23864
|
+
action: 'Create market order',
|
|
23865
|
+
symbol,
|
|
23866
|
+
});
|
|
23732
23867
|
}
|
|
23733
23868
|
/**
|
|
23734
23869
|
* Create a Market on Open (MOO) order - executes in the opening auction
|
|
@@ -23762,13 +23897,10 @@ class AlpacaTradingAPI {
|
|
|
23762
23897
|
if (client_order_id !== undefined) {
|
|
23763
23898
|
body.client_order_id = client_order_id;
|
|
23764
23899
|
}
|
|
23765
|
-
|
|
23766
|
-
|
|
23767
|
-
|
|
23768
|
-
|
|
23769
|
-
this.log(`Error creating MOO order: ${error}`, { type: 'error' });
|
|
23770
|
-
throw error;
|
|
23771
|
-
}
|
|
23900
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23901
|
+
action: 'Create market on open order',
|
|
23902
|
+
symbol,
|
|
23903
|
+
});
|
|
23772
23904
|
}
|
|
23773
23905
|
/**
|
|
23774
23906
|
* Create a Market on Close (MOC) order - executes in the closing auction
|
|
@@ -23802,13 +23934,10 @@ class AlpacaTradingAPI {
|
|
|
23802
23934
|
if (client_order_id !== undefined) {
|
|
23803
23935
|
body.client_order_id = client_order_id;
|
|
23804
23936
|
}
|
|
23805
|
-
|
|
23806
|
-
|
|
23807
|
-
|
|
23808
|
-
|
|
23809
|
-
this.log(`Error creating MOC order: ${error}`, { type: 'error' });
|
|
23810
|
-
throw error;
|
|
23811
|
-
}
|
|
23937
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23938
|
+
action: 'Create market on close order',
|
|
23939
|
+
symbol,
|
|
23940
|
+
});
|
|
23812
23941
|
}
|
|
23813
23942
|
/**
|
|
23814
23943
|
* Create an OCO (One-Cancels-Other) order with take profit and stop loss
|
|
@@ -23834,32 +23963,29 @@ class AlpacaTradingAPI {
|
|
|
23834
23963
|
position_intent,
|
|
23835
23964
|
order_class: 'oco',
|
|
23836
23965
|
type: 'limit',
|
|
23837
|
-
limit_price: this.roundPriceForAlpaca(limitPrice),
|
|
23966
|
+
limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
|
|
23838
23967
|
time_in_force: 'gtc',
|
|
23839
23968
|
take_profit: {
|
|
23840
|
-
limit_price: this.roundPriceForAlpaca(takeProfitPrice),
|
|
23969
|
+
limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
|
|
23841
23970
|
},
|
|
23842
23971
|
stop_loss: {
|
|
23843
|
-
stop_price: this.roundPriceForAlpaca(stopLossPrice),
|
|
23972
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
23844
23973
|
},
|
|
23845
23974
|
};
|
|
23846
23975
|
// If stop loss limit price is provided, create stop-limit order
|
|
23847
23976
|
if (stopLossLimitPrice !== undefined) {
|
|
23848
|
-
body.stop_loss
|
|
23977
|
+
body.stop_loss = {
|
|
23978
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
23979
|
+
limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
|
|
23980
|
+
};
|
|
23849
23981
|
}
|
|
23850
23982
|
if (client_order_id !== undefined) {
|
|
23851
23983
|
body.client_order_id = client_order_id;
|
|
23852
23984
|
}
|
|
23853
|
-
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
this.log(`Error creating OCO order: ${error}`, {
|
|
23858
|
-
symbol,
|
|
23859
|
-
type: 'error',
|
|
23860
|
-
});
|
|
23861
|
-
throw error;
|
|
23862
|
-
}
|
|
23985
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23986
|
+
action: 'Create OCO order',
|
|
23987
|
+
symbol,
|
|
23988
|
+
});
|
|
23863
23989
|
}
|
|
23864
23990
|
/**
|
|
23865
23991
|
* Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.
|
|
@@ -23867,35 +23993,26 @@ class AlpacaTradingAPI {
|
|
|
23867
23993
|
* @returns the current trail percent
|
|
23868
23994
|
*/
|
|
23869
23995
|
async getCurrentTrailPercent(symbol) {
|
|
23870
|
-
|
|
23871
|
-
|
|
23872
|
-
|
|
23873
|
-
|
|
23996
|
+
const orders = await this.getOrders({
|
|
23997
|
+
status: 'open',
|
|
23998
|
+
symbols: [symbol],
|
|
23999
|
+
});
|
|
24000
|
+
const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
|
|
24001
|
+
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
24002
|
+
if (!trailingStopOrder) {
|
|
24003
|
+
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
24004
|
+
symbol,
|
|
23874
24005
|
});
|
|
23875
|
-
|
|
23876
|
-
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
23877
|
-
if (!trailingStopOrder) {
|
|
23878
|
-
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
23879
|
-
symbol,
|
|
23880
|
-
});
|
|
23881
|
-
return null;
|
|
23882
|
-
}
|
|
23883
|
-
if (!trailingStopOrder.trail_percent) {
|
|
23884
|
-
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
23885
|
-
symbol,
|
|
23886
|
-
});
|
|
23887
|
-
return null;
|
|
23888
|
-
}
|
|
23889
|
-
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
23890
|
-
return trailPercent;
|
|
24006
|
+
return null;
|
|
23891
24007
|
}
|
|
23892
|
-
|
|
23893
|
-
this.log(`
|
|
24008
|
+
if (!trailingStopOrder.trail_percent) {
|
|
24009
|
+
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
23894
24010
|
symbol,
|
|
23895
|
-
type: 'error',
|
|
23896
24011
|
});
|
|
23897
|
-
|
|
24012
|
+
return null;
|
|
23898
24013
|
}
|
|
24014
|
+
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
24015
|
+
return trailPercent;
|
|
23899
24016
|
}
|
|
23900
24017
|
/**
|
|
23901
24018
|
* Update the trail percent for a trailing stop order
|
|
@@ -23927,18 +24044,10 @@ class AlpacaTradingAPI {
|
|
|
23927
24044
|
this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
|
|
23928
24045
|
symbol,
|
|
23929
24046
|
});
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
}
|
|
23935
|
-
catch (error) {
|
|
23936
|
-
this.log(`Error updating trailing stop: ${error}`, {
|
|
23937
|
-
symbol,
|
|
23938
|
-
type: 'error',
|
|
23939
|
-
});
|
|
23940
|
-
throw error;
|
|
23941
|
-
}
|
|
24047
|
+
await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
|
|
24048
|
+
action: 'Update trailing stop order',
|
|
24049
|
+
symbol,
|
|
24050
|
+
});
|
|
23942
24051
|
}
|
|
23943
24052
|
/**
|
|
23944
24053
|
* Cancel all open orders
|
|
@@ -23946,10 +24055,16 @@ class AlpacaTradingAPI {
|
|
|
23946
24055
|
async cancelAllOrders() {
|
|
23947
24056
|
this.log(`Canceling all open orders`);
|
|
23948
24057
|
try {
|
|
23949
|
-
await this.makeRequest('/orders', 'DELETE'
|
|
24058
|
+
await this.makeRequest('/orders', 'DELETE', undefined, '', {
|
|
24059
|
+
action: 'Cancel all open orders',
|
|
24060
|
+
});
|
|
23950
24061
|
}
|
|
23951
24062
|
catch (error) {
|
|
23952
|
-
|
|
24063
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24064
|
+
this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24065
|
+
type: 'error',
|
|
24066
|
+
});
|
|
24067
|
+
}
|
|
23953
24068
|
}
|
|
23954
24069
|
}
|
|
23955
24070
|
/**
|
|
@@ -23961,15 +24076,14 @@ class AlpacaTradingAPI {
|
|
|
23961
24076
|
async cancelOrder(orderId) {
|
|
23962
24077
|
this.log(`Attempting to cancel order ${orderId}`);
|
|
23963
24078
|
try {
|
|
23964
|
-
await this.makeRequest(`/orders/${orderId}`, 'DELETE'
|
|
24079
|
+
await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
|
|
24080
|
+
action: `Cancel order ${orderId}`,
|
|
24081
|
+
});
|
|
23965
24082
|
this.log(`Successfully canceled order ${orderId}`);
|
|
23966
24083
|
}
|
|
23967
24084
|
catch (error) {
|
|
23968
24085
|
// If the error is a 422, it means the order is not cancelable
|
|
23969
|
-
if (error instanceof
|
|
23970
|
-
this.log(`Order ${orderId} is not cancelable`, {
|
|
23971
|
-
type: 'error',
|
|
23972
|
-
});
|
|
24086
|
+
if (error instanceof AlpacaRequestError && error.status === 422) {
|
|
23973
24087
|
throw new Error(`Order ${orderId} is not cancelable`);
|
|
23974
24088
|
}
|
|
23975
24089
|
// Re-throw other errors
|
|
@@ -24004,13 +24118,10 @@ class AlpacaTradingAPI {
|
|
|
24004
24118
|
if (client_order_id !== undefined) {
|
|
24005
24119
|
body.client_order_id = client_order_id;
|
|
24006
24120
|
}
|
|
24007
|
-
|
|
24008
|
-
|
|
24009
|
-
|
|
24010
|
-
|
|
24011
|
-
this.log(`Error creating limit order: ${error}`, { type: 'error' });
|
|
24012
|
-
throw error;
|
|
24013
|
-
}
|
|
24121
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
24122
|
+
action: 'Create limit order',
|
|
24123
|
+
symbol,
|
|
24124
|
+
});
|
|
24014
24125
|
}
|
|
24015
24126
|
/**
|
|
24016
24127
|
* Close all equities positions
|
|
@@ -24076,7 +24187,9 @@ class AlpacaTradingAPI {
|
|
|
24076
24187
|
}
|
|
24077
24188
|
}
|
|
24078
24189
|
else {
|
|
24079
|
-
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : ''
|
|
24190
|
+
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
|
|
24191
|
+
action: 'Close all positions',
|
|
24192
|
+
});
|
|
24080
24193
|
}
|
|
24081
24194
|
}
|
|
24082
24195
|
/**
|
|
@@ -24155,7 +24268,9 @@ class AlpacaTradingAPI {
|
|
|
24155
24268
|
queryParams.append('end', params.end);
|
|
24156
24269
|
if (params.date_end)
|
|
24157
24270
|
queryParams.append('date_end', params.date_end);
|
|
24158
|
-
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}
|
|
24271
|
+
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24272
|
+
action: 'Get portfolio history',
|
|
24273
|
+
});
|
|
24159
24274
|
return response;
|
|
24160
24275
|
}
|
|
24161
24276
|
/**
|
|
@@ -24246,7 +24361,10 @@ class AlpacaTradingAPI {
|
|
|
24246
24361
|
this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
|
|
24247
24362
|
symbol: params.underlying_symbols.join(', '),
|
|
24248
24363
|
});
|
|
24249
|
-
const response =
|
|
24364
|
+
const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24365
|
+
action: 'Get option contracts',
|
|
24366
|
+
symbol: params.underlying_symbols.join(', '),
|
|
24367
|
+
});
|
|
24250
24368
|
this.log(`Found ${response.option_contracts.length} option contracts`, {
|
|
24251
24369
|
symbol: params.underlying_symbols.join(', '),
|
|
24252
24370
|
});
|
|
@@ -24261,7 +24379,10 @@ class AlpacaTradingAPI {
|
|
|
24261
24379
|
this.log(`Fetching option contract details for ${symbolOrId}`, {
|
|
24262
24380
|
symbol: symbolOrId,
|
|
24263
24381
|
});
|
|
24264
|
-
const response =
|
|
24382
|
+
const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
|
|
24383
|
+
action: 'Get option contract details',
|
|
24384
|
+
symbol: symbolOrId,
|
|
24385
|
+
});
|
|
24265
24386
|
this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
|
|
24266
24387
|
symbol: symbolOrId,
|
|
24267
24388
|
});
|
|
@@ -24279,10 +24400,10 @@ class AlpacaTradingAPI {
|
|
|
24279
24400
|
*/
|
|
24280
24401
|
async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
|
|
24281
24402
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
24282
|
-
this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
|
|
24403
|
+
this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
|
|
24283
24404
|
}
|
|
24284
24405
|
if (type === 'limit' && limitPrice === undefined) {
|
|
24285
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
24406
|
+
this.log('Limit price is required for limit orders', { symbol, type: 'error' });
|
|
24286
24407
|
}
|
|
24287
24408
|
this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
24288
24409
|
symbol,
|
|
@@ -24300,7 +24421,10 @@ class AlpacaTradingAPI {
|
|
|
24300
24421
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
24301
24422
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
24302
24423
|
}
|
|
24303
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
24424
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24425
|
+
action: 'Create option order',
|
|
24426
|
+
symbol,
|
|
24427
|
+
});
|
|
24304
24428
|
}
|
|
24305
24429
|
/**
|
|
24306
24430
|
* Create a multi-leg option order
|
|
@@ -24311,16 +24435,19 @@ class AlpacaTradingAPI {
|
|
|
24311
24435
|
* @returns The created multi-leg order
|
|
24312
24436
|
*/
|
|
24313
24437
|
async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
|
|
24438
|
+
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
24314
24439
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
24315
|
-
this.log('Quantity must be a positive whole number for option orders', {
|
|
24440
|
+
this.log('Quantity must be a positive whole number for option orders', {
|
|
24441
|
+
symbol: legSymbols,
|
|
24442
|
+
type: 'error',
|
|
24443
|
+
});
|
|
24316
24444
|
}
|
|
24317
24445
|
if (type === 'limit' && limitPrice === undefined) {
|
|
24318
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
24446
|
+
this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
|
|
24319
24447
|
}
|
|
24320
24448
|
if (legs.length < 2) {
|
|
24321
|
-
this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
|
|
24449
|
+
this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
|
|
24322
24450
|
}
|
|
24323
|
-
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
24324
24451
|
this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
24325
24452
|
symbol: legSymbols,
|
|
24326
24453
|
});
|
|
@@ -24334,7 +24461,10 @@ class AlpacaTradingAPI {
|
|
|
24334
24461
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
24335
24462
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
24336
24463
|
}
|
|
24337
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
24464
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24465
|
+
action: 'Create multi-leg option order',
|
|
24466
|
+
symbol: legSymbols,
|
|
24467
|
+
});
|
|
24338
24468
|
}
|
|
24339
24469
|
/**
|
|
24340
24470
|
* Exercise an option contract
|
|
@@ -24345,7 +24475,10 @@ class AlpacaTradingAPI {
|
|
|
24345
24475
|
this.log(`Exercising option contract ${symbolOrContractId}`, {
|
|
24346
24476
|
symbol: symbolOrContractId,
|
|
24347
24477
|
});
|
|
24348
|
-
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST'
|
|
24478
|
+
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
|
|
24479
|
+
action: 'Exercise option contract',
|
|
24480
|
+
symbol: symbolOrContractId,
|
|
24481
|
+
});
|
|
24349
24482
|
}
|
|
24350
24483
|
/**
|
|
24351
24484
|
* Get option positions
|
|
@@ -24381,7 +24514,9 @@ class AlpacaTradingAPI {
|
|
|
24381
24514
|
queryParams.append('date', date);
|
|
24382
24515
|
}
|
|
24383
24516
|
this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
|
|
24384
|
-
return this.makeRequest(`/account/activities?${queryParams.toString()}
|
|
24517
|
+
return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24518
|
+
action: 'Get option activities',
|
|
24519
|
+
});
|
|
24385
24520
|
}
|
|
24386
24521
|
/**
|
|
24387
24522
|
* Create a long call spread (buy lower strike call, sell higher strike call)
|
|
@@ -24479,13 +24614,7 @@ class AlpacaTradingAPI {
|
|
|
24479
24614
|
position_intent: 'buy_to_open',
|
|
24480
24615
|
},
|
|
24481
24616
|
];
|
|
24482
|
-
|
|
24483
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24484
|
-
}
|
|
24485
|
-
catch (error) {
|
|
24486
|
-
this.log(`Error creating iron condor: ${error}`, { type: 'error' });
|
|
24487
|
-
throw error;
|
|
24488
|
-
}
|
|
24617
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24489
24618
|
}
|
|
24490
24619
|
/**
|
|
24491
24620
|
* Create a covered call (sell call option against owned stock)
|
|
@@ -24501,13 +24630,7 @@ class AlpacaTradingAPI {
|
|
|
24501
24630
|
});
|
|
24502
24631
|
// For covered calls, we don't need to include the stock leg if we already own the shares
|
|
24503
24632
|
// We just create a simple sell order for the call option
|
|
24504
|
-
|
|
24505
|
-
return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
24506
|
-
}
|
|
24507
|
-
catch (error) {
|
|
24508
|
-
this.log(`Error creating covered call: ${error}`, { type: 'error' });
|
|
24509
|
-
throw error;
|
|
24510
|
-
}
|
|
24633
|
+
return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
24511
24634
|
}
|
|
24512
24635
|
/**
|
|
24513
24636
|
* Roll an option position to a new expiration or strike
|
|
@@ -24542,13 +24665,7 @@ class AlpacaTradingAPI {
|
|
|
24542
24665
|
position_intent: openPositionIntent,
|
|
24543
24666
|
},
|
|
24544
24667
|
];
|
|
24545
|
-
|
|
24546
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24547
|
-
}
|
|
24548
|
-
catch (error) {
|
|
24549
|
-
this.log(`Error rolling option position: ${error}`, { type: 'error' });
|
|
24550
|
-
throw error;
|
|
24551
|
-
}
|
|
24668
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24552
24669
|
}
|
|
24553
24670
|
/**
|
|
24554
24671
|
* Get option chain for a specific underlying symbol and expiration date
|
|
@@ -24572,10 +24689,12 @@ class AlpacaTradingAPI {
|
|
|
24572
24689
|
return response.option_contracts || [];
|
|
24573
24690
|
}
|
|
24574
24691
|
catch (error) {
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24692
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24693
|
+
this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24694
|
+
type: 'error',
|
|
24695
|
+
symbol: underlyingSymbol,
|
|
24696
|
+
});
|
|
24697
|
+
}
|
|
24579
24698
|
return [];
|
|
24580
24699
|
}
|
|
24581
24700
|
}
|
|
@@ -24606,10 +24725,12 @@ class AlpacaTradingAPI {
|
|
|
24606
24725
|
return Array.from(expirationDates).sort();
|
|
24607
24726
|
}
|
|
24608
24727
|
catch (error) {
|
|
24609
|
-
|
|
24610
|
-
|
|
24611
|
-
|
|
24612
|
-
|
|
24728
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24729
|
+
this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24730
|
+
type: 'error',
|
|
24731
|
+
symbol: underlyingSymbol,
|
|
24732
|
+
});
|
|
24733
|
+
}
|
|
24613
24734
|
return [];
|
|
24614
24735
|
}
|
|
24615
24736
|
}
|
|
@@ -24668,7 +24789,10 @@ class AlpacaTradingAPI {
|
|
|
24668
24789
|
this.log(`Canceling open order for ${order.symbol}`, {
|
|
24669
24790
|
symbol: order.symbol,
|
|
24670
24791
|
});
|
|
24671
|
-
await this.makeRequest(`/orders/${order.id}`, 'DELETE'
|
|
24792
|
+
await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
|
|
24793
|
+
action: `Cancel option order ${order.id}`,
|
|
24794
|
+
symbol: order.symbol,
|
|
24795
|
+
});
|
|
24672
24796
|
}
|
|
24673
24797
|
}
|
|
24674
24798
|
}
|
|
@@ -24691,13 +24815,7 @@ class AlpacaTradingAPI {
|
|
|
24691
24815
|
const quantityToClose = qty || parseInt(position.qty);
|
|
24692
24816
|
const side = position.side === 'long' ? 'sell' : 'buy';
|
|
24693
24817
|
const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
|
|
24694
|
-
|
|
24695
|
-
return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
24696
|
-
}
|
|
24697
|
-
catch (error) {
|
|
24698
|
-
this.log(`Error closing option position: ${error}`, { type: 'error' });
|
|
24699
|
-
throw error;
|
|
24700
|
-
}
|
|
24818
|
+
return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
24701
24819
|
}
|
|
24702
24820
|
/**
|
|
24703
24821
|
* Create a complete equities trade with optional stop loss and take profit
|
|
@@ -24832,16 +24950,10 @@ class AlpacaTradingAPI {
|
|
|
24832
24950
|
this.log(logMessage, {
|
|
24833
24951
|
symbol,
|
|
24834
24952
|
});
|
|
24835
|
-
|
|
24836
|
-
|
|
24837
|
-
|
|
24838
|
-
|
|
24839
|
-
this.log(`Error creating equities trade: ${error}`, {
|
|
24840
|
-
symbol,
|
|
24841
|
-
type: 'error',
|
|
24842
|
-
});
|
|
24843
|
-
throw error;
|
|
24844
|
-
}
|
|
24953
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24954
|
+
action: 'Create equities trade',
|
|
24955
|
+
symbol,
|
|
24956
|
+
});
|
|
24845
24957
|
}
|
|
24846
24958
|
}
|
|
24847
24959
|
|
|
@@ -24892,6 +25004,48 @@ const disco = {
|
|
|
24892
25004
|
|
|
24893
25005
|
// Test file for context functionality
|
|
24894
25006
|
process.env['DEBUG'] === 'true' || false;
|
|
25007
|
+
async function testLLM() {
|
|
25008
|
+
//const models: LLMModel[] = ['gpt-5', 'gpt-5-mini', 'gpt-5.4-mini', 'gpt-5-nano'];
|
|
25009
|
+
const models = ['gpt-5.4-mini'];
|
|
25010
|
+
for (const model of models) {
|
|
25011
|
+
console.log(`\nTesting model: ${model}`);
|
|
25012
|
+
// 1. Basic call
|
|
25013
|
+
try {
|
|
25014
|
+
const basic = await disco.llm.call('What is the capital of France?', { model });
|
|
25015
|
+
if (!basic || !basic.response) {
|
|
25016
|
+
throw new Error('No response from LLM');
|
|
25017
|
+
}
|
|
25018
|
+
console.log(`Response: ${basic.response}`);
|
|
25019
|
+
}
|
|
25020
|
+
catch (e) {
|
|
25021
|
+
console.error(` Basic call error:`, e);
|
|
25022
|
+
}
|
|
25023
|
+
// 2. JSON call
|
|
25024
|
+
try {
|
|
25025
|
+
const jsonPrompt = 'Return a JSON object with keys country and capital for France.';
|
|
25026
|
+
const json = await disco.llm.call(jsonPrompt, { model, responseFormat: 'json' });
|
|
25027
|
+
if (!json || !json.response) {
|
|
25028
|
+
throw new Error('No response from LLM');
|
|
25029
|
+
}
|
|
25030
|
+
console.log(`Response: ${JSON.stringify(json.response)}`);
|
|
25031
|
+
}
|
|
25032
|
+
catch (e) {
|
|
25033
|
+
console.error(` JSON call error:`, e);
|
|
25034
|
+
}
|
|
25035
|
+
// 3. Web search
|
|
25036
|
+
try {
|
|
25037
|
+
const searchPrompt = 'What is the latest news about artificial intelligence? Respond with 3 sentences max.';
|
|
25038
|
+
const tool = await disco.llm.call(searchPrompt, { model, useWebSearch: true });
|
|
25039
|
+
if (!tool || !tool.response) {
|
|
25040
|
+
throw new Error('No response from LLM');
|
|
25041
|
+
}
|
|
25042
|
+
console.log(`Response: ${tool.response}`);
|
|
25043
|
+
}
|
|
25044
|
+
catch (e) {
|
|
25045
|
+
console.error(` Web search error:`, e);
|
|
25046
|
+
}
|
|
25047
|
+
}
|
|
25048
|
+
}
|
|
24895
25049
|
async function testLLMStructuredOutputWithZod() {
|
|
24896
25050
|
if (!process.env.OPENAI_API_KEY) {
|
|
24897
25051
|
console.log('Skipping OpenAI structured output Zod test: OPENAI_API_KEY not set');
|
|
@@ -24906,7 +25060,7 @@ async function testLLMStructuredOutputWithZod() {
|
|
|
24906
25060
|
try {
|
|
24907
25061
|
const prompt = 'Return details for France using the exact schema.';
|
|
24908
25062
|
const result = await disco.llm.call(prompt, {
|
|
24909
|
-
model: 'gpt-5-mini',
|
|
25063
|
+
model: 'gpt-5.4-mini',
|
|
24910
25064
|
schema: structuredSchema,
|
|
24911
25065
|
schemaName: 'capital_response',
|
|
24912
25066
|
schemaDescription: 'Country and capital metadata',
|
|
@@ -24937,7 +25091,6 @@ async function testLLMStructuredOutputWithZod() {
|
|
|
24937
25091
|
// testGetPortfolioDailyHistory();
|
|
24938
25092
|
// testWebSocketConnectAndDisconnect();
|
|
24939
25093
|
// testGetAssetsShortableFilter();
|
|
24940
|
-
// testLLM();
|
|
24941
25094
|
// testImageModelDefaults();
|
|
24942
25095
|
// testGetTradingDaysBack();
|
|
24943
25096
|
// testMOOAndMOCOrders();
|
|
@@ -24947,5 +25100,6 @@ async function testLLMStructuredOutputWithZod() {
|
|
|
24947
25100
|
// testMarketDataSubscription('SPY');
|
|
24948
25101
|
// testMarketDataSubscription('FAKEPACA');
|
|
24949
25102
|
// testGetTradingDate();
|
|
25103
|
+
testLLM();
|
|
24950
25104
|
testLLMStructuredOutputWithZod();
|
|
24951
25105
|
//# sourceMappingURL=test.js.map
|