Блог им. WinterMute
Приветствую. В предыдущем посте описывался интерфейс для генерации тиковых данных – ITickGenerator. Его реализации могут быть разными: данные могут генерироваться на лету, или браться из БД. В случае с БД, возникает необходимость в организации ещё одного слоя приложения – слоя доступа к данным. TickGenerator, всё также будет оповещать подписчиков (стратегии, которые выставляют заявки), но по тем данным, которые он получит из БД.
Сейчас не важно, какая будет база данных, и где она будут храниться – на сервере, в файлах или в оперативной памяти. Не важно, также, какие специфические библиотеки и драйвера буду для этого использоваться. Сейчас, я просто приведу пример того, как можно разделить бизнес-логику приложения и слой доступа к данным.
Я создал отдельный модуль, и там и развернул всю архитектуру, связанную с БД, основные компоненты которой: сущности, репозитории и дата-сервис.
Хотя понятие сущности (Entity), само по себе, достаточно общее, здесь, буду применять его в узком смысле – это классы, представляющие таблицы БД, возможно, с какой-то дополнительной логикой. В простейшем случае, одна сущность – одна таблица. Между сущностями может быть связь (например, один ко многим), которая отражается и в связи между таблицами. Сущность описывается полями класса, которые отражают колонки таблиц.
Репозитории, это один из паттернов проектирования, это концепция манипулирования коллекциями сущностей одного типа: добавление, изменение, выборка по каким-то критериям. У каждой сущности должен быть свой репозиторий. Например, задачей репозитория заявок, может быть добавление новой заявки в коллекцию всех заявок и выборка всех совершённых заявок за какой-то период дат.
И последнее, что необходимо – это класс дата-сервис. По сути, он аккумулирует все репозитории внутри себя. Впоследствии, на него может лечь управление транзакциями и правами доступа к данным. В остальных частях проекта используется именно дата-сервис. Хотелось бы отметить также, что, дата-сервис отвечает и за маппинг. Это значит, что он конвертирует коллекции сущностей, полученные от репозиториев, в так называемые DTO (data transfer object). DTO – это классы-копии сущностей по части полей, но без логики и прочих аспектов. Т.е. DTO это облегченная версия сущности, и именно коллекции DTO должны циркулировать между различными слоями приложения, а не сущности. Для маппинга можно использовать готовые библиотеки, например – Automapper.
Для проведения бэк-тестов и сохранения результатов, в простейшем случае, нужно всего лишь три таблицы: таблица, откуда будут браться тиковые данные, и таблицы для сохранения заявок и сделок.
Таблица заявок (ORDERS) хранит информацию о портфеле, о стратегии, которая выставила эту заявку, цену, объём и прочие данные. Таблица сделок (TRADES) хранит ссылку на заявку, и свои цену/объём – ведь на одну заявку может быть несколько сделок и все по разной цене. В таблицу тиков (TICKS) импортируются тиковые данные.
Теперь, можно представить реализацию ITickGenerator работающую с дата-сервисом:
class TickGenerator : ITickGenerator { public event EventHandler<StockTickEventArgs> OnTick; public event Action OnEnd; private IDataService dataService; public TickGenerator(IDataService dataService) { this.dataService = dataService; } public void Start(string symbol) { var ticks = dataService.Ticks(symbol); foreach (var t in ticks) OnTick?.Invoke(this, new StockTickEventArgs() { Symbol = t.Symbol, Id = t.Id, DateTieme = t.DateTime, Price = t.Price, Vol = t.Vol }); OnEnd?.Invoke(); } }
TickGenerator, ничего не знает о способе хранения данных и организации доступа к ним. Задача TickGenerator’а – на каждый тик оповестить подписчиков (вызвать событие onTick) и в конце просигнализировать о завершении прогона (вызвать событие onEnd). Дата-сервис (IDataService), используется в качестве поставщика данных, и является связующим звеном между бизнес-логикой приложения и слоем доступа к данным.
Для проведения бэк-тестов, я качаю данные (например, с Финама), заливаю их в таблицу TICKS и гоняю тесты. В качестве СУБД я использую ORACLE, есть бесплатные версии – XE. В ORACLE много интересных фишек – например, аналитические функции (о них расскажу позже). Также, можно использовать и PostgreSQL или даже встраиваемые NoSql СУБД, не требующие установки (это удобно для демонстрационных примеров). Что за СУБД не важно, если нет специфических требований по скорости (не важны миллисекунды), то сойдёт любая. БД – это просто способ хранения данных, ещё один аспект реализации. В следующем посте я расскажу про внутреннюю реализацию репозиториев и про способ связи с самой базой данных.
Но вы в целом с какой целью интерисуетесь? не тратьте время