Giter Club home page Giter Club logo

algotrader's Introduction

algotrader

Simple algorithmic stock and option trading for Node.js.

npm package

NPM Version NPM Downloads GitHub Commit GitHub Issues GitHub Stars Discord


Features

  • Extensive broker library
    • Easily place orders
    • Retrieve past orders
    • Query a users portfolio
    • Supported brokers:
      • Robinhood
      • TDAmeritrade (in progress)
      • Oanda (in progress)
      • If you'd like to have another broker supported, submit an issue or a pull request
  • Data library
    • Real time quote data streaming for cryptocurrency, forex, equities
      • Get data on bids, asks, last price, and more from the Yahoo Finance API
      • Stream news headlines along with quotes
    • Up-to-date options data
    • Easily find stocks for various queries
      • Retrieve the day's top gainers
      • Retrieve the day's top losers
      • Get stocks by highest (abnormal) volume
      • Get options contracts by highest open interest
      • And more
    • Get up to the minute breaking headlines
    • Get technical indicators from AlphaVantage
      • SMA, EMA, RSI, etc.
    • Get fundamentals and balance sheet data (in progress)
      • Assets, debt, liabilities, revenue, earnings, etc.
  • Algorithm library (in progress)
    • Create algorithms that will automatically place trades based on your criteria
    • Backtest algorithms on past market data
    • Paper (simulated) trade your algorithm to see how it performs in real time
  • Support for many third-party APIs

Table of Contents


Support

  • Join our Discord: https://discord.gg/DWFWBPn
  • Get answers to questions or help us deal with open issues.
  • Tell us about how you're using Algotrader!

Getting started

Using NPM, you can install Algotrader using the following console command: npm i algotrader --save

Once Algotrader is installed, you can import it into your Node.js project.

const algotrader = require('algotrader');

After, you can instantiate any Algotrader library like so:

const Robinhood = algotrader.Robinhood;
const Data = algotrader.Data;
const Algorithm = algotrader.Algorithm; // in progress

Robinhood

First, you'll need to create a new User instance and authenticate them.

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

const options = {
    doNotSaveToDisk: false, // If the `save` method should not store the user login info to disk (file)
    serializedUserFile: null // File to where the serialized user login info can be saved
};

const myUser = new User("username", "password", options);
myUser.authenticate()
    .then(() => {
        // User was authenticated
    })
    .catch(error => {
        // Either the request failed, or Robinhood responded with an error.
        // (Ex: you don't have internet access or your user credentials were incorrect)
    })

Personally, I either store user data as an array in a .json file, then require it into the class, (insecure) or ask for the user's credentials in the console. You should handle this sensitive data in a way that you're comfortable with.

Note: providing a password in the User constructor is optional. You can also pass it to User.authenticate() as the first parameter like so:

const myUser = new User("username");
// Or with options:
// const myUser = new User("username", null, options);
myUser.authenticate("password")
    .then(() => {
        // User was authenticated
    });

If it is not provided at all, you will be prompted via CLI.

MFA

Algotrader now supports multi-factor authentication. So, if you have this enabled on your account (which is a good idea by the way), you'll be prompted to enter the six-digit code after login. If you run a trading script with this library automatically and have MFA enabled, it may be worth your while to utilize a telecom API (possible through Twilio?) to have the code programmatically retrieved (see below).

The MFA prompt will appear like so:

Algotrader MFA Prompt

To enter the code programmatically, you can pass a function to User.authenticate() that returns a promise containing the MFA code in a six-character string. For example:

function getMFA() {
    return new Promise((resolve, reject) => {
        // Get the code here
        const mfa = "123456"
        resolve(mfa);
    })
}
// Note: the first parameter here is 'password' and is only required if you are re-authenticating
// an expired user or if you did not provide a password in the User constructor.
myUser.authenticate(null, getMFA)
    .then(() => {
        // User was authenticated
    })
Saving & loading a user

In order to reduce time logging in, you can save an authenticated user to disk and load it into memory for subsequent requests. If you're using multi-factor authentication, I definitely recommend this- it really saves a lot of time and energy.

After you've logged in (see above), you can run the following:

const authenticatedUser;
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
    });

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:

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() 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() as the first parameter.

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:

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
    })
    .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.
        }
    });

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 instance, you can grab the portfolio using User.getPortfolio which returns a new Portfolio object.

myUser.getPortfolio()
    .then(myPortfolio => { // Algotrader retrieved the user's portfolio
        // You can find information on specific symbols
        let myTeslaShares = myPortfolio.getQuantity("TSLA"); // Returns the quantity of shares you own in the given symbol: 10
        let bestDayEver = myPortfolio.getPurchaseDate("SHLD"); // Returns the date (Date object) you purchased the given symbol: 2007-04-17
        // You can find information on the entire portfolio
        let mySymbols = myPortfolio.getSymbols(); // Returns an array of all symbols in the user's portfolio: ['FB', 'AMZN', 'NFLX', 'GOOG']
        let myMoneyMakers = myPortfolio.getQuantityGreaterThan(50); // Returns an array of all positions greater than the given amount: [Object]
        // Along with much more. See the link below to visit the Robinhood portfolio documentation.
    })
    .catch(error => {
        // Either the request failed, or Robinhood responded with an error.
        // (Ex: you don't have internet access or your user credentials were incorrect)
    })

For documentation on all portfolio functions, visit the Robinhood Library Docs.

Note: the portfolio object does not return a user's open option positions. See the options section below for details.

Placing an order

Placing an order will require instances of the User, Instrument, Quote, and Order classes.

All orders first require that you grab a new Instrument object which represents, in most cases, a stock or ETF. You can also grab the object from your Portfolio. Then, Robinhood requires that you also submit the stock's market price in the order, so you should retrieve a Quote from them on via Instrument object (the origin of the quote doesn't matter, as long as it contains accurate pricing information- so, the quote returned from the Stream class would also work). You'll then create an object with this and other necessary information to pass as a parameter to a new Order.

The object should contain the following:

  • Instrument - The Robinhood instrument you would like to place an order for.
  • Quote - An updated quote containing the last sale price for the given instrument.
  • type
    • limit - The lowest price to accept in a buy, the highest price in a sell
    • market - Order executes at the current bid/ask price
  • timeInForce
    • GFD - Good for the day (cancels at market close)
    • GTC - Good-til-cancelled (active until you cancel it)
    • IOC - Immediate or cancel (possibly deprecated by Robinhood)
    • OPG - Market/limit on open (possibly deprecated by Robinhood)
  • trigger
    • immediate - The order is active as soon as it's placed
    • stop - The order won't be active until the market price crossed your stop price
  • stopPrice
    • If trigger = stop, this must be specified
  • quantity
    • How many shares should be bought / sold
  • side
    • buy
    • sell
  • extendedHours
    • boolean - Whether the order should be allowed to execute when exchanges are closed
  • overrideDayTradeCheck
    • boolean - Whether to override Pattern Day Trader protection (this should definitely be false)

With this in mind, you can place a simple market order for ten shares of Twitter like so:

// ES6
Instrument.getBySymbol("TWTR").then(async twtrInstrument => {
    // As of ~01/15/19, Robinhood requires an authenticated user to fetch a quote.
    // Working with Algotrader version > 1.4.3, thanks @Gillinghammer!
    let twtrQuote = await twtrInstrument.getQuote(user);
    const myOrder = new Order(user, {
        instrument: twtrInstrument,
        quote: twtrQuote,
        type: "market",
        timeInForce: "gfd",
        trigger: "immediate",
        quantity: 10,
        side: "buy"
    });
    myOrder.submit().then(res => {
        // Order was successful
    }).catch(error => {
        // Either the request failed, or Robinhood responded with an error.
        // (Ex: you don't have internet access or your balance was insufficient)
    });
});

For documentation on all order functions, visit the Robinhood Library Docs.

Options

Receiving open option positions and placing option orders varies slightly from stocks. These actions will require the OptionInstrument and OptionOrder classes.

Here is an example for how to query an option chain and place an order for an individual option. See OptionOrder documentation for details on new order parameters.

const Instrument = algotrader.Robinhood.Instrument;
const OptionInstrument = algotrader.Robinhood.OptionInstrument;
const OptionOrder = algotrader.Robinhood.OptionOrder;

async function gains(user) {

    // First, we'll get the instrument that corresponds to the symbol TLRY.
    const tlry = await Instrument.getBySymbol('TLRY');

    // Next, we'll fetch an option chain containing puts for the upcoming expiration date.
    // This will return an array of OptionInstruments. See the example in the next section below.
    const chain = await OptionInstrument.getChain(user, tlry, 'put');

    // Now that we have the option chain, we'll need to find which OptionInstrument to trade
    // based on its strike price and expiration date. See the example below for how to sort them.
    // For now, we'll just take the first option contract in the array.
    const optionToBuy = chain[0];

    // Finally, we can create and place an order like so:
    let order = new OptionOrder(user, {
    side: 'buy',
    type: 'limit', // Note: Robinhood does not allow market buy orders
    price: '',
    timeInForce: 'gtc',
    quantity: 1,
    option: optionToBuy
    });

    order.submit().then(executedOrder => {
        // Success!
        console.log(executedOrder);
    }).catch(error => console.error(error));
}
Option chains

Represented as an array of OptionInstruments, option chains provide you with all of the tradable contracts for a specific option instrument and expiration date. They are fetched using OptionInstrument.getChain and used for an OptionOrder.

Below is an example of a single element from within the array:

[ OptionInstrument {
    url: 'https://api.robinhood.com',
    tradability: 'tradable',
    strikePrice: 121,
    state: 'active',
    type: 'put',
    symbol: 'TLRY',
    minTicks: { cutoff_price: '3.00', below_tick: '0.01', above_tick: '0.05' },
    instrumentURL: 'https://api.robinhood.com/options/instruments/28c3224d-3aa3-428c-aa78-7e0f5a4d01a0/',
    ids:
     { chain: 'c49063f0-557b-44b7-aeef-11fbc6a51243',
       option: '28c3224d-3aa3-428c-aa78-7e0f5a4d01a0' },
    dates:
     { expiration: 2019-02-01T00:00:00.000Z,
       created: 2019-01-18T03:08:31.325Z,
       updated: 2019-01-18T03:08:31.325Z } }, ...

Here is an example of how you would sort an option chain by strike price and expiration date. For this example, we'll get a quote, the options chain, and option expiration dates and use that data buy the nearest in-the-money call.

const moment = require('moment');

const qqq = await Instrument.getBySymbol('QQQ');
const quote = await qqq.getQuote(user);
const chain = await OptionInstrument.getChain(user, qqq, 'call');
const expirations = await OptionInstrument.getExpirations(user, qqq);
// Returns an array of expiration dates [ 2019-02-01T00:00:00.000Z, 2019-02-08T00:00:00.000Z, ...

const nextExpiration = moment(expirations[0]);

let optionsExpiringNext = [];

chain.forEach(option => {
    let thisExpiration = moment(option.getExpiration());
    if (thisExpiration.isSame(nextExpiration)) {
        optionsExpiringNext.push(option);
    }
});

Algorithm Library

For scheduling tasks, running backtests, and paper-trading, the algorithm library should be more than useful.

Scheduler

Using the Scheduler class, you'll be able to define exactly when you want a function to run using the following methods:

  • Scheduler.onMarketOpen(offset, f)
    • Runs every morning when the NYSE opens. (Typically 9:30 AM EST)
    • Offset is in milliseconds and can be positive (after) or negative (before).
  • Scheduler.onMarketClose(offset, f)
    • Runs every afternoon when the NYSE closes. (Typically 4:00 PM EST)
    • Offset is in milliseconds and can be positive (after) or negative (before).
  • Scheduler.every(minutes, extended, f)
    • Runs every x minutes during market hours or during typical extended trading hours. (9 AM EST - 6 PM EST)

Here's an easy example that runs a function 5 minutes before the market opens and another one every 30 minutes during regular trading hours:

const Scheduler = algotrader.Algorithm.Scheduler;

Scheduler.onMarketOpen(-5 * 60000, () => {
    // Function to run five minutes before the market opens
});

Scheduler.every(30, false, () => {
    // Function to run every 1/2 hour
});

For documentation on all Scheduler functions, visit the Algorithm Library Docs.


Data Library

The data library allows you to retrieve a ton of data on the market as a whole and individual stocks or options. This uses the Yahoo Finance and Alpha Vantage APIs and additional support for other free API's will be added in the future.

I'll only add a few examples here, but for the full documentation visit the Data Library Docs.

Real time streaming

To stream live quotes from Yahoo Finance, you'll need an array of symbols that you want to monitor. If you only need data on one, just fill the array with that single symbol. The Stream class is an extension of the Node EventEmitter, so you can either use .on() or .pipe() like other events.

Once the stream starts, a data object for each symbol is immediately received. You will then begin to get real time updates. Note that the data objects streamed by Yahoo aren't always of the same format, so make sure to have a check for undefined each time you access a key in the object.

const Stream = algotrader.Data.Stream;

const myStream = new Stream(["PG", "DPS", "ULTA", "DIN", "ETSY"]);
myStream.start();

myStream
    .on('quote', quote => {
        // Returns a single Quote object. See the link below for documentation on Quotes.
    })
    .on('response', res => {
        // Returns a response object from the request module. Useful for debugging.
    })
    .on('error', error => {
        // Returns an error if the stream failed to start.
    });

For documentation on Quotes, visit the Global Docs.

Not only can you stream quotes, but you can include news articles using the built-in News Library. This is useful for reacting to breaking headlines with pre-determined trades (for example, earnings reports or FOMC results). To do this, just add a second parameter (an object) to new Stream() as shown below.

const myStreamWithNews = new Stream(["JPM", "COST", "FDX"], {
    news: true, // Tells the streamer to also include news
    allHeadlines: true, // If true, all U.S. headlines will be sent in the stream. If false, only news pertaining to the given symbols will be outputted.
    newsApiKey: "newsApiKeyGoesHere" // Your API key from NewsAPI.org. See the link below for documentation on News.
});
myStreamWithNews.start();

myStreamWithNews
    .on('quote', quote => {
        // Returns a single Quote object. See the link below for documentation on Quotes.
    })
    .on('news', news => {
        // Returns a single News object. See the link below for documentation on News.
    })
    .on('response', res => {
        // Returns a response object from the request module. Useful for debugging.
    })
    .on('error', error => {
        // Returns an error if the stream failed to start.
    });

For documentation on News, visit the Data Library Docs.

You can also instruct the stream class to fire events from IEX. You'll first want to find the streaming endpoint that contains the data you want to query. For the most part, you'll want to use tops, deep, and last. Find them all here.

const streamWithIEX = new Stream(["PG", "DIN", "ULTA"], {
    iex: true,
    iexType: "tops"
});
streamWithIEX.on('iex', iex => {
    // Returns an object described here: https://iextrading.com/developer/docs/#iex-market-data
});

For documentation on IEX, visit the Data Library Docs.

Alpha Vantage

Providing free access to real time and historical market data along with advanced technical analysis, Alpha Vantage has proven to be very helpful when it comes to analyzing stock activity. The only caveat is that, during market hours, their servers can occasionally take a while to respond. But aside from that, you won't find a more well equipped API for free.

To use Algotrader's built-in Alpha Vantage library, you'll first need to grab a free API key here. After the key is displayed on the page, you can copy it to your program and instantiate a new AlphaVantage object like so:

const AlphaVantage = algotrader.Data.AlphaVantage;
const av = new AlphaVantage("myApiKey");

After, you can access any of the information provided in their documentation easily.

// Get real time intraday price information
av.timeSeriesIntraday("AAPL", "1min").then(array => {
    // Returns an array of Quote objects for every minute since market open
    array.forEach(quote => {
        console.log( quote.getOpen() );   // 174.78
        console.log( quote.getVolume() ); // 13523
    });
});
// Get relative strength index
av.rsi("AAPL", "daily", 14, "close").then(array => {
    // Returns an array of objects representing the RSI on each day
    array.forEach(rsi => {
        // { date: 2017-11-17T00:00:00.000Z, RSI: '57.3707' }
    });
});

For documentation on all Alpha Vantage functions, visit the Data Library Docs.

IEX

IEX is a stock exchange founded in 2012 with the goal of creating "fairer markets." True to this goal, they've created a public API for use by everyone, not just institutions that can afford a massive monthly payment for data. Thanks to many factors, such as trading arbitrage, their quotes are the same (if not off by a fraction of a basis point) as the NYSE's and Nasdaq's nearly 100% of the time, even with their low volume comparatively. With that being said, below are a few examples of ways you can access their quote data and corporate financial information. For a full list of IEX queries, visit the Data Library Docs.

const IEX = algotrader.Data.IEX;

// Returns a quote object
IEX.getQuote("CSX").then(quote => {
    // Quote {
    // symbol: 'CSX',
    //     date: 2018-05-04T20:00:00.251Z,
    //     source: 'IEX',
    //     price:
    // { last: 59.97,
    //     open: 58.69,
    //     high: 60.41,
    //     low: 58.575,
    //     close: 59.97,
    //     volume: 4186069 },
    // dom: { bids: [], asks: [] }, - This was written while the market was closed. While the market is open, DOM elements are supported in the Quote object.
    // meta: undefined,
    //     original: undefined }
});

// Returns an array of fiscal reports dating back 5 years
IEX.getFinancials("AVGO").then(financials => {
    // [ { reportDate: '2018-01-31',
    // 	grossProfit: 2643000000,
    // 	costOfRevenue: 2684000000,
    // 	operatingRevenue: 5327000000,
    // 	totalRevenue: 5327000000,
    // 	operatingIncome: 1088000000,
    // 	netIncome: 6230000000,
    // 	researchAndDevelopment: 925000000,
    // 	operatingExpense: 1555000000,
    // 	currentAssets: 11220000000,
    // 	totalAssets: 54544000000,
    // 	totalLiabilities: 28643000000,
    // 	currentCash: 7076000000,
    // 	currentDebt: 117000000,
    // 	totalCash: 7076000000,
    // 	totalDebt: 17592000000,
    // 	shareholderEquity: 25901000000,
    // 	cashChange: -4128000000,
    // 	cashFlow: 1685000000,
    // 	operatingGainsLosses: null },
});

// Returns company name, EPS, divided, short interest, 52-week high/low, percent change, EBITDA, and more.
IEX.getStats("HD").then(stats => {
    // For full output see https://iextrading.com/developer/docs/#key-stats
});

You can even grab a company's logo with:

IEX.getLogo("MMM").then(logoURL => {
    // https://storage.googleapis.com/iex/api/logos/MMM.png
});

Output:

3M

For documentation on IEX queries, visit the Data Library Docs.

Nasdaq

By market cap, the Nasdaq is the second largest global stock exchange behind only the NYSE. They offer a paid subscription for real time streaming, but Algotrader makes use of their public data repository via FTP. Below is an example of how to retrieve an array of all securities listed on their exchange. For a full list of Nasdaq queries, visit the Data Library Docs.

const Nasdaq = algotrader.Data.Nasdaq;

Nasdaq.getListings().then(array => {
    // [
    //     {
    //         Symbol: 'AABA',
    //         'Security Name': 'Altaba Inc. - Common Stock',
    //         'Market Category': 'Q',
    //         'Test Issue': 'N',
    //         'Financial Status': 'N',
    //         'Round Lot Size': '100',
    //         ETF: 'N',
    //         NextShares: 'N'
    //     },
    //     {
    //         Symbol: 'AAL',
    //         'Security Name': 'American Airlines Group, Inc. - Common Stock',
    //         'Market Category': 'Q',
    //         'Test Issue': 'N',
    //         'Financial Status': 'N',
    //         'Round Lot Size': '100',
    //         ETF: 'N',
    //         NextShares: 'N'
    //     },
    // ... and thousands more
});

For documentation on Nasdaq queries, visit the Data Library Docs.

Query

Using the Yahoo Finance and Robinhood APIs, you can easily find stocks based on certain criteria.

Here are a few examples:

const Query = algotrader.Data.Query;

Query.getEarnings(1).then(array => {
    // Returns an array of companies that are reporting their earnings within the next '1' day.
    // [
    //     {
    //         symbol: 'NFLX',
    //         instrument: 'https://api.robinhood.com/instruments/81733743-965a-4d93-b87a-6973cb9efd34/',
    //         year: 2018,
    //         quarter: 1,
    //         eps: { estimate: '0.6400', actual: null },
    //         report: { date: '2018-04-16', timing: 'pm', verified: true },
    //         call:
    //             { datetime: '2018-04-16T22:00:00Z',
    //             broadcast_url: 'http://mmm.wallstreethorizon.com/u.asp?u=152320',
    //             replay_url: null }
    //     },
    // ... and more
});

Query.search("Nordstrom").then(array => {
    // Returns an array of matching stocks, options, ETF's, and others.
    // [
    //     { symbol: 'JWN',
    //         name: 'Nordstrom, Inc.',
    //         exch: 'NYQ',
    //         type: 'S',
    //         exchDisp: 'NYSE',
    //         typeDisp: 'Equity' },
    //     { symbol: 'JWN180420C00045000',
    //         name: 'JWN Apr 2018 call 45.000',
    //         exch: 'OPR',
    //         type: 'O',
    //         exchDisp: 'OPR',
    //         typeDisp: 'Option' },
    //  ... and more
});

Query.getTopGainers(5).then(array => {
    // Returns an array of objects each containing information on the five best performing stocks.
    // You can also use .getTopLosers(count)
});

Query.getHighestVolume(5).then(array => {
    // Returns an array of objects each containing information on five of today's stocks with the highest volume.
});

For documentation on all functions of the Query class, visit the Data Library Docs.

News

Thanks to both News API and Yahoo Finance, you can get breaking news headlines and various articles on either specific companies or the market or world as a whole.

First you'll want to create a reference to the News class: const News = algotrader.Data.News;

You can then use either Yahoo Finance or News API to retrieve news articles, but it's easier to find exactly what you're looking for with the latter.

For Yahoo Finance, simply do the following:

News.getFromYahoo("AAPL").then(array => {
    // Returns an array of news articles for the given symbol
    // [
    //     News {
    //         title: 'Amazon and Walmart Battle for Control of Flipkart',
    //         description: 'The world's largest retailer and its online counterpart compete on many fronts, but the fight for India's largest online retailer may be one of the most important.',
    //         date: 2018-04-15T15:45:00.000Z,
    //         source: undefined,
    //         author: undefined,
    //         url: 'https://finance.yahoo.com/news/amazon-walmart-battle-control-flipkart-154500760.html?.tsrc=rss' },
    //     News {
    //         title: 'President Trump is considering rejoining the Trans Pacific Partnership trade deal',
    //             description: 'President Trump is opening the door to rejoining the Trans Pacific Partnership trade deal. Yahoo Financeโ€™s Jen Rogers and Rick Newman look at the implications.',
    //             date: 2018-04-13T14:40:56.000Z,
    //             source: undefined,
    //             author: undefined,
    //             url: 'https://finance.yahoo.com/video/president-trump-considering-rejoining-trans-144056381.html?.tsrc=rss' },
    // ... and more
});

You'll notice that Yahoo Finance does not provide the author or the source and only links back to their website.

With News API, you'll get many more options on what articles to return. However, you'll need a free API key in order to use their service. Register for one here. You can then get either breaking/recent headlines or search for all articles matching your query.

Each News API query must contain an object with at least one query option. Possible parameters for the two functions are:

  • getHeadlines(apiKey, object)
    • q - Keywords or phrases to search for.
    • category - Possible options: business, entertainment, general, health, science, sports, technology (Cannot be mixed with sources parameter)
    • country- The 2-letter ISO 3166-1 code of the country you want to get headlines for. (Cannot be mixed with sources parameter)
    • sources - A comma-separated string of identifiers (maximum 20) for the news sources or blogs you want headlines from. (Cannot be mixed with country parameter)
    • pageSize - The number of results to return per page. 20 is the default, 100 is the maximum.
    • page - Use this to page through the results.
  • getAll(apiKey, object)
    • q - Keywords or phrases to search for.
    • sources - A comma-separated string of identifiers (maximum 20) for the news sources or blogs you want headlines from.
    • domains - A comma-separated string of domains (eg bbc.co.uk, techcrunch.com, engadget.com) to restrict the search to.
    • from - A date object for the oldest allowed article.
    • to - A date object for the newest allowed article.
    • language - Possible options: ar, de, en, es, fr, he, it, nl, no, pt, ru, se, ud, zh
    • sortBy - Possible options: relevancy, popularity, publishedAt (newest)
    • pageSize - The number of results to return per page. 20 is the default, 100 is the maximum.
    • page - Use this to page through the results.

Here is an example query for U.S. articles relating to using getHeadlines(apiKey, object):

News.getHeadlines("myApiKey", {
    country: "us",
    category: "business"
}).then(array => {
    // Returns an array of News objects related to U.S. business.
    // [
    //     News {
    //         title: 'Two black men were arrested waiting at a Starbucks. Now the company, police are on the defensive.',
    //         description: 'The backlash is a dramatic turn from efforts to craft the company as a progressive 	corporate leader that values โ€œdiversity and inclusion.โ€',
    //         date: 2018-04-15T15:22:22.000Z,
    //         source: 'The Washington Post',
    //         author: null,
    //         url: 'https://www.washingtonpost.com/news/business/wp/2018/04/15/two-black-men-were-arrested-waiting-at-a-starbucks-now-the-company-police-are-on-the-defensive/' },
    //     News {
    //         title: 'Zillow surprises investors by buying up homes',
    //         description: 'Real estate platformย Zillowย changed up its business model this week, announcing that it plans to purchase and sell homes in Las Vegas and Phoenix. Zillow will be working with Berkshire Hathaway and Coldwell Banker to make offers on homes before it finds a buyโ€ฆ',
    //         date: 2018-04-15T00:27:56.000Z,
    //         source: 'TechCrunch',
    //         author: 'Katie Roof',
    //         url: 'https://techcrunch.com/2018/04/14/zillow-surprises-investors-by-buying-up-homes/' }
    // ... and more
});

The News Class provides a few functions that you can run to easily retrieve information you need, such as news.getTitle(), news.getDate(), and news.getDescription(). You can also download the full article from the source:

news.getArticle().then(html => {
    // This will return raw HTML from the source. You'll have to parse it yourself if you want to read the entire article, but typically the description - news.getDescription() - is sufficient.
});

For documentation on all News functions, visit the Data Library Docs.


Notes

Dealing with errors

You should ensure that all promises are provided a catch function in case they are rejected. In order to help with debugging, the Error.toString() method is modified in Algotrader's library. If you don't choose to use this you can continue to simply print the error.

For example:

myOrder.submit().then(res => {
    // Order was successful
}).catch(error => { console.error(error.toString()) });

This would print something similar to the image below, providing the response code and error message(s) from Robinhood. This is a larger error, so keep in mind that most of these would be on one line.

Algotrader Error toString

However, if you don't like this and want to keep your errors uniform, you can simply use console.error(error) without toString().

Algotrader Error

As you can probably see from the images, it's much appreciated if you report unexpected errors as a new Issue on GitHub. Not only can you get help resolving the error if it's an isolated incident, but it also helps fix bugs in future updates.

You can report errors here.

algotrader's People

Contributors

arm1stice avatar cdbattags avatar dakridge avatar dependabot[bot] avatar edzme avatar egorio avatar gillinghammer avatar mattwebbio avatar meschbach avatar nover avatar torreyleonard avatar yorch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

algotrader's Issues

3.0 release milestone

Finally getting back around to this repo and I really want to give some love back. I think this is the best on the market right now. Ideally, Robinhood will support this venture!

Quality of life:

  • typescript refactor
  • backwards compatible

New features:

  • market watch screener
  • one-time passcode puppeteer support

Robinhood

  • fractional shares
  • fix all broken v2

API integrations:

auth

has auth broken? I haven't looked into it I was just made aware all my trades are failing.

this is the error message:

node:64416) UnhandledPromiseRejectionWarning: Error:

