Last active
September 13, 2017 19:39
-
-
Save Kadrian/989aa9fda940f6c02fef588de77fb0d5 to your computer and use it in GitHub Desktop.
Buy BTC / ETH / XRP automatically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ----------- | |
// | |
// ## How to use: | |
// | |
// 1) Install node 8 | |
// | |
// 2) Install dependencies: | |
// `npm install crypto request` | |
// | |
// 3) Get a Bitstamp account, API key and tweak viariables below | |
// | |
// 4) Fire: | |
// `node --harmony buy-coins.js` | |
// | |
// 5) Set up a cron job somewhere that does this e.g. weekly: | |
// `0 9 * * Mon node --harmony buy-coins.js` | |
// | |
// License: MIT | |
// | |
// made by: @kairollmann | |
// | |
// ----------- | |
const crypto = require('crypto'); | |
const request = require('request'); | |
// ----------- | |
// | |
// CHANGE THESE AS YOU LIKE | |
// Amounts need to be a little more than 5 EUR as that's the min. order amount | |
// | |
// ----------- | |
const CUSTOMER_ID = '<Your bitstamp account id>'; | |
const BITSTAMP_API_KEY = '<Your bitstamp key>'; | |
const BITSTAMP_API_SECRET = '<Your bitstamp secret>'; | |
const TO_BUY_IN_EUR = { | |
'BTC': 5.10, | |
'ETH': 5.10, | |
'XRP': 5.10, | |
}; | |
const CURRENCY_PAIRS = { | |
'BTC': "btceur", | |
'ETH': "etheur", | |
'XRP': "xrpeur", | |
}; | |
let globalNonceCounter = 0; | |
// ----------- | |
// | |
// A couple of utility functions | |
// | |
// ----------- | |
function padWithZeros(number, size) { | |
let num = number.toString(); | |
while (num.length < size) num = "0" + num; | |
return num; | |
} | |
function createNonce() { | |
const paddedNonceCounter = padWithZeros(globalNonceCounter++, 4); | |
// Must be a continously increasing integer number | |
return `${Date.now()}${paddedNonceCounter}`; | |
} | |
function createSignature(nonce) { | |
const message = `${nonce}${CUSTOMER_ID}${BITSTAMP_API_KEY}`; | |
return crypto | |
.createHmac('sha256', BITSTAMP_API_SECRET) | |
.update(message) | |
.digest('hex') | |
.toUpperCase(); | |
} | |
async function callApiAuthenticated(options) { | |
const nonce = createNonce(); | |
const signature = createSignature(nonce); | |
return await callApi({ | |
...options, | |
body: { | |
...options.body, | |
key: BITSTAMP_API_KEY, | |
nonce, | |
signature, | |
} | |
}); | |
} | |
function promisifiedRequest(url, options) { | |
return new Promise((resolve, reject) => { | |
request(url, options, (err, res, body) => { | |
if (err) { | |
reject(err); | |
} | |
else { | |
if ( | |
res.statusCode < 200 || | |
res.statusCode >= 300 || | |
JSON.parse(res.body).status === 'error' | |
) { | |
reject(res.body); | |
} else { | |
resolve(res.body); | |
} | |
} | |
}); | |
}); | |
} | |
async function callApi(options) { | |
const requestOptions = options.method | |
? { | |
method: options.method, | |
form: options.body, | |
} | |
: { | |
method: 'GET' | |
}; | |
const p = promisifiedRequest(options.url, requestOptions); | |
const response = await p; | |
const result = JSON.parse(response); | |
console.log(JSON.stringify(result, null, 2)); | |
if (options.successAction) { | |
options.successAction(result); | |
} | |
return result; | |
} | |
function roundToDecimals(value, decimals) { | |
const factor = Math.pow(10, decimals); | |
return Math.round(value * factor) / factor; | |
} | |
function isWeirdBtcPrice(price) { | |
return !price || price < 1000 || price > 10000 | |
} | |
function isWeirdEthPrice(price) { | |
return !price || price < 50 || price > 2000 | |
} | |
function isWeirdXrpPrice(price) { | |
return !price || price < 0.001 || price > 200 | |
} | |
const IS_PRICE_WEIRD = { | |
'BTC': isWeirdBtcPrice, | |
'ETH': isWeirdEthPrice, | |
'XRP': isWeirdXrpPrice, | |
}; | |
async function ensurePriceIsGood({ currency, price }) { | |
if (!price) { | |
price = await getPrice({ currency }); | |
} | |
console.log(`Price is ${price} ${currency}`); | |
if (IS_PRICE_WEIRD[currency](price)) { | |
throw new Error(`${currency} price seems to be broken or outlier-ish`) | |
} | |
console.log(`${currency} price seems legit.`); | |
} | |
// ----------- | |
// | |
// Functions that call the Bitstamp API | |
// | |
// ----------- | |
async function getPrice({ currency }) { | |
console.log(`Getting the ${currency} price...`); | |
const ticker = await callApi({ | |
url: `https://www.bitstamp.net/api/v2/ticker/${CURRENCY_PAIRS[currency]}/` | |
}); | |
return ticker.ask; | |
} | |
async function postBuy({ currency, price, amount }, ) { | |
const totalPrice = roundToDecimals(price * amount, 8); | |
console.log(`Buying ${amount} ${currency} for ${totalPrice} EUR...`); | |
console.log(`( ${currency} price: ${price} )`); | |
await callApiAuthenticated({ | |
url: `https://www.bitstamp.net/api/v2/buy/market/${CURRENCY_PAIRS[currency]}/`, | |
method: 'POST', | |
body: { | |
amount | |
}, | |
successAction: () => { | |
console.log(`SUCCESSFULLY BOUGHT ${amount} ${currency} for ${totalPrice} EUR. \n`); | |
} | |
}); | |
} | |
// ----------- | |
// | |
// MAIN | |
// | |
// ----------- | |
async function buy({ currency }) { | |
const price = await getPrice({ currency }); | |
await ensurePriceIsGood({ currency, price }); | |
const amount = roundToDecimals(TO_BUY_IN_EUR[currency] / price, 8); | |
await postBuy({ | |
currency, | |
price, | |
amount, | |
}); | |
} | |
(async function main() { | |
try { | |
await buy({ currency: 'BTC' }); | |
await buy({ currency: 'ETH' }); | |
await buy({ currency: 'XRP' }); | |
} catch(e) { | |
console.log(e); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment