Информация о портфелях и заявках
При создании собственного адаптера для работы с биржей необходимо реализовать методы для запроса текущего состояния портфеля и заявок. Эти методы вызываются при получении сообщений PortfolioLookupMessage и OrderStatusMessage соответственно.
Запрос состояния портфеля
Для запроса состояния портфеля реализуется метод PortfolioLookupAsync. Этот метод обычно выполняет следующие действия:
- Отправляет подтверждение о получении запроса с помощью SendSubscriptionReply.
- Проверяет, является ли запрос подпиской или отпиской, используя свойство IsSubscribe.
- В случае подписки:
- Отправляет сообщение PortfolioMessage с информацией о портфеле.
- Запрашивает текущие балансы счетов у биржи.
- Для каждого счета создает и отправляет сообщение PositionChangeMessage с информацией о позиции.
- Отправляет сообщение о результате подписки с помощью 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. Этот метод обычно выполняет следующие действия:
- Отправляет подтверждение о получении запроса с помощью IMessageAdapter.SendSubscriptionReply.
- Проверяет, является ли запрос подпиской или отпиской, используя свойство OrderStatusMessage.IsSubscribe.
- В случае подписки:
- Запрашивает список текущих заявок у биржи.
- Для каждой заявки создает и отправляет сообщение ExecutionMessage с информацией о заявке.
- Если требуется, устанавливает подписку на получение обновлений по заявкам в реальном времени.
- Отправляет сообщение о результате подписки с помощью 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);
}