From 08be9fb1d16382fe024cc410d9eb1fe06dcbdb27 Mon Sep 17 00:00:00 2001 From: Chris Vanderloo Date: Thu, 16 Aug 2018 11:50:08 -0400 Subject: [PATCH] added buy/sell --- examples/example.js | 48 ++++++++++++++--------- src/index.js | 93 ++++++++++++++++++++++++++++++++++++--------- src/request.js | 0 3 files changed, 107 insertions(+), 34 deletions(-) create mode 100644 src/request.js diff --git a/examples/example.js b/examples/example.js index 32dcf0a..17efcab 100644 --- a/examples/example.js +++ b/examples/example.js @@ -13,44 +13,58 @@ client.init({ alphaVantage: process.env.ALPHA_VANTAGE, newsAPI: process.env.NEWS_API }, (error) => { + // Main trading function + + // Don't forget to handle any initialization errors if (error) { console.log(error); return; } - console.log('Ready to trade!'); - // Adds an algorithm to run later // // These algorithms should be designed to take data from ONE - // source, aka AAPL or BTC, and not try to balance multiple. + // source, aka AAPL or GE, and not try to balance multiple. // // Algorithms will automatically be wrapped with data getters // Before the algorithm runs, it will fetch the data necessary - // - // Validate algorithm before running by doing a "dry" run of provided - // functions - those that need data requested will be added to - // the dependencies for the algorithm automatically + // using getters in a dataset. Because of the way dependencies + // are grabbed, and to keep down the amount of requests being made + // to Alpha Vantage and other APIs, the data for each should be + // grabbed at the beginning and not live in the function. client.addAlgorithm('algoOne', emaAlgorithm); - // client.execute returns a Promise - // Execute a saved algorithm + // client.execute returns a Promise client.execute({ name: 'algoOne', symbol: 'AAPL', - max_usd: '134.32', - dry: true + max_usd: '134.32', // maximum amount of capital in your account the + // algorithm will be allowed utilize + }).catch((err) => { + console.log(err); + }).then(() => { + client.logout(); }); - client.logout(); + }); // An algorithm that will take in data based on a particular signal -function emaAlgorithm(buy, sell, data) { - console.log(" ") - console.log(data.price); - console.log(data.ema.daily(50)); - console.log(data.macd.daily); +// This algorithm is meant to be run once, straight throw. Multiple executions +// should be defined in the main trading method. +function emaAlgorithm(buy, sell, data, is_check) { + + var ema_40 = data.ema.daily(40); // current EMA over 15 day period + var ema_120 = data.ema.daily(120); // current EMA over 60 day period + + // write algorithm inside this if statement, which is false when + // the algorithm isn't being checked for dependencies but is being + // delivered necessary functions + + if (!is_check) { + if (ema_40 < ema_120) sell(); + else buy(); + } } \ No newline at end of file diff --git a/src/index.js b/src/index.js index 1021b6d..727df10 100644 --- a/src/index.js +++ b/src/index.js @@ -137,11 +137,47 @@ module.exports = { }; this.algo = { - sell: () => { - // if (this.algo.passed_options.dry) + sell: (instr, price, quant) => { + if (quant != 0) { + return rp({ + uri: 'https://api.robinhood.com/orders/', + method: 'POST', + headers: { Authorization: `Token ${token}` }, + json: true, + form: { + account: this.account.url, + instrument: instr.url, + symbol: instr.symbol, + type: 'market', + time_in_force: 'gtc', + trigger: 'immediate', + price: price, + quantity: quant, + side: 'sell' + } + }); + } }, - buy: () => { - // if (this.algo.passed_options.dry) + buy: (instr, price, quant) => { + if (quant != 0) { + return rp({ + uri: 'https://api.robinhood.com/orders/', + method: 'POST', + headers: { Authorization: `Token ${token}` }, + json: true, + form: { + account: this.account.url, + instrument: instr.url, + symbol: instr.symbol, + type: 'market', + time_in_force: 'gtc', + trigger: 'immediate', + price: price, + quantity: quant, + side: 'buy' + } + }); + } }, getStockData: async (opts, callback) => { let instr; @@ -163,6 +199,15 @@ module.exports = { this.algo.passed_options = opts; const data = { + buy: () => { + if (!opts.dry && parseFloat(quote.last_trade_price) < parseFloat(this.account.buying_power)) + this.algo.buy(data.instrument, quote.last_trade_price, + parseInt(parseFloat(this.account.buying_power) / parseFloat(quote.last_trade_price))); + }, + sell: () => { + if (!opts.dry && parseFloat(data.investment) > 0) + this.algo.sell(data.instrument, quote.last_trade_price, parseFloat(data.investment)); + }, ema: { daily: size => data.ema_data.daily[size], weekly: size => data.ema_data.weekly[size], @@ -183,7 +228,10 @@ module.exports = { weekly: {}, monthly: {} }, - macd: {} + macd: {}, + available_money: this.account.buying_power, + price: quote.last_trade_price, + instrument: instr }; const promiseArray = []; const getAV = (func, interval, size, seriesType, cback) => { @@ -201,26 +249,39 @@ module.exports = { }).then((res) => { const resParsed = JSON.parse(res); if (resParsed.Information) { - throw new Error('Alpha Vantage Call volume exceeded - try decreasing how often the API is verified'); + throw new Error('Alpha Vantage Call volume exceeded - try decreasing how often the API is called'); } if (resParsed['Error Message']) { throw new Error(res['Error Message']); } const obj = resParsed[Object.keys(resParsed)[1]]; + if (!obj) throw new Error(obj); const firstEl = obj[Object.keys(obj)[0]]; cback(firstEl[Object.keys(firstEl)[0]]); }); }; + var positions = this.positions + + var stock = positions.find(stock => stock.instrument === instr.url); + if (stock) data.investment = stock.quantity; + else data.investment = '0.0000'; + const getters = { - get invested_money() { - return undefined; - }, get available_money() { - return undefined; + return data.available_money; + }, + get investment() { + return data.investment; }, get price() { - data.price = quote.ask_price; - return undefined; + return data.price; + }, + get quote() { + data.quote = quote; + return data.quote; + }, + get instrument() { + return data.instrument; }, get sentiment() { return undefined; @@ -281,9 +342,9 @@ module.exports = { } }; - callback(() => data, () => data, getters); + callback(() => data, () => data, getters, true); await Promise.all(promiseArray); - callback(this.algo.buy, this.algo.sell, data); + callback(data.buy, data.sell, data, false); }, }; @@ -291,9 +352,7 @@ module.exports = { let toExec; if (opts.name && !func) toExec = this.algorithms.find(x => x.name === opts.name).func; else toExec = func; - return this.algo.getStockData(opts, toExec).catch((err) => { - throw new Error(err); - }); + return this.algo.getStockData(opts, toExec); }; }, }; diff --git a/src/request.js b/src/request.js new file mode 100644 index 0000000..e69de29 -- 2.51.2