9. Торговля
В этой главе рассматривается покупка и продажа товаров, а также стоимость этих товаров в зависимости от меняющихся рыночных условий. Используя опыт создания торговой системы для банка, в главе рассматривается покупка и продажа с двух точек зрения, когда банк покупает и продает одни и те же товары. Банк должен понимать ценность чистого эффекта от этих сделок в различных обстоятельствах.
Каждая сделка описывается контрактом (9.1). Контракт может либо покупать, либо продавать товары, и это полезно для предприятий, которым необходимо отслеживать оба направления сделок. Мы можем посмотреть на чистый эффект от нескольких контрактов, используя портфель (9.2). Мы создаем портфели, чтобы их можно было легко собирать, выбирая контракты разными способами. Для определения критериев отбора мы предоставляем портфелю отдельный объект — фильтр портфеля. Он определяет интерфейс, который может быть реализован различными подтипами. Такая конструкция обеспечивает гибкость для простых и сложных критериев отбора. Это полезная техника для гибкого определения коллекций.
Чтобы понять стоимость контракта, нам нужно понять цену товара, которым торгуют. Цены на товары часто отличаются в зависимости от того, покупаются они или продаются. Такое двустороннее поведение цен можно отразить в котировке (9.3).
На нестабильных рынках цены могут быстро меняться. Трейдерам необходимо оценивать товары с учетом целого ряда возможных изменений. Сценарий (9.4) представляет собой совокупность условий, которые могут выступать в качестве единого состояния рынка для оценки. Сценарии могут быть сложными, и нам нужен способ определить их построение, чтобы мы могли последовательно использовать одну и ту же сценарную конструкцию в разное время. Сценарии полезны для любой области со сложными изменениями цен.
Эта глава основана на проекте по разработке системы торговли валютными деривативами для крупного банка.
- Ключевые понятия
Контракт, портфель, котировка, сценарий.
9.1 Контракт
Самый простой вид финансовой сделки — это покупка какого-либо инструмента у другой стороны. Этим инструментом могут быть акции, товар, валюта или любой другой широко распространенный предмет торговли. Базовой отправной точкой является модель, показанная на рис. 9.1. В этой модели есть контракт, который представляет собой сделку с другой стороной, называемой контрагентом, с некоторым количеством инструмента. На рисунке показан только один инструмент, хотя, строго говоря, все торговые операции включают два инструмента — один инструмент обменивается на другой. На большинстве рынков одним из инструментов всегда является валюта, преобладающая на рынке. Таким образом, цена представлена в виде денежного объекта. Деньги — это подтип количества (см. раздел 3.1), единицей измерения которого является валюта.

Сумма инструмента торгуется с контрагентом. Длинный (long) и короткий (short) — это термины для покупки и продажи, соответственно. Наличие одного контрагента ограничивает количество контрактов, которые могут быть представлены.
Рисунок 9.1. Простая модель контракта.
На валютных рынках инструментом является обменный курс. Это может показаться странным, но на самом деле все инструменты являются обменными курсами. Контракт на продажу акций на бирже Dow на самом деле является контрактом на обмен акций на доллары. В большинстве случаев проще представить это, сказав, что инструмент обменивается на валюту цены, но для обменных курсов лучше иметь обе валюты на инструменте, а цена пусть будет простым числом.
Термины long и short — это термины, которые трейдеры используют для обозначения покупки и продажи, соответственно. (Не только у компьютерщиков странный жаргон!) На рис. 9.1 показано различие между покупкой и продажей с помощью нотации субтипирования. В качестве альтернативы можно использовать булевский атрибут isLong
. Любой из этих способов приемлем, но я предпочитаю явность рисунка 9.1 при концептуальном моделировании. Подтипирование и булевский атрибут эквивалентны в концептуальном моделировании; подтипирование не подразумевает подклассификацию. При моделировании реализации (когда подтипирование подразумевает подклассификацию) рисунок 9.1 не подходит, если только поведение покупки и продажи не отличается (а возможно, и нет). Модель интерфейса может быть любой. В разделе 14.2 описывается, как можно осуществить это преобразование, чтобы сохранить один и тот же интерфейс независимо от того, используются ли подклассы или флаги.
Пример: Megabank продает 1000 акций Aroma Coffee Makers Мартину Фаулеру по цене $30. Это контракт продажи (short), контрагентом которого является Мартин Фаулер, инструментом — акции Aroma Coffee Makers, количество — 1000, а цена — $30.
Пример: Megabank продает 2 миллиона долларов США (USD) за 1 миллион британских фунтов (GBP) от British Railways. Это контракт покупки, в котором контрагентом является British Railways, сумма составляет 1 миллион, цена — 2, а инструмент — GBP/USD. В качестве альтернативы это может быть контракт продажи, в котором сумма составляет 2 миллиона, цена — 0.5, а инструмент — USD/GBP.
Пример: Northeast Steel продает 10 000 тонн стали компании Chrysler. Для Chrysler это контракт покупки с контрагентом Northeast Steel. Инструментом является сталь, и в этом случае объем стали меняется на количество денег, позволяющее представить 10 000 тонн. (Альтернативный вариант — позволить инструменту быть тоннами стали, но это менее гибко для других количеств).
Этот тип модели хорошо подходит для отражения сделок, заключенных между принимающей организацией и другими сторонами. Однако часто сделки заключаются внутри организации, например между отделом опционов и отделом сырьевых товаров. Эти внутренние сделки используются для управления рисками. Распространенным примером является сделка по компенсации риска опциона (так называемый хедж). Такие внутренние сделки вызывают вопрос о том, кто является внутренней стороной. Модель, показанная на рис. 9.2, представляет собой более гибкий способ ответа на этот вопрос. В контракте показаны две стороны: покупатель и продавец. В таком представлении отдел опционов и отдел товаров представлены как отдельные стороны. Если опционный отдел заключает опцион с внешней стороной и хеджирует его сделкой с товарным отделом, то опционный отдел будет являться стороной каждого контракта. Если опционный отдел был покупателем по опциону, то он будет продавцом по контракту хеджирования.

