Today, everyone is talking about cryptocurrency. There have been many cases when people sold bitcoins at an incredibly low price. Well, I once thought to buy 150 BTC for $ 15 ...
But what if we had a time machine that could send crypto commands to the broker in the past? Of course, we would have brought down the global financial system. Nevertheless, let's imagine that we have a car, or, at least, we are close to its creation. We want you, a dirty, hungry freelancer working for food, to create for us an algorithm that generates a sequence of commands for our broker client. (Which we ourselves created a year ago specifically for future use, of course.)
You can use Python or JavaScript. Please check your solution with the included test runner. The one whose decision will earn more money will be chosen to write a bot for a real client.API specification v0.0.18
The task runner should be a pure function that takes two arguments:prices => [{"btc": 1000}, ...]
- Array of Bitcoin prices by dayinitialSum => 100000
- Starting balance in USD
The function must return an array of commands. Commands are called in turn, one per day. That is, for 14 days you must have exactly 14 teams.
Example:[{"op":"buy","amount":1},{"op":"sell","amount":1}]
Commands:"buy"
additional attributes: amount [float] - Buy BTC using current USD account"sell"
additional attributes: amount [float] - Sell BTC using current USD account"pass"
- skip day
'use strict'; const https = require('https'); const currencies = [ 'btc', 'eth', ]; const BASE_CURRENCY = 'usd'; const DEFAULT_CURRENCY = 'btc'; const fetchRates = (days, currency) => new Promise((res, rej) => { https.get(`https://min-api.cryptocompare.com/data/histoday?aggregate=1&e=CCCAGG&extraParams=CryptoCompare&limit=${days}&tryConversion=false&tsym=${BASE_CURRENCY.toUpperCase()}&fsym=${currency.toUpperCase()}`, (resp) => { let data = ''; resp.on('data', (chunk) => { data += chunk; }); resp.on('end', () => { data = JSON.parse(data); data = data.Data; res(data.map(datum => datum['close']).slice(0, -1)); }); }).on("error", err => rej(err)); }); const fetchAllRates = async (days, currencies) => { const prices = {}; for (let currency of currencies) { prices[currency] = await fetchRates(days, currency); } const len = prices[Object.keys(prices)[0]].length; const ret = []; for (let i = 0; i < len; i++) { let price = {}; for (let currency of currencies) { price[currency] = prices[currency][i]; } ret.push(price); } return ret; }; const checkStash = stash => { const vals = Object.values(stash); for (let val of vals) { Test.expect(val >= -Math.pow(10, -6), 'Invalid operation'); if (val < -Math.pow(10, -6)) { throw new Error(`Debts are not supported. Stash: ${JSON.stringify(stash)}`) } } }; const applyTask = (stash, task, prices) => { console.log('- performing task', stash, task, prices); const currency = task.currency || DEFAULT_CURRENCY; switch(task.op) { case 'buy': stash[currency] += task.amount; stash[BASE_CURRENCY] -= task.amount * prices[currency]; break; case 'sell': stash[currency] -= task.amount; stash[BASE_CURRENCY] += task.amount * prices[currency]; break; case 'pass': break; } return stash; }; const runner = async (trader, cases) => { for (let testCase of cases) { let prices = await fetchAllRates(testCase.days, currencies); let stash = testCase.amount; for (let currency of currencies) { stash[currency] = stash[currency] || 0; } console.log(`Testing amount ${stash[BASE_CURRENCY]}, days ${testCase.days}`); let tasks = await trader(prices, stash[BASE_CURRENCY]); for (let i in tasks) { if (!tasks.hasOwnProperty(i)) { continue; } let job = tasks[i]; let todo = job.length ? job : [job]; for (let row of todo) { await applyTask(stash, row, prices[i]); } checkStash(stash); } let result = Math.floor(stash[BASE_CURRENCY] * 100) / 100; console.log(`finished. Resulting amount: ${result}`); } }; runner(trader, [ { amount: { [BASE_CURRENCY]: 100, }, days: 100, }, ]);
import urllib2 import json import math currencies = [ 'btc', 'eth', ] BASE_CURRENCY = 'usd' DEFAULT_CURRENCY = 'btc' def fetch_rates(days, currency): data = urllib2.urlopen( 'https://min-api.cryptocompare.com/data/histoday?aggregate=1&e=CCCAGG&extraParams=CryptoCompare&limit={}&tryConversion=false&tsym={}&fsym={}'.format( days, BASE_CURRENCY.upper(), currency.upper())).read() data = json.loads(data)['Data'] return [row['close'] for row in data][:-1] def fetch_all_rates(days, currencies): prices = {currency: fetch_rates(days, currency) for currency in currencies} return [{currency: prices[currency][i] for currency in currencies} for i in range(days)] def check_stash(stash): for currency in stash: test.assert_equals(stash[currency] >= -0.000001, True, 'Invalid operation') if stash[currency] < -0.000001: raise Exception('Debts are not supported. Stash: {}'.format(stash)) def apply_task(stash, task, prices): print '- performing task {} {} {}'.format(stash, task, prices) currency = task['currency'] if 'currency' in task else DEFAULT_CURRENCY if task['op'] == 'buy': stash[currency] += task['amount'] stash[BASE_CURRENCY] -= task['amount'] * prices[currency] elif task['op'] == 'sell': stash[currency] -= task['amount'] stash[BASE_CURRENCY] += task['amount'] * prices[currency] elif task['op'] == 'pass': pass return stash def runner(trader, cases): for testCase in cases: prices = fetch_all_rates(testCase['days'], currencies) stash = testCase['amount'] for currency in currencies: if currency not in stash: stash[currency] = 0 print 'Testing amount {}, days {}'.format(stash[BASE_CURRENCY], testCase['days']) tasks = trader(prices, stash[BASE_CURRENCY]) for i, job in enumerate(tasks): todo = job if isinstance(job, list) else [job] for row in todo: stash = apply_task(stash, row, prices[i]) check_stash(stash) result = math.floor(stash[BASE_CURRENCY] * 100) / 100 print 'finished. Resulting amount: {}'.format(result) runner(trader, [ { "amount": { BASE_CURRENCY: 100, }, "days": 100, } ])
Source: https://habr.com/ru/post/351096/
All Articles