Как стать автором
Обновить
m2_tech
Строим лучшую PropTech-компанию в России

JavaScript в гугл-таблицах: скрипты для расчета мультивалютной корзины

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров1.7K

Каждый мечтает стать немного богаче — вернуться в 2011 год и купить биткоинов на всю стипендию, чтобы сегодня быть уважаемым человеком. Возможно ли это? Скорее всего нет. Но тем не менее, если мы хотим накопить денег на квартиру или безбедную старость, то задаемся вопросом: в какой валюте или акции хранить перспективно и безопасно? Простой ответ — ни в какой. Если оглянуться в прошлое, то любая национальная валюта теряет в цене, а акции то растут, то падают, как и криптовалюта. Точно предсказать, как будет себя вести конкретная валюта в будущем, — невозможно.

Я не буду делать свои прогнозы, так как не экономист, но покажу как сделать инструмент для подсчета своих активов между разными финансовыми инструментами. А сделал я его из Google-таблиц и AppsScript, последний мне понадобился, чтобы узнавать актуальный курс.

Зачем все это?

Расскажу немного контекста, почему решил написать эту статью, но сначала пару слов про мой бекграунд. На данный я работаю в компании M2 — это онлайн-платформа для решения вопросов с недвижимостью. Сейчас модно быть мультипотенциалом и, похоже, что это про меня. Одновременно я и владелец внутреннего сервиса, и руководитель команды разработки интерфейсов. Моя команда состоит из fullstack-разработчиков, в основе нашего стека — Typescript, а также: React, Gatsby, Nest, Next, Playwright, глобально мы открыты ко всему новому. Суть нашего проекта — делаем админку, которая в основе своей CMS и система управления рекламой.

Итак, почему же я решил написать эту статью? Путешествуя по разным странам, я понял, что совсем не люблю зиму и хочу иметь второй дом в теплой стране, поэтому начал понемногу копить на свою мечту. Мне захотелось копить эффективно, поэтому я стал это делать в разных валютах, в том числе и криптовалютах.

Чтобы следить за всеми своими активами я не нашел ничего удобнее Google-таблиц и поначалу примитивно использовал их. Но однажды, перед нашей командой встала задача, которую было просто решить на Google-таблицах и AppsScript-е, — кстати, об этом чуть позже выйдет статья у Анастасии Сергеевой, а сейчас я расскажу, как упростил жизнь себе. AppsScript — это платформа разработки приложений, которая позволяет интегрироваться с продуктами Google и в основе имеет современный JavaScript.

Даже если вы не имеете навыков программирования, то можете скопировать Google-документ к себе, заполнить его своими данными и пользоваться. А если вы еще и умеете кодить, то сможете написать себе помощника с нуля или прикрутить дополнительные финансовые инструменты, например, акции, подключив скрипты к бирже.

Как я собирал свою корзину

Я предположил, что буду копить в свободно конвертируемой валюте, как это делал Центробанк, и собрал по аналогии бивалютную корзину: 45% евро и 55% долларов. Но валюта постоянно падает по отношению к недвижимости. С акциями сложно из-за санкций, поэтому остается криптовалюта. Тут можно посмотреть топ 100 валют по капитализации и выбрать, чем хочется разбавить накопления. Я не большой специалист, однако в биткоин не верю — у него медленные и дорогие транзакции, его нельзя использовать для собственных проектов. USDT и USDC — это по сути те же доллары, но без гарантий от государства. Я выбрал Ethereum — он поддерживает смартконтракты и наиболее стабильный, так как уже старый. А также TON, конкурент Ethereum, он новый, недооцененный и есть шанс, что будет расти быстрее рынка. Его кошелек встроен в Telegram, переводы можно делать контактам напрямую. В общем, я в него верю, несмотря на то, что основная масса этой валюты сосредоточена в руках нескольких инвесторов. 

Итого корзина вышла: 22,5% евро, 27,5% долларов, 25% Ethereum и 25% TON. Это все для примера, вы можете распределять по своему усмотрению и даже добавить биткоин в корзину, по правде говоря, у меня у самого есть и другие активы, но не хочу усложнять статью, тем более что она не об этом.

Все, что нужно, в одной таблице