Наличие двух сторон позволяет заключать внутренние сделки, полностью внешние сделки и иметь дело с разными сторонами в принимающей организации.
Рисунок 9.2. Обозначение покупателей и продавцов отдельными отношениями.
На рисунке 9.3 представлена аналогичная ситуация в несколько ином виде. Опять же использование двух отношений позволяет представить внутренние сделки. Однако здесь существует понятие первичная стороны и контрагента, а не short и long. При заключении сделки с внешней организацией первичной стороной всегда является домашняя сторона. Во внутренних сделках выбор между первичной стороной и контрагентом произволен, хотя по общему правилу первичной стороной (продавцом) обычно является та, которая инициирует сделку. Подтипом сделки покупки-продажи является характер сделки, как его видит первичная сторона.

Он менее лаконичен, чем рисунок 9.2, но может лучше отобразить видение трейдеров.
Рисунок 9.3. Контрагент и первичная сторона.
При первоначальном анализе модель, показанная на рис. 9.3, выглядит менее ценной, чем модель, показанная на рис. 9.2, потому что она добавляет дополнительную пару подтипов без каких-либо значительных преимуществ. Конечно, с точки зрения моделирования данных её надо отвергнуть, сославшись на более сложную структуру данных. Важным вопросом с точки зрения моделирования ОО является интерфейс. Полезнее ли предоставлять операции, которые запрашивают первичную сторону и контрагент, а также тип контракта (покупка или продажа), или полезнее иметь только связь на основе покупки и продажи? Может оказаться, что модель, показанная на рис. 9.4, которая, по сути, предоставляет оба интерфейса, является наилучшей. Решающим фактором является то, что наиболее полезно для пользователей концепций. Для нашей системы модель на рис. 9.3 была более значимой для трейдеров, чем модель на рис. 9.2, и оказалась более полезной при создании программного обеспечения, хотя в конечном итоге был предоставлен интерфейс на рис. 9.4.
Если вы теряетесь в нотации некоторых диаграмм, то обратитесь к полному описанию в приложении А или к его сокращенной версии в приложении C

Это позволяет охватить все точки зрения, используя вычисление производных дублирующих элементов.
Рисунок 9.4 Использование четырехсторонних сопоставлений.
Выбор того, что сделать производными связями на рис. 9.4 достаточно произволен. Мы с равным успехом можем сделать производным сопоставление по типу контракта. Модель не должна ограничивать исполнителя, который может использовать любой вид реализации. Можно возразить, что можно не делать ничего производным, а просто использовать правила (например, если контракт продажи, то сторона продавца — это тот же объект, что и первичная сторона). Я предпочитаю показывать некоторые производные, чтобы сделать взаимосвязи явными, но в конечном итоге это скорее вопрос вкуса проектировщика.
Следствием моделей, представленных на рисунках 9.2-9.4, является возможность зарегистрировать контракты, в которых не участвует домашняя сторона (наша организация). Мы можем избежать этого, заставив, по крайней мере, первичную сторону быть домашней организацией. В качестве альтернативы мы можем спросить доменного эксперта, будет ли полезен учет таких сделок. Продавцы часто любят записывать сделки, заключенные их клиентами с другими банками, поскольку это дает им информацию о возможных рисках клиентов и позволяет продать контракт, чтобы улучшить ситуацию. Здесь гибкость модели поддерживает новые бизнес-возможности.
Остается открытым вопрос о связи между контрактом в этой торговой модели и сделкой в одной из бухгалтерских моделей из главы 6. Сделку можно рассматривать как операцию, которая, например, снимает 1000 акций Aroma Coffee Makers со счета Megabank и кладет их на счет Мартина Фаулера, перечисляя соответствующую сумму денег в обратном направлении. И сделки, и транзакции полезны, но для разных целей. Для изучения их взаимосвязи необходимо провести дополнительное моделирование.
9.2 Портфель
Мы редко рассматриваем контракты по отдельности, особенно при управлении рисками. Как правило, банк рассматривает группу связанных контрактов и оценивает их совместный риск. Это могут быть контракты, которыми торгует отдельно взятый трейдер, контракты по определенному инструменту, контракты с некоторым контрагентом или какая-то другая комбинация.
По сути, портфель — это набор контрактов, как показано на рис. 9.5. Портфели и контракты можно оценить, установив на них цену в соответствии с некоторым сценарием. Сценарий — это представление состояния рынка, реальное или гипотетическое (более подробно о сценариях мы поговорим в разделе 9.4). Стоимость портфеля — это, по сути, сумма стоимостей входящих в него контрактов.

