This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Alpaca = require('@alpacahq/alpaca-trade-api') | |
const getKeyId = () => process.env.APCA_API_KEY_ID | |
const getSecretKey = () => process.env.APCA_API_SECRET_KEY | |
export const alpaca = new Alpaca({ | |
keyId: getKeyId(), | |
secretKey: getSecretKey(), | |
paper: false, | |
usePolygon: false, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'lodash' | |
import { alpaca } from './alpacaCxn' | |
const getTicker = () => process.env.TICKER | |
const setupAccountInfo = async () => { | |
const account = await alpaca.getAccount() | |
const buyingPower = parseFloat(account.buying_power) | |
const orders = await alpaca.getOrders() | |
const hasOrders = orders.length > 0 | |
const clock = await alpaca.getClock() | |
const isMarketOpen = clock.is_open | |
console.log( | |
`Info: buying power= ${buyingPower}, hasOrders= ${hasOrders}, isMarketOpen= ${isMarketOpen}`, | |
) | |
return { | |
buyingPower, | |
hasOrders, | |
isMarketOpen, | |
} | |
} | |
/** | |
* { last: | |
{ askexchange: 8, | |
askprice: 40.97, | |
asksize: 1, | |
bidexchange: 11, | |
bidprice: 40.94, | |
bidsize: 1, | |
timestamp: 1597449403326 }, | |
status: 'success', | |
symbol: 'GDX' } | |
*/ | |
const getQuoteForSymbol = async () => { | |
const ticker = getTicker() | |
console.log(`Looking up ticker: ${ticker}`) | |
const quote = await alpaca.getLastQuote(ticker) | |
console.log('Ticker quote', quote) | |
const result = { | |
quote, | |
ticker, | |
bid: quote.last.bidprice, | |
isSuccess: quote.status === 'success', | |
} | |
console.log('Result', result) | |
return result | |
} | |
const generateOrdersToEnter = async (bid) => { | |
const bidPriceBelow = [0.02, 0.04, 0.07] | |
const orderSize = 1 | |
return bidPriceBelow.map((pctBelow) => { | |
return { | |
price: bid * (1 - pctBelow), | |
quantity: orderSize, | |
} | |
}) | |
} | |
const enterOrders = async (event) => { | |
const { buyingPower, hasOrders, isMarketOpen } = await setupAccountInfo() | |
const { quote, ticker, bid, isSuccess } = await getQuoteForSymbol() | |
const orderPricesToEnter = await generateOrdersToEnter(bid) | |
console.info( | |
`Last quote was at ${bid}. Entering orders at:`, | |
orderPricesToEnter, | |
) | |
const totalMaxOrderValue = orderPricesToEnter.length * bid | |
if (totalMaxOrderValue >= buyingPower) { | |
throw new Error( | |
`Failed to enter orders because sum of orders (${totalMaxOrderValue}) is less than buying power (${buyingPower})`, | |
) | |
} | |
if (!isSuccess) { | |
throw new Error(`Failed to pull quote for ticker ${ticker}`) | |
} | |
if (hasOrders) { | |
throw new Error( | |
`Failed to put in orders because there are already orders on the book`, | |
) | |
} | |
if (!isMarketOpen) { | |
throw new Error(`Failed: market is not open`) | |
} | |
const orders = [] | |
for (let i = 0; i < orderPricesToEnter.length; i++) { | |
const { price, quantity } = orderPricesToEnter[i] | |
console.info(`Sending order for ${ticker}, price=${price}, qty=${quantity}`) | |
const orderRes = await alpaca.createOrder({ | |
symbol: ticker, | |
qty: quantity, | |
side: 'buy', | |
type: 'limit', | |
limit_price: price, | |
time_in_force: 'day', | |
}) | |
orders.push(orderRes) | |
} | |
return orders | |
} | |
export default enterOrders |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment