Для изменения размера нажмите или перетащите
Создание первого робота

Смысл робота-примера в следующем: программа находит бумагу Лукойл, запоминает первоначальное значение середины спреда равное (bid + ask) / 2. Далее, как только значение спреда отклонится на 0.1%, то выставляется заявка на покупку объемом 1 и ценой текущего спреда. Далее, если произойдет сделка по выставленной заявке, то программа выведет информацию по этой сделке.

Внимание Внимание

Библиотека TRANS2QUIK.dll программы Quik имеет ограничение в разрядности - написана под 32-х разрядные платформы. Поэтому, при компилировании программы необходимо явно указывать разрядность:

Компиляция приложений.

Это позволит запускать торговых роботов под Quik на 64-х разрядных операционных системах.

Примечание Примечание

Исходные коды примера лежат в дистрибутиве в папке Samples\Quik\DDE\SampleConsole.

Необходимые действия:

  1. В самом начале необходимо создать шлюз к торговой системе Quik, используя класс QuikTrader:

    C#
    // создаем шлюз к Quik-у
    var trader = new QuikTrader(@"Ваш путь к Квик директории") { IsDde = true } ;
  2. Затем создадим список таблиц, данные которых будут экспортироваться по DDE.

    C#
    trader.DdeTables = new[] { trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable, trader.EquityPortfoliosTable, trader.OrdersTable };
  3. После создания шлюза необходимо подключиться к торговой системе, используя метод IConnectorConnect. Данный метод асинхронный, то есть результат его выполнения не гарантирует мгновенное установление соединения. Для точного определения, что соединение было установлено, необходимо использовать событие IConnectorConnected:

    C#
    // подписываемся на событие успешного подключения
    // все действия необходимо производить только после подключения
    trader.Connected += () =>
    {
        Console.WriteLine("Подключение было произведено успешно.");
    
        // извещаем об успешном соединении
        waitHandle.Set();
    };
    
    Console.WriteLine("Производим подключение...");
    
    trader.Connect();
    
    // дожидаемся события об успешном соединении
    waitHandle.WaitOne();
  4. Далее, необходимо подписаться на события появления информации по инструментам (так программа получит сведения по бумаге Лукойл), и портфелям (для выставления заявок). А также на событие появления Моих Сделок (сигнал пользователю о том, что произошла сделка по его заявке):

    C#
    trader.NewPortfolios += portfolios =>
    {
        if (_portfolio == null)
        {
            // находим нужный портфель и присваиваем его переменной _portfolio
            _portfolio = portfolios.FirstOrDefault(p => p.Name == account);
    
            if (_portfolio != null)
            {
                Console.WriteLine("Портфель {0} появился.", account);
    
                // если инструмент и стакан уже появились,
                // то извещаем об этом основной поток для выставления заявки
                if (_lkoh != null && _depth != null)
                    waitHandle.Set();
            }
        }
    };
    
    // подписываемся на событие появление инструментов
    trader.NewSecurities += securities =>
    {
        if (_lkoh == null)
        {
            // находим Лукойл и присваиваем ее переменной lkoh
            _lkoh = securities.FirstOrDefault(sec => sec.Code == secCode);
    
            if (_lkoh != null)
            {
                Console.WriteLine("Инструмент Лукойл появился.");
    
                // запускаем экспорт стакана
                trader.RegisterMarketDepth(_lkoh);
    
                if (_portfolio != null)
                    waitHandle.Set();
            }
        }
    };
    
    // подписываемся на событие появления моих новых сделок
    trader.NewMyTrades += myTrades =>
    {
        foreach (var myTrade in myTrades)
        {
            var trade = myTrade.Trade;
            Console.WriteLine("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
        }
    };
    
    // подписываемся на событие обновления стакана
    trader.MarketDepthsChanged += depths =>
    {
        if (_depth == null && _lkoh != null)
        {
            _depth = depths.FirstOrDefault(d => d.Security == _lkoh);
    
            if (_depth != null)
            {
                Console.WriteLine("Стакан Лукойла появился.");
    
                // если портфель уже появился, то извещаем об этом основной поток для выставления заявки
                if (_portfolio != null)
                    waitHandle.Set();
            }
        }
    };

    В обработчике IConnectorNewSecurities запускается экспорт стакана для того, чтобы начали обновляться такие поля как SecurityBestBid, SecurityBestAsk и SecurityBestPair. Подробнее, в разделе Экспорт стакана.

    Внимание Внимание

    Номер счета, который в примере записан в переменную account, это не логин в Quik, а код клиента. Об особенности портфелей в Quik читайте в соответствующем разделе.

    Когда данные начнут приходить в QuikTrader, то будут вызываться события IConnectorNewSecurities, IConnectorNewOrders и т.д. Для тех данных, которые изменяются, вызывается другое событие. Например, для заявок, у которых изменяются значения Состояние, Остаток и т.д. будет вызвано событие IConnectorOrdersChanged.

    Независимо от того, созданы ли данные программно, например, заявки, или же пользователь сам вручную зарегистрировал заявку, для новых данных в таблице Заявки будет вызвано событие IConnectorNewOrders. Это очень удобно в случае, когда пользователь отменяет выставленную заявку, и программа продолжает работать с актуальными данными.

  5. Торговый алгоритм робота:

    C#
    // 0.1% от изменения цены
    const decimal delta = 0.001m;
    
    // запоминаем первоначальное значение середины спреда
    var firstMid = lkoh.BestPair.SpreadPrice / 2;
    if (_lkoh.BestBid == null)
        throw new Exception("Нет лучшего бида для котировки.");
    
    Console.WriteLine("Первоначальное значение середины спреда {0:0.##}", _lkoh.BestBid.Price + firstMid);
    
    while (true)
    {
        var mid = _lkoh.BestPair.SpreadPrice / 2;
    
        // если спред вышел за пределы нашего диапазона
        if    (
                ((firstMid + firstMid * delta) <= mid) ||
                ((firstMid - firstMid * delta) >= mid)
            )
        {
            var order = new Order
            {
                Portfolio = _portfolio,
                Price = _lkoh.ShrinkPrice(lkoh.BestBid + mid),
                Security = _lkoh,
                Volume = 1,
                Direction = OrderDirections.Buy,
            };
            trader.RegisterOrder(order);
            Console.WriteLine("Заявка {0} зарегистрирована", order.Id);
            break;
        }
        else
            Console.WriteLine("Текущее значение середины спреда {0:0.##}", _lkoh.BestBid.Price + mid);
    
        // ждем 1 секунду
        Thread.Sleep(1000);
    }
  6. Завершение работы алгоритма:

    C#
    // останавливаем подключение
    trader.Disconnect();;
Следующие шаги