Table of Contents

Информация о портфелях и заявках

При создании собственного адаптера для работы с биржей необходимо реализовать методы для запроса текущего состояния портфеля и заявок. Эти методы вызываются при получении сообщений PortfolioLookupMessage и OrderStatusMessage соответственно.

Запрос состояния портфеля

Для запроса состояния портфеля реализуется метод PortfolioLookupAsync. Этот метод обычно выполняет следующие действия:

  1. Отправляет подтверждение о получении запроса с помощью SendSubscriptionReply.
  2. Проверяет, является ли запрос подпиской или отпиской, используя свойство IsSubscribe.
  3. В случае подписки:
  • Отправляет сообщение PortfolioMessage с информацией о портфеле.
  • Запрашивает текущие балансы счетов у биржи.
  • Для каждого счета создает и отправляет сообщение PositionChangeMessage с информацией о позиции.
  1. Отправляет сообщение о результате подписки с помощью SendSubscriptionResult.
public override async ValueTask PortfolioLookupAsync(PortfolioLookupMessage lookupMsg, CancellationToken cancellationToken)
{
    var transId = lookupMsg.TransactionId;

    // Отправляем подтверждение о получении запроса
    SendSubscriptionReply(transId);

    if (!lookupMsg.IsSubscribe)
        return;

    // Отправляем сообщение с информацией о портфеле
    SendOutMessage(new PortfolioMessage
    {
        PortfolioName = PortfolioName,
        BoardCode = BoardCodes.Coinbase,
        OriginalTransactionId = transId,
    });

    // Запрашиваем текущие балансы счетов
    var accounts = await _restClient.GetAccounts(cancellationToken);

    foreach (var account in accounts)
    {
        // Для каждого счета создаем и отправляем сообщение с информацией о позиции
        SendOutMessage(new PositionChangeMessage
        {
            PortfolioName = PortfolioName,
            SecurityId = new SecurityId
            {
                SecurityCode = account.Currency,
                BoardCode = BoardCodes.Coinbase,
            },
            ServerTime = CurrentTime.ConvertToUtc(),
        }
        .TryAdd(PositionChangeTypes.CurrentValue, (decimal)account.Available, true)
        .TryAdd(PositionChangeTypes.BlockedValue, (decimal)account.Hold, true));
    }

    // Отправляем сообщение об успешном завершении подписки
    SendSubscriptionResult(lookupMsg);
}

Запрос состояния заявок

Для запроса состояния заявок реализуется метод OrderStatusAsync. Этот метод обычно выполняет следующие действия:

  1. Отправляет подтверждение о получении запроса с помощью IMessageAdapter.SendSubscriptionReply.
  2. Проверяет, является ли запрос подпиской или отпиской, используя свойство OrderStatusMessage.IsSubscribe.
  3. В случае подписки:
  • Запрашивает список текущих заявок у биржи.
  • Для каждой заявки создает и отправляет сообщение ExecutionMessage с информацией о заявке.
  • Если требуется, устанавливает подписку на получение обновлений по заявкам в реальном времени.
  1. Отправляет сообщение о результате подписки с помощью IMessageAdapter.SendSubscriptionResult.
public override async ValueTask OrderStatusAsync(OrderStatusMessage statusMsg, CancellationToken cancellationToken)
{
    // Отправляем подтверждение о получении запроса
    SendSubscriptionReply(statusMsg.TransactionId);

    if (!statusMsg.IsSubscribe)
        return;

    // Запрашиваем список текущих заявок
    var orders = await _restClient.GetOrders(cancellationToken);

    foreach (var order in orders)
        ProcessOrder(order, statusMsg.TransactionId);

    if (!statusMsg.IsHistoryOnly())
    {
        // Устанавливаем подписку на получение обновлений по заявкам в реальном времени
        await _socketClient.SubscribeOrders(cancellationToken);
    }

    // Отправляем сообщение об успешном завершении подписки
    SendSubscriptionResult(statusMsg);
}

private void ProcessOrder(Order order, long originTransId)
{
    if (!long.TryParse(order.ClientOrderId, out var transId))
        return;

    var state = order.Status.ToOrderState();

    // Создаем и отправляем сообщение с информацией о заявке
    SendOutMessage(new ExecutionMessage
    {
        ServerTime = originTransId == 0 ? CurrentTime.ConvertToUtc() : order.CreationTime,
        DataTypeEx = DataType.Transactions,
        SecurityId = order.Product.ToStockSharp(),
        TransactionId = originTransId == 0 ? 0 : transId,
        OriginalTransactionId = originTransId,
        OrderState = state,
        Error = state == OrderStates.Failed ? new InvalidOperationException() : null,
        OrderType = order.Type.ToOrderType(),
        Side = order.Side.ToSide(),
        OrderStringId = order.Id,
        OrderPrice = order.Price?.ToDecimal() ?? 0,
        OrderVolume = order.Size?.ToDecimal(),
        TimeInForce = order.TimeInForce.ToTimeInForce(),
        Balance = (decimal?)order.LeavesQuantity,
        HasOrderInfo = true,
    });
}

Обработка обновлений в реальном времени

Для обработки обновлений состояния заявок в реальном времени обычно реализуется отдельный метод, который вызывается при получении соответствующих событий от WebSocket клиента:

private void SessionOnOrderReceived(Order order)
{
    // Обрабатываем полученное обновление по заявке
    // OriginTransId = 0, так как это обновление в реальном времени, а не ответ на конкретный запрос
    ProcessOrder(order, 0);
}