Всякий раз, когда я захожу в Coinbase, меня встречает панель инструментов, показывающая последние цены на биткойн/эфириум.
Несмотря на то, что знание последней цены полезно, я часто задаю себе вопрос: «Каковы были бы мои прибыли/убытки, если бы я продал сейчас?». Например, цена BTC может составлять 600 евро, и это может быть на 10 % больше, чем в предыдущий день, но если я купил BTC месяц назад за 660 евро, то я мог бы подумать о том, чтобы не продавать из-за 10% портфеля потери, несмотря на то, что цена валюты недавно выросла.
У Coinbase есть всеобъемлющий API, поэтому я решил создать небольшую библиотеку для решения этого вопроса. Я думаю, что важно, чтобы продукты имели такие обширные API, потому что это дает мне возможность расширять продукт для удовлетворения моих потребностей, не спрашивая ни у кого разрешения. С криптовалютами, помимо этого API уровня приложения, мы также получаем API уровня данных (то есть программируемые деньги), который позволяет использовать более сложные варианты использования настройки, чем тот, который я исследую здесь.
Я хотел поделиться парой вещей, которые я узнал/наблюдал при реализации этой библиотеки.
Бухгалтерский учет ФИФО
Формула для расчета процентного изменения выглядит так: (текущая стоимость портфеля — стоимость портфеля) / стоимость портфеля. Сложность расчета стоимости портфеля заключается в том, что я могу держать монеты, которые были куплены по разным ценам, и что за это время я могу продать пару монет.
Одним из методов расчета стоимости портфеля с учетом этих ограничений является использование учета ФИФО. В этом сценарии учет FIFO работает, предполагая, что первые купленные монеты являются первыми проданными, а монеты, купленные позже, покупаются позже.
Пример:
Транзакции:
День 1: Купить 5 BTC за 600 €
День 2: Купить 8 BTC за 660 €
День 3: Продать 3 BTC за 700 €
Инвентарь портфеля на 4-й день:
2 BTC куплены за 600 € (раньше у нас было 5, но 3 были проданы на 3-й день)
8 BTC куплены за 660 €
Стоимость портфеля в 4-й день:
2x600€ + 8x660€ = 6480€
Неизменная структура
Чаще всего я использую immutable-struct для создания объектов-значений.
В этой библиотеке я также использовал ее, когда все еще обнаруживал соавторов объектов данного метода. Иногда вместо использования заглушки RSpec я просто создаю тип с помощью immutable-struct, а затем обновляю его до класса, когда начинаю добавлять больше поведения к этому типу.
Фактически это то, что произошло в этом коммите, я сначала создал Transaction
как ImmutableStruct
, чтобы я мог протестировать AssetConverter
, но при реализации AssetConverter#convert
я заметил, что было бы полезно, если бы Transaction
имел метод price
, поэтому он был обновлен до нормального класса. .
Выяснение вещей по пути
Когда я начал работать над этим, у меня было общее представление о том, что у меня будут транзакции, и объект «ликвидации», который будет реализовывать порядок учета FIFO и рассчитывать прибыли/убытки.
Когда я начал добавлять тестовые примеры в Liquidation
, я заметил, что его тесты усложняются, потому что я тестировал совершенно разные вещи, поэтому я начал выделять это несвязанное поведение для отдельных объектов. Например, ликвидация стала классом, который работал с обработанным инвентарем монет, а не классом, который работал с монетными транзакциями.
Потенциально я мог бы подумать обо всех этих проблемах заранее и придумать окончательный дизайн. Я считаю, что проще и продуктивнее иметь общее представление об основном поведении, которое мне нужно, а затем развивать дизайн по мере того, как я лучше понимаю проблему, и это обычно происходит, когда я добавляю тестовые примеры через TDD.
Именование
Именование всегда сложно. Большая часть используемых терминов пришла из чтения документации API, чтения о нескольких методах учета и чтения о нескольких способах расчета доходности портфеля акций — так что знакомство с предметной областью. Словарь и его раздел тезауруса также всегда пригодятся.
Хотя мне очень нравится правильно формулировать термины, на начальном этапе моей главной целью является создание правильных тестов и поведения, потому что после того, как у меня будут хорошие тесты, изменить имена будет легко. Также легче заметить несоответствия после того, как я получу четкую общую картину.
Вероятно, поэтому у меня есть пара коммитов, переименовывающих кучу вещей в конце. Если история коммитов окажется запутанной, ее всегда можно переписать.
Частный attr_reader
У меня есть привычка использовать private attr_reader
, поэтому я могу получить доступ к переменным экземпляра, используя метод вместо префикса @
(т.е. @transaction
против transaction
). Я, вероятно, обнаружил это в книге или скринкасте (но не могу вспомнить, в каком именно).
Я, вероятно, предпочитаю рассматривать все как методы из-за подсветки синтаксиса или меньшего количества символов для ввода, но у меня нет четкого мнения по этому вопросу.
Заключительные мысли
Со временем, когда мы набираемся опыта в конкретном предмете, у нас начинает развиваться склонность к определенным процессам и инструментам. Я хотел поделиться некоторыми своими тенденциями в программировании, рассмотрев конкретный пример. Обычно это вещи, которые я считаю само собой разумеющимися, и на самом деле это «простые вещи», но они различаются от человека к человеку, поэтому я подумал, что было бы интересно поделиться ими.
Первоначально опубликовано на сайте blog.marionzualo.com 30 октября 2016 г.