Портфель — это совокупность контрактов, которые могут быть оценены как единое целое.
Рисунок 9.5. Представление портфелей.
Ключевой вопрос заключается в кардинальности сопоставления контракта и портфеля. Имеет ли смысл держать контракт в более чем одном портфеле, зависит от того, как мы создаем и используем портфели. Если портфель — это книга трейдера, то контракт лежит в портфеле трейдера, который управляет сделкой. Однако это не позволяет рассматривать вместе все сделки с конкретным контрагентом. Поэтому, по-видимому, есть преимущество в том, чтобы позволить контракту лежать во многих портфелях. Таким образом, портфели могут быть созданы для управления рисками в соответствии с различными перспективами.
Однако при таком использовании портфелей возникает другой вопрос. Предположим, нам нужно сформировать портфель, содержащий все контракты, заключенные с определенным контрагентом. Мы можем создать приложение, которое будет искать все контракты и назначать их в портфели. Однако лучший способ — заставить портфель выбирать свои контракты. Мы можем задать портфелю булевский метод, который принимает контракт в качестве аргумента, как показано на рис. 9.6. Тогда портфель будет состоять из всех контрактов, для которых булевский метод имеет значение true
. Это позволяет нам создавать портфели, которые могут выбирать любую комбинацию свойств контракта, а затем выполнять функции управления портфелем на этом производном множестве.

Это позволяет неявно описывать портфели с помощью свойств контракта.
Рисунок 9.6. Динамические портфели с фильтрами.
Позволить портфелям иметь методы, чтобы они могли формировать себя на основе контрактов — это мощное понятие. Это означает, что нет необходимости выбирать какую-то одну структуру для рассмотрения групп контрактов. Можно использовать различные структуры, причем в произвольном порядке. Как только такая структура определена, ее можно запомнить, чтобы использовать в будущем, и регулярно обновлять ее содержание. Структура может быть определена в любое время, спустя долгое время после того, как был составлен исходный контракт. По сути, мы делаем запрос, и полученная коллекция объектов становится самостоятельным объектом.
Как реализуется булевский метод? В общем случае метод может представлять собой любой блок кода, который возвращает true
или false
при передаче контракта в качестве аргумента. Программисты Smalltalk могут увидеть, что назначение блока с одним аргументом в качестве переменной экземпляра portfolio
обеспечит желаемую возможность. Программисты C++ могут использовать примерно тот же принцип, хотя это более сложно, так как C++ требуется скомпилированная функция. Это та же проблема, что и с методами отдельных экземпляров, рассмотренными в разделе 6.6.
В абстрактном смысле булевский метод может быть лучшим подходом, но на практике можно использовать и более простой метод. Портфели обычно формируются из ряда свойств контрактов, включая контрагента, дилера (первичная сторона), инструмент и даты сделки. Мы можем объединить эти атрибуты в конкретный объект селектора контрактов, как показано на рис. 9.7. Селектор контрактов не такой общий, как булевский метод, и может работать только с ограниченным диапазоном фильтрации. Однако его легко настроить. Пользователь может легко сконфигурировать его с помощью подходящего пользовательского интерфейса. Если мы используем селектор контрактов для обработки большинства портфелей, необходимых пользователю, мы можем значительно сократить объем требуемого программирования.

Обратите внимание, что это пример параметризованного метода (см. раздел 6.6.4). Он не может выбрать все возможные портфели, но он может охватить большинство портфелей, используемых на практике, легче, чем полностью общий случай.
Рисунок 9.7. Селекторы контрактов.
Пример: Портфель состоит из всех сделок с акциями Aroma Coffee Makers, проданными Джону Смиту. Этот портфель имеет фильтр с акциями Aroma Coffee Makers в качестве инструмента и Джоном Смитом в качестве контрагента.
Ничто не вынуждает нас выбирать между контрактными селекторами и булевыми методами для наших фильтров. Мы можем получить лучшее из обоих миров, используя модель, показанную на рис. 9.8. Эта модель абстрагирует интерфейсы как булевого метода, так и селектора контрактов в один абстрактный тип — портфельный фильтр. Это позволяет нам использовать селектор контрактов для простых случаев и использовать ряд жестко закодированных фильтров для более сложных ситуаций. Мы можем легко добавить другие портфельные фильтры. Это пример шаблона стратегии.

Эта модель обеспечивает как гибкость для работы со сложными случаями, так и простую параметризацию для простых случаев. Она представляет собой комбинацию стратегий и параметризованных реализаций (см. раздел 6.6).
Рисунок 9.8. Предоставление нескольких портфельных фильтров.
Операция выбратьКонтракты()
в фильтре портфеля принимает коллекцию контрактов и возвращает другую коллекцию контрактов. Для каждого контракта во входной коллекции операция выбратьКонтракты()
оценивает включенЛи()
и, если true
, добавляет его в результат. Подклассы фильтра портфеля переопределяют включенЛи()
, чтобы обеспечить свое специфическое поведение. Портфель может использовать включенЛи()
для проверки отдельных контрактов.
Хочу добавить пару слов об именовании портфельного фильтра и селектора контрактов. Люди, с которыми я работал, обнаружили, что различие между этими терминами достаточно ценно на практике. Селектор выбирает объекты того типа, именем которого он назван; так, селектор контрактов используется для выбора контрактов, и он возвращает коллекцию контрактов. Фильтр выбирает некоторый другой тип от имени своего именованного типа и предназначен для использования с именованным типом. Так, «фильтр портфеля» выбирает контракты для портфеля. Придерживаясь последовательного именования, легче запомнить обязанности этих двух типов объектов: фильтр — это только механизм отбора, а портфель добавляет дополнительное поведение, например, выдает общее значение. Кроме того, на портфель ссылаются другие части системы, в то время как фильтр используется только для отбора.
Портфели могут быть кратковременными или постоянными. Кратковременные портфели заполняются по требованию. Задается фильтр, и все экземпляры контракта проверяются на соответствие фильтру. Как только клиент закончил работу с портфелем, он удаляется. Постоянные портфели создаются таким же образом, но не удаляются. Когда создаются новые контракты, они проверяются на соответствие существующим постоянным портфелям. Если они соответствуют фильтру, они добавляются в портфель. После этого любая обработка, основанная на портфеле, должна быть обновлена, в идеале — поступательно. Постоянные портфели обеспечивают гораздо более высокую производительность запросов, но замедляют создание контрактов и занимают много места в памяти. Важнейшим принципом моделирования является то, что пользователи не должны знать, являются ли портфели кратковременными или постоянными. Портфели должны переключаться с одного на другой без каких-либо действий со стороны пользователя. Для этого необходимо, чтобы новый фильтр портфеля проверялся на соответствие всем существующим фильтрам постоянных портфелей. Если такой фильтр существует, то следует ссылаться на существующий портфель, а не создавать новый.
Портфели полезны во многих областях. Основная характеристика портфеля — это объект, в котором заключен механизм выбора группы объектов определенного типа. Портфель служит основой для дальнейшей обработки итогов. Эта обработка может быть клиентским объектом, как в этой главе, или же она может быть встроена в сам портфель.
Пример: Автопроизводитель может создавать портфели произведенных автомобилей для обобщения данных о производстве и неисправностях. Фильтры могут отбирать автомобили по заводу, модели, смене производства или некоторому диапазону дат.
Пример: Общественное здравоохранение — это важная отрасль здравоохранения, которая занимается здоровьем популяций пациентов. Мы можем выбирать популяции по целому ряду характеристик: возраст, место проживания, применяемые концепции наблюдения и так далее. Эти популяции можно определить с помощью фильтров, а затем провести наблюдения за ними, например, определить среднюю скорость пикового потока у людей, которые выкуривают более 20 сигарет в день. (Популяция — это портфель людей, в котором фильтром является «курит более 20 сигарет в день»)
9.3 Котировка
Любая вещь, продаваемая на финансовом рынке, имеет цену. Однако эта цена обычно не является единственным числом. Котируются два числа: цена покупки (bid) и цена продажи (offer). Мы можем смоделировать это, используя пару чисел для представления цен, как показано на рис. 9.9.