Нет инструмента, который позволяет хранить все виды активов в едином месте, ну и это небезопасно. Как говорится: «не складывайте все яйца в одну корзину». Однако я понял, что мне важно видеть актуальное состояние корзины по всем активам. А именно: хочу видеть стоимость и количество каждого актива, а также общую стоимость. Все биржи и кошельки позволяют видеть сводную сумму, ими я и вдохновлялся при дизайне таблицы. Однако, во-первых, нет сервиса, который одновременно работает с фиатными и криптоактивами, а во-вторых, даже криптоактивы я не храню в одном месте, что-то на одной бирже, что-то на другой, что-то на одном кошельке, что-то на другом.

Код валюты:

USD

EUR

ETH

TON

Количество:

30

22

0,009

4

Цена в

USD

1

1,087698614

2949,745

6,65425

RUB

90,9239

98,8978

268066,9695

604,7250294

EUR

0,9193723217

1

2713,69055

6,121741147

Стоимость актива в

USD

30

23,92936951

26,547705

26,617

RUB

2727,717

2175,7516

2412,602725

2418,900117

EUR

27,58116965

22

24,42321495

24,48696459

Вверху таблицы я добавил код валюты, сразу под ним — количество и курс в разной конвертируемой валюте для наглядности. Ниже — стоимость актива в корзине, она считается по формуле. На сером фоне изменяемые данные: стоимость актива пересчитывается автоматически при изменении количества.

Автообновления курса валют

Количество задается самостоятельно, а вот курс хочется получать автоматически, чтобы не вбивать его постоянно, тем более четыре актива по трем валютам — это 12(10) постоянно изменяемых значений. И тут на помощь приходит Apps Script. 

Переходим в меню Расширения/Apps Script и открывается удобный редактор скриптов, там используется JavaScript v8. Так вот, первое, что мне хотелось, — это написать функцию, которая бы получала курс одной валюты относительно другой. Я воспользовался API ЦБ РФ и написал такую функцию:

function cbrRate(charCode = 'USD', charCodeIn = 'USD') {
 try{
   const url = 'https://www.cbr-xml-daily.ru/daily_json.js';
   const response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
   const json = response.getContentText();
   const data = JSON.parse(json);
   const currency = data.Valute[charCode];
   const returnCurrency = (outC, inC = {Value:1, Previous: 1})=>{
     const currentRate = outC.Value / inC.Value;
     const previousRate = outC.Previous / inC.Previous;
     return [currentRate, (currentRate - previousRate)/ previousRate];
   }
   if( currency ){
     if(charCodeIn === 'RUB'){
       return returnCurrency(currency);
     } else {
       return returnCurrency(currency, data.Valute[charCodeIn]);
     }
   }
 } catch(e){
   console.error(e);
 }
 return null;
}

ЦБ РФ возвращает курс в рублях, поэтому я сделал разные преобразования, чтобы переводить курс из одного в другой. В дальнейшем мне понадобилось предыдущее значение курса, поэтому я возвращаю массив:

  1. Текущий курс

  2. Предыдущий курс

О криптовалютах ЦБ РФ ничего не знает, но я нашел пару сервисов, которые возвращают курсы в валютах, приведу одну из функций в пример:

function tonapiRate(charCode = 'USD', charCodeIn = 'USD') {
 try{
   const tonURL = `https://tonapi.io/v2/rates?tokens=${charCode}&currencies=${charCodeIn}`;


   const tonResponse = UrlFetchApp.fetch(tonURL, {'muteHttpExceptions': true});
   const tonjson = tonResponse.getContentText();
   const tondata = JSON.parse(tonjson);
   const ton = tondata.rates[charCode];
   if(ton && ton.prices[charCodeIn]){
     return [
       ton.prices[charCodeIn],
       parseFloat(ton.diff_24h[charCodeIn].replace("−","-"))/100
     ];
   }
 } catch(e){
   console.error(e);
 }
 return null;
}

И чтобы окончательно не думать о том, из каких API берутся курсы, я обернул эти функции в следующее:

function exchangeRate(charCode = 'USD', charCodeIn = 'USD') {
 return cbrRate(charCode, charCodeIn)?.[0] || tonapiRate(charCode, charCodeIn)?.[0] || coinbaseRate(charCode, charCodeIn);
}