Not Found

The requested URL /api-token-auth/ was not found on this server.

thanks

Issue with getHistoricals

When trying to get the user historicals, the getHistoricals method is missing the account number in the qs object

qs: { account_number: _this.account, ......

TD/paper trading

hello! Do you have a timeline for TDameritrade support with backtesting and papertrading support? Is this being developed for commercial use or contributors?

Support for indian brokers

Hey bro,

Can you help with one Indian broker (Angel Broking) and i can add more.

Or in near future if we want to implement the same.

Trading RH options with stop loss

Thanks for digging out the API for RH options trading! I can place a limit order to buy options algorithmically. However I was hoping you could provide an example to add a stop loss to my options order. I think it can be enabled by adding to the legs option here:

https://github.com/Ladinn/algotrader/blob/a111eaafd8c85a51e952734429a41d5ba87dd7a6/objects/broker/robinhood/OptionOrder.js#L39

Here is an example of how I can buy qty contracts of instrument x under account a for ask price p:

{
"quantity":qty,
"direction":"debit",
"type":"limit",
"price": p,
"account":a,
"time_in_force":"gfd",
"trigger":"immediate",
"legs":
[
      {"side":"buy","option":instrument,"position_effect":"open","ratio_quantity":"1"}
],
"override_day_trade_checks":False,
"override_dtbp_checks":False, 
"ref_id":ref_id}

How would I amend to this JSON statement to add a stop loss at price q, where q < p?

Open to a TypeScript conversion?

Would you be open to using TypeScript for this project? I'd love to wrap this package and start adding types for intellisense and typeahead for objects.

Would you be open to TypeScript if I configured a build system for it?

Robinhood Auth Issues

I believe the Robin hood api has change and the User class with isAuthenticated method is not working any more. We are using it with GQL and getting Library Error:"this version of robinhood is no longer supported ...."

Any solution?

Robinhood responded with code 401: unauthorized. { "detail": "Incorrect authentication credentials." }

I'm trying to authenticate my Robinhood user programmatically, so I can issue trades programmatically, using the following recommended code:

const myUser = new User(credentials.username, credentials.password, options);

myUser.authenticate()
    .then(() => {
        // User was authenticated
        console.log("Algotrader User Authenticated...");
    })
    .catch(error => {
        console.log("Authentication Error: " + error);
    });

But I'm getting the following error printed to the console when I run the app.js file:

image

Can anyone shed some light on this issue please? Thanks in advance!

IEX token

Hi,

Currently, trying to use the IEX.getLogo() method, but I'm getting a forbidden issue due to no token given to the API.

Is there a way where I can pass in the token as a property within IEX?

Thanks

Robinhood 404

I'm getting an error after following the documentation. Either I missed something, or this is an unexpected error.

(node:186620) UnhandledPromiseRejectionWarning: Error: Robinhood responded with code 404: not found | Not Found

The requested URL /accounts/null/positions/ was not found on this server.

Here is my code:

myUser.getPortfolio()
.then(myPortfolio => {
let myTeslaShares = myPortfolio.getQuantity("TSLA");
let bestDayEver = myPortfolio.getPurchaseDate("SHLD");
let mySymbols = myPortfolio.getSymbols();
let myMoneyMakers = myPortfolio.getQuantityGreaterThan(50);
})
.catch(error => {
console.log("getPortfolio Failed!", error);
})

where myUser is an authenticated Robinhood.User

On Auth: "This version of robinhood is no longer supported..."

Looks like Robinhood has changed their API, and I'm getting this issues:

"This version of Robinhood is no longer supported. Please update your app or use Robinhood for Web to log in to your account."

Looks like there's a fix in for it, any chance we can merge: Gillinghammer-patch-2 ?

Support for fractional shares

Robinhood now supports orders for fractional shares for most equities. Is this possible in algotrader or will it be possible in the future?

How are you connecting to rh?

I see a device token needs to be passed in. Can you put me in the right direction as to how I'm supposed to generate one?

TypeError: Scheduler.onMarketOpen is not a function

Hi,
I am getting following error while using given example in the package. Please help how to fix it.

using node v12.13.0.

c:\test\node examples\highest-open-interest.js
C:\test\node_modules\algotrader2\examples\highest-open-interest.js:28
Scheduler.onMarketOpen(5 * 60000, open).catch(error => console.error(error)); // Run every day on market open
^

TypeError: Scheduler.onMarketOpen is not a function
at Object. (C:\test\node_modules\algotrader2\examples\highest-open-interest.js:28:11)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11

Missing Auth in the Instrument.getFundamentals

Looks like now to get the data from a stock you also need to be logged in. I was getting a 401 when trying to do it without any auth param.

Modified the static getByUrl to accept the user and added the header with the user.getAuthToken

Using in React

Hi, do you know if I should use the same installation steps for a React app? This has been my experience:

  1. Installed with 'yarn add algotrader'
  2. Added 'const algotrader = require('algotrader');'
  3. Compile fails.
    errors

I really like your work, thank you for making it available.

ERROR in ./node_modules/algotrader/objects/broker/robinhood/User.js
Module not found: Error: Can't resolve 'fs' in 'C:\AndroidAppDev\xcharts-react-webview\node_modules\algotrader\objects\broker\robinhood'
 @ ./node_modules/algotrader/objects/broker/robinhood/User.js 19:9-22

Getting option chain quotes/info using OptionInstrument.getBySymbol()

I realize your Options support is in progress. In your documentation for OptionInstrument's method getBySymbol() you acknowledge that

"As there is no apparent way to query Robinhood options by symbol, all instruments will be downloaded and filtered. This will take a while on first run. After, set 'cache' to true."

"Take a while on first run" was quite the understatement in my case! I let it run for about 16 hours, downloading data from Robinhood, and then it crashed because it ran out of memory on the heap.

There's a ton of data. I hacked the code to stringify the data and write to a file stream (to fix the memory issue) ... but the resultant file has so much text that my computer hangs just trying to open it.

Maybe I need to set some parameters to the /options/instruments/ endpoint, or a different endpoint completely that would allow a more targetted request by symbol. I'll keep investigating. Any thoughts you have on this would be appreciated. =)

Error: Robinhood responded with code 401

Running into an issue that happened recently, so I am wondering if something changed in the Robinhood API.

const instrument = await Instrument.getBySymbol(symbol);
// works fine & returns the instrument from Robinhood
// But now when I use that generated instrument to get the Quote I have a 401 response from Robinhood
const stockQuote = await instrument.getQuote();
// Error: Robinhood responded with code 401

binance exchange support

wanna check if this library durable to retrieve binance buy and sell and apply with strategy?

Robinhood OptionOrder: Server Error 500

Robinhood is responding with status code 500 (server error) when submitting an option order.

@briansp2020:

Thanks for your help. I tried to place an option order but was not successful. I'm new to javascript so I'm sure I did something wrong. Could you take a look at the code below and let me know what I'm doing wrong?

myUser.authenticate()
.then(() => {
// User was authenticated

// First, we'll get the instrument and tradable expiration dates for SPY.
Instrument.getBySymbol("SPY").then(ins => {
    OptionInstrument.getExpirations(myUser, ins).then(option => {
        // Next, we'll fetch an option chain for the upcoming expiration date.
    	OptionInstrument.getChain(myUser, ins, option[0], "put").then(optionChain => {
                console.log(optionChain[4]);

    	    // An array of OptionInstruments will be returned. See the example below.
	    // You'll then want to find the specific OptionInstrument that you want to trade.
	    // In this example, we'll buy using the first element in the array.
	    let order = new OptionOrder(null, myUser, optionChain[4], "credit", "gtc", "buy", "market", 1);
	    order.submit().then(res => {
    	        // Order was submitted, the response will be parsed as a completed OptionOrder.
		console.log("Order submitted");
		console.log(res);
		});
	    })
	})
    });
})
.catch(error => {
	// Either the request failed, or Robinhood responded with an error.
    // (Ex: you don't have internet access or your user credentials were incorrect)
})

I get the following error message

OptionInstrument {
  url: 'https://api.robinhood.com',
  tradability: 'tradable',
  strikePrice: 260,
  state: 'active',
  type: 'put',
  symbol: 'SPY',
  minTicks: { cutoff_price: '0.00', below_tick: '0.01', above_tick: '0.01' },
  instrumentURL: 'https://api.robinhood.com/options/instruments/487f72f2-b797-4016-8ff7-8dd172029808/',
  ids: 
   { chain: 'c277b118-58d9-4060-8dc5-a3b5898955cb',
     option: '487f72f2-b797-4016-8ff7-8dd172029808' },
  dates: 
   { expiration: 2019-03-04T00:00:00.000Z,
     created: 2019-01-25T03:08:09.376Z,
     updated: 2019-01-25T03:08:09.376Z } }
(node:25477) UnhandledPromiseRejectionWarning: Error: Robinhood responded with code 500 | <h1>Server Error (500)</h1>

> Please report all unexpected errors on GitHub: https://git.io/vpYYL

    at Function.handleResponse (/home/briansp/node_modules/algotrader/objects/broker/robinhood/Robinhood.js:23:11)
    at Request.request.post [as _callback] (/home/briansp/node_modules/algotrader/objects/broker/robinhood/OptionOrder.js:98:22)
    at Request.self.callback (/home/briansp/node_modules/request/request.js:185:22)
    at emitTwo (events.js:126:13)
    at Request.emit (events.js:214:7)
    at Request.<anonymous> (/home/briansp/node_modules/request/request.js:1161:10)
    at emitOne (events.js:116:13)
    at Request.emit (events.js:211:7)
    at IncomingMessage.<anonymous> (/home/briansp/node_modules/request/request.js:1083:12)
    at Object.onceWrapper (events.js:313:30)
(node:25477) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:25477) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Server error 500 is the same error message I'm getting from the python api. If I change "gtc" to "GTC" as shown in the example in readme, I get 400 error along with the following error message.

(node:25697) UnhandledPromiseRejectionWarning: Error: Robinhood responded with code 400.

{
  "time_in_force": [
    "\"GTC\" is not a valid choice."
  ]
}

Any ideas? I'd like to get the option order placement working using this API before trying to get the python API working. Any help would be appreciated.

Thanks!

Originally posted by @briansp2020 in #12 (comment)

Maybe add period paramter for IEX financials

Hi Team,

i would suggest to add a parameter period for the function getFinancials(symbol) to be able to retrieve the annual data as well or to add a new function for it?

regards

Jan

Can't seem to sign in properly.

I'm attempting to sign into Robinhood using algotracker's methods. I.E. I'm doing this:

const User = robinhood.User;

const myUser = new User("username", "password", "token");

myUser.authenticate()
.then(() => {
// User was authenticated
console.log("User authenticated...")
})
.catch(error => {
// Either the request failed, or Robinhood responded with an error.
// (Ex: you don't have internet access or your user credentials were incorrect)
});

However, I'm getting the following error:

Robinhood responded with code 401: unauthorized.

This at one point did download a number of objects from Robinhood when placing a call to:
const option = await Instrument.getBySymbol(optionSignal.Ticker);

Your guess is as good as mine - better if you get it right.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.