Управление прибылью и убытками
В S# расчёт прибылей и убытков (PnL) реализован через менеджер PnLManager. Менеджер обрабатывает поток сообщений (сделки, рыночные данные) и вычисляет реализованную и нереализованную прибыль.
Интерфейс IPnLManager
Интерфейс IPnLManager определяет базовый контракт:
- RealizedPnL — реализованная прибыль/убыток (decimal). Формируется при закрытии позиций.
- UnrealizedPnL — нереализованная прибыль/убыток (decimal). Пересчитывается по текущим рыночным ценам.
- Reset() — сброс состояния менеджера.
- UpdateSecurity(Level1ChangeMessage) — обновление параметров инструмента (шаг цены, стоимость шага, мультипликатор лота).
- ProcessMessage(Message, ICollection<PortfolioPnLManager>) — обработка сообщения; возвращает PnLInfo при закрытии позиции, иначе
null.
Архитектура
Система PnL имеет трёхуровневую иерархию:
PnLManager
└── PortfolioPnLManager (по имени портфеля)
└── PnLQueue (по SecurityId)
- PnLManager — верхний уровень, управляет словарём портфельных менеджеров.
- PortfolioPnLManager — менеджер PnL для конкретного портфеля, управляет очередями по инструментам.
- PnLQueue — FIFO-очередь для сопоставления сделок по одному инструменту.
PnLQueue — очередь расчёта
PnLQueue отвечает за сопоставление открывающих и закрывающих сделок:
- PriceStep — шаг цены инструмента.
- StepPrice — стоимость шага цены (для фьючерсов).
- Leverage — кредитное плечо.
- LotMultiplier — множитель лота.
Мультипликатор прибыли вычисляется по формуле:
Multiplier = (StepPrice / PriceStep) * Leverage * LotMultiplier
Для обычных акций (где StepPrice не задан) мультипликатор равен 1 * Leverage * LotMultiplier.
PnLInfo — результат обработки сделки
Класс PnLInfo содержит результат закрытия позиции:
- ServerTime — время сделки.
- ClosedVolume — объём закрытой позиции.
- PnL — реализованная прибыль от данной сделки.
Например, если позиция была +2, а пришла сделка на -5 контрактов, то ClosedVolume = 2 (закрыты 2 контракта из позиции).
Настройка источников данных
PnLManager позволяет выбирать источники рыночных данных для расчёта нереализованной прибыли:
| Свойство | По умолчанию | Описание |
|---|---|---|
UseTick |
true |
Использовать тиковые сделки. |
UseOrderBook |
false |
Использовать стакан (лучший bid/ask). |
UseLevel1 |
false |
Использовать данные Level1. |
UseOrderLog |
false |
Использовать лог заявок. |
UseCandles |
true |
Использовать свечи (цена закрытия). |
Интеграция через адаптер
Класс PnLMessageAdapter оборачивает внутренний адаптер и автоматически обрабатывает все сообщения для расчёта PnL.
Интеграция со стратегией
Стратегия (Strategy) предоставляет:
- Свойство
PnLManager— экземпляр менеджера. - Свойство
PnL— суммарная прибыль (RealizedPnL + UnrealizedPnL). - Событие
PnLChanged— уведомление об изменении прибыли. - Событие
PnLReceived2— уведомление при получении новых данных о PnL.
Пример использования
var pnlManager = new PnLManager
{
UseTick = true,
UseOrderBook = true,
UseCandles = true
};
// Обработка сообщений
var info = pnlManager.ProcessMessage(executionMsg);
if (info != null)
{
Console.WriteLine($"Закрыто: {info.ClosedVolume}, PnL: {info.PnL}");
}
// Общая прибыль/убыток
var realizedPnL = pnlManager.RealizedPnL;
var unrealizedPnL = pnlManager.UnrealizedPnL;
var totalPnL = realizedPnL + unrealizedPnL;
Console.WriteLine($"Реализованный PnL: {realizedPnL}");
Console.WriteLine($"Нереализованный PnL: {unrealizedPnL}");
Console.WriteLine($"Итого PnL: {totalPnL}");
Сброс состояния
Метод Reset() очищает все портфельные менеджеры, очереди расчёта и обнуляет реализованный PnL:
pnlManager.Reset();