То есть, если одна не может вернуть значение, он смотрит в следующий сервис и т.д. Впоследствии можно будет расширять функцию другими разными API. Курсы немного отличаются на разных ресурсах, но это не так важно, чтобы оценивать стоимость корзины.

Как изменяется курс и стоимость актива

Дальше мне захотелось смотреть за изменением курса валют и стоимости валюты в корзине. Для этого мне и понадобилось второе значение функции. У ЦБ РФ и у TON API разный смысл: первый показывает цену вчерашнего и позавчерашнего закрытия, а TON API — просто цену 24 часа назад и цену последней сделки. Однако для оценки это тоже не очень важно, мы же копим вдолгую.

Я написал следующую обертку:

function exchangeDiff(charCode = 'USD', charCodeIn = 'USD') {
 const cbr = cbrRate(charCode, charCodeIn);
 if(cbr){
   return cbr[1];
 }
 const ton = tonapiRate(charCode, charCodeIn);
 if(ton){
   return ton[1];
 }
 return null;
}

И сделал удобный вывод в таблице, чтобы добавить вызов функции в таблицу нужно просто написать в ячейке:

=exchangeRate(TON, USD)

Я применил условное форматирование, если курс растет, то разницу показываю на зеленом фоне, если падает, то на красном:

Изменение в

USD

0,00%

0,44%

-1,98%

-4,79%

RUB

-0,37%

0,07%

-2,25%

-5,16%

EUR

-0,44%

0,00%

-1,81%

-5,06%

Изменение 24h актива в

USD

0

0,1050231774

-0,525738114

-1,27448488

RUB

-9,96545863

1,56532535

-54,23829044

-124,7693123

EUR

-0,1205215423

0

-0,4417693176

-1,238740441

Чтобы поддерживать веса в актуальном состоянии, я их записал, а под ними рассчитал текущее распределение активов:

Вес в корзине

27,5

22,5

25

25

Текущее распределение

28,01%

22,35%

24,79%

24,85%

И общее количество

в

все активы

изменение 24h

USD

107,0889995

-1,695199817

RUB

9732,069215

-187,407736

EUR

98,46935066

-1,801031301

Нотификация через Email

Можно легко подключить сервис Gmail для добавления различных нотификаций, например, по условию, что побит очередной рекорд, вот пример кода:

if(sumInBaseCurrency > max){
   GmailApp.sendEmail('mynameissergey@gmail.com', 'Congratulations', `Your balance has reached €${sumInBaseCurrency.toFixed(2)}\n for €${(sumInBaseCurrency - max).toFixed(2)} more`);
 }

Скрипт можно вызывать по триггеру, например, раз в час или реже, зависит от того, как часто вы просматриваете почту.

Попробуйте сами

Чтобы воспользоваться моей наработкой и посмотреть как все работает,

  • откройте ссылку

  • cкопируйте себе в пространство, заполняйте свои веса и количество

Чтобы добавить новую валюту достаточно добавить в заголовок ее код: рубли — RUB, юани — CNY, биткоин  -— BTC, Solana — SOL и т. д.

Итоги и то, как можно развить инструмент дальше

В статье поделился своим кейсом, как можно быстро накидать скрипт, который помогает мониторить актуальное состояние корзины с фиатными активами и криптовалютой. Вы можете кастомизировать его под себя: менять валюты, добавлять новые API, форматы нотификаций и. т. д.

Что дальше? Функции можно вызывать не только из таблицы, но и оформить их как GET/POST API. Есть идея подключить к этой таблице контроллер с маленьким экраном, вроде T-Display-S3, повесить его на холодильник и каждый завтрак, обед и ужин следить на сколько близко я подошел к своей мечте. А также можно мониторить курсы основных активов, но об этом в следующей статье — нужно покопаться в знаниях и вспомнить языки C и С++.

Можно изменять таблицы, обращаться к отдельным листам, вызывать функции по триггеру. Можно хранить исторические данные о курсах, отслеживать сколько, когда и с помощью какого инструмента был пополнен актив. Но это уже другая история!

Теги:
Хабы:
Всего голосов 11: ↑11 и ↓0+11
Комментарии0

Публикации

Информация

Сайт
m2.ru
Дата регистрации
Дата основания
Численность
501–1 000 человек
Местоположение
Россия
Представитель
Макс Дмитров