@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/index.cjs
CHANGED
|
@@ -1148,6 +1148,7 @@ function isOpenRouterModel(model) {
|
|
|
1148
1148
|
const openRouterModels = [
|
|
1149
1149
|
'openai/gpt-5',
|
|
1150
1150
|
'openai/gpt-5-mini',
|
|
1151
|
+
'openai/gpt-5.4-mini',
|
|
1151
1152
|
'openai/gpt-5-nano',
|
|
1152
1153
|
'openai/gpt-5.1',
|
|
1153
1154
|
'openai/gpt-5.4',
|
|
@@ -1616,7 +1617,7 @@ const safeJSON = (text) => {
|
|
|
1616
1617
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1617
1618
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1618
1619
|
|
|
1619
|
-
const VERSION = '6.
|
|
1620
|
+
const VERSION = '6.32.0'; // x-release-please-version
|
|
1620
1621
|
|
|
1621
1622
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1622
1623
|
const isRunningInBrowser = () => {
|
|
@@ -4860,7 +4861,7 @@ class Speech extends APIResource {
|
|
|
4860
4861
|
* const speech = await client.audio.speech.create({
|
|
4861
4862
|
* input: 'input',
|
|
4862
4863
|
* model: 'string',
|
|
4863
|
-
* voice: '
|
|
4864
|
+
* voice: 'string',
|
|
4864
4865
|
* });
|
|
4865
4866
|
*
|
|
4866
4867
|
* const content = await speech.blob();
|
|
@@ -8141,7 +8142,7 @@ class Videos extends APIResource {
|
|
|
8141
8142
|
* Create a new video generation job from a prompt and optional reference assets.
|
|
8142
8143
|
*/
|
|
8143
8144
|
create(body, options) {
|
|
8144
|
-
return this._client.post('/videos',
|
|
8145
|
+
return this._client.post('/videos', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8145
8146
|
}
|
|
8146
8147
|
/**
|
|
8147
8148
|
* Fetch the latest metadata for a generated video.
|
|
@@ -8161,6 +8162,12 @@ class Videos extends APIResource {
|
|
|
8161
8162
|
delete(videoID, options) {
|
|
8162
8163
|
return this._client.delete(path `/videos/${videoID}`, options);
|
|
8163
8164
|
}
|
|
8165
|
+
/**
|
|
8166
|
+
* Create a character from an uploaded video.
|
|
8167
|
+
*/
|
|
8168
|
+
createCharacter(body, options) {
|
|
8169
|
+
return this._client.post('/videos/characters', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8170
|
+
}
|
|
8164
8171
|
/**
|
|
8165
8172
|
* Download the generated video bytes or a derived preview asset.
|
|
8166
8173
|
*
|
|
@@ -8174,6 +8181,25 @@ class Videos extends APIResource {
|
|
|
8174
8181
|
__binaryResponse: true,
|
|
8175
8182
|
});
|
|
8176
8183
|
}
|
|
8184
|
+
/**
|
|
8185
|
+
* Create a new video generation job by editing a source video or existing
|
|
8186
|
+
* generated video.
|
|
8187
|
+
*/
|
|
8188
|
+
edit(body, options) {
|
|
8189
|
+
return this._client.post('/videos/edits', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8190
|
+
}
|
|
8191
|
+
/**
|
|
8192
|
+
* Create an extension of a completed video.
|
|
8193
|
+
*/
|
|
8194
|
+
extend(body, options) {
|
|
8195
|
+
return this._client.post('/videos/extensions', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8196
|
+
}
|
|
8197
|
+
/**
|
|
8198
|
+
* Fetch a character.
|
|
8199
|
+
*/
|
|
8200
|
+
getCharacter(characterID, options) {
|
|
8201
|
+
return this._client.get(path `/videos/characters/${characterID}`, options);
|
|
8202
|
+
}
|
|
8177
8203
|
/**
|
|
8178
8204
|
* Create a remix of a completed video using a refreshed prompt.
|
|
8179
8205
|
*/
|
|
@@ -8455,8 +8481,9 @@ class OpenAI {
|
|
|
8455
8481
|
new URL(path)
|
|
8456
8482
|
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
|
|
8457
8483
|
const defaultQuery = this.defaultQuery();
|
|
8458
|
-
|
|
8459
|
-
|
|
8484
|
+
const pathQuery = Object.fromEntries(url.searchParams);
|
|
8485
|
+
if (!isEmptyObj$1(defaultQuery) || !isEmptyObj$1(pathQuery)) {
|
|
8486
|
+
query = { ...pathQuery, ...defaultQuery, ...query };
|
|
8460
8487
|
}
|
|
8461
8488
|
if (typeof query === 'object' && query && !Array.isArray(query)) {
|
|
8462
8489
|
url.search = this.stringifyQuery(query);
|
|
@@ -11676,6 +11703,11 @@ const openAiModelCosts = {
|
|
|
11676
11703
|
cacheHitCost: 0.025 / 1_000_000,
|
|
11677
11704
|
outputCost: 2 / 1_000_000,
|
|
11678
11705
|
},
|
|
11706
|
+
'gpt-5.4-mini': {
|
|
11707
|
+
inputCost: 0.25 / 1_000_000,
|
|
11708
|
+
cacheHitCost: 0.025 / 1_000_000,
|
|
11709
|
+
outputCost: 2 / 1_000_000,
|
|
11710
|
+
},
|
|
11679
11711
|
'gpt-5-nano': {
|
|
11680
11712
|
inputCost: 0.05 / 1_000_000,
|
|
11681
11713
|
cacheHitCost: 0.005 / 1_000_000,
|
|
@@ -12186,6 +12218,7 @@ const isSupportedModel = (model) => {
|
|
|
12186
12218
|
'gpt-4.1-nano',
|
|
12187
12219
|
'gpt-5',
|
|
12188
12220
|
'gpt-5-mini',
|
|
12221
|
+
'gpt-5.4-mini',
|
|
12189
12222
|
'gpt-5-nano',
|
|
12190
12223
|
'gpt-5.1',
|
|
12191
12224
|
'gpt-5.4',
|
|
@@ -12214,6 +12247,7 @@ function supportsTemperature(model) {
|
|
|
12214
12247
|
'o3',
|
|
12215
12248
|
'gpt-5',
|
|
12216
12249
|
'gpt-5-mini',
|
|
12250
|
+
'gpt-5.4-mini',
|
|
12217
12251
|
'gpt-5-nano',
|
|
12218
12252
|
'gpt-5.1',
|
|
12219
12253
|
'gpt-5.4',
|
|
@@ -12243,6 +12277,7 @@ function isGPT5Model(model) {
|
|
|
12243
12277
|
const gpt5Models = [
|
|
12244
12278
|
'gpt-5',
|
|
12245
12279
|
'gpt-5-mini',
|
|
12280
|
+
'gpt-5.4-mini',
|
|
12246
12281
|
'gpt-5-nano',
|
|
12247
12282
|
'gpt-5.1',
|
|
12248
12283
|
'gpt-5.4',
|
|
@@ -12552,6 +12587,7 @@ const MULTIMODAL_VISION_MODELS = new Set([
|
|
|
12552
12587
|
'gpt-4o',
|
|
12553
12588
|
'gpt-5',
|
|
12554
12589
|
'gpt-5-mini',
|
|
12590
|
+
'gpt-5.4-mini',
|
|
12555
12591
|
'gpt-5-nano',
|
|
12556
12592
|
'gpt-5.1',
|
|
12557
12593
|
'gpt-5.4',
|
|
@@ -19039,7 +19075,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19039
19075
|
*/
|
|
19040
19076
|
async getHistoricalBars(params) {
|
|
19041
19077
|
const symbols = params.symbols;
|
|
19042
|
-
symbols.join(',');
|
|
19078
|
+
const symbolsStr = symbols.join(',');
|
|
19043
19079
|
let allBars = {};
|
|
19044
19080
|
let pageToken = null;
|
|
19045
19081
|
let hasMorePages = true;
|
|
@@ -19050,7 +19086,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19050
19086
|
symbols.forEach((symbol) => {
|
|
19051
19087
|
allBars[symbol] = [];
|
|
19052
19088
|
});
|
|
19053
|
-
log(`Starting
|
|
19089
|
+
log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
|
|
19054
19090
|
while (hasMorePages) {
|
|
19055
19091
|
pageCount++;
|
|
19056
19092
|
const requestParams = {
|
|
@@ -19061,7 +19097,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19061
19097
|
};
|
|
19062
19098
|
const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
|
|
19063
19099
|
if (!response.bars) {
|
|
19064
|
-
log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
19100
|
+
log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
|
|
19065
19101
|
break;
|
|
19066
19102
|
}
|
|
19067
19103
|
// Track currency from first response
|
|
@@ -19095,7 +19131,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19095
19131
|
const dateRangeStr = earliestTimestamp && latestTimestamp
|
|
19096
19132
|
? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
|
|
19097
19133
|
: 'unknown range';
|
|
19098
|
-
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
|
|
19134
|
+
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' });
|
|
19099
19135
|
// Prevent infinite loops
|
|
19100
19136
|
if (pageCount > 1000) {
|
|
19101
19137
|
log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
@@ -19106,7 +19142,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19106
19142
|
const symbolCounts = Object.entries(allBars)
|
|
19107
19143
|
.map(([symbol, bars]) => `${symbol}: ${bars.length}`)
|
|
19108
19144
|
.join(', ');
|
|
19109
|
-
log(
|
|
19145
|
+
log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
|
|
19110
19146
|
return {
|
|
19111
19147
|
bars: allBars,
|
|
19112
19148
|
next_page_token: null, // Always null since we fetch all pages
|
|
@@ -19958,6 +19994,26 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
19958
19994
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|
|
19959
19995
|
|
|
19960
19996
|
const limitPriceSlippagePercent100 = 0.1; // 0.1%
|
|
19997
|
+
class AlpacaRequestError extends Error {
|
|
19998
|
+
method;
|
|
19999
|
+
status;
|
|
20000
|
+
url;
|
|
20001
|
+
responseCode;
|
|
20002
|
+
responseDetails;
|
|
20003
|
+
rawResponse;
|
|
20004
|
+
symbol;
|
|
20005
|
+
constructor(params) {
|
|
20006
|
+
super(params.message);
|
|
20007
|
+
this.name = 'AlpacaRequestError';
|
|
20008
|
+
this.method = params.method;
|
|
20009
|
+
this.status = params.status ?? null;
|
|
20010
|
+
this.url = params.url;
|
|
20011
|
+
this.responseCode = params.responseCode ?? null;
|
|
20012
|
+
this.responseDetails = params.responseDetails ?? null;
|
|
20013
|
+
this.rawResponse = params.rawResponse ?? null;
|
|
20014
|
+
this.symbol = params.symbol;
|
|
20015
|
+
}
|
|
20016
|
+
}
|
|
19961
20017
|
/**
|
|
19962
20018
|
Websocket example
|
|
19963
20019
|
const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
|
|
@@ -20041,6 +20097,75 @@ class AlpacaTradingAPI {
|
|
|
20041
20097
|
roundPriceForAlpaca = (price) => {
|
|
20042
20098
|
return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
|
|
20043
20099
|
};
|
|
20100
|
+
isJsonObject(value) {
|
|
20101
|
+
return value !== null && !Array.isArray(value) && typeof value === 'object';
|
|
20102
|
+
}
|
|
20103
|
+
parseAlpacaAPIErrorResponse(rawResponse) {
|
|
20104
|
+
if (rawResponse.trim() === '') {
|
|
20105
|
+
return null;
|
|
20106
|
+
}
|
|
20107
|
+
try {
|
|
20108
|
+
const parsedValue = JSON.parse(rawResponse);
|
|
20109
|
+
if (!this.isJsonObject(parsedValue)) {
|
|
20110
|
+
return null;
|
|
20111
|
+
}
|
|
20112
|
+
const code = parsedValue['code'];
|
|
20113
|
+
const message = parsedValue['message'];
|
|
20114
|
+
const symbol = parsedValue['symbol'];
|
|
20115
|
+
if (typeof code !== 'number' || typeof message !== 'string') {
|
|
20116
|
+
return null;
|
|
20117
|
+
}
|
|
20118
|
+
if (symbol !== undefined && typeof symbol !== 'string') {
|
|
20119
|
+
return null;
|
|
20120
|
+
}
|
|
20121
|
+
return parsedValue;
|
|
20122
|
+
}
|
|
20123
|
+
catch {
|
|
20124
|
+
return null;
|
|
20125
|
+
}
|
|
20126
|
+
}
|
|
20127
|
+
formatJsonValueForLog(value) {
|
|
20128
|
+
if (value === undefined) {
|
|
20129
|
+
return 'undefined';
|
|
20130
|
+
}
|
|
20131
|
+
if (Array.isArray(value)) {
|
|
20132
|
+
return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
|
|
20133
|
+
}
|
|
20134
|
+
if (value === null) {
|
|
20135
|
+
return 'null';
|
|
20136
|
+
}
|
|
20137
|
+
if (typeof value === 'object') {
|
|
20138
|
+
return JSON.stringify(value);
|
|
20139
|
+
}
|
|
20140
|
+
return `${value}`;
|
|
20141
|
+
}
|
|
20142
|
+
formatAlpacaAPIErrorDetails(errorResponse) {
|
|
20143
|
+
return Object.entries(errorResponse)
|
|
20144
|
+
.filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
|
|
20145
|
+
.map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
|
|
20146
|
+
.join(', ');
|
|
20147
|
+
}
|
|
20148
|
+
formatRequestAction(requestContext) {
|
|
20149
|
+
return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
|
|
20150
|
+
}
|
|
20151
|
+
buildAlpacaAPIErrorMessage(params) {
|
|
20152
|
+
const { requestContext, status, url, errorResponse, rawResponse } = params;
|
|
20153
|
+
const action = this.formatRequestAction(requestContext);
|
|
20154
|
+
const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
|
|
20155
|
+
const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
|
|
20156
|
+
const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
|
|
20157
|
+
const detailText = detailSummary !== ''
|
|
20158
|
+
? ` Details: ${detailSummary}.`
|
|
20159
|
+
: rawResponse.trim() !== '' && errorResponse === null
|
|
20160
|
+
? ` Response: ${rawResponse}.`
|
|
20161
|
+
: '';
|
|
20162
|
+
return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
|
|
20163
|
+
}
|
|
20164
|
+
buildRequestExecutionErrorMessage(params) {
|
|
20165
|
+
const { requestContext, url, errorMessage } = params;
|
|
20166
|
+
const action = this.formatRequestAction(requestContext);
|
|
20167
|
+
return `${action}: ${errorMessage}. Url: ${url}`;
|
|
20168
|
+
}
|
|
20044
20169
|
handleAuthMessage(data) {
|
|
20045
20170
|
if (data.status === 'authorized') {
|
|
20046
20171
|
this.authenticated = true;
|
|
@@ -20268,7 +20393,7 @@ class AlpacaTradingAPI {
|
|
|
20268
20393
|
this.ws?.on('message', handleListenResponse);
|
|
20269
20394
|
});
|
|
20270
20395
|
}
|
|
20271
|
-
async makeRequest(endpoint, method = 'GET', body, queryString = '') {
|
|
20396
|
+
async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
|
|
20272
20397
|
const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
|
|
20273
20398
|
try {
|
|
20274
20399
|
const response = await fetch(url, {
|
|
@@ -20277,9 +20402,27 @@ class AlpacaTradingAPI {
|
|
|
20277
20402
|
body: body ? JSON.stringify(body) : undefined,
|
|
20278
20403
|
});
|
|
20279
20404
|
if (!response.ok) {
|
|
20280
|
-
const
|
|
20281
|
-
|
|
20282
|
-
|
|
20405
|
+
const rawResponse = await response.text();
|
|
20406
|
+
const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
|
|
20407
|
+
const symbol = requestContext?.symbol ?? errorResponse?.symbol;
|
|
20408
|
+
const error = new AlpacaRequestError({
|
|
20409
|
+
message: this.buildAlpacaAPIErrorMessage({
|
|
20410
|
+
requestContext,
|
|
20411
|
+
status: response.status,
|
|
20412
|
+
url,
|
|
20413
|
+
errorResponse,
|
|
20414
|
+
rawResponse,
|
|
20415
|
+
}),
|
|
20416
|
+
method,
|
|
20417
|
+
status: response.status,
|
|
20418
|
+
url,
|
|
20419
|
+
responseCode: errorResponse?.code ?? null,
|
|
20420
|
+
responseDetails: errorResponse,
|
|
20421
|
+
rawResponse,
|
|
20422
|
+
symbol,
|
|
20423
|
+
});
|
|
20424
|
+
this.log(error.message, { symbol, type: 'error' });
|
|
20425
|
+
throw error;
|
|
20283
20426
|
}
|
|
20284
20427
|
// Handle responses with no content (e.g., 204 No Content)
|
|
20285
20428
|
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
@@ -20287,23 +20430,37 @@ class AlpacaTradingAPI {
|
|
|
20287
20430
|
}
|
|
20288
20431
|
const contentType = response.headers.get('content-type');
|
|
20289
20432
|
if (contentType && contentType.includes('application/json')) {
|
|
20290
|
-
return await response.json();
|
|
20433
|
+
return (await response.json());
|
|
20291
20434
|
}
|
|
20292
20435
|
// For non-JSON responses, return the text content
|
|
20293
20436
|
const textContent = await response.text();
|
|
20294
|
-
return textContent || null;
|
|
20437
|
+
return (textContent || null);
|
|
20295
20438
|
}
|
|
20296
|
-
catch (
|
|
20297
|
-
|
|
20298
|
-
|
|
20299
|
-
|
|
20300
|
-
|
|
20439
|
+
catch (error) {
|
|
20440
|
+
if (error instanceof AlpacaRequestError) {
|
|
20441
|
+
throw error;
|
|
20442
|
+
}
|
|
20443
|
+
const normalizedError = error instanceof Error ? error : new Error(`${error}`);
|
|
20444
|
+
const symbol = requestContext?.symbol;
|
|
20445
|
+
const requestError = new AlpacaRequestError({
|
|
20446
|
+
message: this.buildRequestExecutionErrorMessage({
|
|
20447
|
+
requestContext,
|
|
20448
|
+
url,
|
|
20449
|
+
errorMessage: normalizedError.message,
|
|
20450
|
+
}),
|
|
20451
|
+
method,
|
|
20452
|
+
url,
|
|
20453
|
+
rawResponse: null,
|
|
20454
|
+
symbol,
|
|
20301
20455
|
});
|
|
20302
|
-
|
|
20456
|
+
this.log(requestError.message, { symbol, type: 'error' });
|
|
20457
|
+
throw requestError;
|
|
20303
20458
|
}
|
|
20304
20459
|
}
|
|
20305
20460
|
async getPositions(assetClass) {
|
|
20306
|
-
const positions =
|
|
20461
|
+
const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
|
|
20462
|
+
action: 'Get positions',
|
|
20463
|
+
});
|
|
20307
20464
|
if (assetClass) {
|
|
20308
20465
|
return positions.filter((position) => position.asset_class === assetClass);
|
|
20309
20466
|
}
|
|
@@ -20341,22 +20498,15 @@ class AlpacaTradingAPI {
|
|
|
20341
20498
|
if (params.side)
|
|
20342
20499
|
queryParams.append('side', params.side);
|
|
20343
20500
|
const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
20344
|
-
|
|
20345
|
-
|
|
20346
|
-
|
|
20347
|
-
|
|
20348
|
-
this.log(`Error getting orders: ${error}`, { type: 'error' });
|
|
20349
|
-
throw error;
|
|
20350
|
-
}
|
|
20501
|
+
return this.makeRequest(endpoint, 'GET', undefined, '', {
|
|
20502
|
+
action: 'Get orders',
|
|
20503
|
+
symbol: params.symbols?.join(','),
|
|
20504
|
+
});
|
|
20351
20505
|
}
|
|
20352
20506
|
async getAccountDetails() {
|
|
20353
|
-
|
|
20354
|
-
|
|
20355
|
-
}
|
|
20356
|
-
catch (error) {
|
|
20357
|
-
this.log(`Error getting account details: ${error}`, { type: 'error' });
|
|
20358
|
-
throw error;
|
|
20359
|
-
}
|
|
20507
|
+
return this.makeRequest('/account', 'GET', undefined, '', {
|
|
20508
|
+
action: 'Get account details',
|
|
20509
|
+
});
|
|
20360
20510
|
}
|
|
20361
20511
|
/**
|
|
20362
20512
|
* Create a trailing stop order
|
|
@@ -20374,27 +20524,21 @@ class AlpacaTradingAPI {
|
|
|
20374
20524
|
});
|
|
20375
20525
|
const body = {
|
|
20376
20526
|
symbol,
|
|
20377
|
-
qty: Math.abs(qty),
|
|
20527
|
+
qty: Math.abs(qty).toString(),
|
|
20378
20528
|
side,
|
|
20379
20529
|
position_intent,
|
|
20380
20530
|
order_class: 'simple',
|
|
20381
20531
|
type: 'trailing_stop',
|
|
20382
|
-
trail_percent: trailPercent100
|
|
20532
|
+
trail_percent: trailPercent100.toString(),
|
|
20383
20533
|
time_in_force: 'gtc',
|
|
20384
20534
|
};
|
|
20385
20535
|
if (client_order_id !== undefined) {
|
|
20386
20536
|
body.client_order_id = client_order_id;
|
|
20387
20537
|
}
|
|
20388
|
-
|
|
20389
|
-
|
|
20390
|
-
|
|
20391
|
-
|
|
20392
|
-
this.log(`Error creating trailing stop: ${error}`, {
|
|
20393
|
-
symbol,
|
|
20394
|
-
type: 'error',
|
|
20395
|
-
});
|
|
20396
|
-
throw error;
|
|
20397
|
-
}
|
|
20538
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20539
|
+
action: 'Create trailing stop order',
|
|
20540
|
+
symbol,
|
|
20541
|
+
});
|
|
20398
20542
|
}
|
|
20399
20543
|
/**
|
|
20400
20544
|
* Create a stop order (stop or stop-limit)
|
|
@@ -20420,25 +20564,19 @@ class AlpacaTradingAPI {
|
|
|
20420
20564
|
position_intent,
|
|
20421
20565
|
order_class: 'simple',
|
|
20422
20566
|
type: isStopLimit ? 'stop_limit' : 'stop',
|
|
20423
|
-
stop_price: this.roundPriceForAlpaca(stopPrice),
|
|
20567
|
+
stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
|
|
20424
20568
|
time_in_force: 'gtc',
|
|
20425
20569
|
};
|
|
20426
|
-
if (
|
|
20427
|
-
body.limit_price = this.roundPriceForAlpaca(limitPrice);
|
|
20570
|
+
if (limitPrice !== undefined) {
|
|
20571
|
+
body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
20428
20572
|
}
|
|
20429
20573
|
if (client_order_id !== undefined) {
|
|
20430
20574
|
body.client_order_id = client_order_id;
|
|
20431
20575
|
}
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
this.log(`Error creating ${orderType} order: ${error}`, {
|
|
20437
|
-
symbol,
|
|
20438
|
-
type: 'error',
|
|
20439
|
-
});
|
|
20440
|
-
throw error;
|
|
20441
|
-
}
|
|
20576
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20577
|
+
action: `Create ${orderType} order`,
|
|
20578
|
+
symbol,
|
|
20579
|
+
});
|
|
20442
20580
|
}
|
|
20443
20581
|
/**
|
|
20444
20582
|
* Create a market order
|
|
@@ -20464,13 +20602,10 @@ class AlpacaTradingAPI {
|
|
|
20464
20602
|
if (client_order_id !== undefined) {
|
|
20465
20603
|
body.client_order_id = client_order_id;
|
|
20466
20604
|
}
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
this.log(`Error creating market order: ${error}`, { type: 'error' });
|
|
20472
|
-
throw error;
|
|
20473
|
-
}
|
|
20605
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20606
|
+
action: 'Create market order',
|
|
20607
|
+
symbol,
|
|
20608
|
+
});
|
|
20474
20609
|
}
|
|
20475
20610
|
/**
|
|
20476
20611
|
* Create a Market on Open (MOO) order - executes in the opening auction
|
|
@@ -20504,13 +20639,10 @@ class AlpacaTradingAPI {
|
|
|
20504
20639
|
if (client_order_id !== undefined) {
|
|
20505
20640
|
body.client_order_id = client_order_id;
|
|
20506
20641
|
}
|
|
20507
|
-
|
|
20508
|
-
|
|
20509
|
-
|
|
20510
|
-
|
|
20511
|
-
this.log(`Error creating MOO order: ${error}`, { type: 'error' });
|
|
20512
|
-
throw error;
|
|
20513
|
-
}
|
|
20642
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20643
|
+
action: 'Create market on open order',
|
|
20644
|
+
symbol,
|
|
20645
|
+
});
|
|
20514
20646
|
}
|
|
20515
20647
|
/**
|
|
20516
20648
|
* Create a Market on Close (MOC) order - executes in the closing auction
|
|
@@ -20544,13 +20676,10 @@ class AlpacaTradingAPI {
|
|
|
20544
20676
|
if (client_order_id !== undefined) {
|
|
20545
20677
|
body.client_order_id = client_order_id;
|
|
20546
20678
|
}
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
this.log(`Error creating MOC order: ${error}`, { type: 'error' });
|
|
20552
|
-
throw error;
|
|
20553
|
-
}
|
|
20679
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20680
|
+
action: 'Create market on close order',
|
|
20681
|
+
symbol,
|
|
20682
|
+
});
|
|
20554
20683
|
}
|
|
20555
20684
|
/**
|
|
20556
20685
|
* Create an OCO (One-Cancels-Other) order with take profit and stop loss
|
|
@@ -20576,32 +20705,29 @@ class AlpacaTradingAPI {
|
|
|
20576
20705
|
position_intent,
|
|
20577
20706
|
order_class: 'oco',
|
|
20578
20707
|
type: 'limit',
|
|
20579
|
-
limit_price: this.roundPriceForAlpaca(limitPrice),
|
|
20708
|
+
limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
|
|
20580
20709
|
time_in_force: 'gtc',
|
|
20581
20710
|
take_profit: {
|
|
20582
|
-
limit_price: this.roundPriceForAlpaca(takeProfitPrice),
|
|
20711
|
+
limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
|
|
20583
20712
|
},
|
|
20584
20713
|
stop_loss: {
|
|
20585
|
-
stop_price: this.roundPriceForAlpaca(stopLossPrice),
|
|
20714
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20586
20715
|
},
|
|
20587
20716
|
};
|
|
20588
20717
|
// If stop loss limit price is provided, create stop-limit order
|
|
20589
20718
|
if (stopLossLimitPrice !== undefined) {
|
|
20590
|
-
body.stop_loss
|
|
20719
|
+
body.stop_loss = {
|
|
20720
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20721
|
+
limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
|
|
20722
|
+
};
|
|
20591
20723
|
}
|
|
20592
20724
|
if (client_order_id !== undefined) {
|
|
20593
20725
|
body.client_order_id = client_order_id;
|
|
20594
20726
|
}
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
this.log(`Error creating OCO order: ${error}`, {
|
|
20600
|
-
symbol,
|
|
20601
|
-
type: 'error',
|
|
20602
|
-
});
|
|
20603
|
-
throw error;
|
|
20604
|
-
}
|
|
20727
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20728
|
+
action: 'Create OCO order',
|
|
20729
|
+
symbol,
|
|
20730
|
+
});
|
|
20605
20731
|
}
|
|
20606
20732
|
/**
|
|
20607
20733
|
* 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.
|
|
@@ -20609,35 +20735,26 @@ class AlpacaTradingAPI {
|
|
|
20609
20735
|
* @returns the current trail percent
|
|
20610
20736
|
*/
|
|
20611
20737
|
async getCurrentTrailPercent(symbol) {
|
|
20612
|
-
|
|
20613
|
-
|
|
20614
|
-
|
|
20615
|
-
|
|
20738
|
+
const orders = await this.getOrders({
|
|
20739
|
+
status: 'open',
|
|
20740
|
+
symbols: [symbol],
|
|
20741
|
+
});
|
|
20742
|
+
const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
|
|
20743
|
+
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
20744
|
+
if (!trailingStopOrder) {
|
|
20745
|
+
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
20746
|
+
symbol,
|
|
20616
20747
|
});
|
|
20617
|
-
|
|
20618
|
-
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
20619
|
-
if (!trailingStopOrder) {
|
|
20620
|
-
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
20621
|
-
symbol,
|
|
20622
|
-
});
|
|
20623
|
-
return null;
|
|
20624
|
-
}
|
|
20625
|
-
if (!trailingStopOrder.trail_percent) {
|
|
20626
|
-
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
20627
|
-
symbol,
|
|
20628
|
-
});
|
|
20629
|
-
return null;
|
|
20630
|
-
}
|
|
20631
|
-
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
20632
|
-
return trailPercent;
|
|
20748
|
+
return null;
|
|
20633
20749
|
}
|
|
20634
|
-
|
|
20635
|
-
this.log(`
|
|
20750
|
+
if (!trailingStopOrder.trail_percent) {
|
|
20751
|
+
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
20636
20752
|
symbol,
|
|
20637
|
-
type: 'error',
|
|
20638
20753
|
});
|
|
20639
|
-
|
|
20754
|
+
return null;
|
|
20640
20755
|
}
|
|
20756
|
+
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
20757
|
+
return trailPercent;
|
|
20641
20758
|
}
|
|
20642
20759
|
/**
|
|
20643
20760
|
* Update the trail percent for a trailing stop order
|
|
@@ -20669,18 +20786,10 @@ class AlpacaTradingAPI {
|
|
|
20669
20786
|
this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
|
|
20670
20787
|
symbol,
|
|
20671
20788
|
});
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
}
|
|
20677
|
-
catch (error) {
|
|
20678
|
-
this.log(`Error updating trailing stop: ${error}`, {
|
|
20679
|
-
symbol,
|
|
20680
|
-
type: 'error',
|
|
20681
|
-
});
|
|
20682
|
-
throw error;
|
|
20683
|
-
}
|
|
20789
|
+
await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
|
|
20790
|
+
action: 'Update trailing stop order',
|
|
20791
|
+
symbol,
|
|
20792
|
+
});
|
|
20684
20793
|
}
|
|
20685
20794
|
/**
|
|
20686
20795
|
* Cancel all open orders
|
|
@@ -20688,10 +20797,16 @@ class AlpacaTradingAPI {
|
|
|
20688
20797
|
async cancelAllOrders() {
|
|
20689
20798
|
this.log(`Canceling all open orders`);
|
|
20690
20799
|
try {
|
|
20691
|
-
await this.makeRequest('/orders', 'DELETE'
|
|
20800
|
+
await this.makeRequest('/orders', 'DELETE', undefined, '', {
|
|
20801
|
+
action: 'Cancel all open orders',
|
|
20802
|
+
});
|
|
20692
20803
|
}
|
|
20693
20804
|
catch (error) {
|
|
20694
|
-
|
|
20805
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
20806
|
+
this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
20807
|
+
type: 'error',
|
|
20808
|
+
});
|
|
20809
|
+
}
|
|
20695
20810
|
}
|
|
20696
20811
|
}
|
|
20697
20812
|
/**
|
|
@@ -20703,15 +20818,14 @@ class AlpacaTradingAPI {
|
|
|
20703
20818
|
async cancelOrder(orderId) {
|
|
20704
20819
|
this.log(`Attempting to cancel order ${orderId}`);
|
|
20705
20820
|
try {
|
|
20706
|
-
await this.makeRequest(`/orders/${orderId}`, 'DELETE'
|
|
20821
|
+
await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
|
|
20822
|
+
action: `Cancel order ${orderId}`,
|
|
20823
|
+
});
|
|
20707
20824
|
this.log(`Successfully canceled order ${orderId}`);
|
|
20708
20825
|
}
|
|
20709
20826
|
catch (error) {
|
|
20710
20827
|
// If the error is a 422, it means the order is not cancelable
|
|
20711
|
-
if (error instanceof
|
|
20712
|
-
this.log(`Order ${orderId} is not cancelable`, {
|
|
20713
|
-
type: 'error',
|
|
20714
|
-
});
|
|
20828
|
+
if (error instanceof AlpacaRequestError && error.status === 422) {
|
|
20715
20829
|
throw new Error(`Order ${orderId} is not cancelable`);
|
|
20716
20830
|
}
|
|
20717
20831
|
// Re-throw other errors
|
|
@@ -20746,13 +20860,10 @@ class AlpacaTradingAPI {
|
|
|
20746
20860
|
if (client_order_id !== undefined) {
|
|
20747
20861
|
body.client_order_id = client_order_id;
|
|
20748
20862
|
}
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
|
|
20752
|
-
|
|
20753
|
-
this.log(`Error creating limit order: ${error}`, { type: 'error' });
|
|
20754
|
-
throw error;
|
|
20755
|
-
}
|
|
20863
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20864
|
+
action: 'Create limit order',
|
|
20865
|
+
symbol,
|
|
20866
|
+
});
|
|
20756
20867
|
}
|
|
20757
20868
|
/**
|
|
20758
20869
|
* Close all equities positions
|
|
@@ -20818,7 +20929,9 @@ class AlpacaTradingAPI {
|
|
|
20818
20929
|
}
|
|
20819
20930
|
}
|
|
20820
20931
|
else {
|
|
20821
|
-
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : ''
|
|
20932
|
+
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
|
|
20933
|
+
action: 'Close all positions',
|
|
20934
|
+
});
|
|
20822
20935
|
}
|
|
20823
20936
|
}
|
|
20824
20937
|
/**
|
|
@@ -20897,7 +21010,9 @@ class AlpacaTradingAPI {
|
|
|
20897
21010
|
queryParams.append('end', params.end);
|
|
20898
21011
|
if (params.date_end)
|
|
20899
21012
|
queryParams.append('date_end', params.date_end);
|
|
20900
|
-
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}
|
|
21013
|
+
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21014
|
+
action: 'Get portfolio history',
|
|
21015
|
+
});
|
|
20901
21016
|
return response;
|
|
20902
21017
|
}
|
|
20903
21018
|
/**
|
|
@@ -20988,7 +21103,10 @@ class AlpacaTradingAPI {
|
|
|
20988
21103
|
this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
|
|
20989
21104
|
symbol: params.underlying_symbols.join(', '),
|
|
20990
21105
|
});
|
|
20991
|
-
const response =
|
|
21106
|
+
const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21107
|
+
action: 'Get option contracts',
|
|
21108
|
+
symbol: params.underlying_symbols.join(', '),
|
|
21109
|
+
});
|
|
20992
21110
|
this.log(`Found ${response.option_contracts.length} option contracts`, {
|
|
20993
21111
|
symbol: params.underlying_symbols.join(', '),
|
|
20994
21112
|
});
|
|
@@ -21003,7 +21121,10 @@ class AlpacaTradingAPI {
|
|
|
21003
21121
|
this.log(`Fetching option contract details for ${symbolOrId}`, {
|
|
21004
21122
|
symbol: symbolOrId,
|
|
21005
21123
|
});
|
|
21006
|
-
const response =
|
|
21124
|
+
const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
|
|
21125
|
+
action: 'Get option contract details',
|
|
21126
|
+
symbol: symbolOrId,
|
|
21127
|
+
});
|
|
21007
21128
|
this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
|
|
21008
21129
|
symbol: symbolOrId,
|
|
21009
21130
|
});
|
|
@@ -21021,10 +21142,10 @@ class AlpacaTradingAPI {
|
|
|
21021
21142
|
*/
|
|
21022
21143
|
async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
|
|
21023
21144
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21024
|
-
this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
|
|
21145
|
+
this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
|
|
21025
21146
|
}
|
|
21026
21147
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21027
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21148
|
+
this.log('Limit price is required for limit orders', { symbol, type: 'error' });
|
|
21028
21149
|
}
|
|
21029
21150
|
this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21030
21151
|
symbol,
|
|
@@ -21042,7 +21163,10 @@ class AlpacaTradingAPI {
|
|
|
21042
21163
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21043
21164
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21044
21165
|
}
|
|
21045
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21166
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21167
|
+
action: 'Create option order',
|
|
21168
|
+
symbol,
|
|
21169
|
+
});
|
|
21046
21170
|
}
|
|
21047
21171
|
/**
|
|
21048
21172
|
* Create a multi-leg option order
|
|
@@ -21053,16 +21177,19 @@ class AlpacaTradingAPI {
|
|
|
21053
21177
|
* @returns The created multi-leg order
|
|
21054
21178
|
*/
|
|
21055
21179
|
async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
|
|
21180
|
+
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21056
21181
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21057
|
-
this.log('Quantity must be a positive whole number for option orders', {
|
|
21182
|
+
this.log('Quantity must be a positive whole number for option orders', {
|
|
21183
|
+
symbol: legSymbols,
|
|
21184
|
+
type: 'error',
|
|
21185
|
+
});
|
|
21058
21186
|
}
|
|
21059
21187
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21060
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21188
|
+
this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
|
|
21061
21189
|
}
|
|
21062
21190
|
if (legs.length < 2) {
|
|
21063
|
-
this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
|
|
21191
|
+
this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
|
|
21064
21192
|
}
|
|
21065
|
-
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21066
21193
|
this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21067
21194
|
symbol: legSymbols,
|
|
21068
21195
|
});
|
|
@@ -21076,7 +21203,10 @@ class AlpacaTradingAPI {
|
|
|
21076
21203
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21077
21204
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21078
21205
|
}
|
|
21079
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21206
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21207
|
+
action: 'Create multi-leg option order',
|
|
21208
|
+
symbol: legSymbols,
|
|
21209
|
+
});
|
|
21080
21210
|
}
|
|
21081
21211
|
/**
|
|
21082
21212
|
* Exercise an option contract
|
|
@@ -21087,7 +21217,10 @@ class AlpacaTradingAPI {
|
|
|
21087
21217
|
this.log(`Exercising option contract ${symbolOrContractId}`, {
|
|
21088
21218
|
symbol: symbolOrContractId,
|
|
21089
21219
|
});
|
|
21090
|
-
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST'
|
|
21220
|
+
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
|
|
21221
|
+
action: 'Exercise option contract',
|
|
21222
|
+
symbol: symbolOrContractId,
|
|
21223
|
+
});
|
|
21091
21224
|
}
|
|
21092
21225
|
/**
|
|
21093
21226
|
* Get option positions
|
|
@@ -21123,7 +21256,9 @@ class AlpacaTradingAPI {
|
|
|
21123
21256
|
queryParams.append('date', date);
|
|
21124
21257
|
}
|
|
21125
21258
|
this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
|
|
21126
|
-
return this.makeRequest(`/account/activities?${queryParams.toString()}
|
|
21259
|
+
return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21260
|
+
action: 'Get option activities',
|
|
21261
|
+
});
|
|
21127
21262
|
}
|
|
21128
21263
|
/**
|
|
21129
21264
|
* Create a long call spread (buy lower strike call, sell higher strike call)
|
|
@@ -21221,13 +21356,7 @@ class AlpacaTradingAPI {
|
|
|
21221
21356
|
position_intent: 'buy_to_open',
|
|
21222
21357
|
},
|
|
21223
21358
|
];
|
|
21224
|
-
|
|
21225
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21226
|
-
}
|
|
21227
|
-
catch (error) {
|
|
21228
|
-
this.log(`Error creating iron condor: ${error}`, { type: 'error' });
|
|
21229
|
-
throw error;
|
|
21230
|
-
}
|
|
21359
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21231
21360
|
}
|
|
21232
21361
|
/**
|
|
21233
21362
|
* Create a covered call (sell call option against owned stock)
|
|
@@ -21243,13 +21372,7 @@ class AlpacaTradingAPI {
|
|
|
21243
21372
|
});
|
|
21244
21373
|
// For covered calls, we don't need to include the stock leg if we already own the shares
|
|
21245
21374
|
// We just create a simple sell order for the call option
|
|
21246
|
-
|
|
21247
|
-
return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
21248
|
-
}
|
|
21249
|
-
catch (error) {
|
|
21250
|
-
this.log(`Error creating covered call: ${error}`, { type: 'error' });
|
|
21251
|
-
throw error;
|
|
21252
|
-
}
|
|
21375
|
+
return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
21253
21376
|
}
|
|
21254
21377
|
/**
|
|
21255
21378
|
* Roll an option position to a new expiration or strike
|
|
@@ -21284,13 +21407,7 @@ class AlpacaTradingAPI {
|
|
|
21284
21407
|
position_intent: openPositionIntent,
|
|
21285
21408
|
},
|
|
21286
21409
|
];
|
|
21287
|
-
|
|
21288
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21289
|
-
}
|
|
21290
|
-
catch (error) {
|
|
21291
|
-
this.log(`Error rolling option position: ${error}`, { type: 'error' });
|
|
21292
|
-
throw error;
|
|
21293
|
-
}
|
|
21410
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21294
21411
|
}
|
|
21295
21412
|
/**
|
|
21296
21413
|
* Get option chain for a specific underlying symbol and expiration date
|
|
@@ -21314,10 +21431,12 @@ class AlpacaTradingAPI {
|
|
|
21314
21431
|
return response.option_contracts || [];
|
|
21315
21432
|
}
|
|
21316
21433
|
catch (error) {
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21434
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21435
|
+
this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21436
|
+
type: 'error',
|
|
21437
|
+
symbol: underlyingSymbol,
|
|
21438
|
+
});
|
|
21439
|
+
}
|
|
21321
21440
|
return [];
|
|
21322
21441
|
}
|
|
21323
21442
|
}
|
|
@@ -21348,10 +21467,12 @@ class AlpacaTradingAPI {
|
|
|
21348
21467
|
return Array.from(expirationDates).sort();
|
|
21349
21468
|
}
|
|
21350
21469
|
catch (error) {
|
|
21351
|
-
|
|
21352
|
-
|
|
21353
|
-
|
|
21354
|
-
|
|
21470
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21471
|
+
this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21472
|
+
type: 'error',
|
|
21473
|
+
symbol: underlyingSymbol,
|
|
21474
|
+
});
|
|
21475
|
+
}
|
|
21355
21476
|
return [];
|
|
21356
21477
|
}
|
|
21357
21478
|
}
|
|
@@ -21410,7 +21531,10 @@ class AlpacaTradingAPI {
|
|
|
21410
21531
|
this.log(`Canceling open order for ${order.symbol}`, {
|
|
21411
21532
|
symbol: order.symbol,
|
|
21412
21533
|
});
|
|
21413
|
-
await this.makeRequest(`/orders/${order.id}`, 'DELETE'
|
|
21534
|
+
await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
|
|
21535
|
+
action: `Cancel option order ${order.id}`,
|
|
21536
|
+
symbol: order.symbol,
|
|
21537
|
+
});
|
|
21414
21538
|
}
|
|
21415
21539
|
}
|
|
21416
21540
|
}
|
|
@@ -21433,13 +21557,7 @@ class AlpacaTradingAPI {
|
|
|
21433
21557
|
const quantityToClose = qty || parseInt(position.qty);
|
|
21434
21558
|
const side = position.side === 'long' ? 'sell' : 'buy';
|
|
21435
21559
|
const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
|
|
21436
|
-
|
|
21437
|
-
return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
21438
|
-
}
|
|
21439
|
-
catch (error) {
|
|
21440
|
-
this.log(`Error closing option position: ${error}`, { type: 'error' });
|
|
21441
|
-
throw error;
|
|
21442
|
-
}
|
|
21560
|
+
return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
21443
21561
|
}
|
|
21444
21562
|
/**
|
|
21445
21563
|
* Create a complete equities trade with optional stop loss and take profit
|
|
@@ -21574,16 +21692,10 @@ class AlpacaTradingAPI {
|
|
|
21574
21692
|
this.log(logMessage, {
|
|
21575
21693
|
symbol,
|
|
21576
21694
|
});
|
|
21577
|
-
|
|
21578
|
-
|
|
21579
|
-
|
|
21580
|
-
|
|
21581
|
-
this.log(`Error creating equities trade: ${error}`, {
|
|
21582
|
-
symbol,
|
|
21583
|
-
type: 'error',
|
|
21584
|
-
});
|
|
21585
|
-
throw error;
|
|
21586
|
-
}
|
|
21695
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21696
|
+
action: 'Create equities trade',
|
|
21697
|
+
symbol,
|
|
21698
|
+
});
|
|
21587
21699
|
}
|
|
21588
21700
|
}
|
|
21589
21701
|
|