Блог им. WinterMute

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

    • 01 сентября 2017, 11:36
    • |
    • k100
  • Еще

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

     Итак, чтобы проект не зависел от 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.
     С днём знаний, друзья! ;-)

178 | ★5

Читайте на SMART-LAB:
Фото
Не оливье единым: итоги 2025 года и новая иерархия на рынке готовых салатов
Российский рынок готовых салатов в 2025 году продемонстрировал смену лидера: традиционный фаворит «Оливье» уступил первое место «Сельди под...
Фото
🧠 Ресейл и поколение Z: почему молодёжь выбирает разумное потребление
📱 Поколение Z относится к потреблению прагматичнее, чем остальные. Для них важны не громкие слова и статус, а понятная ценность покупки —...
5 идей в российских акциях. Индекс МосБиржи снова на грани 2700
Индекс МосБиржи опять торгуется на грани значимого уровня 2700 п. Сейчас не исключен очередной отскок от указанного уровня. Кроме того, рынок...
Фото
Хэдхантер. Ситуация на рынке труда в декабре идет ко дну - хуже не было никогда
Вышла статистика рынка труда за декабрь 2025 года, которую Хедхантер публикует ежемесячно, что же там интересного: Динамика...

теги блога k100

....все тэги



UPDONW
Новый дизайн