k100
k100 личный блог
01 сентября 2017, 11:36

Торговая система своими руками. Часть 2. Базовые компоненты.

     Приветствую! В предыдущем посте была теория, теперь к делу. Кое-что буду упрощать, чтобы представить картинку в целом.

     Итак, чтобы проект не зависел от API внешней com библиотеки (SmartCom или д.р.), чтобы в коде стратегий  не использовались специфические типы, разработку я начала с обёрток над смарткомом. Я определил три базовых интерфейса: IConnectGate, IMarketDataGate и IPortfolioGate. Соответственно для подключения, для получения маркет-даты и для выставления заявок и работы с портфелем. Причём каждый из этих трёх интерфейсов мне надо было реализовать минимум дважды – для смарткома и для локального тестера.

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

     В случае с локальным тестером, реализации – это по большей части mock объекты, заглушки. Например, реализация IConnectGate для смарткома, это вызов метода подключения  и подписка на результат этого вызова, а в случае с локальным тестером мы никуда физически не подключаемся, а сразу генерируем событие “ Ok! Мы подключились!”.

     Далее, я определил интерфейс IStrategy, всего лишь с одним методом – Start. Вообще, изначально планировал сделать несколько классов  – класс генерирующий сигналы, класс, отвечающий за риск менеджмент, класс, который ведёт и закрывает позицию… Но, подумав, решил не усложнять  – особых плюсов это не дало бы, а только запутало. Все стратегии, которые я бы не делал, все реализуют интерфейс IStrategy. В конструктор стратеги передаются необходимые настройки (торгуемый тиккер, размер допустимой просадки, коэффициенты), инициализируются переменные и происходит подписка на события получения маркет-даты. А метод Start просто запускает процедуру получения маркет-даты и стратегия начинает работать. Конечно, можно было бы определить ещё несколько методов, благодаря которым, мы бы как-то влияли на стратегию во время её работы, или получали от неё какие-то данные, но пока опустим эти детали.

     Если стратегий несколько, и они используют специфические настройки, лучше использовать фабрику для их создания. Фабрика стратегий по некоему ID стратегии возвращает конкретную её реализацию, тем самым мы делегируем фабрике функцию создания стратегий:

interface IStrategyFactory
    {
        IStrategy CreateStrategy(int strategyID);
    }

     Согласно шаблону MVP, один презентер отвечает за одно представление (форму), каждое представление должно иметь презентера. Я создал два класса – некий MainPresenter и MainView для него. При старте программы, после необходимых настроек, вызывается конструктор MainPresenter’а и далее открывается MainView. В последующих постах, я буду детальнее описывать и развивать эту часть. Хочу подчеркнуть – внешний вид не важен, информацию можно получать и из консоли. Учитывая всё вышесказанное можно описать MainPresenter’а в первоначальном виде:

class MainPresenter
    {
        private IMainView mainView;
        private IStrategyFactory strategyFactory;
        private IConnectGate connectGate;

        public MainPresenter(IMainView mainView, IStrategyFactory strategyFactory, IConnectGate connectGate)
        {
            this.mainView = mainView;
            this.strategyFactory = strategyFactory;
            this.connectGate = connectGate;<br />
            this.connectGate.Connected += () =>
              this.strategyFactory.CreateStrategy(1).Start();

            this.connectGate.Connect();
        }

        public IMainView View => mainView;
    }

     В теле конструктора MainPresenter’а происходит инициализация переменных, подписка на событие подключения и собственно подключение. Почём подписка на событие могла бы выглядеть так:

private void ConnectHandler()
    {
        ...
    }

    connectGate.Connected += ConnectHandler; 

     Но первый способ более лаконичен, и для небольших блоков более приемлем. Это т.н. лямбда выражения, или анонимные функции. Лямбды упрощают код, также лямбды используются в выражениях linq (это я покажу в дальнейшем).

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

 

     P.S.
     С днём знаний, друзья! ;-)

0 Комментариев

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн