Skip to content

Instantly share code, notes, and snippets.

@Kadrian
Last active September 13, 2017 19:39
Show Gist options
  • Save Kadrian/989aa9fda940f6c02fef588de77fb0d5 to your computer and use it in GitHub Desktop.
Save Kadrian/989aa9fda940f6c02fef588de77fb0d5 to your computer and use it in GitHub Desktop.
Buy BTC / ETH / XRP automatically
// -----------
//
// ## 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