Рисунок 9.9. Представление цены с помощью двух числовых свойств.
Инструмент может быть оценен с помощью чисел или денежных знаков. Обычно акции оцениваются с помощью денег, а курсы валют — с помощью чисел. Котировка ведет себя одинаково в любом случае. (Мы можем рассматривать котировку как параметризованный тип).
Хотя два числа — обычное дело, они используются не всегда. Иногда котировка представляет собой одну цену, которая является средним значением цены. Единая цена котируется со спредом — разницей между ценой покупки и ценой продажи. В других случаях мы можем видеть только цену покупки или только цену продажи. Это влияет на способ отображения котировки. На валютных рынках такой курс, как USD/GBP, может котироваться как 0.6712/5, что означает цену покупки 0.6712 и цену продажи 0.6715. Если присутствует только цена покупки, котировка отображается как 0.6712/; котировка только с ценой продажи отображается как /0.6715.
Любой объект, который может иметь двустороннее ценообразование — например, обменные курсы валют, сырьевые товары и так далее, — требует ряд поведений, как показано на рис. 9.10. Вынесение этих поведений в отдельный объект «котировка», как показано на рис. 9.11, обеспечивает все поведения, необходимые для двустороннего ценообразования. Всё, что имеет в качестве цены котировку, требует свойство типа «котировка».

Рисунок 9.10. Поведение, необходимое для поддержки двусторонних цен.

Это хороший подход, поскольку он объединяет конкретные обязанности в простую концепцию для многоразового использования.
Рисунок 9.11. Использование отдельного объекта котировки.
Котировка становится фундаментальным типом и как таковая может быть лучше всего представлена как атрибут в тех методах моделирования, которые проводят различие между атрибутами и типами объектов. Важно помнить, что атрибут представляет не структуру данных, а лишь наличие соответствующих операций.
Пример: Курс USD/GBP составляет 0.6712/6. Инструмент — USD/GBP. Этот инструмент имеет котировку с ценой покупки 0.6712, цена продажи 0.6716, средним 0.6714 и спредом 0.0004.
Пример: Биржа компакт-дисков продает подержанные диски за $12 и покупает их по $8. Цена продажи — $12, цена покупки — $8, среднее — $10, спред — $4. Инструмент — полноценный CD.
Часто встречаются двусторонние цены, но иногда используются и односторонние. Моделирование односторонних цен несколько затруднительно. Одна из альтернатив — позволить цене быть либо котировкой, либо числом. Это практически невозможно в сильно типизированных языках, таких как C++. Даже в Smalltalk клиентский код работающий с акциями вынужден определять тип объекта цены, прежде чем что-то с ним делать.
Альтернативный вариант — сделать котировку подтипом числа. Это может сработать, так как котировки могут реагировать на арифметические операции, но это все равно заставляет клиента помнить о различиях при манипулировании ценами акций, кроме как для вывода на печать. В C++, где число не является встроенным типом, а real
и integer
являются таковыми, этот метод не следует использовать, если не предусмотрен класс числа.
Другая альтернатива — сделать число подтипом котировки. Концептуально это имеет определенную привлекательность. Числа — это простые котировки, и несложно представить, что каждый экземпляр числа — это экземпляр котировки, с идентичными ценой продажи и ценой покупки. (Аналогичный аргумент можно использовать, чтобы сказать, что число — это подтип комплексного числа). Хотя этот аргумент имеет концептуальные достоинства, он не работает в интерфейсной модели. Чтобы число было подтипом котировки, оно должно унаследовать весь интерфейс котировки. Котировка полезна только в нескольких областях, в то время как число полезно почти во всех областях. Подтипирование от котировки означает, что она используется во всех областях, включая многие, где поведение котировки не является полезным. Котировка должна быть спроектирована так, чтобы она была видима для числа, а не наоборот.
На этом этапе следует рассмотреть, какие общие черты существуют между котировками в их двусторонней и односторонней формах. Существуют две альтернативы:
либо односторонняя котировка рассматривается как котировка у которой ставка равна предложению,
либо трактовать запрос о ставке или предложение по односторонней котировке как ошибку.
Первый вариант указывает на наличие абстрактной котировки, как показано на рис. 9.12, а второй позволяет избежать подобного обобщения. В первом варианте клиент может одинаково относиться к односторонним и двусторонним котировкам и не обращать внимания на различия. Однако это может привести к неточностям, поскольку клиент не может быть уверен в том, что имеет дело с предложением двусторонней котировки. Необходима операция проверки типа (isTwoWay
или hasType('TwoWayQuote')
), чтобы клиент мог провести проверку. При отсутствии абстрактной котировки такие неточности невозможны, но клиент должен использовать проверку типа каждый раз, когда вызывается операция, чтобы знать, безопасно ли ее использовать.

Односторонние цены рассматриваются как частный случай двусторонних цен.
Рисунок 9.12 Абстрактная котировка с подтипами.
Решение зависит от того, насколько часто допустимо игнорировать разницу между двусторонними и односторонними котировками. Если это почти никогда не допустимо, то лучше не иметь абстрактного типа котировок. Однако если такое допустимо часто (что, как показывает практика, так и есть), то я бы настоятельно рекомендовал использовать абстрактный тип котировки. Важно отметить, что использование абстрактной котировки никогда не требует от клиента больше усилий, чем ее отсутствие. Она позволяет сэкономить усилия, когда различие не требуется.
Абстрактная котировка включает в себя все поведение подтипов, потому что для подтипов не существует дополнительных операций или ассоциаций. Обычно мы не используем подклассы для реализации подтипизации абстрактной котировки, тем более что в C++ для такого фундаментального объекта обычно используется защитная оболочка. Внутренний флаг в классе котировки — более вероятная реализация, тем более что нам часто нужно получить номинальную стоимость акции по двусторонней котировке (то есть превращать ее в одностороннюю) и наоборот, что требует динамической классификации.
Неявная котировка может быть как покупкой, так и продажей, и в этом случае двусторонние котировки не нужны. Они нужны только в тех случаях, когда требуется и покупка, и продажа.
Иногда мы хотим представить цену контракта в виде котировки. Часто, когда контрагенты запрашивают цену контракта, они не указывают направление; в этом случае трейдер отвечает котировкой. Сохраняя котировку, трейдер помнит, каким был спред на момент котировки контракта. Из направления контракта и котировки можно легко вычислить фактическую сумму платежа.
9.4 Сценарий
Цена инструмента никогда не бывает постоянной, иначе фондовые рынки мира были бы гораздо менее интересными местами. Нам нужно уметь показать, как цены могут меняться со временем, и хранить историю этих изменений. Мы можем сделать это, поместив временную точку на котировку, как показано на рис. 9.13, или поместив временную точку на связь между инструментом и котировкой, как показано на рис. 9.14. Разница между этими двумя методами небольшая, но существенная. В первом случае котировка отвечает как за свою двустороннюю природу, так и за свое поведение, зависящее от времени. Во втором методе эти обязанности разделены. Поскольку я рассматриваю котировку как фундаментальный тип, который должен быть максимально простым, я предпочитаю использовать подход, показанный на рис. 9.14.

Временная точка указывает, в какое время котировка является корректной для данного инструмента.
Рисунок 9.13. Добавление временной точки в цитату.

Это отделяет двустороннее поведение (котировка) от понятия стоимости инструмента в определенный момент времени (цена).
Рисунок 9.14. Цена, установленная для акции в определенный момент времени.
В этих моделях поиск цен закрытия на бирже предполагает взятие всех акций на этой бирже и поиск последних котировок для каждой акции. Другой вариант — рассматривать эту коллекцию котировок как самостоятельный объект — сценарий, как показано на рис. 9.15. Сценарий представляет собой состояние биржи в определенный момент времени, а элементы внутри сценария — цены в этот момент.

Это позволяет рассматривать группу цен в один момент времени как единый объект.
Рисунок 9.15 Сценарий
Если мы хотим отразить только опубликованные цены на фондовой бирже, то сценарий, похоже, мало что добавляет к картине. Его легко получить, посмотрев на временные точки в несценарной модели. Важный вопрос заключается в том, откуда трейдер получает цены. Один из источников — публичные котировки биржи. Для тех, кто управляет фондами акций, другим источником информации являются возможные будущие цены. Большая часть усилий управляющих фондами и трейдеров направлена на управление рисками их портфелей при изменении рыночных условий. Такое управление рисками предполагает рассмотрение альтернативных ситуаций и их влияния на цены активов.
Пример: Менеджер фонда управляет портфелем акций. Ее беспокоит возможность падения цен на нефть, что приведет к росту цен на многие акции, но снизит цены на другие, например, на акции нефтяных компаний. Этот менеджер хочет рассмотреть несколько падений разной величины и проанализировать, как они повлияют на портфель. Каждое из этих падений приводит к разным сценариям.
Пример: Менеджер по производству оценивает возможные затраты на производство автомобилей. Затраты на сырье и рабочую силу являются инструментами, связанными с ценообразованием. Можно построить несколько сценариев с различными вероятными значениями этих инструментов.
Приведенные выше примеры являются гипотетическими случаями, которые демонстрируют сильные стороны сценарного подхода. Объект сценария обеспечивает базу для объединения всех факторов в гипотетическом случае, что позволяет легко сравнивать различные случаи.
Также необходимо учитывать рынки, на которых нет единого издателя цены, например валютный рынок. В таких случаях нам необходимо добавить в модель сторону, которая публикует цену. На рисунках 9.16 и 9.17 показаны предыдущие модели с добавленными издающими сторонами. Эффективны как сценарные, так и несценарные подходы, и снова решающим фактором является необходимость в гипотетических сценариях для управления рисками.

Рис. 9.16 Модель с рис. 9.14 с издающей стороной.

