├── .gitignore ├── deno.json ├── .github └── workflows │ ├── deno_test.yml │ ├── deno_test_coverage.yml │ ├── deno_deploy.yml │ └── bump_tag.yml ├── util ├── mockFetch.ts └── mockFetch.test.ts ├── factory ├── createTokenBucket.ts ├── createTokenBucket.test.ts ├── createClient.ts ├── createClient.test.ts └── createStream.ts ├── mod.ts ├── deno.lock ├── api ├── trade.ts └── marketData.ts └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | lcov.info 3 | .env 4 | playground.ts 5 | dist 6 | node_modules 7 | npm 8 | npm-test -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@deno/dnt": "jsr:@deno/dnt@^0.41.1" 4 | }, 5 | "tasks": { 6 | "build": "deno run -A build.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/deno_test.yml: -------------------------------------------------------------------------------- 1 | name: Deno Test 2 | on: 3 | push: 4 | branches: [main] 5 | paths: 6 | - "**/*.ts" 7 | pull_request: 8 | branches: [main] 9 | paths: 10 | - "**/*.ts" 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: setup deno 17 | uses: denoland/setup-deno@v1 18 | with: 19 | deno-version: v1.x 20 | - name: run tests 21 | run: deno test --allow-net --allow-env --allow-read --allow-write 22 | working-directory: ./ 23 | -------------------------------------------------------------------------------- /util/mockFetch.ts: -------------------------------------------------------------------------------- 1 | export type MockResponse = Response | object | string; 2 | 3 | export type MockFetch = (url: string, init?: RequestInit) => Promise; 4 | 5 | // Used to mock the fetch function in tests 6 | export const mockFetch: (response: MockResponse) => MockFetch = 7 | (response) => (_url, _init?) => 8 | // Return a promise that resolves with a response 9 | Promise.resolve( 10 | new Response( 11 | typeof response === "object" 12 | ? JSON.stringify(response) 13 | : (response as string), 14 | { 15 | status: 200, 16 | headers: { 17 | "Content-Type": "application/json", 18 | }, 19 | } 20 | ) 21 | ); 22 | -------------------------------------------------------------------------------- /factory/createTokenBucket.ts: -------------------------------------------------------------------------------- 1 | export type TokenBucketOptions = { 2 | capacity: number; 3 | fillRate: number; 4 | }; 5 | 6 | export const createTokenBucket = ( 7 | { capacity, fillRate }: TokenBucketOptions = { 8 | capacity: 200, 9 | fillRate: 3, 10 | } 11 | ) => { 12 | // Initialize tokens and last fill time 13 | let tokens = capacity; 14 | 15 | // Initialize last fill time 16 | let lastFillTime = Date.now(); 17 | 18 | return { 19 | tokens, 20 | take: (count: number) => { 21 | // Calculate time delta 22 | const now = Date.now(); 23 | const delta = (now - lastFillTime) / 1000; 24 | 25 | // Update last fill time and tokens 26 | lastFillTime = now; 27 | tokens = Math.min(capacity, tokens + delta * fillRate); 28 | 29 | // Check if tokens are available and take them if so 30 | // Otherwise, return false 31 | return tokens >= count ? ((tokens -= count), true) : false; 32 | }, 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /.github/workflows/deno_test_coverage.yml: -------------------------------------------------------------------------------- 1 | name: Deno Test Coverage 2 | on: 3 | push: 4 | branches: [main] 5 | paths: 6 | - "**/*.ts" 7 | pull_request: 8 | branches: [main] 9 | paths: 10 | - "**/*.ts" 11 | jobs: 12 | coverage: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: setup deno 17 | uses: denoland/setup-deno@v1 18 | with: 19 | deno-version: v1.x 20 | - name: generate coverage 21 | run: | 22 | deno test --allow-all --coverage=coverage 23 | deno coverage coverage --lcov > lcov.info 24 | TOTAL_LINES=$(grep -o '^DA:[^,]*' lcov.info | wc -l | xargs) 25 | COVERED_LINES=$(grep -o '^DA:[^,]*' lcov.info | grep -o '1' | wc -l | xargs) 26 | COVERAGE_PERCENT=$((COVERED_LINES * 100 / TOTAL_LINES)) 27 | echo "Test coverage: $COVERAGE_PERCENT%" 28 | if [ "$COVERAGE_PERCENT" -lt 25 ]; then 29 | echo "test coverage is below 25%" 30 | exit 1 31 | fi 32 | shell: bash 33 | -------------------------------------------------------------------------------- /.github/workflows/deno_deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deno Deploy 2 | on: 3 | workflow_run: 4 | workflows: ["Bump Tag"] 5 | types: 6 | - completed 7 | jobs: 8 | build-and-release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 14 | - name: get latest tag 15 | id: latest_tag 16 | run: | 17 | git fetch --tags 18 | latest_tag=$(git describe --tags --abbrev=0) 19 | echo "::set-output name=tag::$latest_tag" 20 | - name: setup deno 21 | uses: denolib/setup-deno@v2 22 | with: 23 | deno-version: v1.x 24 | - name: build npm package 25 | run: | 26 | deno run -A ./build.ts ${{ steps.latest_tag.outputs.tag }} 27 | - name: setup node 28 | uses: actions/setup-node@v2 29 | with: 30 | node-version: "14.x" 31 | registry-url: "https://registry.npmjs.org" 32 | - name: publish to npm 33 | run: | 34 | cd npm 35 | npm publish --access public 36 | env: 37 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/bump_tag.yml: -------------------------------------------------------------------------------- 1 | name: Bump Tag 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: "0" 15 | - name: get latest tag 16 | id: latest_tag 17 | run: | 18 | git fetch --tags 19 | latest_tag=$(git tag --sort=-creatordate | head -n 1) 20 | if [ -z "$latest_tag" ]; then 21 | latest_tag="0.0.0-preview" 22 | fi 23 | echo "::set-output name=tag::$latest_tag" 24 | - name: bump tag 25 | uses: actions/github-script@v6 26 | with: 27 | github-token: ${{ secrets.GITHUB_TOKEN }} 28 | script: | 29 | const currentTag = '${{ steps.latest_tag.outputs.tag }}'; 30 | const [version, suffix] = currentTag.split('-'); 31 | const [major, minor, patch] = version.split('.').map(Number); 32 | const newTag = `${major}.${minor}.${patch + 1}-${suffix || 'preview'}`; 33 | await github.rest.git.createRef({ 34 | owner: context.repo.owner, 35 | repo: context.repo.repo, 36 | ref: `refs/tags/${newTag}`, 37 | sha: context.sha 38 | }); 39 | console.log(`New tag created: ${newTag}`); 40 | -------------------------------------------------------------------------------- /factory/createTokenBucket.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "https://deno.land/std@0.217.0/assert/assert.ts"; 2 | import { createTokenBucket } from "./createTokenBucket.ts"; 3 | 4 | Deno.test( 5 | "createTokenBucket should allow taking tokens within capacity", 6 | () => { 7 | const tokenBucket = createTokenBucket({ 8 | capacity: 200, 9 | fillRate: 3, 10 | }); 11 | 12 | assert(tokenBucket.take(50) === true); 13 | }, 14 | ); 15 | 16 | Deno.test( 17 | "createTokenBucket should reject taking tokens beyond capacity", 18 | () => { 19 | const tokenBucket = createTokenBucket({ 20 | capacity: 200, 21 | fillRate: 3, 22 | }); 23 | 24 | assert(tokenBucket.take(300) === false); 25 | }, 26 | ); 27 | 28 | Deno.test( 29 | "createTokenBucket should refill tokens based on fill rate", 30 | async () => { 31 | const tokenBucket = createTokenBucket({ 32 | capacity: 200, 33 | fillRate: 3, 34 | }); 35 | 36 | tokenBucket.take(50); 37 | 38 | await new Promise((resolve) => setTimeout(resolve, 3000)); 39 | 40 | assert(tokenBucket.take(50) === true); 41 | }, 42 | ); 43 | 44 | Deno.test( 45 | "createTokenBucket should support 200 requests per 60 seconds", 46 | () => { 47 | const tokenBucket = createTokenBucket({ capacity: 200, fillRate: 3 }); 48 | 49 | let successfulRequests = 0; 50 | 51 | for (let i = 0; i < 200; i++) { 52 | if (tokenBucket.take(1)) { 53 | successfulRequests++; 54 | } 55 | } 56 | 57 | assert(successfulRequests === 200); 58 | }, 59 | ); 60 | -------------------------------------------------------------------------------- /util/mockFetch.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "https://deno.land/std@0.217.0/assert/assert.ts"; 2 | import { mockFetch } from "./mockFetch.ts"; 3 | 4 | Deno.test("mockFetch should return a function", () => { 5 | const response = { data: "mocked response" }; 6 | const result = mockFetch(response); 7 | 8 | assert(typeof result === "function"); 9 | }); 10 | 11 | Deno.test( 12 | "mockFetch should return a promise that resolves to a response object", 13 | async () => { 14 | const response = { data: "mocked response" }; 15 | const fetch = mockFetch(response); 16 | const result = await fetch("https://example.com"); 17 | 18 | assert(result instanceof Response); 19 | assert(result.ok === true); 20 | assert(result.status === 200); 21 | assert(result.headers.get("Content-Type") === "application/json"); 22 | } 23 | ); 24 | 25 | Deno.test("mockFetch should return the mocked response data", async () => { 26 | const response = { data: "mocked response" }; 27 | const fetch = mockFetch(response); 28 | const result = await fetch("https://example.com"); 29 | const data = await result.json(); 30 | 31 | assert(data.data === response.data); 32 | }); 33 | 34 | Deno.test("mockFetch should ignore the url and init parameters", async () => { 35 | const response = { data: "mocked response" }; 36 | const fetch = mockFetch(response); 37 | 38 | const a = await fetch("https://example.com"); 39 | const b = await fetch("https://example.com/other", { 40 | method: "POST", 41 | body: JSON.stringify({ key: "value" }), 42 | }); 43 | 44 | const c = await a.json(); 45 | const d = await b.json(); 46 | 47 | assert(c.data === response.data); 48 | assert(d.data === response.data); 49 | }); 50 | -------------------------------------------------------------------------------- /factory/createClient.ts: -------------------------------------------------------------------------------- 1 | import * as marketData from "../api/marketData.ts"; 2 | import * as trade from "../api/trade.ts"; 3 | 4 | import { createTokenBucket, TokenBucketOptions } from "./createTokenBucket.ts"; 5 | 6 | export const baseURLs = { 7 | live: "https://api.alpaca.markets", 8 | paper: "https://paper-api.alpaca.markets", 9 | marketData: "https://data.alpaca.markets", 10 | } as const; 11 | 12 | export type BaseURLKey = keyof typeof baseURLs; 13 | 14 | export type RequestOptions = { 15 | path: string; 16 | method?: string; 17 | baseURL?: (typeof baseURLs)[BaseURLKey]; 18 | data?: object; 19 | params?: object; 20 | }; 21 | 22 | export type Client = 23 | & { [K in keyof typeof trade]: ReturnType<(typeof trade)[K]> } 24 | & { [K in keyof typeof marketData]: ReturnType<(typeof marketData)[K]> }; 25 | 26 | export type ClientContext = { 27 | options: CreateClientOptions; 28 | request: (options: RequestOptions) => Promise; 29 | }; 30 | 31 | export type CreateClientOptions = { 32 | key?: string; 33 | secret?: string; 34 | accessToken?: string; 35 | baseURL?: string; 36 | paper?: boolean; 37 | tokenBucket?: TokenBucketOptions; 38 | }; 39 | 40 | export const createClient = (options: CreateClientOptions) => { 41 | const { 42 | key = "", 43 | secret = "", 44 | accessToken = "", 45 | paper = true, 46 | } = { 47 | key: options.key || Deno.env.get("APCA_KEY_ID"), 48 | secret: options.secret || Deno.env.get("APCA_KEY_SECRET"), 49 | accessToken: options.accessToken || Deno.env.get("APCA_ACCESS_TOKEN"), 50 | }; 51 | 52 | // Check if credentials are provided 53 | if (!accessToken && (!key || !secret)) { 54 | throw new Error("Missing credentials (need accessToken or key/secret)"); 55 | } 56 | 57 | const baseURL = options.baseURL || (paper ? baseURLs.paper : baseURLs.live); 58 | 59 | // Create a token bucket for rate limiting 60 | const bucket = createTokenBucket(options.tokenBucket); 61 | 62 | // Throttled request function that respects the token bucket 63 | const request = async ({ 64 | method = "GET", 65 | path, 66 | params, 67 | data, 68 | }: RequestOptions): Promise => { 69 | await new Promise((resolve) => { 70 | // Poll the token bucket every second 71 | const timer = setInterval(() => { 72 | // If a token is available, resolve the promise 73 | if (bucket.take(1)) { 74 | clearInterval(timer); 75 | resolve(true); 76 | } 77 | }, 1000); 78 | }); 79 | 80 | // Construct the URL 81 | const url = new URL(path, baseURL); 82 | 83 | if (params) { 84 | // Append query parameters to the URL 85 | url.search = new URLSearchParams( 86 | Object.entries(params) as [string, string][], 87 | ).toString(); 88 | } 89 | 90 | // Construct the headers 91 | const headers = new Headers({ 92 | "Content-Type": "application/json", 93 | }); 94 | 95 | if (accessToken) { 96 | // Use the access token for authentication 97 | headers.set("Authorization", `Bearer ${accessToken}`); 98 | } else { 99 | // Use the API key and secret for authentication 100 | headers.set("APCA-API-KEY-ID", key); 101 | headers.set("APCA-API-SECRET-KEY", secret); 102 | } 103 | 104 | // Make the request 105 | return fetch(url, { 106 | method, 107 | headers, 108 | body: data ? JSON.stringify(data) : null, 109 | }).then(async (response) => { 110 | if (!response.ok) { 111 | // The response will contain an error message (usually) 112 | throw new Error(await response.text()); 113 | } 114 | 115 | // Parse the response and cast it to the expected type 116 | return response.json().catch(() => ({})) as Promise; 117 | }); 118 | }; 119 | 120 | // Create a context object to pass to the client factory 121 | const context: ClientContext = { options, request }; 122 | 123 | // Return an object with all methods 124 | return [...Object.values(trade), ...Object.values(marketData)].reduce( 125 | (prev, fn) => ({ ...prev, [fn.name]: fn(context) }), 126 | {} as Client, 127 | ); 128 | }; 129 | -------------------------------------------------------------------------------- /factory/createClient.test.ts: -------------------------------------------------------------------------------- 1 | // import { assert } from "https://deno.land/std@0.217.0/assert/assert.ts"; 2 | // import { assertEquals } from "https://deno.land/std@0.220.0/assert/assert_equals.ts"; 3 | // import { assertThrows } from "https://deno.land/std@0.220.0/assert/assert_throws.ts"; 4 | // import { createClient } from "../src/factory/createClient.ts"; 5 | // import { mockFetch } from "../src/util/mockFetch.ts"; 6 | 7 | // Deno.test( 8 | // "createClient should create a trade client with valid options", 9 | // () => { 10 | // const client = createClient({ 11 | // baseURL: "https://paper-api.alpaca.markets", 12 | // key: "EXAMPLE_KEY_ID", 13 | // secret: "EXAMPLE_KEY_SECRET", 14 | // }); 15 | 16 | // assert(client.v2.account !== undefined); 17 | // assert(typeof client.v2.account.get === "function"); 18 | // } 19 | // ); 20 | 21 | // Deno.test( 22 | // "createClient should create a market data client with valid options", 23 | // () => { 24 | // const client = createClient({ 25 | // baseURL: "https://data.alpaca.markets", 26 | // key: "EXAMPLE_KEY_ID", 27 | // secret: "EXAMPLE_KEY_SECRET", 28 | // }); 29 | 30 | // assert(client.v2.stocks !== undefined); 31 | // assert(typeof client.v2.stocks.bars.get === "function"); 32 | // } 33 | // ); 34 | 35 | // Deno.test("createClient should throw an error with an invalid base URL", () => { 36 | // assertThrows( 37 | // () => 38 | // createClient({ 39 | // // deno-lint-ignore ban-ts-comment 40 | // // @ts-expect-error 41 | // baseURL: "https://invalid-url.com", 42 | // key: "EXAMPLE_KEY_ID", 43 | // secret: "EXAMPLE_KEY_SECRET", 44 | // }), 45 | // Error, 46 | // "Invalid base URL" 47 | // ); 48 | // }); 49 | 50 | // Deno.test("createClient should use the provided token bucket options", () => { 51 | // const tokenBucketOptions = { 52 | // capacity: 100, 53 | // fillRate: 2, 54 | // }; 55 | 56 | // const client = createClient({ 57 | // baseURL: "https://paper-api.alpaca.markets", 58 | // key: "EXAMPLE_KEY_ID", 59 | // secret: "EXAMPLE_KEY_SECRET", 60 | // tokenBucket: tokenBucketOptions, 61 | // }); 62 | 63 | // assert(client._context.options.tokenBucket === tokenBucketOptions); 64 | // }); 65 | 66 | // Deno.test( 67 | // "createClient should use default token bucket options if not provided", 68 | // () => { 69 | // const client = createClient({ 70 | // baseURL: "https://paper-api.alpaca.markets", 71 | // key: "EXAMPLE_KEY_ID", 72 | // secret: "EXAMPLE_KEY_SECRET", 73 | // }); 74 | 75 | // assert(client._context.options.tokenBucket === undefined); 76 | // } 77 | // ); 78 | 79 | // Deno.test( 80 | // "createClient should make a request with the correct options", 81 | // async () => { 82 | // const mockResponse = { mock: "data" }; 83 | // const originalFetch = globalThis.fetch; 84 | 85 | // // deno-lint-ignore ban-ts-comment 86 | // // @ts-expect-error 87 | // globalThis.fetch = mockFetch(mockResponse); 88 | 89 | // const client = createClient({ 90 | // baseURL: "https://paper-api.alpaca.markets", 91 | // key: "EXAMPLE_KEY_ID", 92 | // secret: "EXAMPLE_KEY_SECRET", 93 | // }); 94 | 95 | // const response = await client._context.request({ 96 | // path: "/v2/account", 97 | // }); 98 | 99 | // assertEquals(response, mockResponse); 100 | // globalThis.fetch = originalFetch; 101 | // } 102 | // ); 103 | 104 | // Deno.test( 105 | // "createClient should throttle requests based on token bucket", 106 | // async () => { 107 | // const mockResponse = { mock: "data" }; 108 | // const originalFetch = globalThis.fetch; 109 | 110 | // // deno-lint-ignore ban-ts-comment 111 | // // @ts-expect-error 112 | // globalThis.fetch = mockFetch(mockResponse); 113 | 114 | // const client = createClient({ 115 | // baseURL: "https://paper-api.alpaca.markets", 116 | // key: "EXAMPLE_KEY_ID", 117 | // secret: "EXAMPLE_KEY_SECRET", 118 | // tokenBucket: { 119 | // capacity: 2, 120 | // fillRate: 1, 121 | // }, 122 | // }); 123 | 124 | // const startTime = Date.now(); 125 | 126 | // await Promise.all([ 127 | // client._context.request({ path: "/v2/account" }), 128 | // client._context.request({ path: "/v2/account" }), 129 | // client._context.request({ path: "/v2/account" }), 130 | // ]); 131 | 132 | // const endTime = Date.now(); 133 | // const elapsedTime = endTime - startTime; 134 | 135 | // assert(elapsedTime >= 2000, "Requests should be throttled"); 136 | // globalThis.fetch = originalFetch; 137 | // } 138 | // ); 139 | -------------------------------------------------------------------------------- /factory/createStream.ts: -------------------------------------------------------------------------------- 1 | // NOT CLEANED UP; TYPES MISSING FOR CALLBACKS; BARELY FUNCTIONAL 2 | 3 | import { Nullable } from "../api/trade.ts"; 4 | 5 | const baseURLs = { 6 | data: "wss://stream.data.alpaca.markets", 7 | data_sandbox: "wss://stream.data.sandbox.alpaca.markets", 8 | data_test: "wss://stream.data.alpaca.markets/v2/test", 9 | account: "wss://api.alpaca.markets", 10 | account_paper: "wss://paper-api.alpaca.markets", 11 | } as const; 12 | 13 | type BaseURLKey = keyof typeof baseURLs; 14 | 15 | type CreateStreamOptions = { 16 | type: BaseURLKey; 17 | key?: string; 18 | secret?: string; 19 | version?: "v2"; 20 | feed?: "iex" | "sip"; 21 | autoReconnect?: boolean; 22 | maxRetries?: number; 23 | retryDelay?: number; 24 | }; 25 | 26 | type EventCallback = (data: any) => void; 27 | 28 | type TradeUpdate = { 29 | event: string; 30 | price: string; 31 | qty: string; 32 | timestamp: string; 33 | }; 34 | 35 | export const createStream = (options: CreateStreamOptions) => { 36 | const { 37 | type, 38 | version = "v2", 39 | feed = "iex", 40 | autoReconnect = true, 41 | maxRetries = 5, 42 | retryDelay = 3000, 43 | } = options; 44 | 45 | const key = options.key || Deno.env.get("APCA_KEY_ID"); 46 | const secret = options.secret || Deno.env.get("APCA_KEY_SECRET"); 47 | 48 | if (!key || !secret) { 49 | console.error("API key and secret are required."); 50 | return; 51 | } 52 | 53 | let url: string; 54 | 55 | if (type === "data" || type === "data_sandbox") { 56 | url = `${baseURLs[type]}/${version}/${feed}`; 57 | } else if (type === "data_test") { 58 | url = baseURLs[type]; 59 | } else { 60 | url = `${baseURLs[type]}/stream`; 61 | } 62 | 63 | console.log(url); 64 | let socket: Nullable = null; 65 | let retries = 0; 66 | const eventCallbacks: { [event: string]: EventCallback[] } = {}; 67 | const activeStreams: Set = new Set(); 68 | let isAuthenticated = false; 69 | 70 | const handle = (message: any) => { 71 | const event = message.stream; 72 | if (event && eventCallbacks[event]) { 73 | eventCallbacks[event].forEach((callback) => callback(message)); 74 | } else { 75 | console.debug("Unhandled message:", message); 76 | } 77 | }; 78 | 79 | const connect = () => { 80 | if (!autoReconnect || (maxRetries !== undefined && retries >= maxRetries)) { 81 | console.debug("Auto-reconnect is disabled or max retries reached."); 82 | socket?.close(); 83 | return; 84 | } 85 | 86 | socket = new WebSocket(url); 87 | 88 | socket.onopen = () => { 89 | console.debug( 90 | "WebSocket connection established. Sending authentication message.", 91 | ); 92 | 93 | socket?.send( 94 | JSON.stringify({ 95 | action: "auth", 96 | key: key, 97 | secret: secret, 98 | }), 99 | ); 100 | }; 101 | 102 | socket.onclose = () => { 103 | console.debug("WebSocket connection closed. Attempting to reconnect..."); 104 | retries++; 105 | setTimeout(connect, retryDelay); 106 | }; 107 | 108 | socket.onerror = (error) => { 109 | console.debug("WebSocket encountered an error:", error); 110 | socket?.close(); 111 | }; 112 | 113 | socket.onmessage = ({ data }) => { 114 | if (typeof data === "string") { 115 | console.log("Received text message:", data); 116 | try { 117 | const result = JSON.parse(data); 118 | if ( 119 | result.stream === "authorization" && 120 | result.data.status === "authorized" 121 | ) { 122 | isAuthenticated = true; 123 | sendListenMessage(); 124 | } 125 | handle(result); 126 | } catch (error) { 127 | console.debug("Error parsing text message:", error); 128 | } 129 | } else if (data instanceof Blob) { 130 | console.log("Received binary message:", data); 131 | const reader = new FileReader(); 132 | reader.onload = function () { 133 | if (typeof reader.result === "string") { 134 | try { 135 | const result = JSON.parse(reader.result); 136 | if ( 137 | result.stream === "authorization" && 138 | result.data.status === "authorized" 139 | ) { 140 | isAuthenticated = true; 141 | sendListenMessage(); 142 | } 143 | handle(result); 144 | } catch (error) { 145 | console.debug("Error parsing binary message:", error); 146 | } 147 | } 148 | }; 149 | reader.readAsText(data); 150 | } else { 151 | console.debug("Unknown message type:", data); 152 | } 153 | }; 154 | }; 155 | 156 | connect(); 157 | 158 | const sendListenMessage = () => { 159 | if (socket && socket.readyState === WebSocket.OPEN && isAuthenticated) { 160 | console.log("Sending listen message:", Array.from(activeStreams)); 161 | socket.send( 162 | JSON.stringify({ 163 | action: "listen", 164 | data: { 165 | streams: Array.from(activeStreams), 166 | }, 167 | }), 168 | ); 169 | } else { 170 | console.debug( 171 | "Socket is not open or not authenticated. Cannot send listen message.", 172 | ); 173 | } 174 | }; 175 | 176 | const subscribe = (event: string, callback: EventCallback) => { 177 | console.log("Subscribing to event:", event); 178 | if (!eventCallbacks[event]) { 179 | eventCallbacks[event] = []; 180 | } 181 | eventCallbacks[event].push(callback); 182 | activeStreams.add(event); 183 | sendListenMessage(); 184 | }; 185 | 186 | const unsubscribe = (event: string) => { 187 | if (eventCallbacks[event]) { 188 | delete eventCallbacks[event]; 189 | activeStreams.delete(event); 190 | sendListenMessage(); 191 | } 192 | }; 193 | 194 | return { 195 | socket, 196 | close: () => socket?.close(), 197 | subscribe, 198 | unsubscribe, 199 | }; 200 | }; 201 | 202 | // const stream = createStream({ 203 | // type: "account_paper", 204 | // key: "key", 205 | // secret: "secret", 206 | // autoReconnect: true, 207 | // maxRetries: 5, 208 | // retryDelay: 3000, 209 | // }); 210 | 211 | // stream.subscribe("trade_updates", (data) => { 212 | // // trade update received 213 | // }); 214 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | // If `APCA_DEBUG` false, console.debug() should not log anything. 2 | if (JSON.parse(Deno.env.get("APCA_DEBUG") || "false")) { 3 | console.debug = () => {}; 4 | } else { 5 | // Prefix all debug logs with "@alpacahq/typescript-sdk" to make it easier to 6 | // for users to filter out debug logs from this SDK. 7 | console.debug = (...args) => 8 | console.log("@alpacahq/typescript-sdk:debug", ...args); 9 | } 10 | export { 11 | type CashDividend, 12 | type CashMerger, 13 | type CorporateActions, 14 | type CryptoBar, 15 | type CryptoBars, 16 | type CryptoBarsLatest, 17 | type CryptoOrderbook, 18 | type CryptoOrderbookEntry, 19 | type CryptoOrderbooksLatest, 20 | type CryptoQuote, 21 | type CryptoQuotes, 22 | type CryptoQuotesLatest, 23 | type CryptoSnapshots, 24 | type CryptoTrade, 25 | type CryptoTrades, 26 | type CryptoTradesLatest, 27 | type ForexRate, 28 | type ForexRates, 29 | type ForexRatesLatest, 30 | type ForwardSplit, 31 | getCryptoBars, 32 | type GetCryptoBarsLatestOptions, 33 | type GetCryptoBarsOptions, 34 | type GetCryptoOrderbooksLatestOptions, 35 | getCryptoQuotes, 36 | getCryptoQuotesLatest, 37 | type GetCryptoQuotesLatestOptions, 38 | type GetCryptoQuotesOptions, 39 | getCryptoSnapshots, 40 | type GetCryptoSnapshotsOptions, 41 | getCryptoTrades, 42 | getCryptoTradesLatest, 43 | type GetCryptoTradesLatestOptions, 44 | type GetCryptoTradesOptions, 45 | getForexRates, 46 | type GetForexRatesLatestOptions, 47 | type GetForexRatesOptions, 48 | getLatestCryptoBars, 49 | getLatestCryptoOrderbooks, 50 | getLatestForexRates, 51 | getLogo, 52 | type GetLogoOptions, 53 | getNews, 54 | type GetNewsOptions, 55 | getOptionsBars, 56 | type GetOptionsBarsOptions, 57 | getOptionsExchanges, 58 | getOptionsSnapshots, 59 | type GetOptionsSnapshotsOptions, 60 | getOptionsTrades, 61 | getOptionsTradesLatest, 62 | type GetOptionsTradesLatestOptions, 63 | type GetOptionsTradesOptions, 64 | getStocksAuctions, 65 | type GetStocksAuctionsOptions, 66 | getStocksBars, 67 | getStocksBarsLatest, 68 | type GetStocksBarsLatestOptions, 69 | type GetStocksBarsOptions, 70 | getStocksConditions, 71 | type GetStocksConditionsOptions, 72 | getStocksCorporateActions, 73 | type GetStocksCorporateActionsOptions, 74 | getStocksExchangeCodes, 75 | getStocksMarketMovers, 76 | type GetStocksMarketMoversOptions, 77 | getStocksMostActives, 78 | type GetStocksMostActivesOptions, 79 | getStocksQuotes, 80 | getStocksQuotesLatest, 81 | type GetStocksQuotesLatestOptions, 82 | type GetStocksQuotesOptions, 83 | getStocksSnapshots, 84 | type GetStocksSnapshotsOptions, 85 | getStocksTrades, 86 | getStocksTradesLatest, 87 | type GetStocksTradesLatestOptions, 88 | type GetStocksTradesOptions, 89 | type Logo, 90 | type MarketMover, 91 | type MarketMovers, 92 | type MostActive, 93 | type MostActives, 94 | type NameChange, 95 | type OptionBar, 96 | type OptionsBars, 97 | type OptionsExchanges, 98 | type OptionsSnapshots, 99 | type OptionsSnapshotsQuote, 100 | type OptionsSnapshotsTrade, 101 | type OptionsTrades, 102 | type OptionsTradesLatest, 103 | type Redemption, 104 | type ReverseSplit, 105 | type Sort, 106 | type SpinOff, 107 | type StockAndCashMerger, 108 | type StockBar, 109 | type StockDividend, 110 | type StockMerger, 111 | type StockQuote, 112 | type StocksAuction, 113 | type StocksAuctionPrice, 114 | type StocksAuctions, 115 | type StocksBar, 116 | type StocksBars, 117 | type StocksBarsLatest, 118 | type StocksConditions, 119 | type StocksExchangeCodes, 120 | type StockSnapshots, 121 | type StocksQuotes, 122 | type StocksQuotesLatest, 123 | type StocksTrades, 124 | type StocksTradesLatest, 125 | type StockTrade, 126 | type UnitSplit, 127 | type WorthlessRemoval, 128 | } from "./api/marketData.ts"; 129 | 130 | export { 131 | type Account, 132 | type AccountStatus, 133 | type Activity, 134 | type Asset, 135 | type BaseOrder, 136 | type Calendar, 137 | cancelOrder, 138 | type CancelOrderOptions, 139 | cancelOrders, 140 | type Clock, 141 | closePosition, 142 | type ClosePositionOptions, 143 | closePositions, 144 | type Configurations, 145 | type CorporateAction, 146 | createCryptoTransfer, 147 | type CreateCryptoTransferOptions, 148 | createOrder, 149 | type CreateOrderOptions, 150 | createWatchlist, 151 | type CreateWatchlistOptions, 152 | type CryptoFee, 153 | type CryptoOrder, 154 | type CryptoTransfer, 155 | type CryptoTransferResponse, 156 | type CryptoWallet, 157 | deleteWatchlist, 158 | type DeleteWatchlistOptions, 159 | type Direction, 160 | type EquityOrder, 161 | type ExerciseOption, 162 | exerciseOption, 163 | getAccount, 164 | getActivities, 165 | getActivity, 166 | type GetActivityOptions, 167 | getAsset, 168 | type GetAssetOptions, 169 | getAssets, 170 | type GetAssetsOptions, 171 | getCalendar, 172 | type GetCalendarOptions, 173 | getClock, 174 | getConfigurations, 175 | getCorporateAction, 176 | type GetCorporateActionOptions, 177 | getCorporateActions, 178 | type GetCorporateActionsOptions, 179 | type GetCryptoFeeEstimateOptions, 180 | getCryptoTransfer, 181 | type GetCryptoTransferOptions, 182 | getCryptoTransfers, 183 | type GetCryptoTransfersOptions, 184 | getCryptoWallet, 185 | getCryptoWallets, 186 | getCryptoWhitelistedAddress, 187 | getCryptoWhitelistedAddresses, 188 | type GetCryptoWhitelistedAddressOptions, 189 | getFeeEstimate, 190 | getOptionsContract, 191 | type GetOptionsContractOptions, 192 | getOptionsContracts, 193 | type GetOptionsContractsOptions, 194 | getOrder, 195 | type GetOrderOptions, 196 | getOrders, 197 | type GetOrdersOptions, 198 | getPortfolioHistory, 199 | type GetPortfolioHistoryOptions, 200 | getPosition, 201 | type GetPositionOptions, 202 | getPositions, 203 | type GetWalletOptions, 204 | getWatchlist, 205 | type GetWatchlistOptions, 206 | getWatchlists, 207 | type NonTradeActivity, 208 | type OptionsApprovedLevel, 209 | type OptionsContract, 210 | type OptionsOrder, 211 | type OptionsTradingLevel, 212 | type Order, 213 | type OrderClass, 214 | type PortfolioHistory, 215 | type PositionIntent, 216 | removeCryptoWhitelistedAddress, 217 | type RemoveCryptoWhitelistedAddressOptions, 218 | replaceOrder, 219 | type ReplaceOrderOptions, 220 | requestCryptoWhitelistedAddress, 221 | type RequestCryptoWhitelistedAddressOptions, 222 | type Side, 223 | type StopLoss, 224 | type TakeProfit, 225 | type TimeInForce, 226 | type TradingActivity, 227 | type Type, 228 | type UnstableNumber, 229 | updateConfigurations, 230 | type UpdateConfigurationsOptions, 231 | updateWatchlist, 232 | type UpdateWatchlistOptions, 233 | type Watchlist, 234 | type WhitelistedAddress, 235 | } from "./api/trade.ts"; 236 | 237 | export { 238 | baseURLs, 239 | type Client, 240 | type ClientContext, 241 | createClient, 242 | type CreateClientOptions, 243 | type RequestOptions, 244 | } from "./factory/createClient.ts"; 245 | 246 | export { 247 | createTokenBucket, 248 | type TokenBucketOptions, 249 | } from "./factory/createTokenBucket.ts"; 250 | 251 | export { 252 | type MockFetch, 253 | mockFetch, 254 | type MockResponse, 255 | } from "./util/mockFetch.ts"; 256 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3", 3 | "packages": { 4 | "specifiers": { 5 | "jsr:@deno/cache-dir@^0.8.0": "jsr:@deno/cache-dir@0.8.0", 6 | "jsr:@deno/dnt@^0.41.1": "jsr:@deno/dnt@0.41.1", 7 | "jsr:@deno/graph@^0.69.7": "jsr:@deno/graph@0.69.10", 8 | "jsr:@std/assert@^0.218.2": "jsr:@std/assert@0.218.2", 9 | "jsr:@std/bytes@^0.218.2": "jsr:@std/bytes@0.218.2", 10 | "jsr:@std/fmt@^0.218.2": "jsr:@std/fmt@0.218.2", 11 | "jsr:@std/fs@^0.218.2": "jsr:@std/fs@0.218.2", 12 | "jsr:@std/io@^0.218.2": "jsr:@std/io@0.218.2", 13 | "jsr:@std/path@^0.218.2": "jsr:@std/path@0.218.2", 14 | "npm:@ts-morph/bootstrap@0.22": "npm:@ts-morph/bootstrap@0.22.0", 15 | "npm:code-block-writer@^13.0.1": "npm:code-block-writer@13.0.1" 16 | }, 17 | "jsr": { 18 | "@deno/cache-dir@0.8.0": { 19 | "integrity": "e87e80a404958f6350d903e6238b72afb92468378b0b32111f7a1e4916ac7fe7", 20 | "dependencies": [ 21 | "jsr:@deno/graph@^0.69.7", 22 | "jsr:@std/fs@^0.218.2", 23 | "jsr:@std/io@^0.218.2" 24 | ] 25 | }, 26 | "@deno/dnt@0.41.1": { 27 | "integrity": "8746a773e031ae19ef43d0eece850217b76cf1d0118fdd8e059652d7023d4aff", 28 | "dependencies": [ 29 | "jsr:@deno/cache-dir@^0.8.0", 30 | "jsr:@std/fmt@^0.218.2", 31 | "jsr:@std/fs@^0.218.2", 32 | "jsr:@std/path@^0.218.2", 33 | "npm:@ts-morph/bootstrap@0.22", 34 | "npm:code-block-writer@^13.0.1" 35 | ] 36 | }, 37 | "@deno/graph@0.69.10": { 38 | "integrity": "38fe22ac5686f6ece5daeec5a4df65c6314d7d32adcc33f77917a13cfaffa26f" 39 | }, 40 | "@std/assert@0.218.2": { 41 | "integrity": "7f0a5a1a8cf86607cd6c2c030584096e1ffad27fc9271429a8cb48cfbdee5eaf" 42 | }, 43 | "@std/bytes@0.218.2": { 44 | "integrity": "91fe54b232dcca73856b79a817247f4a651dbb60d51baafafb6408c137241670" 45 | }, 46 | "@std/fmt@0.218.2": { 47 | "integrity": "99526449d2505aa758b6cbef81e7dd471d8b28ec0dcb1491d122b284c548788a" 48 | }, 49 | "@std/fs@0.218.2": { 50 | "integrity": "dd9431453f7282e8c577cc22c9e6d036055a9a980b5549f887d6012969fabcca", 51 | "dependencies": [ 52 | "jsr:@std/assert@^0.218.2", 53 | "jsr:@std/path@^0.218.2" 54 | ] 55 | }, 56 | "@std/io@0.218.2": { 57 | "integrity": "c64fbfa087b7c9d4d386c5672f291f607d88cb7d44fc299c20c713e345f2785f", 58 | "dependencies": [ 59 | "jsr:@std/bytes@^0.218.2" 60 | ] 61 | }, 62 | "@std/path@0.218.2": { 63 | "integrity": "b568fd923d9e53ad76d17c513e7310bda8e755a3e825e6289a0ce536404e2662", 64 | "dependencies": [ 65 | "jsr:@std/assert@^0.218.2" 66 | ] 67 | } 68 | }, 69 | "npm": { 70 | "@nodelib/fs.scandir@2.1.5": { 71 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 72 | "dependencies": { 73 | "@nodelib/fs.stat": "@nodelib/fs.stat@2.0.5", 74 | "run-parallel": "run-parallel@1.2.0" 75 | } 76 | }, 77 | "@nodelib/fs.stat@2.0.5": { 78 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 79 | "dependencies": {} 80 | }, 81 | "@nodelib/fs.walk@1.2.8": { 82 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 83 | "dependencies": { 84 | "@nodelib/fs.scandir": "@nodelib/fs.scandir@2.1.5", 85 | "fastq": "fastq@1.17.1" 86 | } 87 | }, 88 | "@ts-morph/bootstrap@0.22.0": { 89 | "integrity": "sha512-MI5q7pid4swAlE2lcHwHRa6rcjoIMyT6fy8uuZm8BGg7DHGi/H5bQ0GMZzbk3N0r/LfStMdOYPkl+3IwvfIQ2g==", 90 | "dependencies": { 91 | "@ts-morph/common": "@ts-morph/common@0.22.0" 92 | } 93 | }, 94 | "@ts-morph/common@0.22.0": { 95 | "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", 96 | "dependencies": { 97 | "fast-glob": "fast-glob@3.3.2", 98 | "minimatch": "minimatch@9.0.3", 99 | "mkdirp": "mkdirp@3.0.1", 100 | "path-browserify": "path-browserify@1.0.1" 101 | } 102 | }, 103 | "balanced-match@1.0.2": { 104 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 105 | "dependencies": {} 106 | }, 107 | "brace-expansion@2.0.1": { 108 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 109 | "dependencies": { 110 | "balanced-match": "balanced-match@1.0.2" 111 | } 112 | }, 113 | "braces@3.0.2": { 114 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 115 | "dependencies": { 116 | "fill-range": "fill-range@7.0.1" 117 | } 118 | }, 119 | "code-block-writer@13.0.1": { 120 | "integrity": "sha512-c5or4P6erEA69TxaxTNcHUNcIn+oyxSRTOWV+pSYF+z4epXqNvwvJ70XPGjPNgue83oAFAPBRQYwpAJ/Hpe/Sg==", 121 | "dependencies": {} 122 | }, 123 | "fast-glob@3.3.2": { 124 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", 125 | "dependencies": { 126 | "@nodelib/fs.stat": "@nodelib/fs.stat@2.0.5", 127 | "@nodelib/fs.walk": "@nodelib/fs.walk@1.2.8", 128 | "glob-parent": "glob-parent@5.1.2", 129 | "merge2": "merge2@1.4.1", 130 | "micromatch": "micromatch@4.0.5" 131 | } 132 | }, 133 | "fastq@1.17.1": { 134 | "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", 135 | "dependencies": { 136 | "reusify": "reusify@1.0.4" 137 | } 138 | }, 139 | "fill-range@7.0.1": { 140 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 141 | "dependencies": { 142 | "to-regex-range": "to-regex-range@5.0.1" 143 | } 144 | }, 145 | "glob-parent@5.1.2": { 146 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 147 | "dependencies": { 148 | "is-glob": "is-glob@4.0.3" 149 | } 150 | }, 151 | "is-extglob@2.1.1": { 152 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 153 | "dependencies": {} 154 | }, 155 | "is-glob@4.0.3": { 156 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 157 | "dependencies": { 158 | "is-extglob": "is-extglob@2.1.1" 159 | } 160 | }, 161 | "is-number@7.0.0": { 162 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 163 | "dependencies": {} 164 | }, 165 | "merge2@1.4.1": { 166 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 167 | "dependencies": {} 168 | }, 169 | "micromatch@4.0.5": { 170 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 171 | "dependencies": { 172 | "braces": "braces@3.0.2", 173 | "picomatch": "picomatch@2.3.1" 174 | } 175 | }, 176 | "minimatch@9.0.3": { 177 | "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", 178 | "dependencies": { 179 | "brace-expansion": "brace-expansion@2.0.1" 180 | } 181 | }, 182 | "mkdirp@3.0.1": { 183 | "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", 184 | "dependencies": {} 185 | }, 186 | "path-browserify@1.0.1": { 187 | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 188 | "dependencies": {} 189 | }, 190 | "picomatch@2.3.1": { 191 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 192 | "dependencies": {} 193 | }, 194 | "queue-microtask@1.2.3": { 195 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 196 | "dependencies": {} 197 | }, 198 | "reusify@1.0.4": { 199 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 200 | "dependencies": {} 201 | }, 202 | "run-parallel@1.2.0": { 203 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 204 | "dependencies": { 205 | "queue-microtask": "queue-microtask@1.2.3" 206 | } 207 | }, 208 | "to-regex-range@5.0.1": { 209 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 210 | "dependencies": { 211 | "is-number": "is-number@7.0.0" 212 | } 213 | } 214 | } 215 | }, 216 | "remote": { 217 | "https://deno.land/std@0.217.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", 218 | "https://deno.land/std@0.217.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", 219 | "https://deno.land/std@0.220.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", 220 | "https://deno.land/std@0.220.0/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", 221 | "https://deno.land/std@0.220.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", 222 | "https://deno.land/std@0.220.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e", 223 | "https://deno.land/std@0.220.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", 224 | "https://deno.land/std@0.220.0/assert/assert_throws.ts": "31f3c061338aec2c2c33731973d58ccd4f14e42f355501541409ee958d2eb8e5", 225 | "https://deno.land/std@0.220.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", 226 | "https://deno.land/std@0.220.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", 227 | "https://deno.land/std@0.220.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", 228 | "https://deno.land/std@0.92.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", 229 | "https://deno.land/std@0.92.0/_util/has_own_property.ts": "f5edd94ed3f3c20c517d812045deb97977e18501c9b7105b5f5c11a31893d7a2", 230 | "https://deno.land/std@0.92.0/async/deferred.ts": "624bef4b755b71394620508a0c234a93cb8020cbd1b04bfcdad41c174392cef6", 231 | "https://deno.land/std@0.92.0/async/delay.ts": "9de1d8d07d1927767ab7f82434b883f3d8294fb19cad819691a2ad81a728cf3d", 232 | "https://deno.land/std@0.92.0/async/mod.ts": "253b41c658d768613eacfb11caa0a9ca7148442f932018a45576f7f27554c853", 233 | "https://deno.land/std@0.92.0/async/mux_async_iterator.ts": "b9091909db04cdb0af6f7807677372f64c1488de6c4bd86004511b064bf230d6", 234 | "https://deno.land/std@0.92.0/async/pool.ts": "876f9e6815366cd017a3b4fbb9e9ae40310b1b6972f1bd541c94358bc11fb7e5", 235 | "https://deno.land/std@0.92.0/bytes/mod.ts": "1ae1ccfe98c4b979f12b015982c7444f81fcb921bea7aa215bf37d84f46e1e13", 236 | "https://deno.land/std@0.92.0/hash/sha1.ts": "1cca324b4b253885a47f121adafcfac55b4cc96113e22b338e1db26f37a730b8", 237 | "https://deno.land/std@0.92.0/http/_io.ts": "bf1331dd3be8aace9120614c1fedc2bb2449edc4779e31b74c0181ea9173f702", 238 | "https://deno.land/std@0.92.0/http/http_status.ts": "ebaa9bebfb8adc3d7b20c49e11037e4eefd79629ad80d81383933f4cdc91b3eb", 239 | "https://deno.land/std@0.92.0/http/server.ts": "d4e17c2aa5a5c65a2d19b9f24483be5f6c2a3e03665996fdf973e53c43091b48", 240 | "https://deno.land/std@0.92.0/io/buffer.ts": "2a92f02c1d8daaebaf13e5678ea5969c89f4fab533f687b9e7e86f49f11c3118", 241 | "https://deno.land/std@0.92.0/io/bufio.ts": "4053ea5d978479be68ae4d73424045a59c6b7a6e8f66727e4bfde516baa07126", 242 | "https://deno.land/std@0.92.0/io/ioutil.ts": "275fa440494df9b4b3aa656301ced2eeac533feec128b3a39b2b40f4cd957e42", 243 | "https://deno.land/std@0.92.0/io/util.ts": "03ca10e063afce551c501505c607ec336a40b9cb72363f5508e2a9ac81096bbf", 244 | "https://deno.land/std@0.92.0/textproto/mod.ts": "1c89b39a079dd158893ab2e9ff79391c66049433d6ca82da7d64b32280570d51", 245 | "https://deno.land/std@0.92.0/ws/mod.ts": "bc521b3066441eb115ac94e3507bcc73098542f81d8d3ce7aad8d837316ce990" 246 | }, 247 | "workspace": { 248 | "dependencies": [ 249 | "jsr:@deno/dnt@^0.41.1" 250 | ] 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /api/trade.ts: -------------------------------------------------------------------------------- 1 | import { ClientContext } from "../factory/createClient.ts"; 2 | 3 | // Used for fields where the type may change based on the context, such as prices. 4 | export type UnstableNumber = string | number; 5 | 6 | export type Nullable = T | null; 7 | 8 | export type AccountStatus = 9 | | "ONBOARDING" 10 | | "SUBMISSION_FAILED" 11 | | "SUBMITTED" 12 | | "ACCOUNT_UPDATED" 13 | | "APPROVAL_PENDING" 14 | | "ACTIVE" 15 | | "REJECTED"; 16 | 17 | export type OptionsApprovedLevel = 0 | 1 | 2; 18 | 19 | export type OptionsTradingLevel = 0 | 1 | 2; 20 | 21 | export type Account = { 22 | id: string; 23 | account_number: string; 24 | status: AccountStatus; 25 | currency: string; 26 | cash: string; 27 | portfolio_value: string; 28 | non_marginable_buying_power: string; 29 | accrued_fees: string; 30 | pending_transfer_in: string; 31 | pending_transfer_out: string; 32 | pattern_day_trader: boolean; 33 | trade_suspended_by_user: boolean; 34 | trading_blocked: boolean; 35 | transfers_blocked: boolean; 36 | account_blocked: boolean; 37 | created_at: string; 38 | shorting_enabled: boolean; 39 | long_market_value: string; 40 | short_market_value: string; 41 | equity: string; 42 | last_equity: string; 43 | multiplier: string; 44 | buying_power: string; 45 | initial_margin: string; 46 | maintenance_margin: string; 47 | sma: string; 48 | daytrade_count: number; 49 | last_maintenance_margin: string; 50 | daytrading_buying_power: string; 51 | regt_buying_power: string; 52 | options_buying_power: string; 53 | options_approved_level: OptionsApprovedLevel; 54 | options_trading_level: OptionsTradingLevel; 55 | }; 56 | 57 | export const getAccount = ({ request }: ClientContext) => () => 58 | request({ 59 | path: "/v2/account", 60 | }); 61 | 62 | export type BaseOrder = { 63 | id: string; 64 | client_order_id: string; 65 | created_at: string; 66 | updated_at: string; 67 | submitted_at: string; 68 | filled_at: Nullable; 69 | expired_at: Nullable; 70 | canceled_at: Nullable; 71 | failed_at: Nullable; 72 | replaced_at: Nullable; 73 | replaced_by: Nullable; 74 | replaces: Nullable; 75 | asset_id: string; 76 | notional: Nullable; 77 | qty: string; 78 | filled_qty: string; 79 | filled_avg_price: Nullable; 80 | order_class: string; 81 | order_type: string; 82 | type: Type; 83 | side: string; 84 | time_in_force: string; 85 | limit_price: Nullable; 86 | stop_price: Nullable; 87 | status: string; 88 | extended_hours: boolean; 89 | legs?: Nullable; 90 | trail_percent: Nullable; 91 | trail_price: Nullable; 92 | hwm: Nullable; 93 | subtag: Nullable; 94 | source: Nullable; 95 | }; 96 | 97 | export type EquityOrder = BaseOrder & { 98 | asset_class: "us_equity"; 99 | symbol: string; 100 | }; 101 | 102 | export type OptionsOrder = BaseOrder & { 103 | asset_class: "us_option"; 104 | symbol: string; 105 | order_class: "simple"; 106 | }; 107 | 108 | export type CryptoOrder = BaseOrder & { 109 | asset_class: "crypto"; 110 | symbol: string; 111 | }; 112 | 113 | export type Order = EquityOrder | OptionsOrder | CryptoOrder; 114 | 115 | export type Position = { 116 | asset_id: string; 117 | exchange: string; 118 | asset_class: string; 119 | symbol: string; 120 | asset_marginable: boolean; 121 | qty: string; 122 | avg_entry_price: string; 123 | side: Direction; 124 | market_value: string; 125 | cost_basis: string; 126 | unrealized_pl: string; 127 | unrealized_plpc: string; 128 | unrealized_intraday_pl: string; 129 | unrealized_intraday_plpc: string; 130 | current_price: string; 131 | lastday_price: string; 132 | change_today: string; 133 | qty_available: string; 134 | }; 135 | 136 | export type TimeInForce = "day" | "gtc" | "opg" | "cls" | "ioc" | "fok"; 137 | 138 | export type PositionIntent = 139 | | "buy_to_open" 140 | | "buy_to_close" 141 | | "sell_to_open" 142 | | "sell_to_close"; 143 | 144 | export type Type = "market" | "limit" | "stop" | "stop_limit" | "trailing_stop"; 145 | 146 | export type Side = "buy" | "sell"; 147 | 148 | export type OrderClass = "simple" | "oco" | "oto" | "bracket" | ""; 149 | 150 | export type Direction = "long" | "short"; 151 | 152 | export type TakeProfit = { 153 | limit_price?: string; 154 | }; 155 | 156 | export type StopLoss = { 157 | stop_price?: string; 158 | limit_price?: string; 159 | }; 160 | 161 | export type CreateOrderOptions = { 162 | symbol: string; 163 | qty?: UnstableNumber; 164 | notional?: UnstableNumber; 165 | side: Side; 166 | type: Type; 167 | time_in_force: TimeInForce; 168 | limit_price?: UnstableNumber; 169 | stop_price?: UnstableNumber; 170 | trail_price?: UnstableNumber; 171 | trail_percent?: UnstableNumber; 172 | extended_hours?: boolean; 173 | client_order_id?: string; 174 | order_class?: OrderClass; 175 | take_profit?: TakeProfit; 176 | stop_loss?: StopLoss; 177 | position_intent?: PositionIntent; 178 | }; 179 | 180 | export const createOrder = 181 | ({ request }: ClientContext) => (data: CreateOrderOptions) => 182 | request({ 183 | path: "/v2/orders", 184 | method: "POST", 185 | data, 186 | }); 187 | 188 | export type GetOrderOptions = { 189 | order_id: string; 190 | }; 191 | 192 | export const getOrder = 193 | ({ request }: ClientContext) => ({ order_id }: GetOrderOptions) => 194 | request({ 195 | path: `/v2/orders/${order_id}`, 196 | method: "GET", 197 | }); 198 | 199 | export type GetOrdersOptions = { 200 | status?: string; 201 | limit?: UnstableNumber; 202 | after?: string; 203 | until?: string; 204 | direction?: Direction; 205 | nested?: boolean; 206 | symbols?: string; 207 | side?: Side; 208 | order_id: string; 209 | }; 210 | 211 | export const getOrders = 212 | ({ request }: ClientContext) => (params: GetOrdersOptions) => 213 | request({ 214 | path: "/v2/orders", 215 | method: "GET", 216 | params, 217 | }); 218 | 219 | export type ReplaceOrderOptions = { 220 | qty?: UnstableNumber; 221 | time_in_force?: string; 222 | limit_price?: UnstableNumber; 223 | stop_price?: UnstableNumber; 224 | trail?: UnstableNumber; 225 | client_order_id?: string; 226 | order_id: string; 227 | }; 228 | 229 | export const replaceOrder = 230 | ({ request }: ClientContext) => (data: ReplaceOrderOptions) => 231 | request({ 232 | path: `/v2/orders/${data.order_id}`, 233 | method: "PATCH", 234 | data, 235 | }); 236 | 237 | export type CancelOrderOptions = { 238 | order_id: string; 239 | }; 240 | 241 | export const cancelOrder = 242 | ({ request }: ClientContext) => ({ order_id }: CancelOrderOptions) => 243 | request({ 244 | path: `/v2/orders/${order_id}`, 245 | method: "DELETE", 246 | }); 247 | 248 | export const cancelOrders = ({ request }: ClientContext) => () => 249 | request({ 250 | path: "/v2/orders", 251 | method: "DELETE", 252 | }); 253 | 254 | export type GetPositionOptions = { 255 | symbol_or_asset_id: string; 256 | }; 257 | 258 | export const getPosition = 259 | ({ request }: ClientContext) => 260 | ({ symbol_or_asset_id }: GetPositionOptions) => 261 | request({ 262 | path: `/v2/positions/${symbol_or_asset_id}`, 263 | method: "GET", 264 | }); 265 | 266 | export const getPositions = ({ request }: ClientContext) => () => 267 | request>({ 268 | path: "/v2/positions", 269 | method: "GET", 270 | }); 271 | 272 | export type ClosePositionOptions = { 273 | symbol_or_asset_id: string; 274 | }; 275 | 276 | export const closePosition = 277 | ({ request }: ClientContext) => 278 | ({ symbol_or_asset_id }: ClosePositionOptions) => 279 | request({ 280 | path: `/v2/positions/${symbol_or_asset_id}`, 281 | method: "DELETE", 282 | }); 283 | 284 | export const closePositions = ({ request }: ClientContext) => () => 285 | request>>({ 286 | path: "/v2/positions", 287 | method: "DELETE", 288 | }); 289 | 290 | export type GetAssetsOptions = { 291 | status?: string; 292 | asset_class?: string; 293 | asset_status?: string; 294 | }; 295 | 296 | export type ExerciseOption = { 297 | symbol_or_contract_id: string; 298 | }; 299 | 300 | export const exerciseOption = 301 | ({ request }: ClientContext) => ({ symbol_or_contract_id }: ExerciseOption) => 302 | request({ 303 | path: `/v2/positions/${symbol_or_contract_id}/exercise`, 304 | method: "POST", 305 | }); 306 | 307 | export type GetCalendarOptions = { 308 | start?: string; 309 | end?: string; 310 | dateType?: "TRADING" | "SETTLEMENT"; 311 | }; 312 | 313 | export type Calendar = { 314 | date: string; 315 | open: string; 316 | close: string; 317 | settlement_date: string; 318 | }; 319 | 320 | export const getCalendar = 321 | ({ request }: ClientContext) => (params: GetCalendarOptions = {}) => 322 | request({ 323 | path: "/v2/calendar", 324 | method: "GET", 325 | params, 326 | }); 327 | 328 | export type Clock = { 329 | timestamp: string; 330 | is_open: boolean; 331 | next_open: string; 332 | next_close: string; 333 | }; 334 | 335 | export const getClock = ({ request }: ClientContext) => () => 336 | request({ 337 | path: "/v2/clock", 338 | }); 339 | 340 | export type GetAssetOptions = { 341 | symbol_or_asset_id: string; 342 | }; 343 | 344 | export const getAsset = 345 | ({ request }: ClientContext) => ({ symbol_or_asset_id }: GetAssetOptions) => 346 | request({ 347 | path: `/v2/assets/${symbol_or_asset_id}`, 348 | method: "GET", 349 | }); 350 | 351 | export type Asset = { 352 | id: string; 353 | class: string; 354 | exchange: string; 355 | symbol: string; 356 | name: string; 357 | status: string; 358 | tradable: boolean; 359 | marginable: boolean; 360 | shortable: boolean; 361 | easy_to_borrow: boolean; 362 | fractionable: boolean; 363 | maintenance_margin_requirement: string; 364 | tradability: string; 365 | symbol_with_class: string; 366 | asset_id: string; 367 | }; 368 | 369 | export const getAssets = 370 | ({ request }: ClientContext) => (params: GetAssetsOptions = {}) => 371 | request({ 372 | path: "/v2/assets", 373 | method: "GET", 374 | params, 375 | }); 376 | 377 | export type Watchlist = { 378 | id: string; 379 | account_id: string; 380 | created_at: string; 381 | updated_at: string; 382 | name: string; 383 | assets: Asset[]; 384 | }; 385 | 386 | export type GetWatchlistOptions = { 387 | watchlist_id: string; 388 | }; 389 | 390 | export const getWatchlist = 391 | ({ request }: ClientContext) => ({ watchlist_id }: GetWatchlistOptions) => 392 | request({ 393 | path: `/v2/watchlists/${watchlist_id}`, 394 | }); 395 | 396 | export const getWatchlists = ({ request }: ClientContext) => () => 397 | request({ 398 | path: "/v2/watchlists", 399 | }); 400 | 401 | export type CreateWatchlistOptions = { 402 | name: string; 403 | symbols: Nullable; 404 | }; 405 | 406 | export const createWatchlist = 407 | ({ request }: ClientContext) => (data: CreateWatchlistOptions) => 408 | request({ 409 | path: "/v2/watchlists", 410 | method: "POST", 411 | data, 412 | }); 413 | 414 | export type UpdateWatchlistOptions = { 415 | name: string; 416 | symbols: Nullable; 417 | watchlist_id: string; 418 | }; 419 | 420 | export const updateWatchlist = 421 | ({ request }: ClientContext) => (data: UpdateWatchlistOptions) => 422 | request({ 423 | path: `/v2/watchlists/${data.watchlist_id}`, 424 | method: "PATCH", 425 | data, 426 | }); 427 | 428 | export type DeleteWatchlistOptions = { 429 | watchlist_id: string; 430 | }; 431 | 432 | export const deleteWatchlist = 433 | ({ request }: ClientContext) => ({ watchlist_id }: DeleteWatchlistOptions) => 434 | request({ 435 | path: `/v2/watchlists/${watchlist_id}`, 436 | method: "DELETE", 437 | }); 438 | 439 | export type PortfolioHistory = { 440 | timestamp: string[]; 441 | equity: string[]; 442 | profit_loss: string[]; 443 | profit_loss_pct: string[]; 444 | base_value: string; 445 | base_value_asof: string; 446 | timeframe: string; 447 | }; 448 | 449 | export type GetPortfolioHistoryOptions = { 450 | period?: string; 451 | timeframe?: string; 452 | intraday_reporting?: string; 453 | start?: string; 454 | end?: string; 455 | pnl_reset?: string; 456 | }; 457 | 458 | export const getPortfolioHistory = 459 | ({ request }: ClientContext) => (params: GetPortfolioHistoryOptions) => 460 | request({ 461 | path: "/v2/account/portfolio/history", 462 | method: "GET", 463 | params, 464 | }); 465 | 466 | export type Configurations = { 467 | dtbp_check: string; 468 | trade_confirm_email: string; 469 | suspend_trade: boolean; 470 | no_shorting: boolean; 471 | fractional_trading: boolean; 472 | max_margin_multiplier: string; 473 | max_options_trading_level: number; 474 | pdt_check: string; 475 | ptp_no_exception_entry: boolean; 476 | }; 477 | 478 | export const getConfigurations = ({ request }: ClientContext) => () => 479 | request({ 480 | path: "/v2/account/configurations", 481 | }); 482 | 483 | export type UpdateConfigurationsOptions = { 484 | dtbp_check?: string; 485 | trade_confirm_email?: string; 486 | suspend_trade?: boolean; 487 | no_shorting?: boolean; 488 | fractional_trading?: boolean; 489 | max_margin_multiplier?: string; 490 | max_options_trading_level?: number; 491 | pdt_check?: string; 492 | ptp_no_exception_entry?: boolean; 493 | }; 494 | 495 | export const updateConfigurations = 496 | ({ request }: ClientContext) => (data: UpdateConfigurationsOptions) => 497 | request({ 498 | path: "/v2/account/configurations", 499 | method: "PATCH", 500 | data, 501 | }); 502 | 503 | export type TradingActivity = { 504 | activity_type: string; 505 | id: string; 506 | cum_qty: string; 507 | leaves_qty: string; 508 | price: string; 509 | qty: string; 510 | side: string; 511 | symbol: string; 512 | transaction_time: string; 513 | order_id: string; 514 | type: string; 515 | order_status: string; 516 | }; 517 | 518 | export type NonTradeActivity = { 519 | activity_type: string; 520 | id: string; 521 | date: string; 522 | net_amount: string; 523 | symbol?: string; 524 | qty?: string; 525 | per_share_amount?: string; 526 | }; 527 | 528 | export type Activity = TradingActivity | NonTradeActivity; 529 | 530 | export type GetActivityOptions = { 531 | activity_type: string; 532 | activity_types?: string; 533 | date?: string; 534 | until?: string; 535 | after?: string; 536 | direction?: string; 537 | pageSize?: number; 538 | pageToken?: string; 539 | category?: string; 540 | }; 541 | 542 | export const getActivity = 543 | ({ request }: ClientContext) => ({ activity_type }: GetActivityOptions) => 544 | request({ 545 | path: `/v2/account/activities/${activity_type}`, 546 | method: "GET", 547 | }); 548 | 549 | export const getActivities = ({ request }: ClientContext) => () => 550 | request({ 551 | path: "/v2/account/activities", 552 | method: "GET", 553 | }); 554 | 555 | export type OptionsContract = { 556 | id: string; 557 | symbol: string; 558 | name: string; 559 | status: string; 560 | tradable: boolean; 561 | tradability: string; 562 | chain_id: string; 563 | type: string; 564 | option_type: string; 565 | expiration_date: string; 566 | strike_price: string; 567 | min_ticks: { 568 | above_tick: string; 569 | below_tick: string; 570 | cutoff_price: string; 571 | }; 572 | option_style: string; 573 | created_at: string; 574 | updated_at: string; 575 | last_trade_date: string; 576 | underlying: string; 577 | tradable_chain_id: string; 578 | chain_symbol: string; 579 | description: string; 580 | asset_id: string; 581 | }; 582 | 583 | export type GetOptionsContractOptions = { 584 | symbol_or_contract_id: string; 585 | }; 586 | 587 | export const getOptionsContract = 588 | ({ request }: ClientContext) => 589 | ({ symbol_or_contract_id }: GetOptionsContractOptions) => 590 | request({ 591 | path: `/v2/options/contracts/${symbol_or_contract_id}`, 592 | method: "GET", 593 | }); 594 | 595 | export type GetOptionsContractsOptions = { 596 | underlying_symbols?: string; 597 | status?: string; 598 | active?: boolean; 599 | expiration_date?: string; 600 | expiration_date_gte?: string; 601 | expiration_date_lte?: string; 602 | root_symbol?: string; 603 | type?: string; 604 | style?: string; 605 | strike_price_gte?: UnstableNumber; 606 | strike_price_lte?: UnstableNumber; 607 | page_token?: string; 608 | limit?: UnstableNumber; 609 | symbol_or_contract_id: string; 610 | }; 611 | 612 | export const getOptionsContracts = 613 | ({ request }: ClientContext) => (params: GetOptionsContractsOptions) => 614 | request({ 615 | path: "/v2/options/contracts", 616 | method: "GET", 617 | params, 618 | }); 619 | 620 | export type CorporateAction = { 621 | id: string; 622 | corporate_actions_id: string; 623 | ca_type: string; 624 | ca_sub_type: string; 625 | initiating_symbol: string; 626 | initiating_original_cusip: string; 627 | target_symbol: string; 628 | target_original_cusip: string; 629 | declaration_date: string; 630 | expiration_date: string; 631 | record_date: string; 632 | payable_date: string; 633 | cash: string; 634 | old_rate: string; 635 | new_rate: string; 636 | }; 637 | 638 | export type GetCorporateActionOptions = { 639 | id: string; 640 | }; 641 | 642 | export const getCorporateAction = 643 | ({ request }: ClientContext) => ({ id }: GetCorporateActionOptions) => 644 | request({ 645 | path: `/v2/corporate_actions/announcements/${id}`, 646 | method: "GET", 647 | }); 648 | 649 | export type GetCorporateActionsOptions = { 650 | ca_types: string; 651 | since: string; 652 | until: string; 653 | symbol?: string; 654 | cusip?: string; 655 | date_type?: string; 656 | }; 657 | 658 | export const getCorporateActions = 659 | ({ request }: ClientContext) => (params: GetCorporateActionsOptions) => 660 | request({ 661 | path: "/v2/corporate_actions/announcements", 662 | method: "GET", 663 | params, 664 | }); 665 | 666 | export type CryptoWallet = { 667 | id: string; 668 | currency: string; 669 | balance: string; 670 | available: string; 671 | held: string; 672 | profile_id: string; 673 | }; 674 | 675 | export type GetWalletOptions = { 676 | asset: string; 677 | }; 678 | 679 | export const getCryptoWallet = 680 | ({ request }: ClientContext) => ({ asset }: GetWalletOptions) => 681 | request({ 682 | path: `/v2/wallets/${asset}`, 683 | method: "GET", 684 | }); 685 | 686 | export const getCryptoWallets = ({ request }: ClientContext) => () => 687 | request({ 688 | path: "/v2/wallets", 689 | method: "GET", 690 | }); 691 | 692 | export type CryptoFee = { 693 | fee: string; 694 | network_fee: string; 695 | estimated_delivery: string; 696 | }; 697 | 698 | export type GetCryptoFeeEstimateOptions = { 699 | asset: string; 700 | from_address: string; 701 | to_address: string; 702 | amount: string; 703 | }; 704 | 705 | export const getFeeEstimate = 706 | ({ request }: ClientContext) => (params: GetCryptoFeeEstimateOptions) => 707 | request({ 708 | path: "/v2/wallets/fees/estimate", 709 | method: "GET", 710 | params, 711 | }); 712 | 713 | export type CryptoTransfer = { 714 | id: string; 715 | tx_hash: string; 716 | direction: "INCOMING" | "OUTGOING"; 717 | status: "PROCESSING" | "FAILED" | "COMPLETE"; 718 | amount: string; 719 | usd_value: string; 720 | network_fee: string; 721 | fees: string; 722 | chain: string; 723 | asset: string; 724 | from_address: string; 725 | to_address: string; 726 | created_at: string; 727 | }; 728 | 729 | export type CryptoTransferResponse = { 730 | wallets?: CryptoWallet | CryptoWallet[]; 731 | transfers?: CryptoTransfer[]; 732 | }; 733 | 734 | export type GetCryptoTransferOptions = { 735 | transfer_id: string; 736 | }; 737 | 738 | export const getCryptoTransfer = 739 | ({ request }: ClientContext) => ({ transfer_id }: GetCryptoTransferOptions) => 740 | request({ 741 | path: `/v2/wallets/transfers/${transfer_id}`, 742 | method: "GET", 743 | }); 744 | 745 | export type GetCryptoTransfersOptions = { 746 | asset?: string; 747 | }; 748 | 749 | export const getCryptoTransfers = 750 | ({ request }: ClientContext) => (params?: GetCryptoTransfersOptions) => 751 | request({ 752 | path: "/v2/wallets/transfers", 753 | method: "GET", 754 | params, 755 | }); 756 | 757 | export type CreateCryptoTransferOptions = { 758 | amount: string; 759 | address: string; 760 | asset: string; 761 | }; 762 | 763 | export const createCryptoTransfer = 764 | ({ request }: ClientContext) => (data: CreateCryptoTransferOptions) => 765 | request({ 766 | path: "/v2/wallets/transfers", 767 | method: "POST", 768 | data, 769 | }); 770 | 771 | export type WhitelistedAddress = { 772 | id: string; 773 | chain: string; 774 | asset: string; 775 | address: string; 776 | status: "ACTIVE" | "PENDING"; 777 | created_at: string; 778 | }; 779 | 780 | export type GetCryptoWhitelistedAddressOptions = { 781 | address: string; 782 | asset: string; 783 | }; 784 | 785 | export const getCryptoWhitelistedAddress = 786 | ({ request }: ClientContext) => 787 | (params: GetCryptoWhitelistedAddressOptions) => 788 | request({ 789 | path: "/v2/wallets/whitelists", 790 | method: "GET", 791 | params, 792 | }); 793 | 794 | export const getCryptoWhitelistedAddresses = 795 | ({ request }: ClientContext) => () => 796 | request({ 797 | path: "/v2/wallets/whitelists", 798 | method: "GET", 799 | }); 800 | 801 | export type RequestCryptoWhitelistedAddressOptions = { 802 | address: string; 803 | asset: string; 804 | }; 805 | 806 | export const requestCryptoWhitelistedAddress = 807 | ({ request }: ClientContext) => 808 | (data: RequestCryptoWhitelistedAddressOptions) => 809 | request({ 810 | path: "/v2/wallets/whitelists", 811 | method: "POST", 812 | data, 813 | }); 814 | 815 | export type RemoveCryptoWhitelistedAddressOptions = { 816 | whitelisted_address_id: string; 817 | }; 818 | 819 | export const removeCryptoWhitelistedAddress = 820 | ({ request }: ClientContext) => 821 | ({ whitelisted_address_id }: RemoveCryptoWhitelistedAddressOptions) => 822 | request({ 823 | path: `/v2/wallets/whitelists/${whitelisted_address_id}`, 824 | method: "DELETE", 825 | }); 826 | -------------------------------------------------------------------------------- /api/marketData.ts: -------------------------------------------------------------------------------- 1 | import { baseURLs, ClientContext } from "../factory/createClient.ts"; 2 | import { Nullable } from "./trade.ts"; 3 | 4 | export type ReverseSplit = { 5 | symbol: string; 6 | new_rate: number; 7 | old_rate: number; 8 | process_date: string; 9 | ex_date: string; 10 | record_date: string; 11 | payable_date?: string; 12 | }; 13 | 14 | export type ForwardSplit = { 15 | symbol: string; 16 | new_rate: number; 17 | old_rate: number; 18 | process_date: string; 19 | ex_date: string; 20 | record_date: string; 21 | payable_date?: string; 22 | due_bill_redemption_date?: string; 23 | }; 24 | 25 | export type UnitSplit = { 26 | old_symbol: string; 27 | old_rate: number; 28 | new_symbol: string; 29 | new_rate: number; 30 | alternate_symbol: string; 31 | alternate_rate: number; 32 | process_date: string; 33 | effective_date: string; 34 | payable_date?: string; 35 | }; 36 | 37 | export type StockDividend = { 38 | symbol: string; 39 | rate: number; 40 | process_date: string; 41 | ex_date: string; 42 | record_date: string; 43 | payable_date?: string; 44 | }; 45 | 46 | export type CashDividend = { 47 | symbol: string; 48 | rate: number; 49 | special: boolean; 50 | foreign: boolean; 51 | process_date: string; 52 | ex_date: string; 53 | record_date: string; 54 | payable_date?: string; 55 | due_bill_on_date?: string; 56 | due_bill_off_date?: string; 57 | }; 58 | 59 | export type SpinOff = { 60 | source_symbol: string; 61 | source_rate: number; 62 | new_symbol: string; 63 | new_rate: number; 64 | process_date: string; 65 | ex_date: string; 66 | record_date: string; 67 | payable_date?: string; 68 | due_bill_redemption_date?: string; 69 | }; 70 | 71 | export type CashMerger = { 72 | acquirer_symbol: string; 73 | acquiree_symbol: string; 74 | rate: number; 75 | process_date: string; 76 | effective_date: string; 77 | payable_date?: string; 78 | }; 79 | 80 | export type StockMerger = { 81 | acquirer_symbol: string; 82 | acquirer_rate: number; 83 | acquiree_symbol: string; 84 | acquiree_rate: number; 85 | process_date: string; 86 | effective_date: string; 87 | payable_date?: string; 88 | }; 89 | 90 | export type StockAndCashMerger = { 91 | acquirer_symbol: string; 92 | acquirer_rate: number; 93 | acquiree_symbol: string; 94 | acquiree_rate: number; 95 | cash_rate: number; 96 | process_date: string; 97 | effective_date: string; 98 | payable_date?: string; 99 | }; 100 | 101 | export type Redemption = { 102 | symbol: string; 103 | rate: number; 104 | process_date: string; 105 | payable_date?: string; 106 | }; 107 | 108 | export type NameChange = { 109 | old_symbol: string; 110 | new_symbol: string; 111 | process_date: string; 112 | }; 113 | 114 | export type WorthlessRemoval = { 115 | symbol: string; 116 | process_date: string; 117 | }; 118 | 119 | export type Sort = "asc" | "desc"; 120 | 121 | export type CorporateActions = { 122 | corporate_actions: { 123 | reverse_splits?: ReverseSplit[]; 124 | forward_splits?: ForwardSplit[]; 125 | unit_splits?: UnitSplit[]; 126 | stock_dividends?: StockDividend[]; 127 | cash_dividends?: CashDividend[]; 128 | spin_offs?: SpinOff[]; 129 | cash_mergers?: CashMerger[]; 130 | stock_mergers?: StockMerger[]; 131 | stock_and_cash_mergers?: StockAndCashMerger[]; 132 | redemptions?: Redemption[]; 133 | name_changes?: NameChange[]; 134 | worthless_removals?: WorthlessRemoval[]; 135 | next_page_token: Nullable; 136 | }; 137 | }; 138 | 139 | export type GetStocksCorporateActionsOptions = { 140 | symbols: string; 141 | types?: string; 142 | start?: string; 143 | end?: string; 144 | limit?: number; 145 | page_token?: string; 146 | sort?: Sort; 147 | }; 148 | 149 | export const getStocksCorporateActions = 150 | (context: ClientContext) => (params: GetStocksCorporateActionsOptions) => 151 | context.request({ 152 | baseURL: baseURLs.marketData, 153 | path: "/v1beta1/corporate-actions", 154 | method: "GET", 155 | params, 156 | }); 157 | 158 | export type Logo = string; 159 | 160 | export type GetLogoOptions = { 161 | symbol: string; 162 | placeholder?: boolean; 163 | }; 164 | 165 | export const getLogo = (context: ClientContext) => (params: GetLogoOptions) => 166 | context.request({ 167 | baseURL: baseURLs.marketData, 168 | path: "/v1beta1/logos/:symbol", 169 | method: "GET", 170 | params, 171 | }); 172 | 173 | export interface News { 174 | news: NewsArticle[]; 175 | next_page_token: Nullable; 176 | } 177 | 178 | export interface NewsArticleImage { 179 | size: "thumb" | "small" | "large"; 180 | url: string; 181 | } 182 | 183 | export interface NewsArticle { 184 | id: number; 185 | headline: string; 186 | author: string; 187 | created_at: string; 188 | updated_at: string; 189 | summary: string; 190 | content: string; 191 | url: Nullable; 192 | images: NewsArticleImage[]; 193 | symbols: string[]; 194 | source: string; 195 | } 196 | 197 | export type GetNewsOptions = { 198 | start?: string; 199 | end?: string; 200 | sort?: string; 201 | symbols?: string; 202 | limit?: number; 203 | include_content?: boolean; 204 | exclude_contentless?: boolean; 205 | page_token?: string; 206 | }; 207 | 208 | export const getNews = (context: ClientContext) => (params: GetNewsOptions) => 209 | context.request({ 210 | baseURL: baseURLs.marketData, 211 | path: "/v1beta1/news", 212 | method: "GET", 213 | params, 214 | }); 215 | 216 | export type MostActive = { 217 | symbol: string; 218 | volume: number; 219 | trade_count: number; 220 | }; 221 | 222 | export type MostActives = { 223 | most_actives: MostActive[]; 224 | last_updated: string; 225 | }; 226 | 227 | export type MarketMovers = { 228 | gainers: MarketMover[]; 229 | losers: MarketMover[]; 230 | market_type: string; 231 | last_updated: string; 232 | }; 233 | 234 | export type MarketMover = { 235 | symbol: string; 236 | percent_change: number; 237 | change: number; 238 | price: number; 239 | }; 240 | 241 | export type GetStocksMostActivesOptions = { 242 | by?: string; 243 | top?: number; 244 | }; 245 | 246 | export const getStocksMostActives = 247 | (context: ClientContext) => (params: GetStocksMostActivesOptions) => 248 | context.request({ 249 | baseURL: baseURLs.marketData, 250 | path: "/v1beta1/screener/stocks/most-actives", 251 | method: "GET", 252 | params, 253 | }); 254 | 255 | export type GetStocksMarketMoversOptions = { 256 | by?: string; 257 | top?: number; 258 | }; 259 | 260 | export const getStocksMarketMovers = 261 | (context: ClientContext) => (params: GetStocksMarketMoversOptions) => 262 | context.request({ 263 | baseURL: baseURLs.marketData, 264 | path: "/v1beta1/screener/stocks/market-movers", 265 | method: "GET", 266 | params, 267 | }); 268 | 269 | export type GetStocksQuotesOptions = { 270 | symbols: string; 271 | start?: string; 272 | end?: string; 273 | limit?: number; 274 | asof?: string; 275 | feed?: string; 276 | sip?: string; 277 | page_token?: string; 278 | sort?: Sort; 279 | }; 280 | 281 | export type StocksQuotes = { 282 | quotes: { [symbol: string]: StockQuote[] }; 283 | next_page_token: Nullable; 284 | }; 285 | 286 | export const getStocksQuotes = 287 | (context: ClientContext) => (params: GetStocksQuotesOptions) => 288 | context.request({ 289 | baseURL: baseURLs.marketData, 290 | path: "/v2/stocks/quotes", 291 | method: "GET", 292 | params, 293 | }); 294 | 295 | export type GetStocksQuotesLatestOptions = { 296 | symbols: string; 297 | feed?: string; 298 | }; 299 | 300 | export type StocksQuotesLatest = { 301 | quotes: { [symbol: string]: StockQuote }; 302 | }; 303 | 304 | export const getStocksQuotesLatest = 305 | (context: ClientContext) => (params: GetStocksQuotesLatestOptions) => 306 | context.request({ 307 | baseURL: baseURLs.marketData, 308 | path: "/v2/stocks/quotes/latest", 309 | method: "GET", 310 | params, 311 | }); 312 | 313 | export type GetStocksBarsOptions = { 314 | symbols: string; 315 | timeframe: string; 316 | start?: string; 317 | end?: string; 318 | limit?: number; 319 | adjustment?: string; 320 | asof?: string; 321 | feed?: string; 322 | page_token?: string; 323 | sort?: string; 324 | }; 325 | 326 | export type StocksBars = { 327 | bars: { [symbol: string]: StocksBar[] }; 328 | next_page_token: Nullable; 329 | }; 330 | 331 | export type StocksBar = { 332 | t: string; 333 | o: number; 334 | h: number; 335 | l: number; 336 | c: number; 337 | v: number; 338 | n: number; 339 | vw: number; 340 | }; 341 | 342 | export const getStocksBars = 343 | (context: ClientContext) => (params: GetStocksBarsOptions) => 344 | context.request({ 345 | baseURL: baseURLs.marketData, 346 | path: "/v2/stocks/bars", 347 | method: "GET", 348 | params, 349 | }); 350 | 351 | export type GetStocksBarsLatestOptions = { 352 | symbols: string; 353 | feed?: string; 354 | currency?: string; 355 | }; 356 | 357 | export type StocksBarsLatest = { 358 | bars: { [symbol: string]: StocksBar }; 359 | }; 360 | 361 | export const getStocksBarsLatest = 362 | (context: ClientContext) => (params: GetStocksBarsLatestOptions) => 363 | context.request({ 364 | baseURL: baseURLs.marketData, 365 | path: "/v2/stocks/bars/latest", 366 | method: "GET", 367 | params, 368 | }); 369 | 370 | export type GetForexRatesOptions = { 371 | currency_pairs: string; 372 | timeframe: string; 373 | start?: string; 374 | end?: string; 375 | limit?: number; 376 | sort?: Sort; 377 | page_token?: string; 378 | }; 379 | 380 | export type ForexRate = { 381 | bp: number; 382 | mp: number; 383 | ap: number; 384 | t: string; 385 | }; 386 | 387 | export type ForexRates = { 388 | next_page_token: string; 389 | rates: { 390 | [currencyPair: string]: ForexRate[]; 391 | }; 392 | }; 393 | 394 | export const getForexRates = 395 | (context: ClientContext) => (params: GetForexRatesOptions) => 396 | context.request({ 397 | baseURL: baseURLs.marketData, 398 | path: "/v1beta1/forex/rates", 399 | method: "GET", 400 | params, 401 | }); 402 | 403 | export type ForexRatesLatest = { 404 | rates: { 405 | [currencyPair: string]: ForexRate; 406 | }; 407 | }; 408 | 409 | export type GetForexRatesLatestOptions = { 410 | currency_pairs: string; 411 | }; 412 | 413 | export const getLatestForexRates = 414 | (context: ClientContext) => (params: GetForexRatesLatestOptions) => 415 | context.request({ 416 | baseURL: baseURLs.marketData, 417 | path: "/v1beta1/forex/latest/rates", 418 | method: "GET", 419 | params, 420 | }); 421 | 422 | export type GetStocksSnapshotsOptions = { 423 | symbols: string; 424 | feed?: "sip" | "iex" | "otc"; 425 | sip?: string; 426 | }; 427 | 428 | export type StockTrade = { 429 | t: string; 430 | p: number; 431 | s: number; 432 | c: string[]; 433 | i: number; 434 | z: string; 435 | }; 436 | 437 | export type StockQuote = { 438 | t: string; 439 | ax: string; 440 | ap: number; 441 | as: number; 442 | bx: string; 443 | bp: number; 444 | bs: number; 445 | c: string[]; 446 | z: string; 447 | }; 448 | 449 | export type StockBar = { 450 | t: string; 451 | o: number; 452 | h: number; 453 | l: number; 454 | c: number; 455 | v: number; 456 | n: number; 457 | vw: number; 458 | }; 459 | 460 | export type StockSnapshots = { 461 | snapshots: { 462 | [symbol: string]: { 463 | latest_trade: StockTrade; 464 | latest_quote: StockQuote; 465 | minute_bar: StockBar; 466 | daily_bar: StockBar; 467 | prev_daily_bar: StockBar; 468 | }; 469 | }; 470 | }; 471 | 472 | export const getStocksSnapshots = 473 | (context: ClientContext) => (params: GetStocksSnapshotsOptions) => 474 | context.request({ 475 | baseURL: baseURLs.marketData, 476 | path: "/v1beta1/stocks/snapshots", 477 | method: "GET", 478 | params, 479 | }); 480 | 481 | export type StocksAuctions = { 482 | auctions: { [symbol: string]: StocksAuction[] }; 483 | next_page_token: Nullable; 484 | }; 485 | 486 | export type StocksAuction = { 487 | d: string; 488 | o: StocksAuctionPrice[]; 489 | c: StocksAuctionPrice[]; 490 | }; 491 | 492 | export type StocksAuctionPrice = { 493 | c: string; 494 | p: number; 495 | t: string; 496 | x: string; 497 | }; 498 | 499 | export type GetStocksAuctionsOptions = { 500 | symbols: string; 501 | start?: string; 502 | end?: string; 503 | limit?: number; 504 | asof?: string; 505 | feed?: string; 506 | page_token?: string; 507 | sort?: string; 508 | }; 509 | 510 | export const getStocksAuctions = 511 | (context: ClientContext) => (params: GetStocksAuctionsOptions) => 512 | context.request({ 513 | baseURL: baseURLs.marketData, 514 | path: "/v2/stocks/auctions", 515 | method: "GET", 516 | params, 517 | }); 518 | 519 | export type GetStocksConditionsOptions = { 520 | tickType: string; 521 | tape: string; 522 | }; 523 | 524 | export type StocksConditions = { 525 | conditions: { [code: string]: string }; 526 | }; 527 | 528 | export const getStocksConditions = 529 | (context: ClientContext) => (params: GetStocksConditionsOptions) => 530 | context.request({ 531 | baseURL: baseURLs.marketData, 532 | path: `/v2/stocks/meta/conditions/${params.tickType}`, 533 | method: "GET", 534 | params: { tape: params.tape }, 535 | }); 536 | 537 | export type StocksExchangeCodes = { 538 | exchanges: { [code: string]: string }; 539 | }; 540 | 541 | export const getStocksExchangeCodes = (context: ClientContext) => () => 542 | context.request({ 543 | baseURL: baseURLs.marketData, 544 | path: "/v2/stocks/meta/exchanges", 545 | method: "GET", 546 | }); 547 | 548 | export type GetStocksTradesOptions = { 549 | symbols: string; 550 | start?: string; 551 | end?: string; 552 | limit?: number; 553 | asof?: string; 554 | feed?: string; 555 | sip?: string; 556 | page_token?: string; 557 | sort?: Sort; 558 | }; 559 | 560 | export type StocksTrades = { 561 | trades: { [symbol: string]: StockTrade[] }; 562 | next_page_token: Nullable; 563 | }; 564 | 565 | export const getStocksTrades = 566 | (context: ClientContext) => (params: GetStocksTradesOptions) => 567 | context.request({ 568 | baseURL: baseURLs.marketData, 569 | path: "/v2/stocks/trades", 570 | method: "GET", 571 | params, 572 | }); 573 | 574 | export type GetStocksTradesLatestOptions = { 575 | symbols: string; 576 | feed?: "sip" | "iex" | "otc"; 577 | sip?: string; 578 | }; 579 | 580 | export type StocksTradesLatest = { 581 | trades: { [symbol: string]: StockTrade }; 582 | }; 583 | 584 | export const getStocksTradesLatest = 585 | (context: ClientContext) => (params: GetStocksTradesLatestOptions) => 586 | context.request({ 587 | baseURL: baseURLs.marketData, 588 | path: "/v2/stocks/trades/latest", 589 | method: "GET", 590 | params, 591 | }); 592 | 593 | export type OptionsBars = { 594 | bars: OptionBar[]; 595 | next_page_token: Nullable; 596 | }; 597 | 598 | export type OptionBar = { 599 | t: string; 600 | o: number; 601 | h: number; 602 | l: number; 603 | c: number; 604 | v: number; 605 | n: number; 606 | vw: number; 607 | }; 608 | 609 | export type GetOptionsBarsOptions = { 610 | symbols: string; 611 | timeframe: string; 612 | start?: string; 613 | end?: string; 614 | limit?: number; 615 | page_token?: string; 616 | sort?: Sort; 617 | }; 618 | 619 | export const getOptionsBars = 620 | (context: ClientContext) => (params: GetOptionsBarsOptions) => 621 | context.request({ 622 | baseURL: baseURLs.marketData, 623 | path: "/v1beta1/options/bars", 624 | method: "GET", 625 | params, 626 | }); 627 | 628 | export type OptionsExchanges = { 629 | [exchangeCode: string]: string; 630 | }; 631 | 632 | export const getOptionsExchanges = (context: ClientContext) => () => 633 | context.request({ 634 | baseURL: baseURLs.marketData, 635 | path: "/v1beta1/options/meta/exchanges", 636 | method: "GET", 637 | }); 638 | 639 | export type OptionsSnapshotsTrade = { 640 | t: string; 641 | x: string; 642 | p: number; 643 | s: number; 644 | c: string; 645 | }; 646 | 647 | export type OptionsSnapshotsQuote = { 648 | t: string; 649 | ax: string; 650 | ap: number; 651 | as: number; 652 | bx: string; 653 | bp: number; 654 | bs: number; 655 | c: string; 656 | }; 657 | 658 | export type OptionsSnapshots = { 659 | snapshots: { 660 | [symbol: string]: { 661 | latest_trade: OptionsSnapshotsTrade; 662 | latest_quote: OptionsSnapshotsQuote; 663 | }; 664 | }; 665 | }; 666 | 667 | export type GetOptionsSnapshotsOptions = { 668 | symbols: string; 669 | feed?: string; 670 | }; 671 | 672 | export const getOptionsSnapshots = 673 | (context: ClientContext) => (params: GetOptionsSnapshotsOptions) => 674 | context.request({ 675 | baseURL: baseURLs.marketData, 676 | path: "/v1beta1/options/snapshots", 677 | method: "GET", 678 | params, 679 | }); 680 | 681 | export type GetOptionsTradesOptions = { 682 | symbols: string; 683 | start?: string; 684 | end?: string; 685 | limit?: number; 686 | page_token?: string; 687 | sort?: Sort; 688 | }; 689 | 690 | export type OptionsTrades = { 691 | trades: { 692 | [symbol: string]: OptionsSnapshotsTrade[]; 693 | }; 694 | next_page_token: Nullable; 695 | }; 696 | 697 | export const getOptionsTrades = 698 | (context: ClientContext) => (params: GetOptionsTradesOptions) => 699 | context.request({ 700 | baseURL: baseURLs.marketData, 701 | path: "/v1beta1/options/trades", 702 | method: "GET", 703 | params, 704 | }); 705 | 706 | export type OptionsTradesLatest = { 707 | trades: { 708 | [symbol: string]: OptionsSnapshotsTrade[]; 709 | }; 710 | next_page_token: Nullable; 711 | }; 712 | 713 | export type GetOptionsTradesLatestOptions = { 714 | symbols: string; 715 | feed?: string; 716 | }; 717 | 718 | export const getOptionsTradesLatest = 719 | (context: ClientContext) => (params: GetOptionsTradesLatestOptions) => 720 | context.request({ 721 | baseURL: baseURLs.marketData, 722 | path: "/v1beta1/options/trades/latest", 723 | method: "GET", 724 | params, 725 | }); 726 | 727 | export type GetCryptoBarsOptions = { 728 | symbols: string; 729 | timeframe: string; 730 | start?: string; 731 | end?: string; 732 | limit?: number; 733 | page_token?: string; 734 | sort?: Sort; 735 | }; 736 | 737 | export type CryptoBars = { 738 | bars: { 739 | [symbol: string]: CryptoBar[]; 740 | }; 741 | next_page_token: Nullable; 742 | }; 743 | 744 | export type CryptoBar = { 745 | t: string; 746 | o: number; 747 | h: number; 748 | l: number; 749 | c: number; 750 | v: number; 751 | n: number; 752 | vw: number; 753 | }; 754 | 755 | export const getCryptoBars = 756 | (context: ClientContext) => (params: GetCryptoBarsOptions) => 757 | context.request({ 758 | baseURL: baseURLs.marketData, 759 | path: "/v1beta1/crypto/bars", 760 | method: "GET", 761 | params, 762 | }); 763 | 764 | export type GetCryptoBarsLatestOptions = { 765 | loc: string; 766 | symbols: string; 767 | }; 768 | 769 | export type CryptoBarsLatest = { 770 | bars: { [symbol: string]: CryptoBar }; 771 | }; 772 | 773 | export const getLatestCryptoBars = 774 | (context: ClientContext) => (params: GetCryptoBarsLatestOptions) => 775 | context.request({ 776 | baseURL: baseURLs.marketData, 777 | path: `/v1beta3/crypto/${params.loc}/latest/bars`, 778 | method: "GET", 779 | params: { 780 | symbols: params.symbols, 781 | }, 782 | }); 783 | 784 | export type GetCryptoQuotesOptions = { 785 | symbols: string; 786 | start?: string; 787 | end?: string; 788 | limit?: number; 789 | page_token?: string; 790 | sort?: Sort; 791 | }; 792 | 793 | export type CryptoQuote = { 794 | t: string; 795 | bp: number; 796 | bs: number; 797 | ap: number; 798 | as: number; 799 | }; 800 | 801 | export type CryptoQuotes = { 802 | quotes: { 803 | [symbol: string]: CryptoQuote[]; 804 | }; 805 | next_page_token: Nullable; 806 | }; 807 | 808 | export const getCryptoQuotes = 809 | (context: ClientContext) => (params: GetCryptoQuotesOptions) => 810 | context.request({ 811 | baseURL: baseURLs.marketData, 812 | path: "/v1beta1/crypto/quotes", 813 | method: "GET", 814 | params, 815 | }); 816 | 817 | export type CryptoQuotesLatest = { 818 | quotes: { [symbol: string]: CryptoQuote }; 819 | }; 820 | 821 | export type GetCryptoQuotesLatestOptions = { 822 | loc: string; 823 | symbols: string; 824 | }; 825 | 826 | export const getCryptoQuotesLatest = 827 | (context: ClientContext) => (params: GetCryptoQuotesLatestOptions) => 828 | context.request({ 829 | baseURL: baseURLs.marketData, 830 | path: `/v1beta3/crypto/${params.loc}/latest/quotes`, 831 | method: "GET", 832 | params: { 833 | symbols: params.symbols, 834 | }, 835 | }); 836 | 837 | export type CryptoTrade = { 838 | t: string; 839 | p: number; 840 | s: number; 841 | tks: string; 842 | i: number; 843 | }; 844 | 845 | export type CryptoSnapshots = { 846 | snapshots: { 847 | [symbol: string]: { 848 | daily_bar: CryptoBar; 849 | latest_quote: CryptoQuote; 850 | latest_trade: CryptoTrade; 851 | minute_bar: CryptoBar; 852 | prev_daily_bar: CryptoBar; 853 | }; 854 | }; 855 | }; 856 | 857 | export type GetCryptoSnapshotsOptions = { 858 | loc: string; 859 | symbols: string; 860 | }; 861 | 862 | export const getCryptoSnapshots = 863 | (context: ClientContext) => (params: GetCryptoSnapshotsOptions) => 864 | context.request({ 865 | baseURL: baseURLs.marketData, 866 | path: "/v1beta1/crypto/snapshots", 867 | method: "GET", 868 | params, 869 | }); 870 | 871 | export type GetCryptoTradesOptions = { 872 | loc: string; 873 | symbols: string; 874 | start?: string; 875 | end?: string; 876 | limit?: number; 877 | page_token?: string; 878 | sort?: string; 879 | }; 880 | 881 | export type CryptoTrades = { 882 | trades: { [symbol: string]: CryptoTrade[] }; 883 | next_page_token: Nullable; 884 | }; 885 | 886 | export const getCryptoTrades = 887 | (context: ClientContext) => (params: GetCryptoTradesOptions) => 888 | context.request({ 889 | baseURL: baseURLs.marketData, 890 | path: "/v1beta3/crypto/:loc/trades", 891 | method: "GET", 892 | params, 893 | }); 894 | 895 | export type CryptoTradesLatest = { 896 | trades: { [symbol: string]: CryptoTrade[] }; 897 | next_page_token: Nullable; 898 | }; 899 | 900 | export type GetCryptoTradesLatestOptions = { 901 | loc: string; 902 | symbols: string; 903 | }; 904 | 905 | export const getCryptoTradesLatest = 906 | (context: ClientContext) => (params: GetCryptoTradesLatestOptions) => 907 | context.request({ 908 | baseURL: baseURLs.marketData, 909 | path: `/v1beta3/crypto/${params.loc}/latest/trades`, 910 | method: "GET", 911 | params: { 912 | symbols: params.symbols, 913 | }, 914 | }); 915 | 916 | export type CryptoOrderbooksLatest = { 917 | orderbooks: { [symbol: string]: CryptoOrderbook }; 918 | }; 919 | 920 | export type CryptoOrderbook = { 921 | t: string; 922 | b: CryptoOrderbookEntry[]; 923 | a: CryptoOrderbookEntry[]; 924 | }; 925 | 926 | export type CryptoOrderbookEntry = { 927 | p: number; 928 | s: number; 929 | }; 930 | 931 | export type GetCryptoOrderbooksLatestOptions = { 932 | loc: string; 933 | symbols: string; 934 | }; 935 | 936 | export const getLatestCryptoOrderbooks = 937 | (context: ClientContext) => (params: GetCryptoOrderbooksLatestOptions) => 938 | context.request({ 939 | baseURL: baseURLs.marketData, 940 | path: `/v1beta3/crypto/${params.loc}/latest/orderbooks`, 941 | method: "GET", 942 | params: { 943 | symbols: params.symbols, 944 | }, 945 | }); 946 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > This SDK is no longer in development and is not maintained by Alpaca. 2 | > 3 | > Please see [alpaca-trade-api-js](https://github.com/alpacahq/alpaca-trade-api-js/) for our official JavaScript/TypesScript Client SDK. 4 | 5 | # typescript-sdk 6 | 7 | ![version](https://img.shields.io/badge/dynamic/json?label=version&query=$[0].name&url=https://api.github.com/repos/alpacahq/typescript-sdk/tags&style=flat&color=FF33A0) 8 | ![code](https://img.shields.io/github/languages/code-size/alpacahq/typescript-sdk?style=flat&color=196DFF&label=code) 9 | ![test](https://img.shields.io/github/actions/workflow/status/alpacahq/typescript-sdk/deno_test.yml?style=flat&label=test) 10 | ![coverage](https://img.shields.io/github/actions/workflow/status/alpacahq/typescript-sdk/deno_test_coverage.yml?style=flat&label=coverage) 11 | ![build](https://img.shields.io/github/actions/workflow/status/alpacahq/typescript-sdk/deno_deploy.yml?style=flat&label=deploy) 12 | 13 | A TypeScript SDK for the https://alpaca.markets REST API and WebSocket streams. 14 | 15 | - [Features](#features) 16 | - [Install](#install) 17 | - [Usage](#getting-started) 18 | - [Create a Client](#create-a-client) 19 | - [Configuration](#configuration) 20 | - [Environment Variables](#environment-variables) 21 | - [Rate Limiting](#rate-limiting) 22 | - [Methods](#methods) 23 | - [Trading API](#trading-api) 24 | - [Market Data API](#market-data-api) 25 | - [WebSocket](#websocket) 26 | - [How It Works](#how-it-works) 27 | - [Channels](#channels) 28 | - [Examples](#examples) 29 | - [Subscribe](#subscribe) 30 | - [Unsubscribe](#unsubscribe) 31 | - [Handle Messages](#handle-messages) 32 | - [Need Help?](#need-help) 33 | 34 | ## Features 35 | 36 | - [x] REST API 37 | - [x] WebSocket Streams 38 | - [x] Built-in Rate Limiting (Token Bucket) 39 | - [x] TypeScript 40 | - [x] Deno 41 | - [x] Node (ESM) 42 | - [x] > 35% Test Coverage (and growing) 43 | - [x] Tree-shakable 44 | - [x] Both ESM and CJS Support 45 | - [x] Zero Dependencies 🤯 (you read that right) 46 | - [x] Community Driven 🚀 47 | 48 | Feel free to contribute and PR to your 💖's content. 49 | 50 | ## Install 51 | 52 | From NPM: 53 | 54 | ```terminal 55 | npm install @alpacahq/typescript-sdk 56 | ``` 57 | 58 | From Skypack (or any CDN that supports ESM): 59 | 60 | ```ts 61 | import { createClient } from "https://cdn.skypack.dev/@alpacahq/typescript-sdk"; 62 | ``` 63 | 64 | ## Usage 65 | 66 | ### Create a Client 67 | 68 | First, you'll need to create an API key on the Alpaca website. You can do that [here](https://app.alpaca.markets). Once you have an API key, you can use it to create a client. 69 | 70 | ```ts 71 | import { createClient } from "@alpacahq/typescript-sdk"; 72 | 73 | const client = createClient({ 74 | key: "YOUR_API_KEY_ID", 75 | secret: "YOUR_API_SECRET_KEY", 76 | // Or, provide an access token if you're using OAuth. 77 | // accessToken: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 78 | }); 79 | ``` 80 | 81 | By default, the client will make requests to the paper trading environment (`https://paper-api.alpaca.markets`). This is a safety measure to prevent accidental trades. 82 | 83 | ### Configuration 84 | 85 | #### Environment Variables 86 | 87 | You can set the following environment variables to configure the client: 88 | 89 | - `APCA_KEY_ID`: Your API key. 90 | - `APCA_KEY_SECRET`: Your API secret. 91 | - `APCA_ACCESS_TOKEN`: Your access token (if using OAuth). 92 | - `APCA_DEBUG`: Enables debug logging. 93 | 94 | The client will automatically use these values if they are set. They will not override any credentials explicitly passed to `createClient`. 95 | 96 | #### Rate Limiting 97 | 98 | You can customize the rate limiting by passing a `tokenBucket` object to the `createClient` function. This object should contain the `capacity` and `fillRate` for the rate limiter. 99 | 100 | ```ts 101 | tokenBucket: { 102 | // Maximum number of tokens that can be stored 103 | capacity: 200, 104 | // Number of tokens refilled per second 105 | fillRate: 60, 106 | } 107 | ``` 108 | 109 | Bursting is allowed, but the client will block requests if the token bucket is empty. The token bucket is shared across all requests. If you have multiple clients they will not share the same bucket. 110 | 111 | ### Methods 112 | 113 | #### Trading API 114 | 115 | - [`getAccount`](#getaccount) 116 | - [`createOrder`](#createorder) 117 | - [`getOrder`](#getorder) 118 | - [`getOrders`](#getorders) 119 | - [`replaceOrder`](#replaceorder) 120 | - [`cancelOrder`](#cancelorder) 121 | - [`cancelOrders`](#cancelorders) 122 | - [`getPosition`](#getposition) 123 | - [`getPositions`](#getpositions) 124 | - [`closePosition`](#closeposition) 125 | - [`closePositions`](#closepositions) 126 | - [`exerciseOption`](#exerciseoption) 127 | - [`getCalendar`](#getcalendar) 128 | - [`getClock`](#getclock) 129 | - [`getAsset`](#getasset) 130 | - [`getAssets`](#getassets) 131 | - [`getWatchlist`](#getwatchlist) 132 | - [`getWatchlists`](#getwatchlists) 133 | - [`createWatchlist`](#createwatchlist) 134 | - [`updateWatchlist`](#updatewatchlist) 135 | - [`deleteWatchlist`](#deletewatchlist) 136 | - [`getPortfolioHistory`](#getportfoliohistory) 137 | - [`getConfigurations`](#getconfigurations) 138 | - [`updateConfigurations`](#updateconfigurations) 139 | - [`getActivity`](#getactivity) 140 | - [`getActivities`](#getactivities) 141 | - [`getOptionsContract`](#getoptionscontract) 142 | - [`getOptionsContracts`](#getoptionscontracts) 143 | - [`getCorporateAction`](#getcorporateaction) 144 | - [`getCorporateActions`](#getcorporateactions) 145 | - [`getCryptoWallet`](#getcryptowallet) 146 | - [`getCryptoWallets`](#getcryptowallets) 147 | - [`getFeeEstimate`](#getfeeestimate) 148 | - [`getCryptoTransfer`](#getcryptotransfer) 149 | - [`getCryptoTransfers`](#getcryptotransfers) 150 | - [`createCryptoTransfer`](#createcryptotransfer) 151 | - [`getCryptoWhitelistedAddress`](#getcryptowhitelistedaddress) 152 | - [`getCryptoWhitelistedAddresses`](#getcryptowhitelistedaddresses) 153 | - [`requestCryptoWhitelistedAddress`](#requestcryptowhitelistedaddress) 154 | - [`removeCryptoWhitelistedAddress`](#removecryptowhitelistedaddress) 155 | 156 | #### Market Data API 157 | 158 | - [`getStocksCorporateActions`](#getstockscorporateactions) 159 | - [`getLogo`](#getlogo) 160 | - [`getNews`](#getnews) 161 | - [`getStocksMostActives`](#getstocksmostactives) 162 | - [`getStocksMarketMovers`](#getstocksmarketmovers) 163 | - [`getStocksQuotes`](#getstocksquotes) 164 | - [`getStocksQuotesLatest`](#getstocksquoteslatest) 165 | - [`getStocksBars`](#getstocksbars) 166 | - [`getStocksBarsLatest`](#getstocksbarslatest) 167 | - [`getForexRates`](#getforexrates) 168 | - [`getLatestForexRates`](#getlatestforexrates) 169 | - [`getStocksSnapshots`](#getstockssnapshots) 170 | - [`getStocksAuctions`](#getstocksauctions) 171 | - [`getStocksConditions`](#getstocksconditions) 172 | - [`getStocksExchangeCodes`](#getstocksexchangecodes) 173 | - [`getStocksTrades`](#getstockstrades) 174 | - [`getStocksTradesLatest`](#getstockstradeslatest) 175 | - [`getOptionsBars`](#getoptionsbars) 176 | - [`getOptionsExchanges`](#getoptionsexchanges) 177 | - [`getOptionsSnapshots`](#getoptionssnapshots) 178 | - [`getOptionsTrades`](#getoptionstrades) 179 | - [`getOptionsTradesLatest`](#getoptionstradeslatest) 180 | - [`getCryptoBars`](#getcryptobars) 181 | - [`getLatestCryptoBars`](#getlatestcryptobars) 182 | - [`getCryptoQuotes`](#getcryptoquotes) 183 | - [`getCryptoQuotesLatest`](#getcryptoquoteslatest) 184 | - [`getCryptoSnapshots`](#getcryptosnapshots) 185 | - [`getCryptoTrades`](#getcryptotrades) 186 | - [`getCryptoTradesLatest`](#getcryptotradeslatest) 187 | - [`getLatestCryptoOrderbooks`](#getlatestcryptoorderbooks) 188 | 189 | #### `getAccount` 190 | 191 | Retrieves the account information. 192 | 193 | ```typescript 194 | client.getAccount().then(console.log); 195 | ``` 196 | 197 | #### `createOrder` 198 | 199 | Creates a new order. 200 | 201 | ```typescript 202 | client 203 | .createOrder({ 204 | symbol: "AAPL", 205 | qty: 1, 206 | side: "buy", 207 | type: "market", 208 | time_in_force: "day", 209 | }) 210 | .then(console.log); 211 | ``` 212 | 213 | #### `getOrder` 214 | 215 | Retrieves a specific order by its ID. 216 | 217 | ```typescript 218 | client 219 | .getOrder({ order_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }) 220 | .then(console.log); 221 | ``` 222 | 223 | #### `getOrders` 224 | 225 | Retrieves a list of orders based on the specified parameters. 226 | 227 | ```typescript 228 | client 229 | .getOrders({ 230 | status: "open", 231 | limit: 10, 232 | direction: "desc", 233 | }) 234 | .then(console.log); 235 | ``` 236 | 237 | #### `replaceOrder` 238 | 239 | Replaces an existing order with updated parameters. 240 | 241 | ```typescript 242 | client 243 | .replaceOrder({ 244 | qty: 2, 245 | limit_price: 150.0, 246 | order_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 247 | }) 248 | .then(console.log); 249 | ``` 250 | 251 | #### `cancelOrder` 252 | 253 | Cancels a specific order by its ID. 254 | 255 | ```typescript 256 | client 257 | .cancelOrder({ order_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }) 258 | .then(console.log); 259 | ``` 260 | 261 | #### `cancelOrders` 262 | 263 | Cancels all open orders. 264 | 265 | ```typescript 266 | client.cancelOrders().then(console.log); 267 | ``` 268 | 269 | #### `getPosition` 270 | 271 | Retrieves a specific position by symbol or asset ID. 272 | 273 | ```typescript 274 | client 275 | .getPosition({ 276 | symbol_or_asset_id: "AAPL", 277 | }) 278 | .then(console.log); 279 | ``` 280 | 281 | #### `getPositions` 282 | 283 | Retrieves all positions. 284 | 285 | ```typescript 286 | client.getPositions().then(console.log); 287 | ``` 288 | 289 | #### `closePosition` 290 | 291 | Closes a specific position by symbol or asset ID. 292 | 293 | ```typescript 294 | client 295 | .closePosition({ 296 | symbol_or_asset_id: "AAPL", 297 | }) 298 | .then(console.log); 299 | ``` 300 | 301 | #### `closePositions` 302 | 303 | Closes all positions. 304 | 305 | ```typescript 306 | client.closePositions().then(console.log); 307 | ``` 308 | 309 | #### `exerciseOption` 310 | 311 | Exercises an options contract. 312 | 313 | ```typescript 314 | client 315 | .exerciseOption({ 316 | symbol_or_contract_id: "xxxxxxxx", 317 | }) 318 | .then(console.log); 319 | ``` 320 | 321 | #### `getCalendar` 322 | 323 | Retrieves the market calendar. 324 | 325 | ```typescript 326 | client 327 | .getCalendar({ 328 | start: "2023-01-01", 329 | end: "2023-12-31", 330 | }) 331 | .then(console.log); 332 | ``` 333 | 334 | #### `getClock` 335 | 336 | Retrieves the current market clock. 337 | 338 | ```typescript 339 | client.getClock().then(console.log); 340 | ``` 341 | 342 | #### `getAsset` 343 | 344 | Retrieves a specific asset by symbol or asset ID. 345 | 346 | ```typescript 347 | client 348 | .getAsset({ 349 | symbol_or_asset_id: "AAPL", 350 | }) 351 | .then(console.log); 352 | ``` 353 | 354 | #### `getAssets` 355 | 356 | Retrieves a list of assets based on the specified parameters. 357 | 358 | ```typescript 359 | client 360 | .getAssets({ 361 | status: "active", 362 | asset_class: "us_equity", 363 | }) 364 | .then(console.log); 365 | ``` 366 | 367 | #### `getWatchlist` 368 | 369 | Retrieves a specific watchlist by ID. 370 | 371 | ```typescript 372 | client 373 | .getWatchlist({ 374 | watchlist_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 375 | }) 376 | .then(console.log); 377 | ``` 378 | 379 | #### `getWatchlists` 380 | 381 | Retrieves all watchlists. 382 | 383 | ```typescript 384 | client.getWatchlists().then(console.log); 385 | ``` 386 | 387 | #### `createWatchlist` 388 | 389 | Creates a new watchlist. 390 | 391 | ```typescript 392 | client 393 | .createWatchlist({ 394 | name: "My Watchlist", 395 | symbols: ["AAPL", "GOOGL", "AMZN"], 396 | }) 397 | .then(console.log); 398 | ``` 399 | 400 | #### `updateWatchlist` 401 | 402 | Updates an existing watchlist. 403 | 404 | ```typescript 405 | client 406 | .updateWatchlist({ 407 | name: "Updated Watchlist", 408 | symbols: ["AAPL", "GOOGL", "MSFT"], 409 | watchlist_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 410 | }) 411 | .then(console.log); 412 | ``` 413 | 414 | #### `deleteWatchlist` 415 | 416 | Deletes a specific watchlist by ID. 417 | 418 | ```typescript 419 | client 420 | .deleteWatchlist({ 421 | watchlist_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 422 | }) 423 | .then(console.log); 424 | ``` 425 | 426 | #### `getPortfolioHistory` 427 | 428 | Retrieves the portfolio history. 429 | 430 | ```typescript 431 | client 432 | .getPortfolioHistory({ 433 | period: "1M", 434 | timeframe: "1D", 435 | }) 436 | .then(console.log); 437 | ``` 438 | 439 | #### `getConfigurations` 440 | 441 | Retrieves the account configurations. 442 | 443 | ```typescript 444 | client.getConfigurations().then(console.log); 445 | ``` 446 | 447 | #### `updateConfigurations` 448 | 449 | Updates the account configurations. 450 | 451 | ```typescript 452 | client 453 | .updateConfigurations({ 454 | trade_confirm_email: "all", 455 | suspend_trade: false, 456 | }) 457 | .then(console.log); 458 | ``` 459 | 460 | #### `getActivity` 461 | 462 | Retrieves a specific activity type. 463 | 464 | ```typescript 465 | client 466 | .getActivity({ 467 | activity_type: "FILL", 468 | }) 469 | .then(console.log); 470 | ``` 471 | 472 | #### `getActivities` 473 | 474 | Retrieves all activities. 475 | 476 | ```typescript 477 | client.getActivities().then(console.log); 478 | ``` 479 | 480 | #### `getOptionsContract` 481 | 482 | Retrieves a specific options contract by symbol or contract ID. 483 | 484 | ```typescript 485 | client 486 | .getOptionsContract({ 487 | symbol_or_contract_id: "AAPL230616C00150000", 488 | }) 489 | .then(console.log); 490 | ``` 491 | 492 | #### `getOptionsContracts` 493 | 494 | Retrieves a list of options contracts based on the specified parameters. 495 | 496 | ```typescript 497 | client 498 | .getOptionsContracts({ 499 | underlying_symbols: "AAPL", 500 | expiration_date: "2023-06-16", 501 | }) 502 | .then(console.log); 503 | ``` 504 | 505 | #### `getCorporateAction` 506 | 507 | Retrieves a specific corporate action by ID. 508 | 509 | ```typescript 510 | client 511 | .getCorporateAction({ 512 | id: "xxxxxxxx", 513 | }) 514 | .then(console.log); 515 | ``` 516 | 517 | #### `getCorporateActions` 518 | 519 | Retrieves a list of corporate actions based on the specified parameters. 520 | 521 | ```typescript 522 | client 523 | .getCorporateActions({ 524 | ca_types: "MERGER", 525 | since: "2023-01-01", 526 | until: "2023-12-31", 527 | }) 528 | .then(console.log); 529 | ``` 530 | 531 | #### `getCryptoWallet` 532 | 533 | Retrieves a specific crypto wallet by asset. 534 | 535 | ```typescript 536 | client 537 | .getCryptoWallet({ 538 | asset: "BTCUSD", 539 | }) 540 | .then(console.log); 541 | ``` 542 | 543 | #### `getCryptoWallets` 544 | 545 | Retrieves all crypto wallets. 546 | 547 | ```typescript 548 | client.getCryptoWallets().then(console.log); 549 | ``` 550 | 551 | #### `getFeeEstimate` 552 | 553 | Retrieves the fee estimate for a crypto withdrawal. 554 | 555 | ```typescript 556 | client 557 | .getFeeEstimate({ 558 | asset: "BTCUSD", 559 | from_address: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 560 | to_address: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 561 | amount: "0.1", 562 | }) 563 | .then(console.log); 564 | ``` 565 | 566 | #### `getCryptoTransfer` 567 | 568 | Retrieves a specific crypto transfer by ID. 569 | 570 | ```typescript 571 | client 572 | .getCryptoTransfer({ 573 | transfer_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 574 | }) 575 | .then(console.log); 576 | ``` 577 | 578 | #### `getCryptoTransfers` 579 | 580 | Retrieves a list of crypto transfers based on the specified parameters. 581 | 582 | ```typescript 583 | client 584 | .getCryptoTransfers({ 585 | asset: "BTCUSD", 586 | }) 587 | .then(console.log); 588 | ``` 589 | 590 | #### `createCryptoTransfer` 591 | 592 | Creates a new crypto withdrawal. 593 | 594 | ```typescript 595 | client 596 | .createCryptoTransfer({ 597 | amount: "0.1", 598 | address: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 599 | asset: "BTCUSD", 600 | }) 601 | .then(console.log); 602 | ``` 603 | 604 | #### `getCryptoWhitelistedAddress` 605 | 606 | Retrieves a specific whitelisted crypto address. 607 | 608 | ```typescript 609 | client 610 | .getCryptoWhitelistedAddress({ 611 | address: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 612 | asset: "BTCUSD", 613 | }) 614 | .then(console.log); 615 | ``` 616 | 617 | #### `getCryptoWhitelistedAddresses` 618 | 619 | Retrieves all whitelisted crypto addresses. 620 | 621 | ```typescript 622 | client.getCryptoWhitelistedAddresses().then(console.log); 623 | ``` 624 | 625 | #### `requestCryptoWhitelistedAddress` 626 | 627 | Requests a new whitelisted crypto address. 628 | 629 | ```typescript 630 | client 631 | .requestCryptoWhitelistedAddress({ 632 | address: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 633 | asset: "BTCUSD", 634 | }) 635 | .then(console.log); 636 | ``` 637 | 638 | #### `removeCryptoWhitelistedAddress` 639 | 640 | Removes a specific whitelisted crypto address. 641 | 642 | ```typescript 643 | client 644 | .removeCryptoWhitelistedAddress({ 645 | whitelisted_address_id: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 646 | }) 647 | .then(console.log); 648 | ``` 649 | 650 | #### `getStocksCorporateActions` 651 | 652 | Retrieves a list of corporate actions based on the specified parameters. 653 | 654 | ```typescript 655 | client 656 | .getStocksCorporateActions({ 657 | symbols: "AAPL", 658 | types: "cash_dividends", 659 | }) 660 | .then(console.log); 661 | ``` 662 | 663 | #### `getLogo` 664 | 665 | Retrieves the logo for a specific symbol. 666 | 667 | ```typescript 668 | client 669 | .getLogo({ 670 | symbol: "AAPL", 671 | }) 672 | .then(console.log); 673 | ``` 674 | 675 | #### `getNews` 676 | 677 | Retrieves the latest news. 678 | 679 | ```typescript 680 | client 681 | .getNews({ 682 | symbols: "AAPL,TSLA", 683 | limit: 10, 684 | }) 685 | .then(console.log); 686 | ``` 687 | 688 | #### `getStocksMostActives` 689 | 690 | Retrieves a list of the most active stocks. 691 | 692 | ```typescript 693 | client 694 | .getStocksMostActives({ 695 | by: "volume", 696 | top: 10, 697 | }) 698 | .then(console.log); 699 | ``` 700 | 701 | #### `getStocksMarketMovers` 702 | 703 | Retrieves a list of the top market movers. 704 | 705 | ```typescript 706 | client 707 | .getStocksMarketMovers({ 708 | by: "change", 709 | top: 10, 710 | }) 711 | .then(console.log); 712 | ``` 713 | 714 | #### `getStocksQuotes` 715 | 716 | Retrieves a list of stock quotes. 717 | 718 | ```typescript 719 | client 720 | .getStocksQuotes({ 721 | symbols: "AAPL,TSLA", 722 | limit: 10, 723 | }) 724 | .then(console.log); 725 | ``` 726 | 727 | #### `getStocksQuotesLatest` 728 | 729 | Retrieves the latest stock quotes. 730 | 731 | ```typescript 732 | client 733 | .getStocksQuotesLatest({ 734 | symbols: "AAPL,TSLA", 735 | }) 736 | .then(console.log); 737 | ``` 738 | 739 | #### `getStocksBars` 740 | 741 | Retrieves a list of stock bars. 742 | 743 | ```typescript 744 | client 745 | .getStocksBars({ 746 | symbols: "AAPL,TSLA", 747 | timeframe: "1Day", 748 | limit: 10, 749 | }) 750 | .then(console.log); 751 | ``` 752 | 753 | #### `getStocksBarsLatest` 754 | 755 | Retrieves the latest stock bars. 756 | 757 | ```typescript 758 | client 759 | .getStocksBarsLatest({ 760 | symbols: "AAPL,TSLA", 761 | }) 762 | .then(console.log); 763 | ``` 764 | 765 | #### `getForexRates` 766 | 767 | Retrieves a list of forex rates. 768 | 769 | ```typescript 770 | client 771 | .getForexRates({ 772 | currency_pairs: "EURUSD,GBPUSD", 773 | timeframe: "1Min", 774 | limit: 10, 775 | }) 776 | .then(console.log); 777 | ``` 778 | 779 | #### `getLatestForexRates` 780 | 781 | Retrieves the latest forex rates. 782 | 783 | ```typescript 784 | client 785 | .getLatestForexRates({ 786 | currency_pairs: "EURUSD,GBPUSD", 787 | }) 788 | .then(console.log); 789 | ``` 790 | 791 | #### `getStocksSnapshots` 792 | 793 | Retrieves a list of stock snapshots. 794 | 795 | ```typescript 796 | client 797 | .getStocksSnapshots({ 798 | symbols: "AAPL,TSLA", 799 | }) 800 | .then(console.log); 801 | ``` 802 | 803 | #### `getStocksAuctions` 804 | 805 | Retrieves a list of stock auctions. 806 | 807 | ```typescript 808 | client 809 | .getStocksAuctions({ 810 | symbols: "AAPL,TSLA", 811 | limit: 10, 812 | }) 813 | .then(console.log); 814 | ``` 815 | 816 | #### `getStocksConditions` 817 | 818 | Retrieves a list of stock conditions. 819 | 820 | ```typescript 821 | client 822 | .getStocksConditions({ 823 | tickType: "trades", 824 | tape: "xxx", 825 | }) 826 | .then(console.log); 827 | ``` 828 | 829 | #### `getStocksExchangeCodes` 830 | 831 | Retrieves a list of stock exchange codes. 832 | 833 | ```typescript 834 | client.getStocksExchangeCodes().then(console.log); 835 | ``` 836 | 837 | #### `getStocksTrades` 838 | 839 | Retrieves a list of stock trades. 840 | 841 | ```typescript 842 | client 843 | .getStocksTrades({ 844 | symbols: "AAPL,TSLA", 845 | limit: 10, 846 | }) 847 | .then(console.log); 848 | ``` 849 | 850 | #### `getStocksTradesLatest` 851 | 852 | Retrieves the latest stock trades. 853 | 854 | ```typescript 855 | client 856 | .getStocksTradesLatest({ 857 | symbols: "AAPL,TSLA", 858 | }) 859 | .then(console.log); 860 | ``` 861 | 862 | #### `getOptionsBars` 863 | 864 | Retrieves a list of options bars. 865 | 866 | ```typescript 867 | client 868 | .getOptionsBars({ 869 | symbols: "AAPL220617C00270000,TSLA220617C01000000", 870 | timeframe: "1Day", 871 | limit: 10, 872 | }) 873 | .then(console.log); 874 | ``` 875 | 876 | #### `getOptionsExchanges` 877 | 878 | Retrieves a list of options exchanges. 879 | 880 | ```typescript 881 | client.getOptionsExchanges().then(console.log); 882 | ``` 883 | 884 | #### `getOptionsSnapshots` 885 | 886 | Retrieves a list of options snapshots. 887 | 888 | ```typescript 889 | client 890 | .getOptionsSnapshots({ 891 | symbols: "AAPL220617C00270000,TSLA220617C01000000", 892 | }) 893 | .then(console.log); 894 | ``` 895 | 896 | #### `getOptionsTrades` 897 | 898 | Retrieves a list of options trades. 899 | 900 | ```typescript 901 | client 902 | .getOptionsTrades({ 903 | symbols: "AAPL220617C00270000,TSLA220617C01000000", 904 | limit: 10, 905 | }) 906 | .then(console.log); 907 | ``` 908 | 909 | #### `getOptionsTradesLatest` 910 | 911 | Retrieves the latest options trades. 912 | 913 | ```typescript 914 | client 915 | .getOptionsTradesLatest({ 916 | symbols: "AAPL220617C00270000,TSLA220617C01000000", 917 | }) 918 | .then(console.log); 919 | ``` 920 | 921 | #### `getCryptoBars` 922 | 923 | Retrieves a list of crypto bars. 924 | 925 | ```typescript 926 | client 927 | .getCryptoBars({ 928 | symbols: "BTCUSD,ETHUSD", 929 | timeframe: "1Min", 930 | limit: 10, 931 | }) 932 | .then(console.log); 933 | ``` 934 | 935 | #### `getLatestCryptoBars` 936 | 937 | Retrieves the latest crypto bars. 938 | 939 | ```typescript 940 | client 941 | .getLatestCryptoBars({ 942 | loc: "US", 943 | symbols: "BTCUSD,ETHUSD", 944 | }) 945 | .then(console.log); 946 | ``` 947 | 948 | #### `getCryptoQuotes` 949 | 950 | Retrieves a list of crypto quotes. 951 | 952 | ```typescript 953 | client 954 | .getCryptoQuotes({ 955 | symbols: "BTCUSD,ETHUSD", 956 | limit: 10, 957 | }) 958 | .then(console.log); 959 | ``` 960 | 961 | #### `getCryptoQuotesLatest` 962 | 963 | Retrieves the latest crypto quotes. 964 | 965 | ```typescript 966 | client 967 | .getCryptoQuotesLatest({ 968 | loc: "US", 969 | symbols: "BTCUSD,ETHUSD", 970 | }) 971 | .then(console.log); 972 | ``` 973 | 974 | #### `getCryptoSnapshots` 975 | 976 | Retrieves a list of crypto snapshots. 977 | 978 | ```typescript 979 | client 980 | .getCryptoSnapshots({ 981 | loc: "US", 982 | symbols: "BTCUSD,ETHUSD", 983 | }) 984 | .then(console.log); 985 | ``` 986 | 987 | #### `getCryptoTrades` 988 | 989 | Retrieves a list of crypto trades. 990 | 991 | ```typescript 992 | client 993 | .getCryptoTrades({ 994 | loc: "US", 995 | symbols: "BTCUSD,ETHUSD", 996 | limit: 10, 997 | }) 998 | .then(console.log); 999 | ``` 1000 | 1001 | #### `getCryptoTradesLatest` 1002 | 1003 | Retrieves the latest crypto trades. 1004 | 1005 | ```typescript 1006 | client 1007 | .getCryptoTradesLatest({ 1008 | loc: "US", 1009 | symbols: "BTCUSD,ETHUSD", 1010 | }) 1011 | .then(console.log); 1012 | ``` 1013 | 1014 | #### `getLatestCryptoOrderbooks` 1015 | 1016 | Retrieves the latest crypto orderbooks. 1017 | 1018 | ```typescript 1019 | client 1020 | .getLatestCryptoOrderbooks({ 1021 | loc: "US", 1022 | symbols: "BTCUSD,ETHUSD", 1023 | }) 1024 | .then(console.log); 1025 | ``` 1026 | 1027 | ### WebSocket 1028 | 1029 | #### How It Works 1030 | 1031 | todo 1032 | 1033 | #### Channels 1034 | 1035 | todo 1036 | 1037 | #### Examples 1038 | 1039 | todo 1040 | 1041 | ## Need Help? 1042 | 1043 | The primary maintainer of this project is [@117](https://github.com/117). Feel free to reach out on [Slack](https://alpaca-community.slack.com/join/shared_invite/zt-2ebgo7i1f-HbNoBjPWZ_bX72IVQTkcwg) 👋 or by opening an issue on this repo. I'm happy to help with any questions or issues you may have. 1044 | --------------------------------------------------------------------------------