import dotenv from 'dotenv'; dotenv.config(); // eslint-disable-next-line @typescript-eslint/no-require-imports const AlpacaJS = require('@alpacahq/alpaca-trade-api') if (!process.env.ALPACA_KEY_ID || !process.env.ALPACA_SECRET_KEY) { throw new Error('Missing ALPACA_KEY_ID or ALPACA_SECRET_KEY in environment'); } const paper_credentials = { keyId : process.env.ALPACA_KEY_ID, secretKey : process.env.ALPACA_SECRET_KEY, paper : true } export interface AlpacaAccount { cash: string; } export interface AlpacaAsset { symbol: string; fractionable: boolean; status: string; asset_class: string; } export interface AlpacaClock { is_open: boolean; next_open: string; next_close: string; } export interface AlpacaQuote { AskPrice: number; BidPrice: number; } export interface AlpacaOrder { id: string; symbol: string; filled_avg_price: string; filled_qty: string; side: string; status: string; } export interface AlpacaTrade { p: number; // price s: number; // size t: string; // timestamp } export interface AlpacaClient { getAccount(): Promise; getAssets(params: { status: string; asset_class: string }): Promise; getAsset(symbol: string): Promise; getClock(): Promise; getLatestQuote(symbol: string): Promise; getLatestTrades(symbols: string[]): Promise>; createOrder(order: { symbol: string; notional: number; side: 'buy' | 'sell'; type: string; time_in_force: string; }): Promise; } export class Alpaca { private alpaca: AlpacaClient; constructor(live = false, client?: AlpacaClient) { if (client) { this.alpaca = client; } else if (live) { throw new Error("not doing live yet"); } else { this.alpaca = new AlpacaJS(paper_credentials); } } public async getAccount() { return this.alpaca.getAccount(); } public async getAssets() { return this.alpaca.getAssets({ status : 'active', asset_class : 'us_equity' }); } public async getAsset(symbol: string) { return this.alpaca.getAsset(symbol); } public async getClock() { return this.alpaca.getClock(); } public async getLatestAsk(symbol: string): Promise { const quote = await this.alpaca.getLatestQuote(symbol); return quote.AskPrice; } public async getLatestBid(symbol: string): Promise { const quote = await this.alpaca.getLatestQuote(symbol); return quote.BidPrice; } public async getLatestSpread(symbol: string): Promise { const quote = await this.alpaca.getLatestQuote(symbol); return quote.AskPrice - quote.BidPrice; } public async getLatestTrades(symbols: string[]) { return this.alpaca.getLatestTrades(symbols); } public async buy(symbol: string, dollarAmount: number): Promise { const order = await this.alpaca.createOrder({ symbol, notional: dollarAmount, side: 'buy', type: 'market', time_in_force: 'day', }); return parseFloat(order.filled_avg_price); } public async sell(symbol: string, dollarAmount: number): Promise { const order = await this.alpaca.createOrder({ symbol, notional: dollarAmount, side: 'sell', type: 'market', time_in_force: 'day', }); return parseFloat(order.filled_avg_price); } }