Использование издателя — еще одна причина использовать сценарий.
Рис. 9.17 Модель с рис. 9.15 с издающей стороной.
Пример: Торговец, занимающийся импортом/экспортом, рассматривает цены на товары в ряде европейских стран. Мы можем описать эти цены, сформировав сценарий, в котором в качестве инструментов выступают товары вызывающие интерес. Рассматривая разницу между рынками, используя двусторонние цены, он может искать возможности, когда разница в ценах больше, чем стоимость транспортировки товаров (этот процесс называется арбитражем).
9.4.1 Определение способа построения сценария
Откуда берутся цены? В некоторых случаях это может быть простой вопрос, например, когда цены публикуются биржей. В других случаях, особенно при наличии гипотетических сценариев, могут использоваться более сложные схемы.
В общих чертах можно выделить три варианта происхождения цены: публикация каким-либо органом, который широко котируется на рынке, расчет на основе других цен или характеристик рынка, мнение отдельного трейдера или группы аналитиков. Первый случай, показанный на рис. 9.18, является наиболее простым. Для получения соответствующей информации требуются инструкции. Обычно эти инструкции поступают из источника, такого как Reuters, который указывает, где искать информацию (например, «Страница 3, второй столбец строки, начинающейся с IBM»).

Эта модель описывает, откуда берется тот или иной элемент.
Рисунок 9.18 Поиск элемента сценария.
По сути, использование опубликованной цены делает котировку элемента сценария производной. Вместо того чтобы утверждать котировку для элемента сценария, мы выводим ее с помощью индекса источника. Таким образом, есть аргументы в пользу того, чтобы сделать ссылку на котировку производной. Это можно сделать без опасений, если ссылка никогда не может быть утверждена, как в случае, когда трейдер записывает цену согласно своей интуиции. Утверждение котировки может вызвать проблемы, в случаях когда котировка может быть иногда утверждаемой, а иногда производной. Один из способов выйти из этой ситуации — использовать нотацию для гибридных или опционных производных отношений (см. Odell[2], стр. 56). Кажется, что это заводит проблему производных инструментов слишком далеко. Я склонен использовать нотацию для наиболее распространенных случаев и описывать происходящее в сопроводительной документации.
Пример: Аналитик, изучающий цены на товары, заказываемые по почте, может рассматривать каждую компанию как источник информации. Индексом источника может быть номер страницы в каталоге. Затем можно разработать отдельный сценарий для каждой розничной компании или построить общий сценарий, объединяющий все розничные компании. Вместо запроса о цене инструмента поддерживаются такие вопросы, как самая низкая цена и средняя цена некоторого инструмента.
На рис. 9.18 рыночный индикатор представлен как супертип инструмента. Это отражает факт того, что сценарии могут содержать не только инструменты. Для деривативов (производных инструментов) важной частью подхода к ценообразованию является волатильность инструмента — число, показывающее, насколько сильно меняется стоимость инструмента. Эта волатильность не является инструментом, которым можно торговать, но она учитывается в сценарии так же, как и инструмент. Таким образом, рыночный индикатор включает в себя волатильность, а также все инструменты.
Пример: На валютных рынках существует множество рыночных индикаторов, которые не являются инструментами, включая процентные ставки по различным валютам и волатильность обменного курса — показатель того, насколько сильно меняется обменный курс.
Пример: Аналитик, изучающий цены на товары, заказываемые по почте, заинтересован в росте цен на джинсы. Рост цен на джинсы становится индикатором рынка, но не инструментом. Джинсы — это и индикатор рынка, и инструмент.
Расчет элементов сценария также прост. Главное — принять тот факт, что алгоритм расчета цены может быть самостоятельным объектом. Простой пример — кросс-курсы, используемые в валютном обмене. Если нам известны курсы обмена USD/DEM и USD/GBP, то мы можем рассчитать курс обмена GBP/DEM как (USD/DEM) / (USD/GBP). Мы можем представить это с помощью элемента сценария кросс-курса, который моделируется с помощью подтипа элемента сценария, ссылающегося на другие элементы сценария для числителя и знаменателя кросс-курса, как показано на рис. 9.19. Котировка для элемента сценария кросс-курса затем выводится из котировок для элементов сценария знаменателя и числителя.

Это можно использовать для определения третьего элемента из соотношения двух известных элементов.
Рисунок 9.19 Вычисление элементов сценария по перекрестным коэффициентам.
Обратите внимание, что знаменатель и числитель выражены в виде сценарных элементов, а не рыночных индикаторов. Если мы просто выражаем кросс-курсы, как описано выше, то ссылка на рыночные индикаторы кажется наиболее разумной (USD/GBP — это рыночный индикатор). Однако весь смысл предоставления сценариев заключается в том, чтобы позволить нам разместить несколько различных цен, при различных предположениях, для одного и того же рыночного индикатора. Ссылка на элемент сценария позволяет нам сосредоточиться на том, какую из этих цен мы должны использовать. Может быть два показателя USD/DEM: один от Reuters, другой от LIBOR. Ссылаясь на элементы сценария, мы можем указать, какой из них нам нужен.
Пример: Трейдер является специалистом по французскому франку. Она определяет обменный курс между голландскими гульденами (NLG) и французскими франками (FFR) с помощью кросс-курсов с использованием немецкой марки (DEM). Для этого она создает элемент сценария кросс-курса. Рыночный индикатор для этого элемента сценария — NLG/FFR. Для числителя она использует курс NLG/ DEM, котируемый Reuters; это сценарный элемент для инструмента NLG/DEM в сценарии Reuters. Однако для знаменателя она не получает ставки DEM/FFR от Reuters; вместо этого она использует свой собственный сценарий (построенный на основе ее собственных специальных знаний). Таким образом, она формирует кросс-курс из элементов сценария в разных сценариях.
Подход, используемый для кросс-курсов, может быть использован для ряда общих расчетов, где новые виды расчетов поддерживаются новыми подтипами элемента сценария. На рис. 9.20 показано обобщение этой структуры. В этом случае вычисляемый элемент сценария имеет список элементов сценария в качестве аргументов и формулу. Формула представляет собой алгоритм расчета, который использует аргументы, предоставленные ему аргументами элемента вычисляемого сценария. Для перекрестного коэффициента формула имеет вид arg[1] / arg[2]
. Фактические аргументы предоставляются элементом вычисляемого сценария. Это позволяет повторно использовать одну формулу в нескольких элементах расчетного сценария. Кросс-курс для GBP/DEM использует формулу с аргументами <USD/DEM, USD/GBP>, а кросс-курс для GBP/JPY использует аргументы <USD/JPY, USD/GBP>. Обратите внимание на важность предоставления аргументов в виде списка, а не обычного набора для многозначных отображений. Позиция аргументов необходима для правильного написания формул.

Формула может быть формулой в стиле электронной таблицы, основанной на аргументах. Поддерживается ряд арифметических комбинаций элементов сценария.
Рисунок 9.20 Более общий подход к расчетным элементам сценария.
Пример: Изменение цены на джинсы рассчитывается с помощью элемента сценария, который берет разницу между ценами на джинсы в сценарии этого года и прошлого года.
Мы можем реализовать формулы несколькими способами. Один из способов — жестко закодировать формулы в языке реализации. Поскольку общие формулы (например, кросс-курсы) широко используются повторно, жесткое кодирование в этом случае не является недостатком. Если количество формул невелико и не меняется слишком часто, это лучший подход. Даже если каждый месяц добавляется новая формула, это будет достаточно легко контролировать даже для сложной системы. Мы можем использовать более сложный подход, если хотим предоставить пользователю возможность добавлять формулы. Мы можем создать интерпретатор, который распознает простой набор формульных выражений. Эта техника знакома любому пользователю, работавшему с электронными таблицами. Мы могли бы предоставить интерактивный конструктор формул, но любой пользователь, умеющий строить формулы, вероятно, сможет набрать формулу, подобную электронной таблице. Таким образом, интерпретатор не обязан распознавать все возможные формулы. Вполне допустимо, что некоторые формулы будут построены парсером, а некоторые — закодированы. Программному обеспечению для элементов сценария неважно, как построена формула, главное — предоставить аргументы для формулы, которые генерируют вычисленную котировку. Следуя лучшим принципам объектно-ориентированного подхода, интерфейс отделен от реализации. (Более подробное обсуждение этого вопроса см. в разделе 6.6.)
Диаграмма взаимодействия, показанная на рис. 9.21, раскрывает некоторые полезные моменты о том, как может работать такое поведение. Во-первых, обратите внимание на то, что формула получает на вход список котировок, а не список элементов сценария. Не то чтобы это было строгим правилом, но подавать на вход и возвращать одни и те же вещи — полезная политика, которой следует придерживаться. Без этого кодеры могут быстро запутаться в том, с каким типом вещей они имеют дело. Это, конечно, предполагает, что все арифметические операции определены с помощью котировки, что было бы естественным местом для двусторонней арифметики цен. В этом случае мы можем настроить формулы так, чтобы они работали со всем, что поддерживает арифметику, а не только с котировками.

Рисунок 9.21 Диаграмма взаимодействия расчетных элементов сценария.
Поведение по своей природе рекурсивно, поскольку операция получитьКотировки()
вызывает получитьКотировки()
для всех аргументов, что потенциально может привести к длинной цепочке вычислений. Это, как и многие другие рекурсивные структуры, очень элегантно (но трудно показать на диаграмме взаимодействия). Однако на практике это может привести к большому количеству лишних вычислений. Чтобы предотвратить ненужные пересчеты, вызванные повторными вызовами получитьКотировки()
к одному и тому же объекту, необходима политика кэширования вычисленных значений котировок. Как и в случае с любым кэшем, нам, конечно, необходимо обеспечить правильное обновление кэша при изменении значения источника. Мы можем использовать сопоставление аргументов в обратном направлении, чтобы сбросить все зависимые элементы сценария.
Ссылки
Gamma, E., R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.
Martin, J., and J. Odell. Object-Oriented Methods: A Foundation, Englewood Cliffs, NJ: Prentice-Hall, 1995.