@discomedia/utils 1.0.63 → 1.0.64
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 +31 -5
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +31 -5
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +310 -208
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +310 -208
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +2 -2
- package/dist/test.js +310 -208
- 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/types/alpaca-types.d.ts +29 -0
- package/dist/types/types/alpaca-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/types/alpaca-types.d.ts +29 -0
- package/dist/types-frontend/types/alpaca-types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1614,7 +1614,7 @@ const safeJSON = (text) => {
|
|
|
1614
1614
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1615
1615
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1616
1616
|
|
|
1617
|
-
const VERSION = '6.
|
|
1617
|
+
const VERSION = '6.31.0'; // x-release-please-version
|
|
1618
1618
|
|
|
1619
1619
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
1620
1620
|
const isRunningInBrowser = () => {
|
|
@@ -4858,7 +4858,7 @@ class Speech extends APIResource {
|
|
|
4858
4858
|
* const speech = await client.audio.speech.create({
|
|
4859
4859
|
* input: 'input',
|
|
4860
4860
|
* model: 'string',
|
|
4861
|
-
* voice: '
|
|
4861
|
+
* voice: 'string',
|
|
4862
4862
|
* });
|
|
4863
4863
|
*
|
|
4864
4864
|
* const content = await speech.blob();
|
|
@@ -8139,7 +8139,7 @@ class Videos extends APIResource {
|
|
|
8139
8139
|
* Create a new video generation job from a prompt and optional reference assets.
|
|
8140
8140
|
*/
|
|
8141
8141
|
create(body, options) {
|
|
8142
|
-
return this._client.post('/videos',
|
|
8142
|
+
return this._client.post('/videos', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8143
8143
|
}
|
|
8144
8144
|
/**
|
|
8145
8145
|
* Fetch the latest metadata for a generated video.
|
|
@@ -8159,6 +8159,12 @@ class Videos extends APIResource {
|
|
|
8159
8159
|
delete(videoID, options) {
|
|
8160
8160
|
return this._client.delete(path `/videos/${videoID}`, options);
|
|
8161
8161
|
}
|
|
8162
|
+
/**
|
|
8163
|
+
* Create a character from an uploaded video.
|
|
8164
|
+
*/
|
|
8165
|
+
createCharacter(body, options) {
|
|
8166
|
+
return this._client.post('/videos/characters', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8167
|
+
}
|
|
8162
8168
|
/**
|
|
8163
8169
|
* Download the generated video bytes or a derived preview asset.
|
|
8164
8170
|
*
|
|
@@ -8172,6 +8178,25 @@ class Videos extends APIResource {
|
|
|
8172
8178
|
__binaryResponse: true,
|
|
8173
8179
|
});
|
|
8174
8180
|
}
|
|
8181
|
+
/**
|
|
8182
|
+
* Create a new video generation job by editing a source video or existing
|
|
8183
|
+
* generated video.
|
|
8184
|
+
*/
|
|
8185
|
+
edit(body, options) {
|
|
8186
|
+
return this._client.post('/videos/edits', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8187
|
+
}
|
|
8188
|
+
/**
|
|
8189
|
+
* Create an extension of a completed video.
|
|
8190
|
+
*/
|
|
8191
|
+
extend(body, options) {
|
|
8192
|
+
return this._client.post('/videos/extensions', multipartFormRequestOptions({ body, ...options }, this._client));
|
|
8193
|
+
}
|
|
8194
|
+
/**
|
|
8195
|
+
* Fetch a character.
|
|
8196
|
+
*/
|
|
8197
|
+
getCharacter(characterID, options) {
|
|
8198
|
+
return this._client.get(path `/videos/characters/${characterID}`, options);
|
|
8199
|
+
}
|
|
8175
8200
|
/**
|
|
8176
8201
|
* Create a remix of a completed video using a refreshed prompt.
|
|
8177
8202
|
*/
|
|
@@ -8453,8 +8478,9 @@ class OpenAI {
|
|
|
8453
8478
|
new URL(path)
|
|
8454
8479
|
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
|
|
8455
8480
|
const defaultQuery = this.defaultQuery();
|
|
8456
|
-
|
|
8457
|
-
|
|
8481
|
+
const pathQuery = Object.fromEntries(url.searchParams);
|
|
8482
|
+
if (!isEmptyObj$1(defaultQuery) || !isEmptyObj$1(pathQuery)) {
|
|
8483
|
+
query = { ...pathQuery, ...defaultQuery, ...query };
|
|
8458
8484
|
}
|
|
8459
8485
|
if (typeof query === 'object' && query && !Array.isArray(query)) {
|
|
8460
8486
|
url.search = this.stringifyQuery(query);
|
|
@@ -19037,7 +19063,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19037
19063
|
*/
|
|
19038
19064
|
async getHistoricalBars(params) {
|
|
19039
19065
|
const symbols = params.symbols;
|
|
19040
|
-
symbols.join(',');
|
|
19066
|
+
const symbolsStr = symbols.join(',');
|
|
19041
19067
|
let allBars = {};
|
|
19042
19068
|
let pageToken = null;
|
|
19043
19069
|
let hasMorePages = true;
|
|
@@ -19048,7 +19074,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19048
19074
|
symbols.forEach((symbol) => {
|
|
19049
19075
|
allBars[symbol] = [];
|
|
19050
19076
|
});
|
|
19051
|
-
log(`Starting
|
|
19077
|
+
log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
|
|
19052
19078
|
while (hasMorePages) {
|
|
19053
19079
|
pageCount++;
|
|
19054
19080
|
const requestParams = {
|
|
@@ -19059,7 +19085,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19059
19085
|
};
|
|
19060
19086
|
const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
|
|
19061
19087
|
if (!response.bars) {
|
|
19062
|
-
log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
19088
|
+
log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
|
|
19063
19089
|
break;
|
|
19064
19090
|
}
|
|
19065
19091
|
// Track currency from first response
|
|
@@ -19093,7 +19119,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19093
19119
|
const dateRangeStr = earliestTimestamp && latestTimestamp
|
|
19094
19120
|
? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
|
|
19095
19121
|
: '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' });
|
|
19122
|
+
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
19123
|
// Prevent infinite loops
|
|
19098
19124
|
if (pageCount > 1000) {
|
|
19099
19125
|
log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
@@ -19104,7 +19130,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19104
19130
|
const symbolCounts = Object.entries(allBars)
|
|
19105
19131
|
.map(([symbol, bars]) => `${symbol}: ${bars.length}`)
|
|
19106
19132
|
.join(', ');
|
|
19107
|
-
log(
|
|
19133
|
+
log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
|
|
19108
19134
|
return {
|
|
19109
19135
|
bars: allBars,
|
|
19110
19136
|
next_page_token: null, // Always null since we fetch all pages
|
|
@@ -19956,6 +19982,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
19956
19982
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|
|
19957
19983
|
|
|
19958
19984
|
const limitPriceSlippagePercent100 = 0.1; // 0.1%
|
|
19985
|
+
class AlpacaRequestError extends Error {
|
|
19986
|
+
method;
|
|
19987
|
+
status;
|
|
19988
|
+
url;
|
|
19989
|
+
responseCode;
|
|
19990
|
+
responseDetails;
|
|
19991
|
+
rawResponse;
|
|
19992
|
+
symbol;
|
|
19993
|
+
constructor(params) {
|
|
19994
|
+
super(params.message);
|
|
19995
|
+
this.name = 'AlpacaRequestError';
|
|
19996
|
+
this.method = params.method;
|
|
19997
|
+
this.status = params.status ?? null;
|
|
19998
|
+
this.url = params.url;
|
|
19999
|
+
this.responseCode = params.responseCode ?? null;
|
|
20000
|
+
this.responseDetails = params.responseDetails ?? null;
|
|
20001
|
+
this.rawResponse = params.rawResponse ?? null;
|
|
20002
|
+
this.symbol = params.symbol;
|
|
20003
|
+
}
|
|
20004
|
+
}
|
|
19959
20005
|
/**
|
|
19960
20006
|
Websocket example
|
|
19961
20007
|
const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
|
|
@@ -20039,6 +20085,75 @@ class AlpacaTradingAPI {
|
|
|
20039
20085
|
roundPriceForAlpaca = (price) => {
|
|
20040
20086
|
return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
|
|
20041
20087
|
};
|
|
20088
|
+
isJsonObject(value) {
|
|
20089
|
+
return value !== null && !Array.isArray(value) && typeof value === 'object';
|
|
20090
|
+
}
|
|
20091
|
+
parseAlpacaAPIErrorResponse(rawResponse) {
|
|
20092
|
+
if (rawResponse.trim() === '') {
|
|
20093
|
+
return null;
|
|
20094
|
+
}
|
|
20095
|
+
try {
|
|
20096
|
+
const parsedValue = JSON.parse(rawResponse);
|
|
20097
|
+
if (!this.isJsonObject(parsedValue)) {
|
|
20098
|
+
return null;
|
|
20099
|
+
}
|
|
20100
|
+
const code = parsedValue['code'];
|
|
20101
|
+
const message = parsedValue['message'];
|
|
20102
|
+
const symbol = parsedValue['symbol'];
|
|
20103
|
+
if (typeof code !== 'number' || typeof message !== 'string') {
|
|
20104
|
+
return null;
|
|
20105
|
+
}
|
|
20106
|
+
if (symbol !== undefined && typeof symbol !== 'string') {
|
|
20107
|
+
return null;
|
|
20108
|
+
}
|
|
20109
|
+
return parsedValue;
|
|
20110
|
+
}
|
|
20111
|
+
catch {
|
|
20112
|
+
return null;
|
|
20113
|
+
}
|
|
20114
|
+
}
|
|
20115
|
+
formatJsonValueForLog(value) {
|
|
20116
|
+
if (value === undefined) {
|
|
20117
|
+
return 'undefined';
|
|
20118
|
+
}
|
|
20119
|
+
if (Array.isArray(value)) {
|
|
20120
|
+
return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
|
|
20121
|
+
}
|
|
20122
|
+
if (value === null) {
|
|
20123
|
+
return 'null';
|
|
20124
|
+
}
|
|
20125
|
+
if (typeof value === 'object') {
|
|
20126
|
+
return JSON.stringify(value);
|
|
20127
|
+
}
|
|
20128
|
+
return `${value}`;
|
|
20129
|
+
}
|
|
20130
|
+
formatAlpacaAPIErrorDetails(errorResponse) {
|
|
20131
|
+
return Object.entries(errorResponse)
|
|
20132
|
+
.filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
|
|
20133
|
+
.map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
|
|
20134
|
+
.join(', ');
|
|
20135
|
+
}
|
|
20136
|
+
formatRequestAction(requestContext) {
|
|
20137
|
+
return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
|
|
20138
|
+
}
|
|
20139
|
+
buildAlpacaAPIErrorMessage(params) {
|
|
20140
|
+
const { requestContext, status, url, errorResponse, rawResponse } = params;
|
|
20141
|
+
const action = this.formatRequestAction(requestContext);
|
|
20142
|
+
const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
|
|
20143
|
+
const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
|
|
20144
|
+
const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
|
|
20145
|
+
const detailText = detailSummary !== ''
|
|
20146
|
+
? ` Details: ${detailSummary}.`
|
|
20147
|
+
: rawResponse.trim() !== '' && errorResponse === null
|
|
20148
|
+
? ` Response: ${rawResponse}.`
|
|
20149
|
+
: '';
|
|
20150
|
+
return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
|
|
20151
|
+
}
|
|
20152
|
+
buildRequestExecutionErrorMessage(params) {
|
|
20153
|
+
const { requestContext, url, errorMessage } = params;
|
|
20154
|
+
const action = this.formatRequestAction(requestContext);
|
|
20155
|
+
return `${action}: ${errorMessage}. Url: ${url}`;
|
|
20156
|
+
}
|
|
20042
20157
|
handleAuthMessage(data) {
|
|
20043
20158
|
if (data.status === 'authorized') {
|
|
20044
20159
|
this.authenticated = true;
|
|
@@ -20266,7 +20381,7 @@ class AlpacaTradingAPI {
|
|
|
20266
20381
|
this.ws?.on('message', handleListenResponse);
|
|
20267
20382
|
});
|
|
20268
20383
|
}
|
|
20269
|
-
async makeRequest(endpoint, method = 'GET', body, queryString = '') {
|
|
20384
|
+
async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
|
|
20270
20385
|
const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
|
|
20271
20386
|
try {
|
|
20272
20387
|
const response = await fetch(url, {
|
|
@@ -20275,9 +20390,27 @@ class AlpacaTradingAPI {
|
|
|
20275
20390
|
body: body ? JSON.stringify(body) : undefined,
|
|
20276
20391
|
});
|
|
20277
20392
|
if (!response.ok) {
|
|
20278
|
-
const
|
|
20279
|
-
|
|
20280
|
-
|
|
20393
|
+
const rawResponse = await response.text();
|
|
20394
|
+
const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
|
|
20395
|
+
const symbol = requestContext?.symbol ?? errorResponse?.symbol;
|
|
20396
|
+
const error = new AlpacaRequestError({
|
|
20397
|
+
message: this.buildAlpacaAPIErrorMessage({
|
|
20398
|
+
requestContext,
|
|
20399
|
+
status: response.status,
|
|
20400
|
+
url,
|
|
20401
|
+
errorResponse,
|
|
20402
|
+
rawResponse,
|
|
20403
|
+
}),
|
|
20404
|
+
method,
|
|
20405
|
+
status: response.status,
|
|
20406
|
+
url,
|
|
20407
|
+
responseCode: errorResponse?.code ?? null,
|
|
20408
|
+
responseDetails: errorResponse,
|
|
20409
|
+
rawResponse,
|
|
20410
|
+
symbol,
|
|
20411
|
+
});
|
|
20412
|
+
this.log(error.message, { symbol, type: 'error' });
|
|
20413
|
+
throw error;
|
|
20281
20414
|
}
|
|
20282
20415
|
// Handle responses with no content (e.g., 204 No Content)
|
|
20283
20416
|
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
@@ -20285,23 +20418,37 @@ class AlpacaTradingAPI {
|
|
|
20285
20418
|
}
|
|
20286
20419
|
const contentType = response.headers.get('content-type');
|
|
20287
20420
|
if (contentType && contentType.includes('application/json')) {
|
|
20288
|
-
return await response.json();
|
|
20421
|
+
return (await response.json());
|
|
20289
20422
|
}
|
|
20290
20423
|
// For non-JSON responses, return the text content
|
|
20291
20424
|
const textContent = await response.text();
|
|
20292
|
-
return textContent || null;
|
|
20425
|
+
return (textContent || null);
|
|
20293
20426
|
}
|
|
20294
|
-
catch (
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20427
|
+
catch (error) {
|
|
20428
|
+
if (error instanceof AlpacaRequestError) {
|
|
20429
|
+
throw error;
|
|
20430
|
+
}
|
|
20431
|
+
const normalizedError = error instanceof Error ? error : new Error(`${error}`);
|
|
20432
|
+
const symbol = requestContext?.symbol;
|
|
20433
|
+
const requestError = new AlpacaRequestError({
|
|
20434
|
+
message: this.buildRequestExecutionErrorMessage({
|
|
20435
|
+
requestContext,
|
|
20436
|
+
url,
|
|
20437
|
+
errorMessage: normalizedError.message,
|
|
20438
|
+
}),
|
|
20439
|
+
method,
|
|
20440
|
+
url,
|
|
20441
|
+
rawResponse: null,
|
|
20442
|
+
symbol,
|
|
20299
20443
|
});
|
|
20300
|
-
|
|
20444
|
+
this.log(requestError.message, { symbol, type: 'error' });
|
|
20445
|
+
throw requestError;
|
|
20301
20446
|
}
|
|
20302
20447
|
}
|
|
20303
20448
|
async getPositions(assetClass) {
|
|
20304
|
-
const positions =
|
|
20449
|
+
const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
|
|
20450
|
+
action: 'Get positions',
|
|
20451
|
+
});
|
|
20305
20452
|
if (assetClass) {
|
|
20306
20453
|
return positions.filter((position) => position.asset_class === assetClass);
|
|
20307
20454
|
}
|
|
@@ -20339,22 +20486,15 @@ class AlpacaTradingAPI {
|
|
|
20339
20486
|
if (params.side)
|
|
20340
20487
|
queryParams.append('side', params.side);
|
|
20341
20488
|
const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
20342
|
-
|
|
20343
|
-
|
|
20344
|
-
|
|
20345
|
-
|
|
20346
|
-
this.log(`Error getting orders: ${error}`, { type: 'error' });
|
|
20347
|
-
throw error;
|
|
20348
|
-
}
|
|
20489
|
+
return this.makeRequest(endpoint, 'GET', undefined, '', {
|
|
20490
|
+
action: 'Get orders',
|
|
20491
|
+
symbol: params.symbols?.join(','),
|
|
20492
|
+
});
|
|
20349
20493
|
}
|
|
20350
20494
|
async getAccountDetails() {
|
|
20351
|
-
|
|
20352
|
-
|
|
20353
|
-
}
|
|
20354
|
-
catch (error) {
|
|
20355
|
-
this.log(`Error getting account details: ${error}`, { type: 'error' });
|
|
20356
|
-
throw error;
|
|
20357
|
-
}
|
|
20495
|
+
return this.makeRequest('/account', 'GET', undefined, '', {
|
|
20496
|
+
action: 'Get account details',
|
|
20497
|
+
});
|
|
20358
20498
|
}
|
|
20359
20499
|
/**
|
|
20360
20500
|
* Create a trailing stop order
|
|
@@ -20372,27 +20512,21 @@ class AlpacaTradingAPI {
|
|
|
20372
20512
|
});
|
|
20373
20513
|
const body = {
|
|
20374
20514
|
symbol,
|
|
20375
|
-
qty: Math.abs(qty),
|
|
20515
|
+
qty: Math.abs(qty).toString(),
|
|
20376
20516
|
side,
|
|
20377
20517
|
position_intent,
|
|
20378
20518
|
order_class: 'simple',
|
|
20379
20519
|
type: 'trailing_stop',
|
|
20380
|
-
trail_percent: trailPercent100
|
|
20520
|
+
trail_percent: trailPercent100.toString(),
|
|
20381
20521
|
time_in_force: 'gtc',
|
|
20382
20522
|
};
|
|
20383
20523
|
if (client_order_id !== undefined) {
|
|
20384
20524
|
body.client_order_id = client_order_id;
|
|
20385
20525
|
}
|
|
20386
|
-
|
|
20387
|
-
|
|
20388
|
-
|
|
20389
|
-
|
|
20390
|
-
this.log(`Error creating trailing stop: ${error}`, {
|
|
20391
|
-
symbol,
|
|
20392
|
-
type: 'error',
|
|
20393
|
-
});
|
|
20394
|
-
throw error;
|
|
20395
|
-
}
|
|
20526
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20527
|
+
action: 'Create trailing stop order',
|
|
20528
|
+
symbol,
|
|
20529
|
+
});
|
|
20396
20530
|
}
|
|
20397
20531
|
/**
|
|
20398
20532
|
* Create a stop order (stop or stop-limit)
|
|
@@ -20418,25 +20552,19 @@ class AlpacaTradingAPI {
|
|
|
20418
20552
|
position_intent,
|
|
20419
20553
|
order_class: 'simple',
|
|
20420
20554
|
type: isStopLimit ? 'stop_limit' : 'stop',
|
|
20421
|
-
stop_price: this.roundPriceForAlpaca(stopPrice),
|
|
20555
|
+
stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
|
|
20422
20556
|
time_in_force: 'gtc',
|
|
20423
20557
|
};
|
|
20424
|
-
if (
|
|
20425
|
-
body.limit_price = this.roundPriceForAlpaca(limitPrice);
|
|
20558
|
+
if (limitPrice !== undefined) {
|
|
20559
|
+
body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
20426
20560
|
}
|
|
20427
20561
|
if (client_order_id !== undefined) {
|
|
20428
20562
|
body.client_order_id = client_order_id;
|
|
20429
20563
|
}
|
|
20430
|
-
|
|
20431
|
-
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
this.log(`Error creating ${orderType} order: ${error}`, {
|
|
20435
|
-
symbol,
|
|
20436
|
-
type: 'error',
|
|
20437
|
-
});
|
|
20438
|
-
throw error;
|
|
20439
|
-
}
|
|
20564
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20565
|
+
action: `Create ${orderType} order`,
|
|
20566
|
+
symbol,
|
|
20567
|
+
});
|
|
20440
20568
|
}
|
|
20441
20569
|
/**
|
|
20442
20570
|
* Create a market order
|
|
@@ -20462,13 +20590,10 @@ class AlpacaTradingAPI {
|
|
|
20462
20590
|
if (client_order_id !== undefined) {
|
|
20463
20591
|
body.client_order_id = client_order_id;
|
|
20464
20592
|
}
|
|
20465
|
-
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
this.log(`Error creating market order: ${error}`, { type: 'error' });
|
|
20470
|
-
throw error;
|
|
20471
|
-
}
|
|
20593
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20594
|
+
action: 'Create market order',
|
|
20595
|
+
symbol,
|
|
20596
|
+
});
|
|
20472
20597
|
}
|
|
20473
20598
|
/**
|
|
20474
20599
|
* Create a Market on Open (MOO) order - executes in the opening auction
|
|
@@ -20502,13 +20627,10 @@ class AlpacaTradingAPI {
|
|
|
20502
20627
|
if (client_order_id !== undefined) {
|
|
20503
20628
|
body.client_order_id = client_order_id;
|
|
20504
20629
|
}
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
|
|
20509
|
-
this.log(`Error creating MOO order: ${error}`, { type: 'error' });
|
|
20510
|
-
throw error;
|
|
20511
|
-
}
|
|
20630
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20631
|
+
action: 'Create market on open order',
|
|
20632
|
+
symbol,
|
|
20633
|
+
});
|
|
20512
20634
|
}
|
|
20513
20635
|
/**
|
|
20514
20636
|
* Create a Market on Close (MOC) order - executes in the closing auction
|
|
@@ -20542,13 +20664,10 @@ class AlpacaTradingAPI {
|
|
|
20542
20664
|
if (client_order_id !== undefined) {
|
|
20543
20665
|
body.client_order_id = client_order_id;
|
|
20544
20666
|
}
|
|
20545
|
-
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
this.log(`Error creating MOC order: ${error}`, { type: 'error' });
|
|
20550
|
-
throw error;
|
|
20551
|
-
}
|
|
20667
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20668
|
+
action: 'Create market on close order',
|
|
20669
|
+
symbol,
|
|
20670
|
+
});
|
|
20552
20671
|
}
|
|
20553
20672
|
/**
|
|
20554
20673
|
* Create an OCO (One-Cancels-Other) order with take profit and stop loss
|
|
@@ -20574,32 +20693,29 @@ class AlpacaTradingAPI {
|
|
|
20574
20693
|
position_intent,
|
|
20575
20694
|
order_class: 'oco',
|
|
20576
20695
|
type: 'limit',
|
|
20577
|
-
limit_price: this.roundPriceForAlpaca(limitPrice),
|
|
20696
|
+
limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
|
|
20578
20697
|
time_in_force: 'gtc',
|
|
20579
20698
|
take_profit: {
|
|
20580
|
-
limit_price: this.roundPriceForAlpaca(takeProfitPrice),
|
|
20699
|
+
limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
|
|
20581
20700
|
},
|
|
20582
20701
|
stop_loss: {
|
|
20583
|
-
stop_price: this.roundPriceForAlpaca(stopLossPrice),
|
|
20702
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20584
20703
|
},
|
|
20585
20704
|
};
|
|
20586
20705
|
// If stop loss limit price is provided, create stop-limit order
|
|
20587
20706
|
if (stopLossLimitPrice !== undefined) {
|
|
20588
|
-
body.stop_loss
|
|
20707
|
+
body.stop_loss = {
|
|
20708
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
20709
|
+
limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
|
|
20710
|
+
};
|
|
20589
20711
|
}
|
|
20590
20712
|
if (client_order_id !== undefined) {
|
|
20591
20713
|
body.client_order_id = client_order_id;
|
|
20592
20714
|
}
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
this.log(`Error creating OCO order: ${error}`, {
|
|
20598
|
-
symbol,
|
|
20599
|
-
type: 'error',
|
|
20600
|
-
});
|
|
20601
|
-
throw error;
|
|
20602
|
-
}
|
|
20715
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20716
|
+
action: 'Create OCO order',
|
|
20717
|
+
symbol,
|
|
20718
|
+
});
|
|
20603
20719
|
}
|
|
20604
20720
|
/**
|
|
20605
20721
|
* 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 +20723,26 @@ class AlpacaTradingAPI {
|
|
|
20607
20723
|
* @returns the current trail percent
|
|
20608
20724
|
*/
|
|
20609
20725
|
async getCurrentTrailPercent(symbol) {
|
|
20610
|
-
|
|
20611
|
-
|
|
20612
|
-
|
|
20613
|
-
|
|
20726
|
+
const orders = await this.getOrders({
|
|
20727
|
+
status: 'open',
|
|
20728
|
+
symbols: [symbol],
|
|
20729
|
+
});
|
|
20730
|
+
const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
|
|
20731
|
+
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
20732
|
+
if (!trailingStopOrder) {
|
|
20733
|
+
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
20734
|
+
symbol,
|
|
20614
20735
|
});
|
|
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;
|
|
20736
|
+
return null;
|
|
20631
20737
|
}
|
|
20632
|
-
|
|
20633
|
-
this.log(`
|
|
20738
|
+
if (!trailingStopOrder.trail_percent) {
|
|
20739
|
+
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
20634
20740
|
symbol,
|
|
20635
|
-
type: 'error',
|
|
20636
20741
|
});
|
|
20637
|
-
|
|
20742
|
+
return null;
|
|
20638
20743
|
}
|
|
20744
|
+
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
20745
|
+
return trailPercent;
|
|
20639
20746
|
}
|
|
20640
20747
|
/**
|
|
20641
20748
|
* Update the trail percent for a trailing stop order
|
|
@@ -20667,18 +20774,10 @@ class AlpacaTradingAPI {
|
|
|
20667
20774
|
this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
|
|
20668
20775
|
symbol,
|
|
20669
20776
|
});
|
|
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
|
-
}
|
|
20777
|
+
await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
|
|
20778
|
+
action: 'Update trailing stop order',
|
|
20779
|
+
symbol,
|
|
20780
|
+
});
|
|
20682
20781
|
}
|
|
20683
20782
|
/**
|
|
20684
20783
|
* Cancel all open orders
|
|
@@ -20686,10 +20785,16 @@ class AlpacaTradingAPI {
|
|
|
20686
20785
|
async cancelAllOrders() {
|
|
20687
20786
|
this.log(`Canceling all open orders`);
|
|
20688
20787
|
try {
|
|
20689
|
-
await this.makeRequest('/orders', 'DELETE'
|
|
20788
|
+
await this.makeRequest('/orders', 'DELETE', undefined, '', {
|
|
20789
|
+
action: 'Cancel all open orders',
|
|
20790
|
+
});
|
|
20690
20791
|
}
|
|
20691
20792
|
catch (error) {
|
|
20692
|
-
|
|
20793
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
20794
|
+
this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
20795
|
+
type: 'error',
|
|
20796
|
+
});
|
|
20797
|
+
}
|
|
20693
20798
|
}
|
|
20694
20799
|
}
|
|
20695
20800
|
/**
|
|
@@ -20701,15 +20806,14 @@ class AlpacaTradingAPI {
|
|
|
20701
20806
|
async cancelOrder(orderId) {
|
|
20702
20807
|
this.log(`Attempting to cancel order ${orderId}`);
|
|
20703
20808
|
try {
|
|
20704
|
-
await this.makeRequest(`/orders/${orderId}`, 'DELETE'
|
|
20809
|
+
await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
|
|
20810
|
+
action: `Cancel order ${orderId}`,
|
|
20811
|
+
});
|
|
20705
20812
|
this.log(`Successfully canceled order ${orderId}`);
|
|
20706
20813
|
}
|
|
20707
20814
|
catch (error) {
|
|
20708
20815
|
// 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
|
-
});
|
|
20816
|
+
if (error instanceof AlpacaRequestError && error.status === 422) {
|
|
20713
20817
|
throw new Error(`Order ${orderId} is not cancelable`);
|
|
20714
20818
|
}
|
|
20715
20819
|
// Re-throw other errors
|
|
@@ -20744,13 +20848,10 @@ class AlpacaTradingAPI {
|
|
|
20744
20848
|
if (client_order_id !== undefined) {
|
|
20745
20849
|
body.client_order_id = client_order_id;
|
|
20746
20850
|
}
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
this.log(`Error creating limit order: ${error}`, { type: 'error' });
|
|
20752
|
-
throw error;
|
|
20753
|
-
}
|
|
20851
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
20852
|
+
action: 'Create limit order',
|
|
20853
|
+
symbol,
|
|
20854
|
+
});
|
|
20754
20855
|
}
|
|
20755
20856
|
/**
|
|
20756
20857
|
* Close all equities positions
|
|
@@ -20816,7 +20917,9 @@ class AlpacaTradingAPI {
|
|
|
20816
20917
|
}
|
|
20817
20918
|
}
|
|
20818
20919
|
else {
|
|
20819
|
-
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : ''
|
|
20920
|
+
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
|
|
20921
|
+
action: 'Close all positions',
|
|
20922
|
+
});
|
|
20820
20923
|
}
|
|
20821
20924
|
}
|
|
20822
20925
|
/**
|
|
@@ -20895,7 +20998,9 @@ class AlpacaTradingAPI {
|
|
|
20895
20998
|
queryParams.append('end', params.end);
|
|
20896
20999
|
if (params.date_end)
|
|
20897
21000
|
queryParams.append('date_end', params.date_end);
|
|
20898
|
-
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}
|
|
21001
|
+
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21002
|
+
action: 'Get portfolio history',
|
|
21003
|
+
});
|
|
20899
21004
|
return response;
|
|
20900
21005
|
}
|
|
20901
21006
|
/**
|
|
@@ -20986,7 +21091,10 @@ class AlpacaTradingAPI {
|
|
|
20986
21091
|
this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
|
|
20987
21092
|
symbol: params.underlying_symbols.join(', '),
|
|
20988
21093
|
});
|
|
20989
|
-
const response =
|
|
21094
|
+
const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21095
|
+
action: 'Get option contracts',
|
|
21096
|
+
symbol: params.underlying_symbols.join(', '),
|
|
21097
|
+
});
|
|
20990
21098
|
this.log(`Found ${response.option_contracts.length} option contracts`, {
|
|
20991
21099
|
symbol: params.underlying_symbols.join(', '),
|
|
20992
21100
|
});
|
|
@@ -21001,7 +21109,10 @@ class AlpacaTradingAPI {
|
|
|
21001
21109
|
this.log(`Fetching option contract details for ${symbolOrId}`, {
|
|
21002
21110
|
symbol: symbolOrId,
|
|
21003
21111
|
});
|
|
21004
|
-
const response =
|
|
21112
|
+
const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
|
|
21113
|
+
action: 'Get option contract details',
|
|
21114
|
+
symbol: symbolOrId,
|
|
21115
|
+
});
|
|
21005
21116
|
this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
|
|
21006
21117
|
symbol: symbolOrId,
|
|
21007
21118
|
});
|
|
@@ -21019,10 +21130,10 @@ class AlpacaTradingAPI {
|
|
|
21019
21130
|
*/
|
|
21020
21131
|
async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
|
|
21021
21132
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21022
|
-
this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
|
|
21133
|
+
this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
|
|
21023
21134
|
}
|
|
21024
21135
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21025
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21136
|
+
this.log('Limit price is required for limit orders', { symbol, type: 'error' });
|
|
21026
21137
|
}
|
|
21027
21138
|
this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21028
21139
|
symbol,
|
|
@@ -21040,7 +21151,10 @@ class AlpacaTradingAPI {
|
|
|
21040
21151
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21041
21152
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21042
21153
|
}
|
|
21043
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21154
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21155
|
+
action: 'Create option order',
|
|
21156
|
+
symbol,
|
|
21157
|
+
});
|
|
21044
21158
|
}
|
|
21045
21159
|
/**
|
|
21046
21160
|
* Create a multi-leg option order
|
|
@@ -21051,16 +21165,19 @@ class AlpacaTradingAPI {
|
|
|
21051
21165
|
* @returns The created multi-leg order
|
|
21052
21166
|
*/
|
|
21053
21167
|
async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
|
|
21168
|
+
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21054
21169
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
21055
|
-
this.log('Quantity must be a positive whole number for option orders', {
|
|
21170
|
+
this.log('Quantity must be a positive whole number for option orders', {
|
|
21171
|
+
symbol: legSymbols,
|
|
21172
|
+
type: 'error',
|
|
21173
|
+
});
|
|
21056
21174
|
}
|
|
21057
21175
|
if (type === 'limit' && limitPrice === undefined) {
|
|
21058
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
21176
|
+
this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
|
|
21059
21177
|
}
|
|
21060
21178
|
if (legs.length < 2) {
|
|
21061
|
-
this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
|
|
21179
|
+
this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
|
|
21062
21180
|
}
|
|
21063
|
-
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
21064
21181
|
this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
21065
21182
|
symbol: legSymbols,
|
|
21066
21183
|
});
|
|
@@ -21074,7 +21191,10 @@ class AlpacaTradingAPI {
|
|
|
21074
21191
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
21075
21192
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
21076
21193
|
}
|
|
21077
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
21194
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21195
|
+
action: 'Create multi-leg option order',
|
|
21196
|
+
symbol: legSymbols,
|
|
21197
|
+
});
|
|
21078
21198
|
}
|
|
21079
21199
|
/**
|
|
21080
21200
|
* Exercise an option contract
|
|
@@ -21085,7 +21205,10 @@ class AlpacaTradingAPI {
|
|
|
21085
21205
|
this.log(`Exercising option contract ${symbolOrContractId}`, {
|
|
21086
21206
|
symbol: symbolOrContractId,
|
|
21087
21207
|
});
|
|
21088
|
-
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST'
|
|
21208
|
+
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
|
|
21209
|
+
action: 'Exercise option contract',
|
|
21210
|
+
symbol: symbolOrContractId,
|
|
21211
|
+
});
|
|
21089
21212
|
}
|
|
21090
21213
|
/**
|
|
21091
21214
|
* Get option positions
|
|
@@ -21121,7 +21244,9 @@ class AlpacaTradingAPI {
|
|
|
21121
21244
|
queryParams.append('date', date);
|
|
21122
21245
|
}
|
|
21123
21246
|
this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
|
|
21124
|
-
return this.makeRequest(`/account/activities?${queryParams.toString()}
|
|
21247
|
+
return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
21248
|
+
action: 'Get option activities',
|
|
21249
|
+
});
|
|
21125
21250
|
}
|
|
21126
21251
|
/**
|
|
21127
21252
|
* Create a long call spread (buy lower strike call, sell higher strike call)
|
|
@@ -21219,13 +21344,7 @@ class AlpacaTradingAPI {
|
|
|
21219
21344
|
position_intent: 'buy_to_open',
|
|
21220
21345
|
},
|
|
21221
21346
|
];
|
|
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
|
-
}
|
|
21347
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21229
21348
|
}
|
|
21230
21349
|
/**
|
|
21231
21350
|
* Create a covered call (sell call option against owned stock)
|
|
@@ -21241,13 +21360,7 @@ class AlpacaTradingAPI {
|
|
|
21241
21360
|
});
|
|
21242
21361
|
// For covered calls, we don't need to include the stock leg if we already own the shares
|
|
21243
21362
|
// 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
|
-
}
|
|
21363
|
+
return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
21251
21364
|
}
|
|
21252
21365
|
/**
|
|
21253
21366
|
* Roll an option position to a new expiration or strike
|
|
@@ -21282,13 +21395,7 @@ class AlpacaTradingAPI {
|
|
|
21282
21395
|
position_intent: openPositionIntent,
|
|
21283
21396
|
},
|
|
21284
21397
|
];
|
|
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
|
-
}
|
|
21398
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
21292
21399
|
}
|
|
21293
21400
|
/**
|
|
21294
21401
|
* Get option chain for a specific underlying symbol and expiration date
|
|
@@ -21312,10 +21419,12 @@ class AlpacaTradingAPI {
|
|
|
21312
21419
|
return response.option_contracts || [];
|
|
21313
21420
|
}
|
|
21314
21421
|
catch (error) {
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21422
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21423
|
+
this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21424
|
+
type: 'error',
|
|
21425
|
+
symbol: underlyingSymbol,
|
|
21426
|
+
});
|
|
21427
|
+
}
|
|
21319
21428
|
return [];
|
|
21320
21429
|
}
|
|
21321
21430
|
}
|
|
@@ -21346,10 +21455,12 @@ class AlpacaTradingAPI {
|
|
|
21346
21455
|
return Array.from(expirationDates).sort();
|
|
21347
21456
|
}
|
|
21348
21457
|
catch (error) {
|
|
21349
|
-
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21458
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
21459
|
+
this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
21460
|
+
type: 'error',
|
|
21461
|
+
symbol: underlyingSymbol,
|
|
21462
|
+
});
|
|
21463
|
+
}
|
|
21353
21464
|
return [];
|
|
21354
21465
|
}
|
|
21355
21466
|
}
|
|
@@ -21408,7 +21519,10 @@ class AlpacaTradingAPI {
|
|
|
21408
21519
|
this.log(`Canceling open order for ${order.symbol}`, {
|
|
21409
21520
|
symbol: order.symbol,
|
|
21410
21521
|
});
|
|
21411
|
-
await this.makeRequest(`/orders/${order.id}`, 'DELETE'
|
|
21522
|
+
await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
|
|
21523
|
+
action: `Cancel option order ${order.id}`,
|
|
21524
|
+
symbol: order.symbol,
|
|
21525
|
+
});
|
|
21412
21526
|
}
|
|
21413
21527
|
}
|
|
21414
21528
|
}
|
|
@@ -21431,13 +21545,7 @@ class AlpacaTradingAPI {
|
|
|
21431
21545
|
const quantityToClose = qty || parseInt(position.qty);
|
|
21432
21546
|
const side = position.side === 'long' ? 'sell' : 'buy';
|
|
21433
21547
|
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
|
-
}
|
|
21548
|
+
return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
21441
21549
|
}
|
|
21442
21550
|
/**
|
|
21443
21551
|
* Create a complete equities trade with optional stop loss and take profit
|
|
@@ -21572,16 +21680,10 @@ class AlpacaTradingAPI {
|
|
|
21572
21680
|
this.log(logMessage, {
|
|
21573
21681
|
symbol,
|
|
21574
21682
|
});
|
|
21575
|
-
|
|
21576
|
-
|
|
21577
|
-
|
|
21578
|
-
|
|
21579
|
-
this.log(`Error creating equities trade: ${error}`, {
|
|
21580
|
-
symbol,
|
|
21581
|
-
type: 'error',
|
|
21582
|
-
});
|
|
21583
|
-
throw error;
|
|
21584
|
-
}
|
|
21683
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
21684
|
+
action: 'Create equities trade',
|
|
21685
|
+
symbol,
|
|
21686
|
+
});
|
|
21585
21687
|
}
|
|
21586
21688
|
}
|
|
21587
21689
|
|