@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/test.js
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);
|
|
@@ -22297,7 +22323,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22297
22323
|
*/
|
|
22298
22324
|
async getHistoricalBars(params) {
|
|
22299
22325
|
const symbols = params.symbols;
|
|
22300
|
-
symbols.join(',');
|
|
22326
|
+
const symbolsStr = symbols.join(',');
|
|
22301
22327
|
let allBars = {};
|
|
22302
22328
|
let pageToken = null;
|
|
22303
22329
|
let hasMorePages = true;
|
|
@@ -22308,7 +22334,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22308
22334
|
symbols.forEach((symbol) => {
|
|
22309
22335
|
allBars[symbol] = [];
|
|
22310
22336
|
});
|
|
22311
|
-
log(`Starting
|
|
22337
|
+
log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
|
|
22312
22338
|
while (hasMorePages) {
|
|
22313
22339
|
pageCount++;
|
|
22314
22340
|
const requestParams = {
|
|
@@ -22319,7 +22345,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22319
22345
|
};
|
|
22320
22346
|
const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
|
|
22321
22347
|
if (!response.bars) {
|
|
22322
|
-
log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
22348
|
+
log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
|
|
22323
22349
|
break;
|
|
22324
22350
|
}
|
|
22325
22351
|
// Track currency from first response
|
|
@@ -22353,7 +22379,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22353
22379
|
const dateRangeStr = earliestTimestamp && latestTimestamp
|
|
22354
22380
|
? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
|
|
22355
22381
|
: 'unknown range';
|
|
22356
|
-
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
|
|
22382
|
+
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { symbol: symbolsStr, type: 'debug' });
|
|
22357
22383
|
// Prevent infinite loops
|
|
22358
22384
|
if (pageCount > 1000) {
|
|
22359
22385
|
log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
@@ -22364,7 +22390,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
22364
22390
|
const symbolCounts = Object.entries(allBars)
|
|
22365
22391
|
.map(([symbol, bars]) => `${symbol}: ${bars.length}`)
|
|
22366
22392
|
.join(', ');
|
|
22367
|
-
log(
|
|
22393
|
+
log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
|
|
22368
22394
|
return {
|
|
22369
22395
|
bars: allBars,
|
|
22370
22396
|
next_page_token: null, // Always null since we fetch all pages
|
|
@@ -23216,6 +23242,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
23216
23242
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|
|
23217
23243
|
|
|
23218
23244
|
const limitPriceSlippagePercent100 = 0.1; // 0.1%
|
|
23245
|
+
class AlpacaRequestError extends Error {
|
|
23246
|
+
method;
|
|
23247
|
+
status;
|
|
23248
|
+
url;
|
|
23249
|
+
responseCode;
|
|
23250
|
+
responseDetails;
|
|
23251
|
+
rawResponse;
|
|
23252
|
+
symbol;
|
|
23253
|
+
constructor(params) {
|
|
23254
|
+
super(params.message);
|
|
23255
|
+
this.name = 'AlpacaRequestError';
|
|
23256
|
+
this.method = params.method;
|
|
23257
|
+
this.status = params.status ?? null;
|
|
23258
|
+
this.url = params.url;
|
|
23259
|
+
this.responseCode = params.responseCode ?? null;
|
|
23260
|
+
this.responseDetails = params.responseDetails ?? null;
|
|
23261
|
+
this.rawResponse = params.rawResponse ?? null;
|
|
23262
|
+
this.symbol = params.symbol;
|
|
23263
|
+
}
|
|
23264
|
+
}
|
|
23219
23265
|
/**
|
|
23220
23266
|
Websocket example
|
|
23221
23267
|
const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
|
|
@@ -23299,6 +23345,75 @@ class AlpacaTradingAPI {
|
|
|
23299
23345
|
roundPriceForAlpaca = (price) => {
|
|
23300
23346
|
return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
|
|
23301
23347
|
};
|
|
23348
|
+
isJsonObject(value) {
|
|
23349
|
+
return value !== null && !Array.isArray(value) && typeof value === 'object';
|
|
23350
|
+
}
|
|
23351
|
+
parseAlpacaAPIErrorResponse(rawResponse) {
|
|
23352
|
+
if (rawResponse.trim() === '') {
|
|
23353
|
+
return null;
|
|
23354
|
+
}
|
|
23355
|
+
try {
|
|
23356
|
+
const parsedValue = JSON.parse(rawResponse);
|
|
23357
|
+
if (!this.isJsonObject(parsedValue)) {
|
|
23358
|
+
return null;
|
|
23359
|
+
}
|
|
23360
|
+
const code = parsedValue['code'];
|
|
23361
|
+
const message = parsedValue['message'];
|
|
23362
|
+
const symbol = parsedValue['symbol'];
|
|
23363
|
+
if (typeof code !== 'number' || typeof message !== 'string') {
|
|
23364
|
+
return null;
|
|
23365
|
+
}
|
|
23366
|
+
if (symbol !== undefined && typeof symbol !== 'string') {
|
|
23367
|
+
return null;
|
|
23368
|
+
}
|
|
23369
|
+
return parsedValue;
|
|
23370
|
+
}
|
|
23371
|
+
catch {
|
|
23372
|
+
return null;
|
|
23373
|
+
}
|
|
23374
|
+
}
|
|
23375
|
+
formatJsonValueForLog(value) {
|
|
23376
|
+
if (value === undefined) {
|
|
23377
|
+
return 'undefined';
|
|
23378
|
+
}
|
|
23379
|
+
if (Array.isArray(value)) {
|
|
23380
|
+
return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
|
|
23381
|
+
}
|
|
23382
|
+
if (value === null) {
|
|
23383
|
+
return 'null';
|
|
23384
|
+
}
|
|
23385
|
+
if (typeof value === 'object') {
|
|
23386
|
+
return JSON.stringify(value);
|
|
23387
|
+
}
|
|
23388
|
+
return `${value}`;
|
|
23389
|
+
}
|
|
23390
|
+
formatAlpacaAPIErrorDetails(errorResponse) {
|
|
23391
|
+
return Object.entries(errorResponse)
|
|
23392
|
+
.filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
|
|
23393
|
+
.map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
|
|
23394
|
+
.join(', ');
|
|
23395
|
+
}
|
|
23396
|
+
formatRequestAction(requestContext) {
|
|
23397
|
+
return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
|
|
23398
|
+
}
|
|
23399
|
+
buildAlpacaAPIErrorMessage(params) {
|
|
23400
|
+
const { requestContext, status, url, errorResponse, rawResponse } = params;
|
|
23401
|
+
const action = this.formatRequestAction(requestContext);
|
|
23402
|
+
const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
|
|
23403
|
+
const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
|
|
23404
|
+
const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
|
|
23405
|
+
const detailText = detailSummary !== ''
|
|
23406
|
+
? ` Details: ${detailSummary}.`
|
|
23407
|
+
: rawResponse.trim() !== '' && errorResponse === null
|
|
23408
|
+
? ` Response: ${rawResponse}.`
|
|
23409
|
+
: '';
|
|
23410
|
+
return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
|
|
23411
|
+
}
|
|
23412
|
+
buildRequestExecutionErrorMessage(params) {
|
|
23413
|
+
const { requestContext, url, errorMessage } = params;
|
|
23414
|
+
const action = this.formatRequestAction(requestContext);
|
|
23415
|
+
return `${action}: ${errorMessage}. Url: ${url}`;
|
|
23416
|
+
}
|
|
23302
23417
|
handleAuthMessage(data) {
|
|
23303
23418
|
if (data.status === 'authorized') {
|
|
23304
23419
|
this.authenticated = true;
|
|
@@ -23526,7 +23641,7 @@ class AlpacaTradingAPI {
|
|
|
23526
23641
|
this.ws?.on('message', handleListenResponse);
|
|
23527
23642
|
});
|
|
23528
23643
|
}
|
|
23529
|
-
async makeRequest(endpoint, method = 'GET', body, queryString = '') {
|
|
23644
|
+
async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
|
|
23530
23645
|
const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
|
|
23531
23646
|
try {
|
|
23532
23647
|
const response = await fetch(url, {
|
|
@@ -23535,9 +23650,27 @@ class AlpacaTradingAPI {
|
|
|
23535
23650
|
body: body ? JSON.stringify(body) : undefined,
|
|
23536
23651
|
});
|
|
23537
23652
|
if (!response.ok) {
|
|
23538
|
-
const
|
|
23539
|
-
|
|
23540
|
-
|
|
23653
|
+
const rawResponse = await response.text();
|
|
23654
|
+
const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
|
|
23655
|
+
const symbol = requestContext?.symbol ?? errorResponse?.symbol;
|
|
23656
|
+
const error = new AlpacaRequestError({
|
|
23657
|
+
message: this.buildAlpacaAPIErrorMessage({
|
|
23658
|
+
requestContext,
|
|
23659
|
+
status: response.status,
|
|
23660
|
+
url,
|
|
23661
|
+
errorResponse,
|
|
23662
|
+
rawResponse,
|
|
23663
|
+
}),
|
|
23664
|
+
method,
|
|
23665
|
+
status: response.status,
|
|
23666
|
+
url,
|
|
23667
|
+
responseCode: errorResponse?.code ?? null,
|
|
23668
|
+
responseDetails: errorResponse,
|
|
23669
|
+
rawResponse,
|
|
23670
|
+
symbol,
|
|
23671
|
+
});
|
|
23672
|
+
this.log(error.message, { symbol, type: 'error' });
|
|
23673
|
+
throw error;
|
|
23541
23674
|
}
|
|
23542
23675
|
// Handle responses with no content (e.g., 204 No Content)
|
|
23543
23676
|
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
@@ -23545,23 +23678,37 @@ class AlpacaTradingAPI {
|
|
|
23545
23678
|
}
|
|
23546
23679
|
const contentType = response.headers.get('content-type');
|
|
23547
23680
|
if (contentType && contentType.includes('application/json')) {
|
|
23548
|
-
return await response.json();
|
|
23681
|
+
return (await response.json());
|
|
23549
23682
|
}
|
|
23550
23683
|
// For non-JSON responses, return the text content
|
|
23551
23684
|
const textContent = await response.text();
|
|
23552
|
-
return textContent || null;
|
|
23685
|
+
return (textContent || null);
|
|
23553
23686
|
}
|
|
23554
|
-
catch (
|
|
23555
|
-
|
|
23556
|
-
|
|
23557
|
-
|
|
23558
|
-
|
|
23687
|
+
catch (error) {
|
|
23688
|
+
if (error instanceof AlpacaRequestError) {
|
|
23689
|
+
throw error;
|
|
23690
|
+
}
|
|
23691
|
+
const normalizedError = error instanceof Error ? error : new Error(`${error}`);
|
|
23692
|
+
const symbol = requestContext?.symbol;
|
|
23693
|
+
const requestError = new AlpacaRequestError({
|
|
23694
|
+
message: this.buildRequestExecutionErrorMessage({
|
|
23695
|
+
requestContext,
|
|
23696
|
+
url,
|
|
23697
|
+
errorMessage: normalizedError.message,
|
|
23698
|
+
}),
|
|
23699
|
+
method,
|
|
23700
|
+
url,
|
|
23701
|
+
rawResponse: null,
|
|
23702
|
+
symbol,
|
|
23559
23703
|
});
|
|
23560
|
-
|
|
23704
|
+
this.log(requestError.message, { symbol, type: 'error' });
|
|
23705
|
+
throw requestError;
|
|
23561
23706
|
}
|
|
23562
23707
|
}
|
|
23563
23708
|
async getPositions(assetClass) {
|
|
23564
|
-
const positions =
|
|
23709
|
+
const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
|
|
23710
|
+
action: 'Get positions',
|
|
23711
|
+
});
|
|
23565
23712
|
if (assetClass) {
|
|
23566
23713
|
return positions.filter((position) => position.asset_class === assetClass);
|
|
23567
23714
|
}
|
|
@@ -23599,22 +23746,15 @@ class AlpacaTradingAPI {
|
|
|
23599
23746
|
if (params.side)
|
|
23600
23747
|
queryParams.append('side', params.side);
|
|
23601
23748
|
const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
|
23602
|
-
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
this.log(`Error getting orders: ${error}`, { type: 'error' });
|
|
23607
|
-
throw error;
|
|
23608
|
-
}
|
|
23749
|
+
return this.makeRequest(endpoint, 'GET', undefined, '', {
|
|
23750
|
+
action: 'Get orders',
|
|
23751
|
+
symbol: params.symbols?.join(','),
|
|
23752
|
+
});
|
|
23609
23753
|
}
|
|
23610
23754
|
async getAccountDetails() {
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
}
|
|
23614
|
-
catch (error) {
|
|
23615
|
-
this.log(`Error getting account details: ${error}`, { type: 'error' });
|
|
23616
|
-
throw error;
|
|
23617
|
-
}
|
|
23755
|
+
return this.makeRequest('/account', 'GET', undefined, '', {
|
|
23756
|
+
action: 'Get account details',
|
|
23757
|
+
});
|
|
23618
23758
|
}
|
|
23619
23759
|
/**
|
|
23620
23760
|
* Create a trailing stop order
|
|
@@ -23632,27 +23772,21 @@ class AlpacaTradingAPI {
|
|
|
23632
23772
|
});
|
|
23633
23773
|
const body = {
|
|
23634
23774
|
symbol,
|
|
23635
|
-
qty: Math.abs(qty),
|
|
23775
|
+
qty: Math.abs(qty).toString(),
|
|
23636
23776
|
side,
|
|
23637
23777
|
position_intent,
|
|
23638
23778
|
order_class: 'simple',
|
|
23639
23779
|
type: 'trailing_stop',
|
|
23640
|
-
trail_percent: trailPercent100
|
|
23780
|
+
trail_percent: trailPercent100.toString(),
|
|
23641
23781
|
time_in_force: 'gtc',
|
|
23642
23782
|
};
|
|
23643
23783
|
if (client_order_id !== undefined) {
|
|
23644
23784
|
body.client_order_id = client_order_id;
|
|
23645
23785
|
}
|
|
23646
|
-
|
|
23647
|
-
|
|
23648
|
-
|
|
23649
|
-
|
|
23650
|
-
this.log(`Error creating trailing stop: ${error}`, {
|
|
23651
|
-
symbol,
|
|
23652
|
-
type: 'error',
|
|
23653
|
-
});
|
|
23654
|
-
throw error;
|
|
23655
|
-
}
|
|
23786
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23787
|
+
action: 'Create trailing stop order',
|
|
23788
|
+
symbol,
|
|
23789
|
+
});
|
|
23656
23790
|
}
|
|
23657
23791
|
/**
|
|
23658
23792
|
* Create a stop order (stop or stop-limit)
|
|
@@ -23678,25 +23812,19 @@ class AlpacaTradingAPI {
|
|
|
23678
23812
|
position_intent,
|
|
23679
23813
|
order_class: 'simple',
|
|
23680
23814
|
type: isStopLimit ? 'stop_limit' : 'stop',
|
|
23681
|
-
stop_price: this.roundPriceForAlpaca(stopPrice),
|
|
23815
|
+
stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
|
|
23682
23816
|
time_in_force: 'gtc',
|
|
23683
23817
|
};
|
|
23684
|
-
if (
|
|
23685
|
-
body.limit_price = this.roundPriceForAlpaca(limitPrice);
|
|
23818
|
+
if (limitPrice !== undefined) {
|
|
23819
|
+
body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
23686
23820
|
}
|
|
23687
23821
|
if (client_order_id !== undefined) {
|
|
23688
23822
|
body.client_order_id = client_order_id;
|
|
23689
23823
|
}
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
|
|
23694
|
-
this.log(`Error creating ${orderType} order: ${error}`, {
|
|
23695
|
-
symbol,
|
|
23696
|
-
type: 'error',
|
|
23697
|
-
});
|
|
23698
|
-
throw error;
|
|
23699
|
-
}
|
|
23824
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23825
|
+
action: `Create ${orderType} order`,
|
|
23826
|
+
symbol,
|
|
23827
|
+
});
|
|
23700
23828
|
}
|
|
23701
23829
|
/**
|
|
23702
23830
|
* Create a market order
|
|
@@ -23722,13 +23850,10 @@ class AlpacaTradingAPI {
|
|
|
23722
23850
|
if (client_order_id !== undefined) {
|
|
23723
23851
|
body.client_order_id = client_order_id;
|
|
23724
23852
|
}
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
this.log(`Error creating market order: ${error}`, { type: 'error' });
|
|
23730
|
-
throw error;
|
|
23731
|
-
}
|
|
23853
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23854
|
+
action: 'Create market order',
|
|
23855
|
+
symbol,
|
|
23856
|
+
});
|
|
23732
23857
|
}
|
|
23733
23858
|
/**
|
|
23734
23859
|
* Create a Market on Open (MOO) order - executes in the opening auction
|
|
@@ -23762,13 +23887,10 @@ class AlpacaTradingAPI {
|
|
|
23762
23887
|
if (client_order_id !== undefined) {
|
|
23763
23888
|
body.client_order_id = client_order_id;
|
|
23764
23889
|
}
|
|
23765
|
-
|
|
23766
|
-
|
|
23767
|
-
|
|
23768
|
-
|
|
23769
|
-
this.log(`Error creating MOO order: ${error}`, { type: 'error' });
|
|
23770
|
-
throw error;
|
|
23771
|
-
}
|
|
23890
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23891
|
+
action: 'Create market on open order',
|
|
23892
|
+
symbol,
|
|
23893
|
+
});
|
|
23772
23894
|
}
|
|
23773
23895
|
/**
|
|
23774
23896
|
* Create a Market on Close (MOC) order - executes in the closing auction
|
|
@@ -23802,13 +23924,10 @@ class AlpacaTradingAPI {
|
|
|
23802
23924
|
if (client_order_id !== undefined) {
|
|
23803
23925
|
body.client_order_id = client_order_id;
|
|
23804
23926
|
}
|
|
23805
|
-
|
|
23806
|
-
|
|
23807
|
-
|
|
23808
|
-
|
|
23809
|
-
this.log(`Error creating MOC order: ${error}`, { type: 'error' });
|
|
23810
|
-
throw error;
|
|
23811
|
-
}
|
|
23927
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23928
|
+
action: 'Create market on close order',
|
|
23929
|
+
symbol,
|
|
23930
|
+
});
|
|
23812
23931
|
}
|
|
23813
23932
|
/**
|
|
23814
23933
|
* Create an OCO (One-Cancels-Other) order with take profit and stop loss
|
|
@@ -23834,32 +23953,29 @@ class AlpacaTradingAPI {
|
|
|
23834
23953
|
position_intent,
|
|
23835
23954
|
order_class: 'oco',
|
|
23836
23955
|
type: 'limit',
|
|
23837
|
-
limit_price: this.roundPriceForAlpaca(limitPrice),
|
|
23956
|
+
limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
|
|
23838
23957
|
time_in_force: 'gtc',
|
|
23839
23958
|
take_profit: {
|
|
23840
|
-
limit_price: this.roundPriceForAlpaca(takeProfitPrice),
|
|
23959
|
+
limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
|
|
23841
23960
|
},
|
|
23842
23961
|
stop_loss: {
|
|
23843
|
-
stop_price: this.roundPriceForAlpaca(stopLossPrice),
|
|
23962
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
23844
23963
|
},
|
|
23845
23964
|
};
|
|
23846
23965
|
// If stop loss limit price is provided, create stop-limit order
|
|
23847
23966
|
if (stopLossLimitPrice !== undefined) {
|
|
23848
|
-
body.stop_loss
|
|
23967
|
+
body.stop_loss = {
|
|
23968
|
+
stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
|
|
23969
|
+
limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
|
|
23970
|
+
};
|
|
23849
23971
|
}
|
|
23850
23972
|
if (client_order_id !== undefined) {
|
|
23851
23973
|
body.client_order_id = client_order_id;
|
|
23852
23974
|
}
|
|
23853
|
-
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
this.log(`Error creating OCO order: ${error}`, {
|
|
23858
|
-
symbol,
|
|
23859
|
-
type: 'error',
|
|
23860
|
-
});
|
|
23861
|
-
throw error;
|
|
23862
|
-
}
|
|
23975
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
23976
|
+
action: 'Create OCO order',
|
|
23977
|
+
symbol,
|
|
23978
|
+
});
|
|
23863
23979
|
}
|
|
23864
23980
|
/**
|
|
23865
23981
|
* Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.
|
|
@@ -23867,35 +23983,26 @@ class AlpacaTradingAPI {
|
|
|
23867
23983
|
* @returns the current trail percent
|
|
23868
23984
|
*/
|
|
23869
23985
|
async getCurrentTrailPercent(symbol) {
|
|
23870
|
-
|
|
23871
|
-
|
|
23872
|
-
|
|
23873
|
-
|
|
23986
|
+
const orders = await this.getOrders({
|
|
23987
|
+
status: 'open',
|
|
23988
|
+
symbols: [symbol],
|
|
23989
|
+
});
|
|
23990
|
+
const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
|
|
23991
|
+
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
23992
|
+
if (!trailingStopOrder) {
|
|
23993
|
+
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
23994
|
+
symbol,
|
|
23874
23995
|
});
|
|
23875
|
-
|
|
23876
|
-
(order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
|
|
23877
|
-
if (!trailingStopOrder) {
|
|
23878
|
-
this.log(`No closing trailing stop order found for ${symbol}`, {
|
|
23879
|
-
symbol,
|
|
23880
|
-
});
|
|
23881
|
-
return null;
|
|
23882
|
-
}
|
|
23883
|
-
if (!trailingStopOrder.trail_percent) {
|
|
23884
|
-
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
23885
|
-
symbol,
|
|
23886
|
-
});
|
|
23887
|
-
return null;
|
|
23888
|
-
}
|
|
23889
|
-
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
23890
|
-
return trailPercent;
|
|
23996
|
+
return null;
|
|
23891
23997
|
}
|
|
23892
|
-
|
|
23893
|
-
this.log(`
|
|
23998
|
+
if (!trailingStopOrder.trail_percent) {
|
|
23999
|
+
this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
|
|
23894
24000
|
symbol,
|
|
23895
|
-
type: 'error',
|
|
23896
24001
|
});
|
|
23897
|
-
|
|
24002
|
+
return null;
|
|
23898
24003
|
}
|
|
24004
|
+
const trailPercent = parseFloat(trailingStopOrder.trail_percent);
|
|
24005
|
+
return trailPercent;
|
|
23899
24006
|
}
|
|
23900
24007
|
/**
|
|
23901
24008
|
* Update the trail percent for a trailing stop order
|
|
@@ -23927,18 +24034,10 @@ class AlpacaTradingAPI {
|
|
|
23927
24034
|
this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
|
|
23928
24035
|
symbol,
|
|
23929
24036
|
});
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
}
|
|
23935
|
-
catch (error) {
|
|
23936
|
-
this.log(`Error updating trailing stop: ${error}`, {
|
|
23937
|
-
symbol,
|
|
23938
|
-
type: 'error',
|
|
23939
|
-
});
|
|
23940
|
-
throw error;
|
|
23941
|
-
}
|
|
24037
|
+
await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
|
|
24038
|
+
action: 'Update trailing stop order',
|
|
24039
|
+
symbol,
|
|
24040
|
+
});
|
|
23942
24041
|
}
|
|
23943
24042
|
/**
|
|
23944
24043
|
* Cancel all open orders
|
|
@@ -23946,10 +24045,16 @@ class AlpacaTradingAPI {
|
|
|
23946
24045
|
async cancelAllOrders() {
|
|
23947
24046
|
this.log(`Canceling all open orders`);
|
|
23948
24047
|
try {
|
|
23949
|
-
await this.makeRequest('/orders', 'DELETE'
|
|
24048
|
+
await this.makeRequest('/orders', 'DELETE', undefined, '', {
|
|
24049
|
+
action: 'Cancel all open orders',
|
|
24050
|
+
});
|
|
23950
24051
|
}
|
|
23951
24052
|
catch (error) {
|
|
23952
|
-
|
|
24053
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24054
|
+
this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24055
|
+
type: 'error',
|
|
24056
|
+
});
|
|
24057
|
+
}
|
|
23953
24058
|
}
|
|
23954
24059
|
}
|
|
23955
24060
|
/**
|
|
@@ -23961,15 +24066,14 @@ class AlpacaTradingAPI {
|
|
|
23961
24066
|
async cancelOrder(orderId) {
|
|
23962
24067
|
this.log(`Attempting to cancel order ${orderId}`);
|
|
23963
24068
|
try {
|
|
23964
|
-
await this.makeRequest(`/orders/${orderId}`, 'DELETE'
|
|
24069
|
+
await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
|
|
24070
|
+
action: `Cancel order ${orderId}`,
|
|
24071
|
+
});
|
|
23965
24072
|
this.log(`Successfully canceled order ${orderId}`);
|
|
23966
24073
|
}
|
|
23967
24074
|
catch (error) {
|
|
23968
24075
|
// If the error is a 422, it means the order is not cancelable
|
|
23969
|
-
if (error instanceof
|
|
23970
|
-
this.log(`Order ${orderId} is not cancelable`, {
|
|
23971
|
-
type: 'error',
|
|
23972
|
-
});
|
|
24076
|
+
if (error instanceof AlpacaRequestError && error.status === 422) {
|
|
23973
24077
|
throw new Error(`Order ${orderId} is not cancelable`);
|
|
23974
24078
|
}
|
|
23975
24079
|
// Re-throw other errors
|
|
@@ -24004,13 +24108,10 @@ class AlpacaTradingAPI {
|
|
|
24004
24108
|
if (client_order_id !== undefined) {
|
|
24005
24109
|
body.client_order_id = client_order_id;
|
|
24006
24110
|
}
|
|
24007
|
-
|
|
24008
|
-
|
|
24009
|
-
|
|
24010
|
-
|
|
24011
|
-
this.log(`Error creating limit order: ${error}`, { type: 'error' });
|
|
24012
|
-
throw error;
|
|
24013
|
-
}
|
|
24111
|
+
return this.makeRequest('/orders', 'POST', body, '', {
|
|
24112
|
+
action: 'Create limit order',
|
|
24113
|
+
symbol,
|
|
24114
|
+
});
|
|
24014
24115
|
}
|
|
24015
24116
|
/**
|
|
24016
24117
|
* Close all equities positions
|
|
@@ -24076,7 +24177,9 @@ class AlpacaTradingAPI {
|
|
|
24076
24177
|
}
|
|
24077
24178
|
}
|
|
24078
24179
|
else {
|
|
24079
|
-
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : ''
|
|
24180
|
+
await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
|
|
24181
|
+
action: 'Close all positions',
|
|
24182
|
+
});
|
|
24080
24183
|
}
|
|
24081
24184
|
}
|
|
24082
24185
|
/**
|
|
@@ -24155,7 +24258,9 @@ class AlpacaTradingAPI {
|
|
|
24155
24258
|
queryParams.append('end', params.end);
|
|
24156
24259
|
if (params.date_end)
|
|
24157
24260
|
queryParams.append('date_end', params.date_end);
|
|
24158
|
-
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}
|
|
24261
|
+
const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24262
|
+
action: 'Get portfolio history',
|
|
24263
|
+
});
|
|
24159
24264
|
return response;
|
|
24160
24265
|
}
|
|
24161
24266
|
/**
|
|
@@ -24246,7 +24351,10 @@ class AlpacaTradingAPI {
|
|
|
24246
24351
|
this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
|
|
24247
24352
|
symbol: params.underlying_symbols.join(', '),
|
|
24248
24353
|
});
|
|
24249
|
-
const response =
|
|
24354
|
+
const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24355
|
+
action: 'Get option contracts',
|
|
24356
|
+
symbol: params.underlying_symbols.join(', '),
|
|
24357
|
+
});
|
|
24250
24358
|
this.log(`Found ${response.option_contracts.length} option contracts`, {
|
|
24251
24359
|
symbol: params.underlying_symbols.join(', '),
|
|
24252
24360
|
});
|
|
@@ -24261,7 +24369,10 @@ class AlpacaTradingAPI {
|
|
|
24261
24369
|
this.log(`Fetching option contract details for ${symbolOrId}`, {
|
|
24262
24370
|
symbol: symbolOrId,
|
|
24263
24371
|
});
|
|
24264
|
-
const response =
|
|
24372
|
+
const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
|
|
24373
|
+
action: 'Get option contract details',
|
|
24374
|
+
symbol: symbolOrId,
|
|
24375
|
+
});
|
|
24265
24376
|
this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
|
|
24266
24377
|
symbol: symbolOrId,
|
|
24267
24378
|
});
|
|
@@ -24279,10 +24390,10 @@ class AlpacaTradingAPI {
|
|
|
24279
24390
|
*/
|
|
24280
24391
|
async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
|
|
24281
24392
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
24282
|
-
this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
|
|
24393
|
+
this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
|
|
24283
24394
|
}
|
|
24284
24395
|
if (type === 'limit' && limitPrice === undefined) {
|
|
24285
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
24396
|
+
this.log('Limit price is required for limit orders', { symbol, type: 'error' });
|
|
24286
24397
|
}
|
|
24287
24398
|
this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
24288
24399
|
symbol,
|
|
@@ -24300,7 +24411,10 @@ class AlpacaTradingAPI {
|
|
|
24300
24411
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
24301
24412
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
24302
24413
|
}
|
|
24303
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
24414
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24415
|
+
action: 'Create option order',
|
|
24416
|
+
symbol,
|
|
24417
|
+
});
|
|
24304
24418
|
}
|
|
24305
24419
|
/**
|
|
24306
24420
|
* Create a multi-leg option order
|
|
@@ -24311,16 +24425,19 @@ class AlpacaTradingAPI {
|
|
|
24311
24425
|
* @returns The created multi-leg order
|
|
24312
24426
|
*/
|
|
24313
24427
|
async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
|
|
24428
|
+
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
24314
24429
|
if (!Number.isInteger(qty) || qty <= 0) {
|
|
24315
|
-
this.log('Quantity must be a positive whole number for option orders', {
|
|
24430
|
+
this.log('Quantity must be a positive whole number for option orders', {
|
|
24431
|
+
symbol: legSymbols,
|
|
24432
|
+
type: 'error',
|
|
24433
|
+
});
|
|
24316
24434
|
}
|
|
24317
24435
|
if (type === 'limit' && limitPrice === undefined) {
|
|
24318
|
-
this.log('Limit price is required for limit orders', { type: 'error' });
|
|
24436
|
+
this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
|
|
24319
24437
|
}
|
|
24320
24438
|
if (legs.length < 2) {
|
|
24321
|
-
this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
|
|
24439
|
+
this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
|
|
24322
24440
|
}
|
|
24323
|
-
const legSymbols = legs.map((leg) => leg.symbol).join(', ');
|
|
24324
24441
|
this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
|
|
24325
24442
|
symbol: legSymbols,
|
|
24326
24443
|
});
|
|
@@ -24334,7 +24451,10 @@ class AlpacaTradingAPI {
|
|
|
24334
24451
|
if (type === 'limit' && limitPrice !== undefined) {
|
|
24335
24452
|
orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
|
|
24336
24453
|
}
|
|
24337
|
-
return this.makeRequest('/orders', 'POST', orderData
|
|
24454
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24455
|
+
action: 'Create multi-leg option order',
|
|
24456
|
+
symbol: legSymbols,
|
|
24457
|
+
});
|
|
24338
24458
|
}
|
|
24339
24459
|
/**
|
|
24340
24460
|
* Exercise an option contract
|
|
@@ -24345,7 +24465,10 @@ class AlpacaTradingAPI {
|
|
|
24345
24465
|
this.log(`Exercising option contract ${symbolOrContractId}`, {
|
|
24346
24466
|
symbol: symbolOrContractId,
|
|
24347
24467
|
});
|
|
24348
|
-
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST'
|
|
24468
|
+
return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
|
|
24469
|
+
action: 'Exercise option contract',
|
|
24470
|
+
symbol: symbolOrContractId,
|
|
24471
|
+
});
|
|
24349
24472
|
}
|
|
24350
24473
|
/**
|
|
24351
24474
|
* Get option positions
|
|
@@ -24381,7 +24504,9 @@ class AlpacaTradingAPI {
|
|
|
24381
24504
|
queryParams.append('date', date);
|
|
24382
24505
|
}
|
|
24383
24506
|
this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
|
|
24384
|
-
return this.makeRequest(`/account/activities?${queryParams.toString()}
|
|
24507
|
+
return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
|
|
24508
|
+
action: 'Get option activities',
|
|
24509
|
+
});
|
|
24385
24510
|
}
|
|
24386
24511
|
/**
|
|
24387
24512
|
* Create a long call spread (buy lower strike call, sell higher strike call)
|
|
@@ -24479,13 +24604,7 @@ class AlpacaTradingAPI {
|
|
|
24479
24604
|
position_intent: 'buy_to_open',
|
|
24480
24605
|
},
|
|
24481
24606
|
];
|
|
24482
|
-
|
|
24483
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24484
|
-
}
|
|
24485
|
-
catch (error) {
|
|
24486
|
-
this.log(`Error creating iron condor: ${error}`, { type: 'error' });
|
|
24487
|
-
throw error;
|
|
24488
|
-
}
|
|
24607
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24489
24608
|
}
|
|
24490
24609
|
/**
|
|
24491
24610
|
* Create a covered call (sell call option against owned stock)
|
|
@@ -24501,13 +24620,7 @@ class AlpacaTradingAPI {
|
|
|
24501
24620
|
});
|
|
24502
24621
|
// For covered calls, we don't need to include the stock leg if we already own the shares
|
|
24503
24622
|
// We just create a simple sell order for the call option
|
|
24504
|
-
|
|
24505
|
-
return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
24506
|
-
}
|
|
24507
|
-
catch (error) {
|
|
24508
|
-
this.log(`Error creating covered call: ${error}`, { type: 'error' });
|
|
24509
|
-
throw error;
|
|
24510
|
-
}
|
|
24623
|
+
return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
|
|
24511
24624
|
}
|
|
24512
24625
|
/**
|
|
24513
24626
|
* Roll an option position to a new expiration or strike
|
|
@@ -24542,13 +24655,7 @@ class AlpacaTradingAPI {
|
|
|
24542
24655
|
position_intent: openPositionIntent,
|
|
24543
24656
|
},
|
|
24544
24657
|
];
|
|
24545
|
-
|
|
24546
|
-
return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24547
|
-
}
|
|
24548
|
-
catch (error) {
|
|
24549
|
-
this.log(`Error rolling option position: ${error}`, { type: 'error' });
|
|
24550
|
-
throw error;
|
|
24551
|
-
}
|
|
24658
|
+
return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
|
|
24552
24659
|
}
|
|
24553
24660
|
/**
|
|
24554
24661
|
* Get option chain for a specific underlying symbol and expiration date
|
|
@@ -24572,10 +24679,12 @@ class AlpacaTradingAPI {
|
|
|
24572
24679
|
return response.option_contracts || [];
|
|
24573
24680
|
}
|
|
24574
24681
|
catch (error) {
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24682
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24683
|
+
this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24684
|
+
type: 'error',
|
|
24685
|
+
symbol: underlyingSymbol,
|
|
24686
|
+
});
|
|
24687
|
+
}
|
|
24579
24688
|
return [];
|
|
24580
24689
|
}
|
|
24581
24690
|
}
|
|
@@ -24606,10 +24715,12 @@ class AlpacaTradingAPI {
|
|
|
24606
24715
|
return Array.from(expirationDates).sort();
|
|
24607
24716
|
}
|
|
24608
24717
|
catch (error) {
|
|
24609
|
-
|
|
24610
|
-
|
|
24611
|
-
|
|
24612
|
-
|
|
24718
|
+
if (!(error instanceof AlpacaRequestError)) {
|
|
24719
|
+
this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
|
|
24720
|
+
type: 'error',
|
|
24721
|
+
symbol: underlyingSymbol,
|
|
24722
|
+
});
|
|
24723
|
+
}
|
|
24613
24724
|
return [];
|
|
24614
24725
|
}
|
|
24615
24726
|
}
|
|
@@ -24668,7 +24779,10 @@ class AlpacaTradingAPI {
|
|
|
24668
24779
|
this.log(`Canceling open order for ${order.symbol}`, {
|
|
24669
24780
|
symbol: order.symbol,
|
|
24670
24781
|
});
|
|
24671
|
-
await this.makeRequest(`/orders/${order.id}`, 'DELETE'
|
|
24782
|
+
await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
|
|
24783
|
+
action: `Cancel option order ${order.id}`,
|
|
24784
|
+
symbol: order.symbol,
|
|
24785
|
+
});
|
|
24672
24786
|
}
|
|
24673
24787
|
}
|
|
24674
24788
|
}
|
|
@@ -24691,13 +24805,7 @@ class AlpacaTradingAPI {
|
|
|
24691
24805
|
const quantityToClose = qty || parseInt(position.qty);
|
|
24692
24806
|
const side = position.side === 'long' ? 'sell' : 'buy';
|
|
24693
24807
|
const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
|
|
24694
|
-
|
|
24695
|
-
return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
24696
|
-
}
|
|
24697
|
-
catch (error) {
|
|
24698
|
-
this.log(`Error closing option position: ${error}`, { type: 'error' });
|
|
24699
|
-
throw error;
|
|
24700
|
-
}
|
|
24808
|
+
return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
|
|
24701
24809
|
}
|
|
24702
24810
|
/**
|
|
24703
24811
|
* Create a complete equities trade with optional stop loss and take profit
|
|
@@ -24832,16 +24940,10 @@ class AlpacaTradingAPI {
|
|
|
24832
24940
|
this.log(logMessage, {
|
|
24833
24941
|
symbol,
|
|
24834
24942
|
});
|
|
24835
|
-
|
|
24836
|
-
|
|
24837
|
-
|
|
24838
|
-
|
|
24839
|
-
this.log(`Error creating equities trade: ${error}`, {
|
|
24840
|
-
symbol,
|
|
24841
|
-
type: 'error',
|
|
24842
|
-
});
|
|
24843
|
-
throw error;
|
|
24844
|
-
}
|
|
24943
|
+
return this.makeRequest('/orders', 'POST', orderData, '', {
|
|
24944
|
+
action: 'Create equities trade',
|
|
24945
|
+
symbol,
|
|
24946
|
+
});
|
|
24845
24947
|
}
|
|
24846
24948
|
}
|
|
24847
24949
|
|