Pull to refresh

Нефтерубль

Reading time 4 min
Views 41K
Рубль падает, нефть дешевеет. Стало уже входить в привычку заглядывать и любоваться графиками на Яндексе: RUR/USD и USD/BAR. Естественно, в какой-то момент стало интересно в какой пропорции это происходит — что быстрее дешевеет? Простая операция умножения, и вуаля — стоимость BAR/RUB. В целом, получается, что вроде как баррель в рублях стоит на месте.

И тут мне, конечно, захотелось посмотреть долгосрочную статистику. Яндекс в явном виде по api не предоставляет эти данные, но для своих графиков он отдает нехитрые xml. Поэтому — Sinatra, Bootstrap, Chart.js и Heroku.

image

Самое показательное — колебания около 3600 рублей за последние безумные 3 месяца. Резкие всплески — отставание курса рубля от изменений стоимости нефти. Просто здесь резвятся спекулянты)

image
На большем промежутке видно, что текущая цена на нефть в рублях держится с 2011 года.

Также интересно, что во времена кризиса 2008 рубль не был столь жестко привязан к стоимости нефти, как сейчас. С другой стороны, принцип был тот же — сначала меняется цена на нефть, а потом, с задержкой догоняет рубль.

Такая вот нехитрая аналитика.

Само приложение: http://rubbar.herokuapp.com/.

P.S. Так что, поздравляю, товарищи, этот баян сегодня как никогда актуален:

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

UPD:

Немного про то, как приложение писалось и как устроено внутри.
Все достаточно просто, но раз есть интерес — дополняю статью.

Сначала нужно было отловить как приходят данные с Яндекса. Оказались две XML-ки: graph_1.xml и graph_1006.xml. Это все данные, которые будут использоваться.

Поскольку сам занимаюсь разработкой на Ruby, взял за основу легкий фреймворк Sinatra, подключил шаблонизатор Slim для единственной вьюхи. Экшена два — один рендерит шаблон (привязан к корню сайта), а второй — возвращает json с данными для графика. Для генерации json взял гем oj, а для парсинга xml — ox.

В исходных данных, конечно же, оказались разные таймстампы (курс рубль/доллар и доллар/баррель обновляются не синхронно), поэтому берется ближайшее обновление курса рубля до рассматриваемого обновления барреля.

Получилось, что запрос json-ки занимает заметное глазу время — в первую очередь из-за двух запросов к Яндексу. Поэтому результат захотелось закешировать. Тем более, что данные от Яндекса будут обновляться два раза за сутки. Изучив возможности Heroku на бесплатном аккаунте, обрадовался куче облачных вариантов Redis и Memcache от 5 до 25 Мб, что намного больше требуемого объема. Но, оказалось что предоставляются они только после ввода данных по кредитке, что несколько настораживает — есть подозрение, что деньги будут списываться, если превысить бесплатный объем. А хотелось залить — и не думать. Посему был запилен класс, с гордым названием StupidCache. Смысл в том, что приложение на Sinatra резидентно в памяти, и значит статические атрибуты класса сохраняются между запросами. Весь код контроллера получился таким:

get '/chart/rub_bar.json' do
  result_json = StupidCache.fetch :rub_bar do
    # этот код выполняется и кешируется, только если кеш пуст
    Oj.dump ChartModel.get_rub_bar, mode: :compat
  end

  content_type 'application/json'
  result_json
end


Сначала были мысли запрашивать данные за определенные временные промежутки, но учитывая размер получившегося json < 100KB решил, что можно всегда отдавать все целиком — кроме того, так можно менять диапазоны без перезагрузки страницы.

Остался сам интерфейс. Для сборки взял bower, вытянул bootstrap, jquery, fontawesome и chartjs (потом переключил, правда jquery и fontawesome на CDN, и сам fontawesome пригодился только для значка github в подвале).

Особой магией пришлось заниматься только с chartjs. Chartjs весьма удобен:

var data = {
    labels: labels, //массив, полученный ajax
    datasets: [
        {
            /* здесь пропущена конфигурация цветовой схемы кривой */
            data: values //массив, полученный ajax
        }
    ]
};
var ctx = $("#oil_chart").get(0).getContext("2d"); // #oil_chart - это элемент canvas
new Chart(ctx).Line(data, { /* здесь пропущена конфигурация графика */ });


То, что есть в приложении, это почти что конфигурация из коробки, кроме одной неприятности: если выполнить вышеуказанный код заново (а это нужно для переключения между периодами), то графики накладывались друг на друга. Проблема была успешно костылирована такой строчкой перед перерисовкой:

$("#oil_chart").replaceWith('<canvas id="oil_chart" height="400"></canvas>');


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

var skip = Math.floor(values_all.length/30);
skip = skip < 1 ? 1 : skip;
var values = [];
for (var i = 0; i < values_all.length; i = i + skip) {
    values.push(values_all[i]);
}


И последнее — деплой на Heroku, про который есть приличное количество статей на Хабре.

Для продакшена лучше избавится от стандартного WEBrick и использовать шуструю многопоточную Puma. Хоть Heroku и рекомендует Unicorn, но на бесплатном аккаунте, да еще и с запросами на сторонние сервисы Puma должна чувствовать себя гораздо комфортнее. Для этого достаточно добавить gem 'puma' в Gemfile. Еще для порядка добавлен Procfile, хотя и без него Heroku все запускает.

Для самого деплоя — регистрируем аккаунт, ставим их консольную утилиту, логинимся через нее, коммитим проект в гит, git push heroku.

Занавес.

Код на Гитхаб
Only registered users can participate in poll. Log in, please.
Какая будет динамика в ближайшие пол года?
4.89% Курсы заморозятся на текущем уровне 114
61.65% Нефть и рубль продолжат падение 1437
10.77% Нефть и рубль начнут расти 251
19.48% Нефть вырастет, рубль останется или упадет 454
3.22% Рубль вырастет, нефть останется или упадет 75
2331 users voted. 782 users abstained.
Tags:
Hubs:
+64
Comments 147
Comments Comments 147

Articles