Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 11 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,51 +187,25 @@ In order to reduce time logging in, you can save an authenticated user to disk a
After you've logged in (see above), you can run the following:

```js
const authenticatedUser;
const authenticatedUser = new User("username", "password");
// ...
authenticatedUser.save()
.then(() => {
// The user data was saved to:
// project/node_modules/algotrader/objects/broker/robinhood/User.json
// This filepath can be configured in the options parameter in `User` constructor
.then((serializedUser) => {
// You can store `serializedUser` to where you want, like a Database
});
```

Note that your password will never be saved to disk. Keep this in mind when having to re-authenticate.

Once saved, you can easily login like so:

```js
const robinhood = require('algotrader').Robinhood;
const User = robinhood.User;

User.load()
.then(myUser => {
myUser.isAuthenticated(); // Boolean - see below
})
.catch(error => {
// Make sure to always catch possible errors. You'll need to re-authenticate here.
// - Possible errors: user session has expired, a saved user does not exist.
if (error) {
// Re-auth here and save if desired.
}
});
// ...
```

However, authentication tokens issued by Robinhood expire after 24 hours. Version 1.4.5 takes this into account and [```User.isAuthenticated()```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) will return ```false``` if the token has expired. Make sure to check for this and re-authenticate if necessary. When re-authenticating, you will need to provide a password either through CLI or when calling [```User.authenticate()```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) as the first parameter.
Note that your password will never be part of the serialized user object. Keep this in mind when having to re-authenticate.

If you need to save and retrieve the user login info to somewhere else (like a Database, specially useful to keep your service stateless), you can use:
Once saved, you can easily login like so:

```js
const options = { doNotSaveToDisk: true };
const authenticatedUser = new User("username", "password", options);
// ...
authenticatedUser.save()
.then((serializedUser) => {
// You can store `serializedUser` to where you want, like a Database
});

// ...
const serializedUser = ''; // Get this value from your storage

User.load(serializedUser)
.then(myUser => {
myUser.isAuthenticated(); // Boolean - see below
Expand All @@ -245,6 +219,9 @@ User.load(serializedUser)
});
```

However, authentication tokens issued by Robinhood expire after 24 hours. Version 1.4.5 takes this into account and [```User.isAuthenticated()```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) will return ```false``` if the token has expired. Make sure to check for this and re-authenticate if necessary. When re-authenticating, you will need to provide a password either through CLI or when calling [```User.authenticate()```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) as the first parameter.


#### Get a user's portfolio

There are a good amount of query functions that you can run on the user's portfolio. Using your [```User```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) instance, you can grab the portfolio using [```User.getPortfolio```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#User) which returns a new [```Portfolio```](https://github.com/torreyleonard/algotrader/blob/master/docs/ROBINHOOD.md#Portfolio) object.
Expand Down
42 changes: 5 additions & 37 deletions objects/broker/robinhood/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const OptionOrder = require('./OptionOrder');
const OptionInstrument = require('./OptionInstrument');

const request = require('request');
const fs = require('fs');
const async = require('async');
const path = require('path');
const prompt = require('prompt');
Expand All @@ -25,7 +24,7 @@ class User extends Robinhood {
* @param {String} password - Optional. If not provided the user will be prompted via CLI.
* @param {String} deviceToken
*/
constructor(username, password, deviceToken, options) {
constructor(username, password, deviceToken = 'ea9fa5c6-01e0-46c9-8430-5b422c99bd16') {
super();
this.username = username;
this.password = password;
Expand All @@ -34,16 +33,6 @@ class User extends Robinhood {
this.account = null; // Account number
this.expires = null; // Auth expiration date (24 hours after login)
this.refreshToken = null; // Refresh token can be used to obtain another access token after auth expiration

const {
doNotSaveToDisk = false,
serializedUserFile = path.join(__dirname, 'User.json')
} = options;

// File to save the serialized user
this.serializedUserFile = serializedUserFile;
// Will avoid saving the serialized user to disk, and instead will let the consumer store the user as needed (ie: database)
this.doNotSaveToDisk = doNotSaveToDisk;
}

/**
Expand Down Expand Up @@ -209,9 +198,6 @@ class User extends Robinhood {
if (error) reject(error);
else if (response.statusCode !== 200) reject(new LibraryError(body));
else {
if (!this.doNotSaveToDisk) {
try { fs.unlinkSync(this.serializedUserFile); } catch (e) {}
}
resolve(true);
}
})
Expand Down Expand Up @@ -269,23 +255,15 @@ class User extends Robinhood {
else {
delete _this.refreshToken; // It's not secure to store refreshToken locally
const serializedUser = _this.serialize();
if (this.doNotSaveToDisk) {
// We return the user so the consumer can decide how to store the serialized user
resolve(serializedUser);
return;
}
try { fs.unlinkSync(this.serializedUserFile); } catch (e) {}
fs.writeFile(this.serializedUserFile, serializedUser, error => {
if (error) reject(error);
else resolve(true);
})
// We return the user so the consumer can decide how to store the serialized user
resolve(serializedUser);
return;
}
})
}

/**
* If a saved user exists, this will load it into system memory. Recommended if using multi-factor authentication.
* If using `doNotSaveToDisk`, consumer will need to pass the serialized user as an argument
* @author Torrey Leonard <https://github.com/Ladinn>
* @returns {Promise<User>}
*/
Expand All @@ -302,17 +280,7 @@ class User extends Robinhood {
})
.catch(error => reject(error));
}
if (this.doNotSaveToDisk) {
_load(serializedUser);
}
fs.readFile(this.serializedUserFile, 'utf8', (error, data) => {
if (error) {
if (error.errno === -2) reject(new Error("A saved user does not exist!"));
else reject(error);
} else {
_load(data);
}
});
_load(serializedUser);
})
}

Expand Down