Рубль падает, нефть дешевеет. Стало уже входить в привычку заглядывать и любоваться графиками на Яндексе: RUR/USD и USD/BAR. Естественно, в какой-то момент стало интересно в какой пропорции это происходит — что быстрее дешевеет? Простая операция умножения, и вуаля — стоимость BAR/RUB. В целом, получается, что вроде как баррель в рублях стоит на месте.
И тут мне, конечно, захотелось посмотреть долгосрочную статистику. Яндекс в явном виде по api не предоставляет эти данные, но для своих графиков он отдает нехитрые xml. Поэтому — Sinatra, Bootstrap, Chart.js и Heroku.
Самое показательное — колебания около 3600 рублей за последние безумные 3 месяца. Резкие всплески — отставание курса рубля от изменений стоимости нефти. Просто здесь резвятся спекулянты)
На большем промежутке видно, что текущая цена на нефть в рублях держится с 2011 года.
Также интересно, что во времена кризиса 2008 рубль не был столь жестко привязан к стоимости нефти, как сейчас. С другой стороны, принцип был тот же — сначала меняется цена на нефть, а потом, с задержкой догоняет рубль.
Такая вот нехитрая аналитика.
Само приложение: http://rubbar.herokuapp.com/.
P.S. Так что, поздравляю, товарищи, этот баян сегодня как никогда актуален:
Просто ловлю себя на том, что пересчитываю сколько бочек нефти оставил в гипермаркете, и представляю монетки с канистрами и купюры в один, пол и четверть барреля — раз уж мы так к ним привязаны.
UPD:
И тут мне, конечно, захотелось посмотреть долгосрочную статистику. Яндекс в явном виде по api не предоставляет эти данные, но для своих графиков он отдает нехитрые xml. Поэтому — Sinatra, Bootstrap, Chart.js и Heroku.
Самое показательное — колебания около 3600 рублей за последние безумные 3 месяца. Резкие всплески — отставание курса рубля от изменений стоимости нефти. Просто здесь резвятся спекулянты)
На большем промежутке видно, что текущая цена на нефть в рублях держится с 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 резидентно в памяти, и значит статические атрибуты класса сохраняются между запросами. Весь код контроллера получился таким:
Сначала были мысли запрашивать данные за определенные временные промежутки, но учитывая размер получившегося json < 100KB решил, что можно всегда отдавать все целиком — кроме того, так можно менять диапазоны без перезагрузки страницы.
Остался сам интерфейс. Для сборки взял bower, вытянул bootstrap, jquery, fontawesome и chartjs (потом переключил, правда jquery и fontawesome на CDN, и сам fontawesome пригодился только для значка github в подвале).
Особой магией пришлось заниматься только с chartjs. Chartjs весьма удобен:
То, что есть в приложении, это почти что конфигурация из коробки, кроме одной неприятности: если выполнить вышеуказанный код заново (а это нужно для переключения между периодами), то графики накладывались друг на друга. Проблема была успешно костылирована такой строчкой перед перерисовкой:
Еще одна мелочь: на экран хорошо влезают данные за месяц, т.е. 30 точек. Несколько тысяч же — тормозят и выглядят плохо. Поэтому пропускаем отсчеты чтобы точек было от 30 до 59:
И последнее — деплой на Heroku, про который есть приличное количество статей на Хабре.
Для продакшена лучше избавится от стандартного WEBrick и использовать шуструю многопоточную Puma. Хоть Heroku и рекомендует Unicorn, но на бесплатном аккаунте, да еще и с запросами на сторонние сервисы Puma должна чувствовать себя гораздо комфортнее. Для этого достаточно добавить gem 'puma' в Gemfile. Еще для порядка добавлен Procfile, хотя и без него Heroku все запускает.
Для самого деплоя — регистрируем аккаунт, ставим их консольную утилиту, логинимся через нее, коммитим проект в гит, git push heroku.
Занавес.
Код на Гитхаб
Сначала нужно было отловить как приходят данные с Яндекса. Оказались две 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.
Занавес.
Код на Гитхаб
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какая будет динамика в ближайшие пол года?
4.89% Курсы заморозятся на текущем уровне114
61.65% Нефть и рубль продолжат падение1437
10.77% Нефть и рубль начнут расти251
19.48% Нефть вырастет, рубль останется или упадет454
3.22% Рубль вырастет, нефть останется или упадет75
Проголосовал 2331 пользователь. Воздержались 782 пользователя.