knicola / tdameritradejs

TD Ameritrade Library for Node.js
MIT License
37 stars 18 forks source link

User guide #19

Open kevinsherman opened 3 years ago

kevinsherman commented 3 years ago

Hello. Any chance you can put together a brief user guide? I'm able to get to the point where I receive the 'code' in the callback URL, but I'm not 100% sure what to do with it :) and/or how the access token/refresh token is persisted and used. Great work by the way!

knicola commented 3 years ago

Thank you! I've been meaning to put together a wiki page but I haven't gotten around to it yet.

The library tries to take care of as much of the authentication process as possible. For example, it'll bootstrap an https server when it determines it is necessary to authenticate through TD's OAuth2 service, it'll refresh the token automatically when a 401 is received and it will of course update its config every time a new token is issued.

The most important part is persisting the configuration itself. The key APIs for this are .on('token', callback), which notifies when a new token is issued, and .login(), which checks if the token is good to go, if it needs to be refreshed or if it's time to bootstrap OAuth2 authentication.

Until I get around to writing an official guide, here's how I use it:

Install npm packages

$ npm i @knicola/tdameritrade dotenv opn

Generate SSL

$ openssl req -x509 -nodes -newkey rsa:2048 -keyout selfsigned.key -out selfsigned.crt -batch

# OR

$ openssl req -x509 -newkey rsa:2048 -nodes -sha256 -out selfsigned.crt -keyout selfsigned.key \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

Create a .env file

API_KEY=your_client_id_goes_here
REDIRECT_URI=https://localhost:8443

Create a td.js file

'use strict'

const { TDAmeritrade } = require('@knicola/tdameritrade')
const opn = require('opn')
const fs = require('fs')
const path = require('path')

const defaultConfig = {
    apiKey: process.env.API_KEY,
    redirectUri: process.env.REDIRECT_URI,
    sslKey: 'selfsigned.key',
    sslCert: 'selfsigned.crt',
}

const configFile = path.resolve('config.json')

const config = fs.existsSync(configFile)
    ? JSON.parse(fs.readFileSync(configFile))
    : defaultConfig

const td = new TDAmeritrade(config)

td.on('login', opn)
td.on('token', () => {
    const content = JSON.stringify(td.config, null, 2)
    fs.writeFile(configFile, content, error => {
        if (error) {
            console.log(`Failed to update config: ${configFile}\n${error}`)
        } else {
            console.log(`Updated config: ${configFile}`)
        }
    })
})

module.exports = td

and an index.js file

'use strict'

require('dotenv').config()
const td = require('./td')

td.login().then(async () => {
    const { candles } = await td.getPriceHistory(security.symbol, {
        periodType: 'day',
        period: 1,
        frequencyType: 'minute',
        frequency: 1,
    })
    // ...
})

Hope this helps!