@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.mjs
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);
|
|
@@ -11674,6 +11701,11 @@ const openAiModelCosts = {
|
|
|
11674
11701
|
cacheHitCost: 0.025 / 1_000_000,
|
|
11675
11702
|
outputCost: 2 / 1_000_000,
|
|
11676
11703
|
},
|
|
11704
|
+
'gpt-5.4-mini': {
|
|
11705
|
+
inputCost: 0.25 / 1_000_000,
|
|
11706
|
+
cacheHitCost: 0.025 / 1_000_000,
|
|
11707
|
+
outputCost: 2 / 1_000_000,
|
|
11708
|
+
},
|
|
11677
11709
|
'gpt-5-nano': {
|
|
11678
11710
|
inputCost: 0.05 / 1_000_000,
|
|
11679
11711
|
cacheHitCost: 0.005 / 1_000_000,
|
|
@@ -12184,6 +12216,7 @@ const isSupportedModel = (model) => {
|
|
|
12184
12216
|
'gpt-4.1-nano',
|
|
12185
12217
|
'gpt-5',
|
|
12186
12218
|
'gpt-5-mini',
|
|
12219
|
+
'gpt-5.4-mini',
|
|
12187
12220
|
'gpt-5-nano',
|
|
12188
12221
|
'gpt-5.1',
|
|
12189
12222
|
'gpt-5.4',
|
|
@@ -12212,6 +12245,7 @@ function supportsTemperature(model) {
|
|
|
12212
12245
|
'o3',
|
|
12213
12246
|
'gpt-5',
|
|
12214
12247
|
'gpt-5-mini',
|
|
12248
|
+
'gpt-5.4-mini',
|
|
12215
12249
|
'gpt-5-nano',
|
|
12216
12250
|
'gpt-5.1',
|
|
12217
12251
|
'gpt-5.4',
|
|
@@ -12241,6 +12275,7 @@ function isGPT5Model(model) {
|
|
|
12241
12275
|
const gpt5Models = [
|
|
12242
12276
|
'gpt-5',
|
|
12243
12277
|
'gpt-5-mini',
|
|
12278
|
+
'gpt-5.4-mini',
|
|
12244
12279
|
'gpt-5-nano',
|
|
12245
12280
|
'gpt-5.1',
|
|
12246
12281
|
'gpt-5.4',
|
|
@@ -12550,6 +12585,7 @@ const MULTIMODAL_VISION_MODELS = new Set([
|
|
|
12550
12585
|
'gpt-4o',
|
|
12551
12586
|
'gpt-5',
|
|
12552
12587
|
'gpt-5-mini',
|
|
12588
|
+
'gpt-5.4-mini',
|
|
12553
12589
|
'gpt-5-nano',
|
|
12554
12590
|
'gpt-5.1',
|
|
12555
12591
|
'gpt-5.4',
|
|
@@ -19037,7 +19073,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19037
19073
|
*/
|
|
19038
19074
|
async getHistoricalBars(params) {
|
|
19039
19075
|
const symbols = params.symbols;
|
|
19040
|
-
symbols.join(',');
|
|
19076
|
+
const symbolsStr = symbols.join(',');
|
|
19041
19077
|
let allBars = {};
|
|
19042
19078
|
let pageToken = null;
|
|
19043
19079
|
let hasMorePages = true;
|
|
@@ -19048,7 +19084,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19048
19084
|
symbols.forEach((symbol) => {
|
|
19049
19085
|
allBars[symbol] = [];
|
|
19050
19086
|
});
|
|
19051
|
-
log(`Starting
|
|
19087
|
+
log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
|
|
19052
19088
|
while (hasMorePages) {
|
|
19053
19089
|
pageCount++;
|
|
19054
19090
|
const requestParams = {
|
|
@@ -19059,7 +19095,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19059
19095
|
};
|
|
19060
19096
|
const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
|
|
19061
19097
|
if (!response.bars) {
|
|
19062
|
-
log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
19098
|
+
log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
|
|
19063
19099
|
break;
|
|
19064
19100
|
}
|
|
19065
19101
|
// Track currency from first response
|
|
@@ -19093,7 +19129,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19093
19129
|
const dateRangeStr = earliestTimestamp && latestTimestamp
|
|
19094
19130
|
? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
|
|
19095
19131
|
: 'unknown range';
|
|
19096
|
-
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
|
|
19132
|
+
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' });
|
|
19097
19133
|
// Prevent infinite loops
|
|
19098
19134
|
if (pageCount > 1000) {
|
|
19099
19135
|
log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
@@ -19104,7 +19140,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19104
19140
|
const symbolCounts = Object.entries(allBars)
|
|
19105
19141
|
.map(([symbol, bars]) => `${symbol}: ${bars.length}`)
|
|
19106
19142
|
.join(', ');
|
|
19107
|
-
log(
|
|
19143
|
+
log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
|
|
19108
19144
|
return {
|
|
19109
19145
|
bars: allBars,
|
|
19110
19146
|
next_page_token: null, // Always null since we fetch all pages
|
|
@@ -19956,6 +19992,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19956
19992
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|
|
19957
19993
|
|
|
19958
19994
|
const limitPriceSlippagePercent100 = 0.1; // 0.1%
|
|
19995
|
+
class AlpacaRequestError extends Error {
|
|
19996
|
+
method;
|
|
19997
|
+
status;
|
|
19998
|
+
url;
|
|
19999
|
+
responseCode;
|
|
20000
|
+
responseDetails;
|
|
20001
|
+
rawResponse;
|
|
20002
|
+
symbol;
|
|
20003
|
+
constructor(params) {
|
|
20004
|
+
super(params.message);
|
|
20005
|
+
this.name = 'AlpacaRequestError';
|
|
20006
|
+
this.method = params.method;
|
|
20007
|
+
this.status = params.status ?? null;
|
|
20008
|
+
this.url = params.url;
|
|
20009
|
+
this.responseCode = params.responseCode ?? null;
|
|
20010
|
+
this.responseDetails = params.responseDetails ?? null;
|
|
20011
|
+
this.rawResponse = params.rawResponse ?? null;
|
|
20012
|
+
this.symbol = params.symbol;
|
|
20013
|
+
}
|
|
20014
|
+
}
|
|
19959
20015
|
/**
|
|
19960
20016
|
Websocket example
|
|
19961
20017
|
const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
|
|
@@ -20039,6 +20095,75 @@ class AlpacaTradingAPI {
|
|
|
20039
20095
|
roundPriceForAlpaca = (price) => {
|
|
20040
20096
|
return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
|
|
20041
20097
|
};
|
|
20098
|
+
isJsonObject(value) {
|
|
20099
|
+
return value !== null && !Array.isArray(value) && typeof value === 'object';
|
|
20100
|
+
}
|
|
20101
|
+
parseAlpacaAPIErrorResponse(rawResponse) {
|
|
20102
|
+
if (rawResponse.trim() === '') {
|
|
20103
|
+
return null;
|
|
20104
|
+
}
|
|
20105
|
+
try {
|
|
20106
|
+
const parsedValue = JSON.parse(rawResponse);
|
|
20107
|
+
if (!this.isJsonObject(parsedValue)) {
|
|
20108
|
+
return null;
|
|
20109
|
+
}
|
|
20110
|
+
const code = parsedValue['code'];
|
|
20111
|
+
const message = parsedValue['message'];
|
|
20112
|
+
const symbol = parsedValue['symbol'];
|
|
20113
|
+
if (typeof code !== 'number' || typeof message !== 'string') {
|
|
20114
|
+
return null;
|
|
20115
|
+
}
|
|
20116
|
+
if (symbol !== undefined && typeof symbol !== 'string') {
|
|
20117
|
+
return null;
|
|
20118
|
+
}
|
|
20119
|
+
return parsedValue;
|
|
20120
|
+
}
|
|
20121
|
+
catch {
|
|
20122
|
+
return null;
|
|
20123
|
+
}
|
|
20124
|
+
}
|
|
20125
|
+
formatJsonValueForLog(value) {
|
|
20126
|
+
if (value === undefined) {
|
|
20127
|
+
return 'undefined';
|
|
20128
|
+
}
|
|
20129
|
+
if (Array.isArray(value)) {
|
|
20130
|
+
return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
|
|
20131
|
+
}
|
|
20132
|
+
if (value === null) {
|
|
20133
|
+
return 'null';
|
|
20134
|
+
}
|
|
20135
|
+
if (typeof value === 'object') {
|
|
20136
|
+
return JSON.stringify(value);
|
|
20137
|
+
}
|
|
20138
|
+
return `${value}`;
|
|
20139
|
+
}
|
|
20140
|
+
formatAlpacaAPIErrorDetails(errorResponse) {
|
|
20141
|
+
return Object.entries(errorResponse)
|
|
20142
|
+
.filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
|
|
20143
|
+
.map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
|
|
20144
|
+
.join(', ');
|
|
20145
|
+
}
|
|
20146
|
+
formatRequestAction(requestContext) {
|
|
20147
|
+
return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
|
|
20148
|
+
}
|
|
20149
|
+
buildAlpacaAPIErrorMessage(params) {
|
|
20150
|
+
const { requestContext, status, url, errorResponse, rawResponse } = params;
|
|
20151
|
+
const action = this.formatRequestAction(requestContext);
|
|
20152
|
+
const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
|
|
20153
|
+
const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
|
|
20154
|
+
const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
|
|
20155
|
+
const detailText = detailSummary !== ''
|
|
20156
|
+
? ` Details: ${detailSummary}.`
|
|
20157
|
+
: rawResponse.trim() !== '' && errorResponse === null
|
|
20158
|
+
? ` Response: ${rawResponse}.`
|
|
20159
|
+
: '';
|
|
20160
|
+
return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
|
|
20161
|
+
}
|
|
20162
|
+
buildRequestExecutionErrorMessage(params) {
|
|
20163
|
+
const { requestContext, url, errorMessage } = params;
|
|
20164
|
+
const action = this.formatRequestAction(requestContext);
|
|
20165
|
+
return `${action}: ${errorMessage}. Url: ${url}`;
|
|
20166
|
+
}
|
|
20042
20167
|
handleAuthMessage(data) {
|
|
20043
20168
|
if (data.status === 'authorized') {
|
|
20044
20169
|
this.authenticated = true;
|
|
@@ -20266,7 +20391,7 @@ class AlpacaTradingAPI {
|
|
|
20266
20391
|
this.ws?.on('message', handleListenResponse);
|
|
20267
20392
|
});
|
|
20268
20393
|
}
|
|
20269
|
-
async makeRequest(endpoint, method = 'GET', body, queryString = '') {
|
|
20394
|
+
async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
|
|
20270
20395
|
const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
|
|
20271
20396
|
try {
|
|
20272
20397
|
const response = await fetch(url, {
|
|
@@ -20275,9 +20400,27 @@ class AlpacaTradingAPI {
|
|
|
20275
20400
|
body: body ? JSON.stringify(body) : undefined,
|
|
20276
20401
|
});
|
|
20277
20402
|
if (!response.ok) {
|
|
20278
|
-
const
|
|
20279
|
-
|
|
20280
|
-
|
|
20403
|
+
const rawResponse = await response.text();
|
|
20404
|
+
const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
|
|
20405
|
+
const symbol = requestContext?.symbol ?? errorResponse?.symbol;
|
|
20406
|
+
const error = new AlpacaRequestError({
|
|
20407
|
+
message: this.buildAlpacaAPIErrorMessage({
|
|
20408
|
+
requestContext,
|
|
20409
|
+
status: response.status,
|
|
20410
|
+
url,
|
|
20411
|
+
errorResponse,
|
|
20412
|
+
rawResponse,
|
|
20413
|
+
}),
|
|
20414
|
+
method,
|
|
20415
|
+
status: response.status,
|
|
20416
|
+
url,
|
|
20417
|
+
responseCode: errorResponse?.code ?? null,
|
|
20418
|
+
responseDetails: errorResponse,
|
|
20419
|
+
rawResponse,
|
|
20420
|
+
symbol,
|
|
20421
|
+
});
|
|
20422
|
+
this.log(error.message, { symbol, type: 'error' });
|
|
20423
|
+
throw error;
|
|
20281
20424
|
}
|
|
20282
20425
|
// Handle responses with no content (e.g., 204 No Content)
|
|
20283
20426
|
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
@@ -20285,23 +20428,37 @@ class AlpacaTradingAPI {
|
|
|
20285
20428
|
}
|
|
20286
20429
|
const contentType = response.headers.get('content-type');
|
|
20287
20430
|
if (contentType && contentType.includes('application/json')) {
|
|
20288
|
-
return await response.json();
|
|
20431
|
+
return (await response.json());
|
|
20289
20432
|
}
|
|
20290
20433
|
// For non-JSON responses, return the text content
|
|
20291
20434
|
const textContent = await response.text();
|
|
20292
|
-
return textContent || null;
|
|
20435
|
+
return (textContent || null);
|
|
20293
20436
|
}
|
|
20294
|
-
catch (
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20437
|
+
catch (error) {
|
|
20438
|
+
if (error instanceof AlpacaRequestError) {
|
|
20439
|
+
throw error;
|
|
20440
|
+
}
|
|
20441
|
+
const normalizedError = error instanceof Error ? error : new Error(`${error}`);
|
|
20442
|
+
const symbol = requestContext?.symbol;
|
|
20443
|
+
const requestError = new AlpacaRequestError({
|
|
20444
|
+
message: this.buildRequestExecutionErrorMessage({
|
|
20445
|
+
requestContext,
|
|
20446
|
+
url,
|
|
20447
|
+
errorMessage: normalizedError.message,
|
|
20448
|
+
}),
|
|
20449
|
+
method,
|
|
20450
|
+
url,
|
|
20451
|
+
rawResponse: null,
|
|
20452
|
+
symbol,
|
|
20299
20453
|
});
|
|
20300
|
-
|
|
20454
|
+
this.log(requestError.message, { symbol, type: 'error' });
|
|
20455
|
+
throw requestError;
|
|
20301
20456
|
}
|
|
20302
20457
|
}
|
|
20303
20458
|
async getPositions(assetClass) {
|
|
20304
|
-
const positions =
|
|
20459
|
+
const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
|
|
20460
|
+
action: 'Get positions',
|
|
20461
|
+
});
|
|
20305
20462
|
if (assetClass) {
|
|
20306
20463
|
return positions.filter((position) => position.asset_class === assetClass);
|
|
20307
20464
|
}
|
|
@@ -20339,22 +20496,15 @@ class AlpacaTradingAPI {
|
|
|
20339
20496
|
if (params.side)
|
|
20340
20497
|
queryParams.append('side', params.side);
|
|
20341
20498
|
const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
20342
|
-
|
|
20343
|
-
|
|
20344
|
-
|
|
20345
|
-
|
|
20346
|
-
this.log(`Error getting orders: ${error}`, { type: 'error' });
|
|
20347
|
-
throw error;
|
|
20348
|
-
}
|
|
20499
|
+
return this.makeRequest(endpoint, 'GET', undefined, '', {
|
|
20500
|
+
action: 'Get orders',
|
|
20501
|
+
symbol: params.symbols?.join(','),
|
|
20502
|
+
});
|
|
20349
20503
|
}
|
|
20350
20504
|
async getAccountDetails() {
|
|
20351
|
-
|
|
20352
|
-
|
|
20353
|
-
}
|
|
20354
|
-
catch (error) {
|
|
20355
|
-
this.log(`Error getting account details: ${error}`, { type: 'error' });
|
|
20356
|
-
throw error;
|
|
20357
|
-
}
|
|
20505
|
+
return this.makeRequest('/account', 'GET', undefined, '', {
|
|
20506
|
+
action: 'Get account details',
|
|
20507
|
+
});
|
|
20358
20508
|
}
|
|
20359
20509
|
/**
|
|
20360
20510
|
* Create a trailing stop order
|
|
@@ -20372,27 +20522,21 @@ class AlpacaTradingAPI {
|
|
|
20372
20522
|
});
|
|
20373
20523
|
const body = {
|
|
20374
20524
|
symbol,
|
|
20375
|
-
qty: Math.abs(qty),
|
|
20525
|
+
qty: Math.abs(qty).toString(),
|
|
20376
20526
|
side,
|
|
20377
20527
|
position_intent,
|
|
20378
20528
|
order_class: 'simple',
|
|
20379
20529
|
type: 'trailing_stop',
|
|
20380
|
-
trail_percent: trailPercent100
|
|
20530
|
+
trail_percent: trailPercent100.toString(),
|
|
20381
20531
|
time_in_force: 'gtc',
|
|
20382
20532
|
};
|
|
20383
20533
|
if (client_order_id !== undefined) {
|
|
20384
20534
|
body.client_order_id = client_order_id;
|
|
20385
20535
|
}
|
|
20386
|
-
|
|
20387
|
-
|
|
20388
|
-
|
|
20389
|
-
|
|
20390
|
-
this.log(`Error creating trailing stop: ${error}`, {
|
|
20391
|
-
symbol,
|
|
20392
|
-
type: 'error',
|
|
20393
|
-
});
|
|
20394
|
-
throw error;
|
|
20395
|
-
}
|
|
20536
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20537
|
+
action: 'Create trailing stop order',
|
|
20538
|
+
symbol,
|
|
20539
|
+
});
|
|
20396
20540
|
}
|
|
20397
20541
|
/**
|
|
20398
20542
|
* Create a stop order (stop or stop-limit)
|
|
@@ -20418,25 +20562,19 @@ class AlpacaTradingAPI {
|
|
|
20418
20562
|
position_intent,
|
|
20419
20563
|
order_class: 'simple',
|
|
20420
20564
|
type: isStopLimit ? 'stop_limit' : 'stop',
|
|
20421
|
-
stop_price: this.roundPriceForAlpaca(stopPrice),
|
|
20565
|
+
stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
|
|
20422
20566
|
time_in_force: 'gtc',
|
|
20423
20567
|
};
|
|
20424
|
-
if (
|
|
20425
|
-
body.limit_price = this.roundPriceForAlpaca(limitPrice);
|
|
20568
|
+
if (limitPrice !== undefined) {
|
|
20569
|
+
body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
20426
20570
|
}
|
|
20427
20571
|
if (client_order_id !== undefined) {
|
|
20428
20572
|
body.client_order_id = client_order_id;
|
|
20429
20573
|
}
|
|
20430
|
-
|
|
20431
|
-
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
this.log(`Error creating ${orderType} order: ${error}`, {
|
|
20435
|
-
symbol,
|
|
20436
|
-
type: 'error',
|
|
20437
|
-
});
|
|
20438
|
-
throw error;
|
|
20439
|
-
}
|
|
20574
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20575
|
+
action: `Create ${orderType} order`,
|
|
20576
|
+
symbol,
|
|
20577
|
+
});
|
|
20440
20578
|
}
|
|
20441
20579
|
/**
|
|
20442
20580
|
* Create a market order
|
|
@@ -20462,13 +20600,10 @@ class AlpacaTradingAPI {
|
|
|
20462
20600
|
if (client_order_id !== undefined) {
|
|
20463
20601
|
body.client_order_id = client_order_id;
|
|
20464
20602
|
}
|
|
20465
|
-
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
this.log(`Error creating market order: ${error}`, { type: 'error' });
|
|
20470
|
-
throw error;
|
|
20471
|
-
}
|
|
20603
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20604
|
+
action: 'Create market order',
|
|
20605
|
+
symbol,
|
|
20606
|
+
});
|
|
20472
20607
|
}
|
|
20473
20608
|
/**
|
|
20474
20609
|
* Create a Market on Open (MOO) order - executes in the opening auction
|
|
@@ -20502,13 +20637,10 @@ class AlpacaTradingAPI {
|
|
|
20502
20637
|
if (client_order_id !== undefined) {
|
|
20503
20638
|
body.client_order_id = client_order_id;
|
|
20504
20639
|
}
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
|
|
20509
|
-
this.log(`Error creating MOO order: ${error}`, { type: 'error' });
|
|
20510
|
-
throw error;
|
|
20511
|
-
}
|
|
20640
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20641
|
+
action: 'Create market on open order',
|
|
20642
|
+
symbol,
|
|
20643
|
+
});
|
|
20512
20644
|
}
|
|
20513
20645
|
/**
|
|
20514
20646
|
* Create a Market on Close (MOC) order - executes in the closing auction
|
|
@@ -20542,13 +20674,10 @@ class AlpacaTradingAPI {
|
|
|
20542
20674
|
if (client_order_id !== undefined) {
|
|
20543
20675
|
body.client_order_id = client_order_id;
|
|
20544
20676
|
}
|
|
20545
|
-
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
this.log(`Error creating MOC order: ${error}`, { type: 'error' });
|
|
20550
|
-
throw error;
|
|
20551
|
-
}
|
|
20677
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20678
|
+
action: 'Create market on close order',
|
|
20679
|
+
symbol,
|
|
20680
|
+
});
|
|
20552
20681
|
}
|
|
20553
20682
|
/**
|
|
20554
20683
|
* Create an OCO (One-Cancels-Other) order with take profit and stop loss
|
|
@@ -20574,32 +20703,29 @@ class AlpacaTradingAPI {
|
|
|
20574
20703
|
position_intent,
|
|
20575
20704
|
order_class: 'oco',
|
|
20576
20705
|
type: 'limit',
|
|
20577
|
-
limit_price: this.roundPriceForAlpaca(limitPrice),
|
|
20706
|
+
limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
|
|
20578
20707
|
time_in_force: 'gtc',
|
|
20579
20708
|
take_profit: {
|
|
20580
|
-
limit_price: this.roundPriceForAlpaca(takeProfitPrice),
|
|
20709
|
+
limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
|
|
20581
20710
|
},
|
|
20582
20711
|
stop_loss: {
|
|
20583
|
-
stop_price: this.roundPriceForAlpaca(stopLossPrice),
|
|
20712
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20584
20713
|
},
|
|
20585
20714
|
};
|
|
20586
20715
|
// If stop loss limit price is provided, create stop-limit order
|
|
20587
20716
|
if (stopLossLimitPrice !== undefined) {
|
|
20588
|
-
body.stop_loss
|
|
20717
|
+
body.stop_loss = {
|
|
20718
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20719
|
+
limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
|
|
20720
|
+
};
|
|
20589
20721
|
}
|
|
20590
20722
|
if (client_order_id !== undefined) {
|
|
20591
20723
|
body.client_order_id = client_order_id;
|
|
20592
20724
|
}
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
this.log(`Error creating OCO order: ${error}`, {
|
|
20598
|
-
symbol,
|
|
20599
|
-
type: 'error',
|
|
20600
|
-
});
|
|
20601
|
-
throw error;
|
|
20602
|
-
}
|
|
20725
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20726
|
+
action: 'Create OCO order',
|
|
20727
|
+
symbol,
|
|
20728
|
+
});
|
|
20603
20729
|
}
|
|
20604
20730
|
/**
|
|
20605
20731
|
* 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.
|
|
@@ -20607,35 +20733,26 @@ class AlpacaTradingAPI {
|
|
|
20607
20733
|
* @returns the current trail percent
|
|
20608
20734
|
*/
|
|
20609
20735
|
async getCurrentTrailPercent(symbol) {
|
|
20610
|
-
|
|
20611
|
-
|
|
20612
|
-
|
|
20613
|
-
|
|
20736
|
+
const orders = await this.getOrders({
|
|
20737
|
+
status: 'open',
|
|
20738
|
+
symbols: [symbol],
|
|
20739
|
+
});
|
|
20740
|
+
const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
|
|
20741
|
+
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
20742
|
+
if (!trailingStopOrder) {
|
|
20743
|
+
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
20744
|
+
symbol,
|
|
20614
20745
|
});
|
|
20615
|
-
|
|
20616
|
-
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
20617
|
-
if (!trailingStopOrder) {
|
|
20618
|
-
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
20619
|
-
symbol,
|
|
20620
|
-
});
|
|
20621
|
-
return null;
|
|
20622
|
-
}
|
|
20623
|
-
if (!trailingStopOrder.trail_percent) {
|
|
20624
|
-
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
20625
|
-
symbol,
|
|
20626
|
-
});
|
|
20627
|
-
return null;
|
|
20628
|
-
}
|
|
20629
|
-
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
20630
|
-
return trailPercent;
|
|
20746
|
+
return null;
|
|
20631
20747
|
}
|
|
20632
|
-
|
|
20633
|
-
this.log(`
|
|
20748
|
+
if (!trailingStopOrder.trail_percent) {
|
|
20749
|
+
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
20634
20750
|
symbol,
|
|
20635
|
-
type: 'error',
|
|
20636
20751
|
});
|
|
20637
|
-
|
|
20752
|
+
return null;
|
|
20638
20753
|
}
|
|
20754
|
+
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
20755
|
+
return trailPercent;
|
|
20639
20756
|
}
|
|
20640
20757
|
/**
|
|
20641
20758
|
* Update the trail percent for a trailing stop order
|
|
@@ -20667,18 +20784,10 @@ class AlpacaTradingAPI {
|
|
|
20667
20784
|
this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
|
|
20668
20785
|
symbol,
|
|
20669
20786
|
});
|
|
20670
|
-
|
|
20671
|
-
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
}
|
|
20675
|
-
catch (error) {
|
|
20676
|
-
this.log(`Error updating trailing stop: ${error}`, {
|
|
20677
|
-
symbol,
|
|
20678
|
-
type: 'error',
|
|
20679
|
-
});
|
|
20680
|
-
throw error;
|
|
20681
|
-
}
|
|
20787
|
+
await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
|
|
20788
|
+
action: 'Update trailing stop order',
|
|
20789
|
+
symbol,
|
|
20790
|
+
});
|
|
20682
20791
|
}
|
|
20683
20792
|
/**
|
|
20684
20793
|
* Cancel all open orders
|
|
@@ -20686,10 +20795,16 @@ class AlpacaTradingAPI {
|
|
|
20686
20795
|
async cancelAllOrders() {
|
|
20687
20796
|
this.log(`Canceling all open orders`);
|
|
20688
20797
|
try {
|
|
20689
|
-
await this.makeRequest('/orders', 'DELETE'
|
|
20798
|
+
await this.makeRequest('/orders', 'DELETE', undefined, '', {
|
|
20799
|
+
action: 'Cancel all open orders',
|
|
20800
|
+
});
|
|
20690
20801
|
}
|
|
20691
20802
|
catch (error) {
|
|
20692
|
-
|
|
20803
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
20804
|
+
this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
20805
|
+
type: 'error',
|
|
20806
|
+
});
|
|
20807
|
+
}
|
|
20693
20808
|
}
|
|
20694
20809
|
}
|
|
20695
20810
|
/**
|
|
@@ -20701,15 +20816,14 @@ class AlpacaTradingAPI {
|
|
|
20701
20816
|
async cancelOrder(orderId) {
|
|
20702
20817
|
this.log(`Attempting to cancel order ${orderId}`);
|
|
20703
20818
|
try {
|
|
20704
|
-
await this.makeRequest(`/orders/${orderId}`, 'DELETE'
|
|
20819
|
+
await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
|
|
20820
|
+
action: `Cancel order ${orderId}`,
|
|
20821
|
+
});
|
|
20705
20822
|
this.log(`Successfully canceled order ${orderId}`);
|
|
20706
20823
|
}
|
|
20707
20824
|
catch (error) {
|
|
20708
20825
|
// If the error is a 422, it means the order is not cancelable
|
|
20709
|
-
if (error instanceof
|
|
20710
|
-
this.log(`Order ${orderId} is not cancelable`, {
|
|
20711
|
-
type: 'error',
|
|
20712
|
-
});
|
|
20826
|
+
if (error instanceof AlpacaRequestError && error.status === 422) {
|
|
20713
20827
|
throw new Error(`Order ${orderId} is not cancelable`);
|
|
20714
20828
|
}
|
|
20715
20829
|
// Re-throw other errors
|
|
@@ -20744,13 +20858,10 @@ class AlpacaTradingAPI {
|
|
|
20744
20858
|
if (client_order_id !== undefined) {
|
|
20745
20859
|
body.client_order_id = client_order_id;
|
|
20746
20860
|
}
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
this.log(`Error creating limit order: ${error}`, { type: 'error' });
|
|
20752
|
-
throw error;
|
|
20753
|
-
}
|
|
20861
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20862
|
+
action: 'Create limit order',
|
|
20863
|
+
symbol,
|
|
20864
|
+
});
|
|
20754
20865
|
}
|
|
20755
20866
|
/**
|
|
20756
20867
|
* Close all equities positions
|
|
@@ -20816,7 +20927,9 @@ class AlpacaTradingAPI {
|
|
|
20816
20927
|
}
|
|
20817
20928
|
}
|
|
20818
20929
|
else {
|
|
20819
|
-
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : ''
|
|
20930
|
+
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
|
|
20931
|
+
action: 'Close all positions',
|
|
20932
|
+
});
|
|
20820
20933
|
}
|
|
20821
20934
|
}
|
|
20822
20935
|
/**
|
|
@@ -20895,7 +21008,9 @@ class AlpacaTradingAPI {
|
|
|
20895
21008
|
queryParams.append('end', params.end);
|
|
20896
21009
|
if (params.date_end)
|
|
20897
21010
|
queryParams.append('date_end', params.date_end);
|
|
20898
|
-
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}
|
|
21011
|
+
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21012
|
+
action: 'Get portfolio history',
|
|
21013
|
+
});
|
|
20899
21014
|
return response;
|
|
20900
21015
|
}
|
|
20901
21016
|
/**
|
|
@@ -20986,7 +21101,10 @@ class AlpacaTradingAPI {
|
|
|
20986
21101
|
this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
|
|
20987
21102
|
symbol: params.underlying_symbols.join(', '),
|
|
20988
21103
|
});
|
|
20989
|
-
const response =
|
|
21104
|
+
const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21105
|
+
action: 'Get option contracts',
|
|
21106
|
+
symbol: params.underlying_symbols.join(', '),
|
|
21107
|
+
});
|
|
20990
21108
|
this.log(`Found ${response.option_contracts.length} option contracts`, {
|
|
20991
21109
|
symbol: params.underlying_symbols.join(', '),
|
|
20992
21110
|
});
|
|
@@ -21001,7 +21119,10 @@ class AlpacaTradingAPI {
|
|
|
21001
21119
|
this.log(`Fetching option contract details for ${symbolOrId}`, {
|
|
21002
21120
|
symbol: symbolOrId,
|
|
21003
21121
|
});
|
|
21004
|
-
const response =
|
|
21122
|
+
const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
|
|
21123
|
+
action: 'Get option contract details',
|
|
21124
|
+
symbol: symbolOrId,
|
|
21125
|
+
});
|
|
21005
21126
|
this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
|
|
21006
21127
|
symbol: symbolOrId,
|
|
21007
21128
|
});
|
|
@@ -21019,10 +21140,10 @@ class AlpacaTradingAPI {
|
|
|
21019
21140
|
*/
|
|
21020
21141
|
async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
|
|
21021
21142
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21022
|
-
this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
|
|
21143
|
+
this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
|
|
21023
21144
|
}
|
|
21024
21145
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21025
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21146
|
+
this.log('Limit price is required for limit orders', { symbol, type: 'error' });
|
|
21026
21147
|
}
|
|
21027
21148
|
this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21028
21149
|
symbol,
|
|
@@ -21040,7 +21161,10 @@ class AlpacaTradingAPI {
|
|
|
21040
21161
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21041
21162
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21042
21163
|
}
|
|
21043
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21164
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21165
|
+
action: 'Create option order',
|
|
21166
|
+
symbol,
|
|
21167
|
+
});
|
|
21044
21168
|
}
|
|
21045
21169
|
/**
|
|
21046
21170
|
* Create a multi-leg option order
|
|
@@ -21051,16 +21175,19 @@ class AlpacaTradingAPI {
|
|
|
21051
21175
|
* @returns The created multi-leg order
|
|
21052
21176
|
*/
|
|
21053
21177
|
async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
|
|
21178
|
+
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21054
21179
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21055
|
-
this.log('Quantity must be a positive whole number for option orders', {
|
|
21180
|
+
this.log('Quantity must be a positive whole number for option orders', {
|
|
21181
|
+
symbol: legSymbols,
|
|
21182
|
+
type: 'error',
|
|
21183
|
+
});
|
|
21056
21184
|
}
|
|
21057
21185
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21058
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21186
|
+
this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
|
|
21059
21187
|
}
|
|
21060
21188
|
if (legs.length < 2) {
|
|
21061
|
-
this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
|
|
21189
|
+
this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
|
|
21062
21190
|
}
|
|
21063
|
-
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21064
21191
|
this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21065
21192
|
symbol: legSymbols,
|
|
21066
21193
|
});
|
|
@@ -21074,7 +21201,10 @@ class AlpacaTradingAPI {
|
|
|
21074
21201
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21075
21202
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21076
21203
|
}
|
|
21077
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21204
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21205
|
+
action: 'Create multi-leg option order',
|
|
21206
|
+
symbol: legSymbols,
|
|
21207
|
+
});
|
|
21078
21208
|
}
|
|
21079
21209
|
/**
|
|
21080
21210
|
* Exercise an option contract
|
|
@@ -21085,7 +21215,10 @@ class AlpacaTradingAPI {
|
|
|
21085
21215
|
this.log(`Exercising option contract ${symbolOrContractId}`, {
|
|
21086
21216
|
symbol: symbolOrContractId,
|
|
21087
21217
|
});
|
|
21088
|
-
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST'
|
|
21218
|
+
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
|
|
21219
|
+
action: 'Exercise option contract',
|
|
21220
|
+
symbol: symbolOrContractId,
|
|
21221
|
+
});
|
|
21089
21222
|
}
|
|
21090
21223
|
/**
|
|
21091
21224
|
* Get option positions
|
|
@@ -21121,7 +21254,9 @@ class AlpacaTradingAPI {
|
|
|
21121
21254
|
queryParams.append('date', date);
|
|
21122
21255
|
}
|
|
21123
21256
|
this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
|
|
21124
|
-
return this.makeRequest(`/account/activities?${queryParams.toString()}
|
|
21257
|
+
return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21258
|
+
action: 'Get option activities',
|
|
21259
|
+
});
|
|
21125
21260
|
}
|
|
21126
21261
|
/**
|
|
21127
21262
|
* Create a long call spread (buy lower strike call, sell higher strike call)
|
|
@@ -21219,13 +21354,7 @@ class AlpacaTradingAPI {
|
|
|
21219
21354
|
position_intent: 'buy_to_open',
|
|
21220
21355
|
},
|
|
21221
21356
|
];
|
|
21222
|
-
|
|
21223
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21224
|
-
}
|
|
21225
|
-
catch (error) {
|
|
21226
|
-
this.log(`Error creating iron condor: ${error}`, { type: 'error' });
|
|
21227
|
-
throw error;
|
|
21228
|
-
}
|
|
21357
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21229
21358
|
}
|
|
21230
21359
|
/**
|
|
21231
21360
|
* Create a covered call (sell call option against owned stock)
|
|
@@ -21241,13 +21370,7 @@ class AlpacaTradingAPI {
|
|
|
21241
21370
|
});
|
|
21242
21371
|
// For covered calls, we don't need to include the stock leg if we already own the shares
|
|
21243
21372
|
// We just create a simple sell order for the call option
|
|
21244
|
-
|
|
21245
|
-
return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
21246
|
-
}
|
|
21247
|
-
catch (error) {
|
|
21248
|
-
this.log(`Error creating covered call: ${error}`, { type: 'error' });
|
|
21249
|
-
throw error;
|
|
21250
|
-
}
|
|
21373
|
+
return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
21251
21374
|
}
|
|
21252
21375
|
/**
|
|
21253
21376
|
* Roll an option position to a new expiration or strike
|
|
@@ -21282,13 +21405,7 @@ class AlpacaTradingAPI {
|
|
|
21282
21405
|
position_intent: openPositionIntent,
|
|
21283
21406
|
},
|
|
21284
21407
|
];
|
|
21285
|
-
|
|
21286
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21287
|
-
}
|
|
21288
|
-
catch (error) {
|
|
21289
|
-
this.log(`Error rolling option position: ${error}`, { type: 'error' });
|
|
21290
|
-
throw error;
|
|
21291
|
-
}
|
|
21408
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21292
21409
|
}
|
|
21293
21410
|
/**
|
|
21294
21411
|
* Get option chain for a specific underlying symbol and expiration date
|
|
@@ -21312,10 +21429,12 @@ class AlpacaTradingAPI {
|
|
|
21312
21429
|
return response.option_contracts || [];
|
|
21313
21430
|
}
|
|
21314
21431
|
catch (error) {
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21432
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21433
|
+
this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21434
|
+
type: 'error',
|
|
21435
|
+
symbol: underlyingSymbol,
|
|
21436
|
+
});
|
|
21437
|
+
}
|
|
21319
21438
|
return [];
|
|
21320
21439
|
}
|
|
21321
21440
|
}
|
|
@@ -21346,10 +21465,12 @@ class AlpacaTradingAPI {
|
|
|
21346
21465
|
return Array.from(expirationDates).sort();
|
|
21347
21466
|
}
|
|
21348
21467
|
catch (error) {
|
|
21349
|
-
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21468
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21469
|
+
this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21470
|
+
type: 'error',
|
|
21471
|
+
symbol: underlyingSymbol,
|
|
21472
|
+
});
|
|
21473
|
+
}
|
|
21353
21474
|
return [];
|
|
21354
21475
|
}
|
|
21355
21476
|
}
|
|
@@ -21408,7 +21529,10 @@ class AlpacaTradingAPI {
|
|
|
21408
21529
|
this.log(`Canceling open order for ${order.symbol}`, {
|
|
21409
21530
|
symbol: order.symbol,
|
|
21410
21531
|
});
|
|
21411
|
-
await this.makeRequest(`/orders/${order.id}`, 'DELETE'
|
|
21532
|
+
await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
|
|
21533
|
+
action: `Cancel option order ${order.id}`,
|
|
21534
|
+
symbol: order.symbol,
|
|
21535
|
+
});
|
|
21412
21536
|
}
|
|
21413
21537
|
}
|
|
21414
21538
|
}
|
|
@@ -21431,13 +21555,7 @@ class AlpacaTradingAPI {
|
|
|
21431
21555
|
const quantityToClose = qty || parseInt(position.qty);
|
|
21432
21556
|
const side = position.side === 'long' ? 'sell' : 'buy';
|
|
21433
21557
|
const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
|
|
21434
|
-
|
|
21435
|
-
return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
21436
|
-
}
|
|
21437
|
-
catch (error) {
|
|
21438
|
-
this.log(`Error closing option position: ${error}`, { type: 'error' });
|
|
21439
|
-
throw error;
|
|
21440
|
-
}
|
|
21558
|
+
return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
21441
21559
|
}
|
|
21442
21560
|
/**
|
|
21443
21561
|
* Create a complete equities trade with optional stop loss and take profit
|
|
@@ -21572,16 +21690,10 @@ class AlpacaTradingAPI {
|
|
|
21572
21690
|
this.log(logMessage, {
|
|
21573
21691
|
symbol,
|
|
21574
21692
|
});
|
|
21575
|
-
|
|
21576
|
-
|
|
21577
|
-
|
|
21578
|
-
|
|
21579
|
-
this.log(`Error creating equities trade: ${error}`, {
|
|
21580
|
-
symbol,
|
|
21581
|
-
type: 'error',
|
|
21582
|
-
});
|
|
21583
|
-
throw error;
|
|
21584
|
-
}
|
|
21693
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21694
|
+
action: 'Create equities trade',
|
|
21695
|
+
symbol,
|
|
21696
|
+
});
|
|
21585
21697
|
}
|
|
21586
21698
|
}
|
|
21587
21699
|
|