Глава 3 - Транзакции   

Содержание:

3.1. Введение

3.2. Правила реализации транзакций

3.3 Транзакции



3.1. Введение

Ядро каждой транзакции TPC-E выполняется на Сервере баз данных, но логика транзакций взаимодействует с несколькими компонентами среды контрольного теста. Этот раздел определяет все характеристики Транзакций, включая побочное влияние на другие компоненты окружения контрольного тестирования.

3.1.1 Определения

3.1.1.1 Транзакция состоит из EGenTxnHarness и вызова одного или более Фреймов. Транзакция Trade-Cleanup является исключением. Организатор может, но не обязан выполнять Транзакцию Trade-Cleanup из EGenTxnHarness.

3.1.1.2 EGenTxnHarness – это логика транзакций, предоставляемая TPC, которую недозволено изменять Организатору. Метод реализации EGenTxnHarness предотвращает объединение нескольких Фреймов в Транзакции.

Фрейм – это реализованная Организатором логика Транзакции, которая вызывается как исполняемая единица с помощью EGenTxnHarness. Все взаимодействия Транзакции с базой данных инициируются из ее Фреймов.

3.1.1.3


Figure 3.a - Взаимодействие Фреймов с EGenTxnHarness и базой данных.

3.1.1.4 Транзакция базы данных является единицей работы со свойствами ACID

3.1.2 Определение Слепка базы данных.

Эта Глава описывает формат, используемый для обозначения Слепка базы данных каждой Транзакции в этом контрольном тесте.

3.1.2.1 Слепок транзакции базы данных – это набор необходимых взаимодействий с базой данных, выполняемых этой Транзакцией.

3.1.2.2 Каждый Слепок базы данных представлен в табличном формате, в котором колонки представляют следующее:

  • Первая из колонок содержит обозначение либо одной из таблиц базы данных, описанных в Пункте 2.2 либо слова «Transaction Control» которые обозначают Транзакцию целиком. Последний ряд обозначает всю Транзакцию.

  • Вторая колонок обозначает одно из следующего:

    • Название определенной колонки таблицы базы данных, как определено в Пункте 2.2.

    • Строку «# rows», которая указывает точное количество рядов, содержащих все колоноки таблицы базы данных. К примеру, «2 rows» обозначает два полных ряда таблицы базы данных.

    • Строку «row(s)», котоpая указывает переменное количество рядов, содержащих все колонки таблицы базы данных.

  • Остальные колонки связаны со всеми Фреймами Транзакции и содержат все взаимодействия с базой данных или управляющие операции Транзакции, которые необходимо выполнить в этом Фрейме.

3.1.2.3 Следующая таблица является примером Слепка базы данных Транзакции.

Пример Слепка базы данных

Таблица

Колонка

Фрейм

1

2*

3*

CUSTOMER_ACCOUNT

CA_BAL

Reference

 

 

CA_C_ID

Return

 

 

CA_TAX_ST

Return

 

 

HOLDING

H_PRICE

 

Return

 

H_QTY

 

Modify

 

Row(s)

 

Remove *

 

1 row

 

Add *

 

TRADE_HISTORY

1 row

 

 

Add

Transaction Control

Start

Rollback *

Commit

 

  • В последнем ряду Слепка базы данных, где написаны слова «Transaction Control», каждая колонка связана с одним из Фреймов транзакции. Содержимое колонок указывает, какая из управляющих операций транзакции возникает во Фрейме. Возможны следующие управляющие операции Транзакции:
  • Слово «Start» указывает, что выбранный Фрейм содержит контрольную операцию, начинающую Транзакцию базы данных. Запуск Транзакции базы данных может произойти только во Фрейме, в котором указано слово «Start».
Rollback
  • Слово «Rollback» означает, что указанный Фрейм содержит контролирующую операцию, которая откатывает Транзакцию Базы данных. Откат Транзакции может быть осуществлен только во Фрейме, в котором указано слово «Rollback».

Слово «Commit» указывает, что соответствующий Фрейм содержит управляющую операцию, которая подтверждает Транзакцию базы данных. Commit: Контрольная операция в СУБД, которая делает временные изменения, внесенные транзакцией в данные, постоянными

  • Явное подтверждение Транзакции базы данных возможно только во Фрейме, где указано слово «Commit».
Примечание: В одном Фрейме могут возникнуть несколько операций управления Транзакцией. Например, Транзакция, состоящая из одного Фрейма, будет содержать и «Start» и «Commit» в ее колонке Слепка базы данных, связанной с Фреймом 1.
  • В отношении остальных рядов Слепка базы данных, колонка, связанная с каждым Фреймом, содержит метод доступа к колонке таблицы, содержащейся в этом ряду. Возможные методы доступа:


  • Слово «Reference» обозначает, что в базе данных идентифицирована колонка таблицы TPC-E, и ее содержимое доступно в пределах Фрейма без передачи содержимого колонки таблицы в EGenTxnHarness.
  • Слово «Return» обозначает, что существует ссылка на колонку таблицы TPC-E, и что ее содержимое извлекается из базы данных и направляется в EGenTxnHarness. Ссылка на колонку должна производиться в том же Фрейме, где указано слово «Return». Содержимое колонки таблицы может быть передано в последующие Фреймы при помощи параметров ввода и вывода, указанных среди параметров Фрейма.
  • Слово «Modify» означает, что содержимое таблиц TPC-E изменяется во Фрейме. Содержимое колонки таблицы может быть изменено только во Фрейме, в котором обозначено слово «Modify». Когда исходное содержимое колонки таблицы также должно быть возвращено, или на него должна быть создана ссылка перед тем, как оно будет изменено, также указываются методы доступа «Reference» или «Return»
  • Слово «Add» означает, что в таблицу TPC-E, указанную Слепком базы данных добавляется набор рядов. Ряд(ы) таблицы TPC-E могут быть добавлены только во Фрейме, в котором обозначено слово «Add». Количество добавляемых рядов указано во второй колонке Слепка базы данных при помощи либо записи «# row» для фиксированного количества рядов, либо «row(s)» для неустановленного количества рядов
  • Слово «Remove» обозначает, что некоторое количество рядов удаляется из таблицы TPC-E, указанной Слепком базы данных. Ряд(ы) таблицы могут быть удалены только во Фрейме, в котором указано слово «Remove». Количество удаляемых рядов указывается во второй колонке Слепка базы данных либо при помощи либо «# row» для фиксированного количества рядов, либо «row(s)» для неустановленного количества рядов.

Примечание 1: знак звездочки, следующий за любым объектом в колонке заданного Фрейма, обозначает, что управление транзакцией, взаимодействие с базой данных или выполнение всего Фрейма зависит от условий. EGenTxnHarness определяет, при каких условиях Фрейм будет выполняться.

Примечание 2: В примере Слепка базы данных, приведенном выше, Транзакция базы данных начинается во Фрейме 1. Если выполняется Фрейм 2, Транзакция базы данных может быть откачена. Если выполняется Фрейм 3, Транзакция базы данных должна быть Подтверждена. Для таблицы CUSTOMER_ACCOUNT создается ссылка на колонку CA_BAL, и колонки CA_C_ID и CA_TAX_ST возвращены во Фрейме 1. Для таблицы HOLDING возвращается колонка H_PRICE и если выполяется Фрейм 2, то изменяется H_QTY. Дополнительно при выполнении Фрейма 2 из таблицы HOLDING условно удаляется набор рядов, и один ряд условно добавляется в таблицу HOLDING . В таблице TRADE_HISTORY добавляется ряд, если выполняется Фрейм 3.

Примечание 3: Семантики программирования, используемые для реализации требуемых методов доступа к заданным колонкам таблиц, не ограничены от исполнения операций, обычно связанных с другими методами доступа, до тех пор, пока реализация Фрейма функционально равнозначна назначенному Псевдокоду. Например, «select for update» и «select with UPDLOCK» являются применимыми реализациями метода доступа Reference.

3.2. Правила реализаций транзакций

3.2.1.1 В реализации Фрейма недопустимо использование любых предварительных сведений о методах создания данных EGen, или значениях, определенных в схеме базы данных для контрольного тестирования, за исключением констант EGen, перечисленных в таблице, приведенной ниже.

Примечание 1: Целью данного пункта является предотвращение использования Фреймами постоянных значений или других средств для ограничения обращений базы данных к статичным или нечасто используемым элементам данных. В основном использование любых сведений о частных случаях, характерных для контрольного тестирования, полученных при помощи входных данных Транзакции или Псевдокода Транзакции, но не предназначенных явным образом для Транзакции или Фрейма, запрещено.

3.2.1.2 Следующая таблица показывает инструмент использования констант EGen в качестве пределов во время создания набор значений для входных данный Транзакций или приема их выходных данных. Эти пределы констант предоставлены в спецификации для использования в Пункте 3.3 Реализация Фреймов.

Описание

Константа

Значение

Имя файла EGen

Broker-Volume

Минимальное число вводимых имен брокера

Min_broker_list_len

20

TxnHarnessStructs.h

Максимальное число вводимых имен брокера

max_broker_list_len

40

TxnHarnessStructs.h

Customer-Position

Максимальное число счетов на каждого клиента

max_acct_len

10

TxnHarnessStructs.h

Максимальное количество возвращаемых рядов TRADE_HISTORY

max_hist_len

30

TxnHarnessStructs.h

Market-Feed

Максимальное количество элементов на тиккере

max_feed_len

20

TxnHarnessStructs.h

Security-Detail

Минимальное число возвращаемых рядов DAILY_MARKET

min_day_len

5

TxnHarnessStructs.h

Максимальное число возвращаемых рядов DAILY_MARKET

max_day_len

20

TxnHarnessStructs.h

Максимальное число возвращаемых рядов FINANCIAL

max_fin_len

20

TxnHarnessStructs.h

Максимальное число возвращаемых рядов NEWS_ITEM

max_news_len

2

TxnHarnessStructs.h

Максимальное числ возвращаемы рядов COMPANY_COMPETITOR

max_comp_len

3

TxnHarnessStructs.h

Trade-Lookup

Максимальное число рядов TRADE, возвращаемых на Транзакцию.

TradeLookupMaxRows

20

MiscConsts.h

Максимальное число рядов TRADE, возвращаемых для Фрейма 1.

TradeLookupFrame1MaxRows

20

MiscConsts.h

Максимальное число рядов TRADE, возвращаемое для Фрейма 2.

TradeLookupFrame2MaxRows

20

MiscConsts.h

Максимальное число рядов TRADE,  возвращаемое для Фрейма 3.

TradeLookupFrame3MaxRows

20

MiscConsts.h

Максимальное число возвращаемых рядов TRADE _HISTORY

TradeLookupMaxTradeHistoryRowsReturned

3

MiscConsts.h

Trade-Status

Максимальное возвращаемое число рядов статуса торгов.

max_trade_status_len

50

TxnHarnessStructs.h

Trade-Update

Максимальное число рядов TRADE, возвращаемых для Транзакции.

TradeUpdateMaxRows

20

MiscConsts.h

Максимальное число рядов TRADE, возвращаемых для Фрейма 1.

TradeUpdateFrame1MaxRows

20

MiscConsts.h

Максимальное число рядов TRADE, возвращаемых для Фрейма 2.

TradeUpdateFrame2MaxRows

20

MiscConsts.h

Максимальное число рядов TRADE, возвращаемых для Фрейма 3.

TradeUpdateFrame3MaxRows

20

MiscConsts.h

Максимальное число возвращаемых рядов TRADE _HISTORY

TradeUpdateMaxTradeHistoryRowsReturned

3

MiscConsts.h

3.2.1.3 Весь обмен данными между Фреймами должен быть осуществлен EGenTxnHarness через исользование входных и выходных параметров, передаваемых в и из Фреймов.

Примечание 1: Целью данного пункта является предотвращение использования Фреймами глобальных переменных или других средств для хранения и получения информации между несколькими вызовами одного или разных Фреймов с целью избежания выполнения действий, необходимых в работе каждого отдельного вызова.

Примечание 2: Организатор теста может усовершенствовать каждый Фрейм при помощи кода, распаковывающего входные параметры, получаемые из EGenTxnHarness, и сжимающего выходные параметры, возвращаемые в EGenTxnHarness.

3.2.1.4 Каждая реализация Фрейма должна выполнять каждое взаимодействие с базой данных, указанное в Слепке базы данных Транзакции, используя обозначенный метод доступа.

3.2.1.5 Реализация Фрейма должна осуществлять доступ к любой колонке, обозначенной как Ссылка. Она также может иметь доступ к другим колонкам, которые не отмечены, как Ссылки. В отношении других взаимодействий с базой данных, Реализация Фрейма должна осуществлять все требуемые операции и/или возвращать все указанные значения колонок.

3.2.1.6 Реализация каждого Фрейма должна быть функционально равнозначна Псевдокоду, предоставляемому для этого Фрейма в Пункте 3.3. Функциональная равнозначность соблюдена, когда:

  • для заданного набора входных данных реализация создает те же выходные данные и выполняет те же изменения в состоянии базы данных, что и Псевдокод. Изменение в состоянии базы данных – это изменение таблицы или колонки таблицы TPC-E в результате использование любых из методов доступа «Изменить», «Добавить» или «Удалить», определенных в Слепке базы данных Транзакции.
  •  Все методы доступа в Слепке базы данных выполняются.
  •  Не выполняется никаких дополнительных методов доступа Изменить/Добавить/Удалить по отношению к какой либо таблице TPC-E.

Примечание: дополнительный метод «Ссылка» может быть исполнен по отношению к любой таблице TPC-E. Могут быть исполнены любые дополнительные методы по отношению к любому Определенному пользователем объекту.

3.2.1.7 Минимальной точностью для каждого расчета, выполняемого как часть Фрейма, должна быть максимальная точность всех отдельных элементов в этом расчете.

3.2.1.8 Каждый Фрейм и Транзакция имеют выходной параметр статуса, используемый для обозначения статуса исполнения Фрейма или Транзакции. Значение статуса 0 обозначает успешное выполнение. Отрицательное значение статуса обозначает ошибку, которая нарушит Выполнение Теста. Положительное ненулевое целое значение статуса обозначает предупреждение. Предупреждения означают, что был создан неожиданный результат, и Организатору и Аудитору следует исследовать неожиданный результат. Неожиданный результат может быть следствием редких, но корректных условий, или использования некорректной реализации, или ошибки выполнения. Если причиной предупреждения является последнее, оно должно рассматриваться как ошибка, нарушающая Выполнение теста.

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

3.2.1.9 Если используется монитор обработки транзакций (здесь и далее называемый TM), он должен быть коммерчески доступным программным продуктом, предоставляющим следующие возможности/функции:


Исполнение - TM должен обеспечивать:

  • приоретизацию запросов/обслуживания.
  • мультиплексирование/демультиплексирование запросов/обслуживания
  • автоматическую балансировку нагрузок
  • одновременное получение, постановку в очередь и исполнение запросов/обслуживания.


Безопасность - TM должен обеспечивать:

  •  возможность проверять и авторизовывать каждую службу в момент запроса этой службы.
  •  ограничение администраторских функций авторизованных пользователей.

Администрирование/Обслуживание - TM должен иметь предопределенную возможность производить централизованное, непрограммируемое (т.е должно быть реализовано в стандартном продукте и не требовать дополнительного программирования) и динамическое управление конфигурацией ресурсов TM, включая оборудование, сети, службы (одиночные и групповые), правила установки приоритетов в управлении очередями, и т.д.

Восстановление - TM также должен иметь возможность:

 

  •  публиковать коды ошибок приложения.
  •  обнаруживать и прерывать исполнение выполняющихся в течение длительного промежутка времени транзакций, основанных на предопределенных временных триггерах.

 

Прозрачность приложений – контекст(ы) сообщений, существующий между клиентской и серверной прикладными программами, должен управляться исключительно при помощи TM. Клиентская и серверная прикладные программы не должны иметь никаких сведений о контексте сообщения или нижележащем механизме обмена сообщениями, который обеспечивает этот контекст.

Примечание 1: ниже приведены примеры реализация, не соответствующих требованиям Прозрачности приложений.
Клиентская и серверная прикладные программы используют общий идентификатор (например, оснастку или указатель) для поддержания контекста соообщений для нескольких транзакций.

Когда количество очередей или равнозначный структур данных, используемых ТМ для обслуживания контекста сообщений между клиентской и серверной прикладными программами, меняется администрацией ТМ, требуется изменение и/или рекомпиляция клиентской и/или серверной прикладной программы.


Примечание 2: Целью данного пункта является побуждение к использованию коммерчески доступных Транзакционных мониторов общего назначения, и исключение программ специального назначения, разработанного для тестирований или другого ограниченного использования. Понятен факт того, что реализации возможностей и функций, описанных выше, варьируется между архитектурами, предоставляемыми поставщиками. Эти различия не являются препятствием к соответствию требованиям этого пункта.


3.2.2 Разделение Клиентов и создание входных данных Транзакций.

3.2.2.1 Если используется разделение клиентов, и Фрейм Вызывается Клиентом, EGenDriverCE будет применять следующие правила при любом создании идентификатора клиента, идентификатора счета или налогового идентификатора клиента:

  • 50% временных данных выбираются из диапазона клиентов раздела.
  • 50% временных данных выбираются из всего диапазона клиентов.

Если разделение клиентов не используется, или Фрейм не Вызывается Клиентом, EGenDriverCE будет создавать идентификаторы клиентов, идентификаторы счетов и налоговые идентификаторы клиентов из всего диапазона клиентов.

3.3 Транзакции
Контрольное тестирование TPC-E состоит из одиннадцати Транзакций и одной Транзакции очистки. Для создания разумно сбалансированной нагрузки, которая отображает реальное рабочее окружение, Транзакции должны осуществлять широкий охват системных функций. Десять Транзакций работают в конкретном сочетании для того, чтобы создать требуемую нагрузку, одновременно сохраняя среду тестирования простой, воспроизводимой и легко исполняемой. Одиннадцатая Транзакция не является частью Сочетания Транзакций, но исполняется через фиксированные интервалы. Эта транзакция, называемая «Data-Maintenance», имитирует административные обновления таблиц, которые не изменяются иным образом с помощью Транзакций в сочетании. Транзакция Очистки, называемая «Trade-Cleanup», служит для очистки ожидающих и отправленных торгов, которые могут существовать со времен более ранних выполнений.

Одной из ключевых характеристик производительности системы базы данных – это соотношение операций чтения и записи, создаваемых объемом нагрузки. Для моделирования подобного соотношения, TPC-E определило Транзакции с характеристиками только для чтения, равно как транзакции с характеристиками чтения и записи. Дополнительно, Транзакции осуществляют различную нагрузку на процессор.
Различные требования к частоте процессора, операций ввода-вывода и выполнения Транзакций дает возможность тестированию моделировать реальное окружение с высокой нагрузкой на процессор, одновременно поддерживая разумные нагрузки ввода-вывода в простой конфигурации тестирования.

Транзакции в сочетании могут быть сгруппированы по трем категориям:
Инициированная клиентом

  • Инициированная брокером
  • Вызванные рынком

   
В добавок к сочетанию транзакцй, описанному выше, тестирование описывает транзакцию Data-Maintenance, вызываемую через фиксированные интервалы времени, как описано в Пункте 6.3.3. Также определена транзакция Trade-Cleanup (см. Пункт 6.3.4), которая не может исполняться во время Выполнения теста, но должна исполняться однократно перед Выполнением Теста, если база данных не находится в ее состоянии изначального наполнения (т.е., если выполнялись любые предварительные запуски).

Следующая сводная таблица описывает базовые характеристики транзакций:

3.3.1 Транзакция Broker-Volume
Транзакция Broker-Volume предназначена для имитации ежеминутных внутренних бизнес-процессов брокерской фирмы. Примером Транзакции Broker-Volume может выступить менеджер, составляющий отчет о текущем потенциале производительности различных брокеров.

Broker-Volume вызывается EGenDriverCE и состоит из одного Фрейма. Транзакция осуществляет поиск ожидающих заявок по пределу для нахождения заявок, которые связаны с заданным списком брокеров, работающих с ценными бумагами заданного сектора. Стоимость каждой заявки рассчитывается исходя из предлагаемой цены BID и количества акций и добавляются к объему промежуточной суммы соответствующего брокера. В результате возвращается список брокеров с соответствующими промежуточными суммами, перечисленными в порядке убывания объема.

3.3.1.1 Параметры транзакции Broker-Volume
Входные данные транзакции Broker-Volume создаются кодом EGenDriverCE в CETxnInputGenerator.cpp, и структуры данных, определенные в TxnHarnessStructs.h, должны использоваться для связи входных и выходных параметров.


Параметры транзакции Broker-Volume:


3.3.1.2 Слепок базы данных транзакции Broker-Volume

Эта Транзакция работает в режиме только для чтения, и не вносит каких либо изменений в базу данных. Слепок базы данных Broker-Volume выглядит следующим образом:


3.3.1.3 Фрейм 1 из 1-го Транзакции Broker Volume

Все методы доступа, используемые во Фрейме 1 принадлежат к типу Return.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:

{
invoke (Broker-Volume_Frame-1)
if (list_len < 0) then
{
status = -111
}
}


Параметрые Фрейма 1 из 1-го Транзакции Broker-Volume:


 

Псевдокод Broker-Volume_Frame-1: Брокерские объемы



{

start transaction
// Should return 0 to 40 rows
select
   broker_name[] = B_NAME,
   volume[] = sum(TR_QTY * TR_BID_PRICE)
from
   TRADE_REQUEST,
   SECTOR,
   INDUSTRY
   COMPANY,
   BROKER,
   SECURITY
where
   TR_B_ID = B_ID and
   TR_S_SYMB = S_SYMB and
   S_CO_ID = CO_ID and
   CO_IN_ID = IN_ID and
   SC_ID = IN_SC_ID and
   B_NAME in (broker_list) and
   SC_NAME = sector_name
group by
   B_NAME
order by
   2 DESC

// row_count will frequently be zero near the start of a Test Run when
// TRADE_REQUEST table is mostly empty.
list_len = row_count
commit transaction

}

3.3.2 Транзакция Customer-Position

 

Транзакция Customer-Position вызывается EGenDriverCE. Она состоит из трех Фреймов, (Фреймы 2 и 3 являются взаимно исключающими). Клиент указывается либо при помощи идентификатора клиента, либо при помощи его налогового идентификатора. Если идентификатор клиента, переданный в Транзакцию, равен 0, то тогда для поиска идентификатора клиента используется его налоговый идентификатор. Извлекается детализированная информация о профиле клиента. Дополнительно, для каждого из счетов клиента возвращается значение баланса денежных средств на счет и суммарное текущее значение стоимости всех активов акций на счете.
Если запрашивается история торговой деятельности, то извлекается информация по десяти наименее давним торгам на одном из случайно выбранных счетов клиента.

3.3.2.1 Параметры Транзакции Customer-Position

Входные данные транзакции Customer-Position создаются кодом EGenDriverCE в CETxnInputGenerator.cpp, и структуры данных, определенные в TxnHarnessStructs.h, должны использоваться для связи входных и выходных параметров.

Customer-Position Transaction Parameters:

 

3.3.2.2 Слепок базы данных Транзакции Customer-Position

3.3.2.3 Фрейм 1 из 3-х Транзакции Customer-Position

Если входной параметр cust_id установлен в 0, Фрейм должен использовать входной параметр tax_id для поиска в таблице CUSTOMER идентификатора клиента. Фрейм извлекает детализированную информацию по клиенту и осуществляет поиск баланса денежных средств по каждому из счетов клиента и общее значение активов акций по каждому счету. Помимо детализированной клиентской информации, Фрейм возвращает список счетов с балансом денежных средств и активами на них, отсортированный по значению активов.

Методы доступа к базе данных, используемые во Фрейме 1 – это Reference и Return.

EGenTxnHarness управляет исполнением Фрейма 1 следующим образом:

  {
         invoke (Customer-Position_Frame-1)
         if (acct_len < 1) or (acct_len > max_acct_len) then
        {
                 status = -211
        )
  }

Параметры Фрейма 1 из 3-х Транзакции Customer-Position:


Псевдокод Customer-Position_Frame-1: Получение информации по всем активам клиента


{
      start transaction
      if (cust_id == null_cust_id) then {
           select
                cust_id = C_ID
            from
                CUSTOMER
            where
                C_TAX_ID = tax_id
       }

      select
           c_st_id = C_ST_ID,
           c_l_name = C_L_NAME,
           c_f_name = C_F_NAME,
           c_m_name = C_M_NAME,
           c_gndr = C_GNDR,
           c_tier = C_TIER,
           c_dob = C_DOB,
           c_ad_id = C_AD_ID,
           c_ctry_1 = C_CTRY_1,
           c_area_1 = C_AREA_1,
           c_local_1 = C_LOCAL_1,
           c_ext_1 = C_EXT_1,
           c_ctry_2 = C_CTRY_2,
           c_area_2 = C_AREA_2,
           c_local_2 = C_LOCAL_2,
           c_ext_2 = C_EXT_2,
           c_ctry_3 = C_CTRY_3,
           c_area_3 = C_AREA_3,
           c_local_3 = C_LOCAL_3,
           c_ext_3 = C_EXT_3,
           c_email_1 = C_EMAIL_1,
           c_email_2 = C_EMAIL_2
     from
           CUSTOMER
     where
           C_ID = cust_id

     // Should return 1 to max_acct_len (10).
     select first max_acct_len rows
         acct_id[]         = CA_ID,
         cash_bal[]      = CA_BAL,
         assets_total[]= ifnull((sum(HS_QTY * LT_PRICE)),0)

      from
         CUSTOMER_ACCOUNT left outer join
         HOLDING_SUMMARY on HS_CA_ID = CA_ID,
         LAST_TRADE
      where
         CA_C_ID = cust_id and
         LT_S_SYMB = HS_S_SYMB
     group by
         CA_ID, CA_BAL
     order by
         3 asc

     acct_len = row_count

}

3.3.2.4 Фрейм 2 из 3-х Транзакции Customer-Position

Этот Фрейм выполняется только если транзакционный параметр get_history установлен в значение TRUE. Используя идентификатор счета клиента, Фрейм должен совершить поиск в таблицах TRADE и TRADE_HISTORY и получить 30 рядов истории, которые соответствуют 10 наименее давним торгам, исполняемым на счете клиента. Для каждого события Фрейм должен вернуть значения T_ID, T_S_SYMB, T_QTY, TH_DTS и ST_NAME для всех событий в порядке убывания по дате, полученной в TH_DTS. Этот Фрейм завершает работу и подтверждает Транзакцию.

Методы доступа к базе данных, используемые во Фрейме 2 принадлежат к типу Return.

EGenTxnHarness управляет исполнение Фрейма 2 следующим образом:

{
       if (get_history == 1) then
      {
                 frame2.acct_id = frame1.acct_id[acct_id_idx]
                 invoke (Customer-Position_Frame-2)
                 if (hist_len < 1) or (hist_len > max_hist_len) then
                {
                         status = -221
                }
               exit
       }
}

Параметры Фрейма 2 из 3-х Транзакции Customer-Position:


Псевдокод Customer-Position_Frame-2: Получение истории торгов клиента


{
          // Should return 10 to 30 rows.
          select first 30 rows
                trade_id[] = T_ID,
                symbol[] = T_S_SYMB,
                qty[] = T_QTY,
                trade_status[] = ST_NAME,
                hist_dts[] = TH_DTS
          from
               (select first 10 rows
                     T_ID as ID
                 from
                     TRADE
                 where
                     T_CA_ID = acct_id
                 order by T_DTS desc) as T,
              TRADE,
              TRADE_HISTORY,
              STATUS_TYPE
         where
              T_ID = ID and
              TH_T_ID = T_ID and
              ST_ID = TH_ST_ID
         order by
              TH_DTS desc

         hist_len = row_count

         commit transaction
}


 

3.3.2.5 Фрейм 3 из 3-х Транзакции Customer-Position

Этот Фрейм исполняется только если для входного параметра get_history установлено значение FALSE. Этот Фрейм подтверждает Транзакцию, начатую во Фрейме 1, и возвращает статус.
Во Фрейме 3 не используется методов доступа к базе данных. Этот Фрейм лишь использует операции управления Транзакцией.
EGenTxnHarness управляет исполнением Фрейма 3 следующим образом:

  {
          if (get_history != 1)
          {
                    invoke (Customer-Position_Frame-3)
           }
   }


Параметры Фрейма 3 из 3-х Транзакции Customer-Position:


Customer-Position_Frame-3: Окончание транзакции базы данных


{

      commit transaction
}

3.3.3 Транзакция Market-Feed

Market-Feed вызывается EGenDriverMEE. Она состоит из единственного Фрейма. Транзакция получает информацию по последней торговой деятельности (символ, цена, величина и т.д.) от биржи. Как результат обработки информации на биржевом табло, стоимость ценных бумаг будет расти или убывать. Эти изменения цен могут вызвать срабатывание ожидающих заявок по пределам. В случае срабатывания выполняется обработка заявки по пределу путем отправки подробностей торговой заявки в MEE через интерфейс SendToMarketFromFrame.

Каждый тиккер Market-Feed состоит из 20 записей (константа max_feed_len в TxnHarnessStructs.h). Десять из этих записей являются результатом торгов, отправленных в MEE этой брокерской фирмой. Остальные записи генерируются MEE для имитации предоставления отчетов о торгах другими брокерскими фирмами. В транзакции Market-Feed допустима обработка любого количества элементов табло (от одного до всех) в каждую Транзакцию базы данных.

3.3.3.1 Параметры Транзакции Market-Feed
Входные данные Транзакции Market-Feed генерируются при помощи кода EGenDriverMEE в MEE.cpp. Структуры данных, определенные в TxnHarnessStructs.h должны использоваться для связи входных и выходных параметров.

          Параметры Транзакции Market-Feed:

3.3.3.2 Слепок базы данных Транзакции Market-Feed

Слепок базы данных Транзакции Market-Feed представлен следующим образом:


3.3.3.3 Фрейм 1 из 1-го Транзакции Market-Feed
             Используя записи из списка табло, Фрейм предназначается для:
  •  дополнения рядов таблицы LAST_TRADE новыми ценами, новыми дневными объемами и новыми датами последних торгов.
  •  обнаружения всех ожидающих заявок по пределам, которые должны сработать по данной цене на тиккере, их обработка и отправка в MEE

Методы доступа к базе данные, используемые во Фрейме 1, это Modify, Add, Reference, Remove и Return.

EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:

  {
       invoke (Market-Feed_Frame-1)
  }

Параметры Фрейма 1 из 1-го Транзакции Market-Feed:



Псевдокод Market-Feed_Frame-1: Запись стоимостей акций и обработка всех ожидающих запросов по уровню, которые срабатывают по цене на тиккере.

{
            declare now_dts DATETIME
            declare TradeRequestBuffer[]
            declare req_price_quote S_PRICE_T
            declare req_trade_id TRADE_T
            declare req_trade_qty S_QTY_T
            declare req_trade_type CHAR(3)
            declare rows_updated int
            declare rows_sent int

            get_current_dts(now_dts)
            rows_updated = 0

            for (i = 1, i<=max_feed_len, i++) {
                start transaction

                rows_sent = 0

                update
                   LAST_TRADE
                set
                   LT_PRICE = price_quote[i],
                   LT_VOL = LT_VOL + trade_qty[i],
                   LT_DTS = now_dts
                where
                   LT_S_SYMB = symbol[i]

                rows_updated = rows_updated + row_count

               declare request_list cursor for
                   select
                         TR_T_ID,
                         TR_BID_PRICE,
                         TR_TT_ID,
                         TR_QTY
                   from
                         TRADE_REQUEST
                   where
                         TR_S_SYMB = symbol[i] and (
                           (TR_TT_ID = type_stop_loss and
                           TR_BID_PRICE >= price_quote[i]) or
                           (TR_TT_ID = type_limit_sell and
                             TR_BID_PRICE <= price_quote[i]) or
                           (TR_TT_ID = type_limit_buy and
                            TR_BID_PRICE >= price_quote[i])
                            )

               open request_list
               fetch from
                  request_list
               into
                  req_trade_id,
                  req_price_quote,
                  req_trade_type,
                  req_trade_qty
               do until (request_list.end_of_cursor) {
                    update
                        TRADE
                    set
                        T_DTS = now_dts,
                        T_ST_ID = status_submitted
                    where
                        T_ID = req_trade_id

                    delete
                        TRADE_REQUEST
                    where
                        current of request_list

                    insert into
                        TRADE_HISTORY
                    values (
                        TH_T_ID = req_trade_id,
                        TH_DTS = now_dts,
                        TH_ST_ID = status_submitted
 )

                    TradeRequestBuffer[rows_sent].symbol = symbol[i]
                    TradeRequestBuffer[rows_sent].trade_id = req_trade_id
                    TradeRequestBuffer[rows_sent].price_quote = req_price_quote
                    TradeRequestBuffer[rows_sent].trade_qty = req_trade_qty
                    TradeRequestBuffer[rows_sent].trade_type = req_trade_type
                    rows_sent = rows_sent + 1

                    fetch from
                    request_list
              into
                    req_trade_id,
                    req_price_quote,
                    req_trade_type,
                    req_trade_qty
} /* end of cursor fetch loop */
close request_list
commit transaction

send_len = send_len + rows_sent

//send triggered trades to the Market Exchange Emulator
//via the SendToMarket interface. This should be done
//after the related database changes have committed
For (j=0; j
  {
                     SendToMarketFromFrame(TradeRequestBuffer[i].symbol,
                                                              TradeRequestBuffer[i].trade_id,
                                                              TradeRequestBuffer[i].price_quote,
                                                              TradeRequestBuffer[i].trade_qty,
                                                              TradeRequestBuffer[i].trade_type);
   }
   } /* end of ticker loop */


 if (rows_updated != max_feed_len) then
   {
 status = -311
 }

}



3.3.4     Транзакция Market-Watch
Транзакция Market-Watch предназначена для имитации процесса наблюдения за общей производительностью рынка путем предоставления клиенту возможности отслеживать текущую дневную тенденцию (растущую или убывающую) набора ценных бумаг. Набор отслеживаемых ценных бумаг может быть основан на текущих активах клиента, намерениях клиента о будущих приобретениях ценных бумаг, конкретной области индустрии.

Market-Watch вызывается EGenDriverCE. Она состоит из единственного Фрейма. Эта Транзакция подсчитывает процентное изменение значения рыночной капитализации набора ценных бумаг по отношению цены на момент закрытия выбранного дня к текущей рыночной стоимости. Выбранный день выбирается неравномерно из 1305 дней рыночных данных, загруженных во время начального наполнения базы данных. Расчет выполнятся путем рассмотрения цены закрытия в выбранный день всех ценных бумаг в списке и умножения ее на количество торгуемых акций. Этот результат добавляется к промежуточной сумме капитализации закрывающегося рынка выбранного дня. Дополнительно, текущая стоимость всех ценных бумаг в списке умножается на число торгуемых пакетов акций. Этот результат добавляется к промежуточной сумме текущей рыночной капитализации. Возвращается разница между общей рыночной капитализации на момент закрытия выбранного дня к общей текущей, выраженная в процентах.
Транзакция обеспечивает эти расчеты рыночного наблюдения по группе ценных бумаг, выбранных по следующему списку критериев:
  •  Prospective-Watch – Набор ценных бумаг выбирается, используя все ценные бумаги в списке наблюдения клиента. Правила для определения диапазона доступных клиентов и соответствующих списков наблюдения описаны в Пункте 3.2.2.1.
  •  Industry-Watch – Набор ценных бумаг выбирается, используя все ценные бумаги в индустрии, принадлежащие компаниям в обозначенном диапазоне. Название индустрии выбирается случайным образом из возможных названий индустрии, используя равномерное распределение.
  •  Portfolio-Watch – Набор ценных бумаг выбирается, используя все ценные бумаги, находящиеся в активе на счете клиента. Правила для определения диапазона доступных клиентов описаны в Пункте 3.3.1.1. Идентификатор счета клиента выбирается случайно из всех возможных счет этого клиента, используя равномерное распределение.

3.3.4.1   Параметры Транзакции Market-Watch
Входные данные для транзакции Market-Watch создаются кодом EGenDriverCE в CETxnInputGenerator.cpp. Структуры данных, определенные в TxnHarnessStructs.h должны использоваться для связи входных и выходных параметров.


            Параметры Транзакции Market-Watch:

3.3.4.2     Слепок базы данных Транзакции Market-Watch
                Слепок базы данных Транзакции Market-Watch представлен следующим образом:

3.3.4.3 Фрейм 1 из 1-го Транзакции Market-Watch
             Метод доступа к базе данных, используемый во Фрейме 1 – это Reference.
             EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:
               {
                    if (acct_id != 0) or (cust_id != 0) or (industry_name != ««) then
                    {
                           invoke (Market-Watch_Frame-1)
                    }
                    else
                    {
                           status = -411
                    }
              }

           Параметры Фрейма1 из 1-го Транзакции Market-Watch:



Market-Watch_Frame-1 Pseudo-code: Построение списка ценных бумаг и расчет процентного соотношения


{
         start transaction
         if (cust_id != 0) then {
            declare stock_list cursor for
            select
                 WI_S_SYMB
            from
                 WATCH_ITEM,
                 WATCH_LIST
           where
                 WI_WL_ID = WL_ID and
                 WL_C_ID = cust_id
      else if (industry_name != "") then {
          declare stock_list cursor for
            select
               S_SYMB
            from
               INDUSTRY,
               COMPANY,
               SECURITY
            where
               IN_NAME = industry_name and
               CO_IN_ID = IN_ID and
               CO_ID between (starting_co_id and ending_co_id) and
               S_CO_ID = CO_ID
         } else if (acct_id != 0) then {
              declare stock_list cursor for
            select
               HS_S_SYMB
            from
               HOLDING_SUMMARY
           where
               HS_CA_ID = acct_id
}
          old_mkt_cap = 0.0
          new_mkt_cap = 0.0
          pct_change = 0.0
          open stock_list
          do until (stock_list.end_of_cursor) {
             fetch from
                 stock_list cursor
             into
                 symbol

             select
                 new_price = LT_PRICE
              from
                  LAST_TRADE
             where
                  LT_S_SYMB = symbol

              select
                  s_num_out = S_NUM_OUT
               from
                  SECURITY
             where
                  S_SYMB = symbol

   // Closing price for this security on the chosen day.
   select
       old_price = DM_CLOSE
   from
       DAILY_MARKET
   where
       DM_S_SYMB = symbol and
       DM_DATE = start_date

  old_mkt_cap += s_num_out * old_price
  new_mkt_cap += s_num_out * new_price
  }
  if (old_mkt_cap != 0) then
  {
 // value of 0.00 for pct_change is valid
  pct_change = 100 * (new_mkt_cap / old_mkt_cap - 1)
  }
   else
  {
  // no rows found, this can happen rarely when an account has no holdings
  pct_change = 0.0
  status = +412
  }
  close stock_list
  commit transaction

}


3.3.5 Транзакция Security-Detail

Security-Detail вызывается EGenDriverCE. Она состоит из единственного Фрейма. Для заданных ценных бумаг Транзакция будет возвращать детализированную информацию по ценным бумагам и компании, список конкурентов компании, текущие и исторические финансовые данные и недавние новостные сюжеты о компании.

3.3.5.1 Параметры Транзакции Security-Detail

Входные данные для Транзакции Security-Detail создаются кодом EGenDriverCE в CETxnInputGenerator.cpp и структуры данных, определенные в TxnHarnessStructs.h должны использоваться для связи входных и выходных параметров.


              Параметры Транзакции Security-Detail:

3.3.5.2 Слепок базы данных Транзакции Security-Detail

Слепок базы данных Транзакции Security-Detail представлен следующим образом:



3.3.5.3 Фрейм 1 из 1-го Транзакции Security Detail

Методы доступа к базе данных, используемые во Фрейме 1 – это Возврат и Ссылка.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:

{
               invoke (Security-Detail_Frame-1)
               if (day_len < min_day_len) or (day_len > max_day_len) then
              {
                    status = -511
              }
              else if (fin_len != max_fin_len) then
              {
                    status = -512
              }
              else if (news_len != max_news_len) then
              {
                    status = -513
              }
}



       Параметры Фрейма 1 из 1-го Транзакции Security-Detail:

                  

Псевдокод Security-Detail_Frame-1: Получение всех сведений по ценным бумагам

{
       Declare co_id IDENT_T
       start transaction

       select
            s_name = S_NAME,
            co_id = CO_ID,
            co_name = CO_NAME,
            sp_rate = CO_SP_RATE
            ceo_name = CO_CEO,
            co_desc = CO_DESC,
            open_date = CO_OPEN_DATE,
            co_st_id = CO_ST_ID,
            co_ad_line1 = CA.AD_LINE1,
            co_ad_line2 = CA.AD_LINE2,
            co_ad_town = ZCA.ZC_TOWN,
            co_ad_div = ZCA.ZC_DIV,
            co_ad_zip = CA.AD_ZC_CODE,
            co_ad_ctry = CA.AD_CTRY,
            num_out = S_NUM_OUT,
            start_date = S_START_DATE,
            exch_date = S_EXCH_DATE,
            pe_ratio = S_PE,
            52_wk_high = S_52WK_HIGH,
            52_wk_high_date = S_52WK_HIGH_DATE,
            52_wk_low = S_52WK_LOW,
            52_wk_low_date = S_52WK_LOW_DATE,
            divid = S_DIVIDEND,
            yield = S_YIELD,
            ex_ad_div = ZEA.ZC_DIV,
            ex_ad_ctry = EA.AD_CTRY
            ex_ad_line1 = EA.AD_LINE1,
            ex_ad_line2 = EA.AD_LINE2,
            ex_ad_town = ZEA.ZC_TOWN,
            ex_ad_zip = EA.AD_ZC_CODE,
            ex_close = EX_CLOSE,
            ex_desc = EX_DESC,
            ex_name = EX_NAME,
            ex_num_symb = EX_NUM_SYMB,
            ex_open = EX_OPEN
      from
            SECURITY,
            COMPANY,
           ADDRESS CA,
           ADDRESS EA,
           ZIP_CODE ZCA,
           ZIP_CODE ZEA,
           EXCHANGE
     where
           S_SYMB = symbol and
           CO_ID = S_CO_ID and
           CA.AD_ID = CO_AD_ID and
           EA.AD_ID = EX_AD_ID and
           EX_ID = S_EX_ID and
           ca.ad_zc_code = zca.zc_code and
           ea.ad_zc_code =zea.zc_code

     // Should return max_comp_len (3) rows
     select first max_comp_len rows
          cp_co_name[] = CO_NAME,
          cp_in_name[] = IN_NAME
     from
         COMPANY_COMPETITOR, COMPANY, INDUSTRY
    where
         CP_CO_ID = co_id and
         CO_ID = CP_COMP_CO_ID and
         IN_ID = CP_IN_ID

    // Should return max_fin_len (20) rows
    select first max_fin_len rows
         fin[].year            = FI_YEAR,
         fin[].qtr               = FI_QTR,
         fin[].strart_date = FI_QTR_START_DATE,
         fin[].rev              = FI_REVENUE,
         fin[].net_earn     = FI_NET_EARN,
         fin[].basic_eps    = FI_BASIC_EPS,
         fin[].dilut_eps     = FI_DILUT_EPS,
         fin[].margin         = FI_MARGIN,
         fin[].invent          = FI_INVENTORY,
         fin[].assets          = FI_ASSETS,
         fin[].liab               = FI_LIABILITY,
         fin[].out_basic     = FI_OUT_BASIC,
         fin[].out_dilut      = FI_OUT_DILUT
    from
         FINANCIAL
    where
         FI_CO_ID = co_id
    order by
         FI_YEAR asc,
         FI_QTR

     fin_len = row_count

     // Should return max_rows_to_return rows
    // max_rows_to_return is between 5 and 20
    select first max_rows_to_return rows
        day[].date = DM_DATE,
        day[].close = DM_CLOSE,
        day[].high = DM_HIGH,
        day[].low = DM_LOW,
        day[].vol = DM_VOL
    from
         DAILY_MARKET
    where
         DM_S_SYMB = symbol and
         DM_DATE >= start_day
    order by
         DM_DATE asc

    day_len = row_count

    select
         last_price = LT_PRICE,
         last_open = LT_OPEN_PRICE,
         last_vol = LT_VOL
    from
         LAST_TRADE
    where
         LT_S_SYMB = symbol

   // Should return max_news_len (2) rows
   if (access_lob_flag)
     select first max_news_len rows
          news[].item = NI_ITEM,
          news[].dts = NI_DTS,
          news[].src = NI_SOURCE,
          news[].auth = NI_AUTHOR,
          news[].headline = “”,
          news[].summary = “”
     from
          NEWS_XREF,
          NEWS_ITEM
     where
         NI_ID = NX_NI_ID and
         NX_CO_ID = co_id
     else
     select first max_news_len rows
         news[].item = “”,
         news[].dts = NI_DTS,
         news[].src = NI_SOURCE,
         news[].auth = NI_AUTHOR,
         news[].headline = NI_HEADLINE,
         news[].summary = NI_SUMMARY
     from
         NEWS_XREF,
         NEWS_ITEM
     where
         NI_ID = NX_NI_ID and
         NX_CO_ID = co_id

      news_len = row_count

     commit transaction

}


3.3.6 Транзакция Trade-Lookup

Транзакция Trade-Lookup предназначена для имитации изъятия информации либо клиентом, либо брокером для получения ответов на их вопросы, касающиеся торгов. Различные виды торгов выбраны таким образом, чтобы работа представляла собой:
  •  Осуществление общего анализа рынка
  •  обзор торгов за период времени, предшествующий последней выписке из счета
  •  анализ последних событий по конкретным ценным бумагам
  •  анализ истории счета конкретного клиента.
Trade-Lookup вызывается EGenDriverCE. Она состоит из четырех взаимно исключающих Фреймов. Каждый Фрейм реализует различную технику поиска исторических данных по торгам.

Фрейм 1 применяет список идентификаторов торгов. Возвращается информация по каждому из торгов в списке.

Фрейм 2 применяет в качестве входных данных идентификатор счета клиента, начальную отметку времени, конечную отметку времени и число торгов (N). Он возвращает информацию по первым N торгам на указанном счете клиента между начальной и конечной отметками времени включительно.

Фрейм 3 применяет в качестве входных данных символ ценных бумаг, начальную отметку времени, конечную отметку времени и число торгов (N). Он возвращает информацию по первым N торгм по заданным ценным бумагам между начальной и конечной отметками времени включительно.

Фрейм 4 применяет в качестве входных данных идентификатор счета клиента и отметку времени. Определяются первые торги на этом счете клиента в отмеченный момент времени или после него. Затем возвращаются максимум 20 исторических изменений в активах по идентификатору этих торгов.

3.3.6.1 Параметры Транзакции Trade-Lookup

Входные данные Транзакции Trade-Lookup генерируются кодом EGenDriverCE в CETxnInputGenerator.cpp. Структуры данных, определенные в TxnHarnessStructs.h должны использоваться для связи входных и выходных параметров.

             Параметры Транзакции Trade-Lookup:

3.3.6.2 Слепок базы данных Транзакции Trade-Lookup

Слепок базы данных Транзакции Trade-Lookup представлен следующим образом:


3.3.6.3 Фрейм 1 из 4-х Транзакции Trade-Lookup

Первый Фрейм предназначен для получения информации по заданному массиву идентификаторов торгов.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:

{
        if( frame_to_execute == 1 )
        {
            invoke (Trade-Lookup_Frame-1)
            if (num_found != max_trades) then
           {
                  status = -611
           }
           frame_executed = 1
}

[...]

Параметры Фрейма 1 из 4-х Транзакции Trade-Lookup:




Псевдокод Trade-Lookup_Frame-1: Получение информации о торгах по каждому идентификатору торгов в массиве trade_id


{
         declare i int
         start transaction

         num_found = 0

         for (i = 0; i++; i < max_trades) do {
              // Get trade information
             // Should only return one row for each trade
            select
                  bid_price[i] = T_BID_PRICE,
                  exec_name[i] = T_EXEC_NAME,
                  is_cash[i] = T_IS_CASH,
                  is_market[i] = TT_IS_MRKT,
                  trade_price[i] = T_TRADE_PRICE
            from
                  TRADE,
                  TRADE_TYPE
           where
                  T_ID = trade_id[i] and
                  T_TT_ID = TT_ID

           num_found = num_found + row_count

          // Get settlement information
         // Should only return one row for each trade
          select
              settlement_amount[i]             = SE_AMT,
              settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
              settlement_cash_type[i]         = SE_CASH_TYPE
         from
              SETTLEMENT
         where
              SE_T_ID = trade_id[i]

         // get cash information if this is a cash transaction
        // Should only return one row for each trade that was a cash transaction
        if (is_cash[i]) then {
          select
              cash_transaction_amount[i] = CT_AMT,
              cash_transaction_dts[i] = CT_DTS,
              cash_transaction_name[i] = CT_NAME
         from
              CASH_TRANSACTION
         where
              CT_T_ID = trade_id[i]
         }


       // read trade_history for the trades
      // Should return 2 to 3 rows per trade
      select first 3 rows
                trade_history_dts[i][] = TH_DTS,
                trade_history_status_id[i][] = TH_ST_ID
      from
                TRADE_HISTORY
      where
               TH_T_ID = trade_id[i]
      order by
               TH_DTS
      } // end for loop

      commit transaction
}


3.3.6.4 Фрейм 2 из 4-х Транзакции Trade-Lookup

Второй Фрейм возвращает информацию о первых N торгах, выполненных с указанного счета клиента между заданными начальным и конечным моментами времени. Если заданный начальный момент времени слишком близок к конечному, то возможно, что будет возвращено количество торгов меньшее, чем N.
EGenTxnHarness управляет выполнением Фрейма 2 следующим образом:

[...]
           else if( frame_to_execute == 2 )
           {
               invoke (Trade-Lookup_Frame-2)
               if (num_found < 0) then
              {
                    status = -621
              }
              else if (num_found == 0) then
              {
                   // Can happen rarely in large databases when an account has no trades
                  // in the last 4 days
                  status = +621
              }
              frame_executed = 2
          }

[...]

        Параметры Фрейма 2 из 4-х Транзакци Trade-Lookup:



Псевдокод Фрейма 2 Транзакции Trade-Lookup_Frame-2: Получение информации по торгам по первым N торгам на указанном счете клиента, начиная с заданного момента времени.

{
        declare i int
        start transaction

        // Get trade information
       // Should return between 0 and max_trades rows
       select first max_trades rows
             bid_price[] = T_BID_PRICE,
             exec_name[] = T_EXEC_NAME,
             is_cash[] = T_IS_CASH,
             trade_list[] = T_ID,
             trade_price[] = T_TRADE_PRICE
       from
             TRADE
      where
             T_CA_ID = acct_id and
             T_DTS >= start_trade_dts and
             T_DTS <= end_trade_dts
      order by
             T_DTS asc

      num_found = row_count

      // Get extra information for each trade in the trade list.
      for (i = 0; i < num_found; i++) {
     // Get settlement information
    // Should return only one row for each trade
   select
       settlement_amount[i] = SE_AMT,
       settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
       settlement_cash_type[i] = SE_CASH_TYPE
   from
       SETTLEMENT
  where
       SE_T_ID = trade_list[i]

    // get cash information if this is a cash transaction
   // Should return only one row for each trade that was a cash transaction
   if (is_cash[i]) then {
   select
        cash_transaction_amount[i] = CT_AMT,
        cash_transaction_dts[i] = CT_DTS
        cash_transaction_name[i] = CT_NAME
   from
        CASH_TRANSACTION
   where
        CT_T_ID = trade_list[i]
  }

     // read trade_history for the trades
    // Should return 2 to 3 rows per trade
      select first 3 rows
          trade_history_dts[i][] = TH_DTS,
          trade_history_status_id[i][] = TH_ST_ID
      from
         TRADE_HISTORY
     where
         TH_T_ID = trade_list[i]
     order by
         TH_DTS

    } // end for loop

     commit transaction
}


3.3.6.5 Фрейм 3 из 4-х Транзакции Trade-Lookup

Третий Фрейм возвращает информацию о первых N торгах по указанным ценным бумагам за период между заданными начальным и конечным моментами времени. Если заданное время начала слишком близко к заданному моменту конца, то возможно, что будет возвращена информация по менее, чем N.
EGenTxnHarness управляет выполнением Фрейма 3 следующим образом:

[...]
               else if( frame_to_execute == 3 )
               {
                        invoke (Trade-Lookup_Frame-3)
                        if (num_found < 0) then
                       {
                                   status = -631
                       }
                       else if (num_found == 0) then
                       {
                          // Can happen rarely in large databases
                          status = +631
                       }
                       frame_executed = 3
               }
}


Параметры Фрейма 3 из 4-х Транзакции Trade-Lookup:




Псевдокод Trade-Lookup_Frame-3: Получение списка N торгов, осуществленных по определенным ценным бумагам, начиная с заданного момента времени.

{
                declare i int
                start transaction

               // Should return between 0 and max_trades rows.
               select first max_trades rows
                    acct_id[] = T_CA_ID,
                    exec_name[] = T_EXEC_NAME,
                    is_cash[] = T_IS_CASH,
                    price[] = T_TRADE_PRICE,
                    quantity[] = T_QTY,
                    trade_dts[] = T_DTS,
                    trade_list[] = T_ID,
                    trade_type[] = T_TT_ID
              from
                    TRADE
              where
                    T_S_SYMB = symbol and
                    T_DTS >= start_trade_dts and
                    T_DTS <= end_trade_dts
                    // The max_acct_id “where” clause is a hook used for engineering purposes
                   // only and is not required for benchmark publication purposes.
                  // T_CA_ID <= max_acct_id
             order by
                   T_DTS asc

             num_found = row_count

                   // Get extra information for each trade in the trade list.
                  for (i = 0; i < num_found; i++) {
                 // Get settlement information
                // Should return only one row for each trade
            select
                settlement_amount[i]             = SE_AMT,
                settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
                settlement_cash_type[i]         = SE_CASH_TYPE
            from
                SETTLEMENT
           where
                SE_T_ID = trade_list[i]

            // get cash information if this is a cash transaction
            // Should return only one row for each trade that was a cash transaction
              if (is_cash[i]) then {
           select
               cash_transaction_amount[i] = CT_AMT,
               cash_transaction_dts[i] = CT_DTS
           cash_transaction_name[i] = CT_NAME
               from
                 CASH_TRANSACTION
              where
                 CT_T_ID = trade_list[i]
         }

           // read trade_history for the trades
          // Should return 2 to 3 rows per trade
          select first 3 rows
                trade_history_dts[i][] = TH_DTS,
                trade_history_status_id[i][] = TH_ST_ID
         from
                TRADE_HISTORY
         where
                TH_T_ID = trade_list[i]
         order by
                TH_DTS asc

         } // end for loop

     commit transaction
}


3.3.6.6 Фрейм 4 из 4-х Транзакции Trade-Lookup

Четвертый Фрейм определяет первые торги на указанном счете клиента в заданный момент времени или после него. Затем возвращается до 20 первых рядов HOLDING_HISTORY с соответствующим идентификатором торгов. Если заданное время слишком близко к исторической дате торгов, то возможно, что не будет найдено ни одних соответствующих торгов по указанному счету клиента.

EGenTxnHarness управляет выполнением Фрейма 4 следующим образом:

[...]
            else if( frame_to_execute == 4 )
            {
                invoke (Trade-Lookup_Frame-4)
                frame_executed = 4
            }
[...]

Параметры Фрейма 4 из 4-х Транзакции Trade-Lookup:




Псевдокод Trade-Lookup_Frame-4: Возврат информации HOLDING_HISTORY по конкретному идентификатору торгов.

{
            start transaction

            select first 1 row
               trade_id = T_ID
            from
               TRADE
            where
               T_CA_ID = acct_id and
               T_DTS >= start_trade_dts
            order by
               T_DTS asc

            if (row_count == 0) then
           {
                status = +641
           }
           // The trade_id is used in the subquery to find the original trade_id
          // (HH_H_T_ID), which then is used to list all the entries.

         // Should return 0 to (capped) 20 rows.
          select first 20 rows
                holding_history_id[]           = HH_H_T_ID,
                holding_history_trade_id[] = HH_T_ID,
                quantity_before[]                = HH_BEFORE_QTY,
                quantity_after[]                   = HH_AFTER_QTY
          from
                HOLDING_HISTORY
         where
                HH_H_T_ID in
                  (select
                      HH_H_T_ID
                    from
                      HOLDING_HISTORY
                    where
                   HH_T_ID = trade_id)

         num_found = row_count

         commit transaction
}


3.3.7    Транзакция Trade-Order

Транзакция Trade-Order предназначена для имитации процесса покупки или продажи ценных бумаг Клиентом, Брокером или авторизованным третьим лицом. Если лицо, выполняющее торговую заявку, не является владельцем счета, Транзакцией будет проверено, что это лицо имеет соответствующую авторизацию на выполнение этой торговой заявки. Транзакция позволяет человеку, осуществляющему торги, производить покупки, продажи по текущей рыночной цене или ограниченные покупки и продажи по запрошенной цене. Транзакция также предоставляет оценку финансовых последствий вероятных торгов, показывая данные о прибыли/убытках, налоговых вычетах и ожидаемых комиссионных платежах. Это позволяет торгующему оценить желанность вероятных торгов ценными бумагами прежде, чем подтвердить или отменить торги.
Транзакция Trade-Order вызывается EGenDriverCE. Она состоит из шести Фреймов. Транзакция начинается с передачи в Транзакцию идентификатора счета клиента с целью получения информации о клиенте, счете клиента и брокере, обслуживающем счет.e broker for the account.
Затем Транзакция проверяет, что человек, выполняющий торги, авторизован для совершения такиех действий на указанном счете. Если исполнитель не авторизован, то тогда Транзакция откатывается. Однако, во время выполнения контрольного тестирования CE всегда будет генерировать авторизованных исполнителей.
Следующим шагом станет оценка общего финансового эффекта от осуществления торгов. В случае заявок по уровню в оценке используется запрошенная стоимость; в случае заявок по рынку, запрошенная стоимость устанавливается равной текущей рыночной стоимости ценных бумаг, и это значение используется в оценке. Оценка включает в себя влияние, которое окажут заявленные торги на существующие активы (например, продажа существующих длинных позиций или закрытие существующих коротких позиций) Если в результате этих торгов будет получена прибыль, то будут рассчитаны налоги на полученный капитал. Также подсчитываются административные платежи и брокерская комиссия за осуществление торгов. Если торги осуществлены по маржинальной схеме, то оцениваются общие активы клиента на счете. Вся информация, перечисленная выше, используется для записи заявки.
После завершения описанной обработки, выбирается небольшой процент Транзакций Trade-Order для имитации либо отмены заявки либо состояния ошибки путем отката всех внесенных изменений. Все остальные Транзакции Trade-Order подтверждаются. После успешного Подтверждения рыночной заявки, EGenTxnHarness отправляет заявку на торги в соответствующий MEE.

3.3.7.1   Параметры Транзакции Trade-Order

Входные данные для Транзакции Trade-Order создаются кодом EGenDriverCE в CETxnInputGenerator.cpp. Структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров..


             Параметры Транзакции Trade-Order:




3.3.7.2   Слепок базы данных Транзакции Trade-Order

Эта Транзакция содержит сочетание методов доступа Add, Reference и Return. Слепок базы данных Транзакции Trade-Order представлен следующим образом:



3.3.7.3   Фрейм 1 из 6-и Транзакции Trade-Order

Первый Фрейм предназначен для получения информации о клиенте, счете клиента и его брокере.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:

{
      invoke (Trade-Order_Frame-1)
}

     Парамерты Фрейма 1 из 6-ти Транзакции Trade-Order:



Псевдокод Trade-Order_Frame-1: Получение информации о клиенте, счете клиента и его брокере.

{
          start transation

          // Get account, customer, and broker information
          select
              acct_name = CA_NAME,
              broker_id = CA_B_ID,
              cust_id = CA_C_ID,
              tax_status = CA_TAX_ST
          from
              CUSTOMER_ACCOUNT
         where
              CA_ID = acct_id

          if (row_count == 0) then
          {
               status = -711
          }

          select
               cust_f_name = C_F_NAME,
               cust_l_name = C_L_NAME,
               cust_tier       = C_TIER,
               tax_id           = C_TAX_ID
          from
               CUSTOMER
          where
               C_ID = cust_id

         select
               broker_name = B_NAME
         from
               BROKER
        where
           B_ID = broker_id
}

3.3.7.4   Фрейм 2 из 6-ти Транзакции Trade-Order

Второй Фрейм выполняется в случае, если имя, фамилия, налоговый идентификатор вызвавшего Транзакцию не соответствует имени, фамилии, налоговому идентификатору клиента, полученным во Фрейме 1. Фрейм 2 предназначен для проверки разрешений исполнителя на создание торговых заявок на заданном счете клиента.

Все методы доступа, используемые во Фрейме 2 - это References.
{
        if (exec_l_name != cust_l_name or
             exec_f_name != cust_f_name or
             exec_tax_id != tax_id) then
       {
            invoke (Trade-Order_Frame-2)
            if (status < 0) then
           {
              // This code is here for “completeness”.
             // During the benchmark execution the CE always
            // generates an executor with valid permissions on
           // the account.
               return error
           }
        }
}

     Параметры Фрейма 2 из 6-ти Транзакции Trade-Order:



Псевдокод Trade-Order_Frame-2 Pseudo-code : Проверка разрешений исполнителя.

{
         select
             
ap_acl = AP_ACL
         from
             
ACCOUNT_PERMISSION
         where
            
  AP_CA_ID = acct_id and
              AP_F_NAME = exec_f_name and
              AP_L_NAME = exec_l_name and
              AP_TAX_ID = exec_tax_id

        if (ap_acl is NULL) then
        {
         
rollback
          status = -721
        }
}

3.3.7.5   Фрейм 3 из 6-ти Транзакции Trade-Order

Третий Фрейм предназначен для оценки общего эффекта от совершения запрошенных торгов. Подсчитываются оценки сумм прибылей и убытков, а также налоги на приобретенный капитал, исходя из любых прибылей. Взимаются административные платежи и ставки комиссии. Если это маржинальная торговля, то, используя текущие рыночные стоимости, подсчитываются активы клиента, необходимые для покрытия стоимости торговли.

Методы доступа к базе данных, используемые во Фрейме 3 - это Reference и Return.

EGenTxnHarness управляет выполнением Фрейма 3 следующим образом:

{
        invoke (Trade-Order_Frame-3)
        if ((sell_value > buy_value) and
             ((tax_status == 1) or (tax_status == 2)) and
             (tax_amount == 0.00)) then
        {
             status = -731
        }
        else if (comm_rate == 0.0000) then
       {
             status = -732
       }
       else if (charge_amount == 0.00) then
       {
             status = -733
        }
        else if (type_is_margin) and (cust_assets == 0.00) then
        {
          // This happens rarely when sum(hs_qty * lt_price) + acct_bal
         // for an account equals zero.
              status = +734
        }
}

    Параметры Фрейма 3 из 6-и Транзакции Trade-Order Frame:




Псевдокод Trade-Order_Frame-3: Оценка суммарных эффектов торгов

{
         Declare co_id IDENT_T
         Declare exch_id CHAR(6)

        // Get information on the security
        if (symbol == “”) then {
            select
               
co_id = CO_ID
            from
             COMPANY
           where
             CO_NAME = co_name

          select
               
    exch_id = S_EX_ID,
                s_name = S_NAME,
                symbol = S_SYMB
          from
                
SECURITY
          where
              
   S_CO_ID = co_id and
              S_ISSUE = issue

      } else {
          select
                
co_id = S_CO_ID,
                
exch_id = S_EX_ID,
                
s_name = S_NAME
          from
                
SECURITY
          where
                
S_SYMB = symbol

          select
                
co_name = CO_NAME
          from
                
COMPANY
          where
                
CO_ID = co_id
          }

          // Get current pricing information for the security
            select
               
market_price = LT_PRICE
            from
               
LAST_TRADE
            where
               
LT_S_SYMB = symbol

            // Set trade characteristics based on the type of trade.
            select
                
MRKT,
type_is_market = TT_IS_
                
type_is_sell = TT_IS_SELL
            from
                
TRADE_TYPE
            where
                
TT_ID = trade_type_id

            // If this is a limit-order, then the requested_price was passed in to the frame, 
           // but if this a market-order, then the requested_price needs to be set to the
          // current market price.
            if( type_is_market ) then {
                
requested_price = market_price
          }

         // Local frame variables used when estimating impact of this trade on
        // any current holdings of the same security.
        Declare hold_price S_PRICE_T
        Declare hold_qty S_QTY_T
        Declare needed_qty S_QTY_T
        Declare hs_qty S_QTY_T

       // Initialize variables
       buy_value = 0.0
       sell_value = 0.0
       needed_qty = trade_qty

       select
          
hs_qty = HS_QTY
       from
          
HOLDING_SUMMARY
       where
          
HS_CA_ID = acct_id and
          
HS_S_SYMB = symbol

       if (hs_qty is NULL) then // No prior holdings exist – no rows returned
       hs_qty = 0

       if (type_is_sell) then {
       // This is a sell transaction, so estimate the impact to any currently held
      // long postions in the security.
     //
     if (hs_qty > 0) then {
     if (is_lifo) then {
     // Estimates will be based on closing most recently acquired holdings
    // Could return 0, 1 or many rows
     declare hold_list cursor for
     select
      
H_QTY,
     H_PRICE
    from
      
HOLDING
    where
      
H_CA_ID = acct_id and
      
H_S_SYMB = symbol
    order by
      
H_DTS desc
   } else {
     // Estimates will be based on closing oldest holdings
    // Could return 0, 1 or many rows
    declare hold_list cursor for
     select
       
H_QTY,
       
H_PRICE
     from
       
HOLDING
     where
       
H_CA_ID = acct_id and
       
H_S_SYMB = symbol
     order by
       
H_DTS asc
     }

      // Estimate, based on the requested price, any profit that may be realized
     // by selling current holdings for this security. The customer may have
    // multiple holdings at different prices for this security (representing
   // multiple purchases different times).
     open hold_list
     do until (needed_qty = 0 or end_of_hold_list) {
     fetch from
     hold_list
     into
     hold_qty,
     hold_price
     if (hold_qty > needed_qty) then {
    // Only a portion of this holding would be sold as a result of the
   // trade.
    buy_value += needed_qty * hold_price
    sell_value += needed_qty * requested_price
    needed_qty = 0
   } else {
    // All of this holding would be sold as a result of this trade.
    buy_value += hold_qty * hold_price
    sell_value += hold_qty * requested_price
    needed_qty = needed_qty - hold_qty
  }
  }
   close hold_list
  }
    // NOTE: If needed_qty is still greater than 0 at this point, then the
   // customer would be liquidating all current holdings for this security, and
   // then creating a new short position for the remaining balance of
   // this transaction.
  } else {

   // This is a buy transaction, so estimate the impact to any currently held
   // short positions in the security. These are represented as negative H_QTY
  // holdings. Short postions will be covered before opening a long postion in
  // this security.
   if (hs_qty < 0) then { // Existing short position to buy
   if (is_lifo) then {
     // Estimates will be based on closing most recently acquired holdings
    // Could return 0, 1 or many rows
      declare hold_list cursor for
      select
         
H_QTY,
         
H_PRICE
      from
         
HOLDING
      where
         
H_CA_ID = acct_id and
        H_S_SYMB = symbol
      order by
         
H_DTS desc
  
   } else {
       // Estimates will be based on closing oldest holdings
       // Could return 0, 1 or many rows
            declare hold_list cursor for
              select
                   
H_QTY,
                   
H_PRICE
         
     from
                   
HOLDING
             where
                    H_CA_ID = acct_id and
                    H_S_SYMB = symbol
             order by
                    H_DTS asc
      }

     
       // Estimate, based on the requested price, any profit that may be realized
           // by covering short postions currently held for this security. The customer
           // may have multiple holdings at different prices for this security
           // (representing multiple purchases at different times).
          open hold_list
          do until (needed_qty = 0 or end_of_hold_list) {
          fetch from
            hold_list
          into
            hold_qty,
            hold_price
          if (hold_qty + needed_qty < 0) then {
          // Only a portion of this holding would be covered (bought back) as
          // a result of this trade.
              sell_value += needed_qty * hold_price
              buy_value += needed_qty * requested_price
              needed_qty = 0
         } else {
          // All of this holding would be covered (bought back) as
         // a result of this trade.
       // NOTE: Local variable hold_qty is made positive for easy
      // calculations
                hold_qty = -hold_qty
                sell_value += hold_qty * hold_price
                buy_value += hold_qty * requested_price
                needed_qty = needed_qty - hold_qty
           }
      }
             close hold_list
     }
     // NOTE: If needed_qty is still greater than 0 at this point, then the
     // customer would cover all current short positions (if any) for this security,
       // and then open a new long position for the remaining balance
      // of this transaction.
     }

       // Estimate any capital gains tax that would be incurred as a result of this
      // transaction.
                tax_amount = 0.0
             if ((sell_value > buy_value) and
               ((tax_status == 1) or (tax_status == 2)) then {
       //
            // Customers may be subject to more than one tax at different rates.
          // Therefore, get the sum of the tax rates that apply to the customer
        // and estimate the overall amount of tax that would result from this order.
    //
      Declare tax_rates S_PRICE_T
        select
            tax_rates = sum(TX_RATE)
       from
            TAXRATE
       where
            TX_ID in (
        select
            CX_TX_ID
        from
            CUSTOMER_TAXRATE
        where
            CX_C_ID = cust_id)
            tax_amount = (sell_value – buy_value) * tax_rates
       }

        // Get administrative fees (e.g. trading charge, commision rate)
           select
              comm_rate = CR_RATE
           from
              COMMISSION_RATE
           where
              CR_C_TIER = cust_tier and
              CR_TT_ID = trade_type_id and
              CR_EX_ID = exch_id and
              CR_FROM_QTY <= trade_qty and
              CR_TO_QTY >= trade_qty
           select
              charge_amount = CH_CHRG
           from
               CHARGE
           where
               CH_C_TIER = cust_tier and
               CH_TT_ID = trade_type_id

          // Compute assets on margin trades
           Declare acct_bal BALANCE_T
           Declare hold_assets S_PRICE_T

        cust_assets = 0.0
          if (type_is_margin) then {
        select
             acct_bal = CA_BAL
        from
             CUSTOMER_ACCOUNT
        where
             CA_ID = acct_id

         // Should return 0 or 1 row
          select
          hold_assets = sum(HS_QTY * LT_PRICE)
       from
           HOLDING_SUMMARY,
           LAST_TRADE
       where
           HS_CA_ID = acct_id and
           LT_S_SYMB = HS_S_SYMB

       if (hold_assets is NULL) /* account currently has no holdings */
           cust_assets = acct_bal
       else
           cust_assets = hold_assets + acct_bal
    }

         // Set the status for this trade
         if (type_is_market then {
         status_id = st_submitted_id
         } else {
         status_id = st_pending_id
    }
}


3.3.7.6 Trade-Order Transaction Frame 4 of 6
The fourth Frame is responsible for creating an audit trail record of the order and assigning a unique trade ID to it.
The database access methods used in Frame 4 are all Adds.
{
      // Estimate the total commision amount for this trade.
      comm_amount = (comm_rate / 100) * trade_qty * requested_price
      exec_name = exec_f_name + " " + exec_l_name
      is_cash = !(type_is_margin)
      invoke (Trade-Order_Frame-4)
{

         Trade-Order Frame 4 of 6 Parameters:



Псевдокод Trade-Order_Frame-4: Запись торговой заявки путем внесения всех соответствующих изменений.

{
         // Get the timestamp and unique trade ID for this trade.
         Declare now_dts DATETIME
         get_current_dts ( now_dts )
         get_new_trade_id ( trade_id )

         // Record trade information in TRADE table.
         insert into
           TRADE (
           T_ID, T_DTS, T_ST_ID, T_TT_ID, T_IS_CASH,
           T_S_SYMB, T_QTY, T_BID_PRICE, T_CA_ID, T_EXEC_NAME,
           T_TRADE_PRICE, T_CHRG, T_COMM, T_TAX, T_LIFO
           )
         values (
                    trade_id,                            // T_ID
                    now_dts,                           // T_DTS
                    status_id,                          // T_ST_ID
                    trade_type  _id,                // T_TT_ID
                    is_cash,                            // T_IS_CASH
                    symbol,                             // T_S_SYMB
                    trade_qty,                        // T_QTY
                    requested_price,              // T_BID_PRICE
                    acct_id,                            // T_CA_ID
                    exec_name,                     // T_EXEC_NAME
                    NULL,                              // T_TRADE_PRICE
                    charge_amount,               // T_CHRG
                    comm_amount                 // T_COMM
                    0,                                   // T_TAX
                    is_lifo                            // T_LIFO
                    )
           // Record pending trade information in TRADE_REQUEST table if this trade is a
           // limit trade
            if (!type_is_market) {
               insert into
                   TRADE_REQUEST (
                   TR_T_ID, TR_TT_ID, TR_S_SYMB,
                   TR_QTY, TR_BID_PRICE, TR_B_ID
                   )
               values (
                    trade_id,                    // TR_T-ID
                    trade_type_id,          // TR_TT_ID
                    symbol,                     // TR_S_SYMB
                    trade_qty,                // TR_QTY
                    requested_price,     // TR_BID_PRICE
                    broker_id                // TR_B_ID
                     )
                }

                // Record trade information in TRADE_HISTORY table.
                 insert into
                    TRADE_HISTORY (
                    TH_T_ID, TH_DTS, TH_ST_ID
                      )
                values (
                            trade_id,         // TH_T_ID
                            now_dts,        // TH_DTS
                            status_id        // TH_ST_ID
                           )
}


3.3.7.7 Фрейм 5 из 6-и Транзакции Trade-Order

Фрейм 5 выполняется в том случае, если параметр roll_it_back установлен равным 1. Этот Фрейм предназначен для намеренного отката всех изменений, внесенных в базу данных этой Транзакцией, одновременно оценивая выполнение функциой отката.

Во Фрейме 5 не используются методы доступа к базе данных, Этот Фрей использует только операции управления Транзакцией.

EGenTxnHarness управляет выполнением Фрейма 5 следующим образом:
{
          if (roll_it_back) then {
                 invoke (Trade-Order_Frame-5)
                 exit // Rest of transaction and SendToMarket are skipped
          }
{

Параметры Фрейма 5 из 6 Транзакции Trade-Order:


Псевдокод Trade-Order_Frame-5: откатить транзакцию базы данных.

{
         // Intentional rollback of transaction caused by driver (CE).
         rollback transaction
}

3.3.7.8   Фрейм 6 из 6-и Транзакции Trade-Order

Шестой Фрейм выполняется в том случае, если параметр roll_it_back установлен равным 0. Этот Фрейм предназначен для подтверждения всех изменений, внесенных в базу данных этой Транзакцией.

Во Фрейме 6 не используются никакие методы доступа к базе данных. Этот Фрейм лишь использует операции управления Транзакцией.

EGenTxnHarness управляет выполнением Фрейма 6 следующим образом:
{
         invoke (Trade-Order_Frame-6)

         if (type_is_market) then {
             eAction = eMEEProcessOrder
         }
        else {
             eAction = eMEESetLimitOrderTrigger
        }

       // Send the trade to the Market Exchange Emulator (MEE)
       SendToMarketFromHarness (
                requested_price,
                symbol,
                trade_id,
                trade_qty,
                trade_type_id,
               eAction
       )
}

      Параметры Фрейма 6 из 6-и Транзакции Trade-Order:


Trade-Order Frame 6 Pseudo-code: Commit database transaction

{
         commit transaction
}


3.3.8    Транзакция Trade-Result

Транзакция Trade-Result предназначена для имитации процесса завершения торгов акциями на рынке. Это является представлением получения брокерской фирмой от рынка финального подтверждения и цены на эти торги. Средства, которыми владеет клиент, обновляются для отражения того, что торги были завершены. Приблизительные оценки брокерской комиссии и прочие подобные величины, созданные, когда были заявлены торги, заменяются точными значениями и историческая информация о торгах записывается для дальнейшего использования.

Транзакция Trade-Result вызывается EGenDriverMEE. Она состоит из шести Фреймов. Транзакция начинается с передачи в нее идентификатора торгов для получения информации по торгам. Полученная информация включает в себя идентификатор счета клиента, который используется для поиска дополнительной информации о счете.

Затем, для отображения завершения торгов, обновляются активы клиента. Конкретный набор выполняемых действий зависит от типа торгов (покупка или продажа), количество акций, и текующаяя позиция клиента (короткая или длинная) по отношению к ценным бумагам. Во время продажи акций, текущие активы ликвидируются для покрытия продажи. Если у клиента нет необходимого количества акций для покрытия продажи, ликвидируются все акции, находящиеся в активах на данный момент, и по балансу акций принимается короткая позиция . Если клиент уже находится в короткой позиции, и продаются дополнительные акции, то короткая позиция просто увеличивается. Аналогичная ситуация возникает и при покупке акций. Любые купленные акции будут сначала использованы для закрытия текущих коротких позиций, после этого купленные акции будут использоваться для создания и увеличения длинной позиции.

Если после приведения в соответствие результатов торгов с текущим состояние активов, было показано, что продажа акций принесла прибыль, и эта прибыль облагается налогом, то размер налоговых сборов также рассчитывается.

Затем рассчитывается брокерская комиссия, и после записывается вся информация, относящаяся к торгам.

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

3.3.8.1   Параметры Транзакции Trade-Result
 
Входные данные для Транзакции Trade-Result генерируются при помощи кода EGenDriverMEE в MEE.cpp. Структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров..


       Trade-Result Transaction Parameters:


3.3.8.2   Слепок базы данных ТранзакцииTrade-Result
Эта Транзакция включает в себя сочетание действий Reference, Return, Modify, Remove и Add. Слепок базы данных ТранзакцииTrade-Result представлен следующим образом:



3.3.8.3   Фрейм 1 из 6-и ТранзакцииTrade-Result

Первый Фрейм предназначен для изъятия информации о клиенте и его торговле.

Методы доступа к базе данных, используемые во Фрейме 1 - это Return.

EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:
{
        invoke (Trade-Result_Frame-1)
}

     Параметры Фрейма 1 из 6-и Транзакции Trade-Result:


Псевдокод Trade-Result_Frame-1: Получение информации по торгам и счету клиента

{
          start transaction

          select
               acct_id            = T_CA_ID,
               type_id            = T_TT_ID,
               symbol             = T_S_SYMB,
               trade_qty        = T_QTY,
               charge             = T_CHRG,
               is_lifo              = T_LIFO,
               trade_is_cash = T_IS_CASH
          from
              TRADE
          where
              T_ID = trade_id

          if (row_count == 0) then
         {
              status = -811
         }

           select
                type_name = TT_NAME,
                type_is_sell = TT_IS_SELL,
                type_is_market = TT_IS_MRKT
           from
                TRADE_TYPE
           where
                TT_ID = type_id

           select
                hs_qty = HS_QTY
           from
                HOLDING_SUMMARY
           where
               HS_CA_ID = acct_id and
               HS_S_SYMB = symbol

            if (hs_qty is NULL) then // no prior holdings exist
            hs_qty = 0
}


3.3.8.4  Фрейм 2 из 6-и Транзакции Trade-Result

Второй Фрейм предназначен для изменения активов клиента с целью отражения результатов торгов покупки или продажи.
Методы доступа к базе данных, используемые во Фрейме 2 - это Reference, Modify Remove и Add.

EGenTxnHarness управляет выполнением Фрейма 2 следующим образом:
{
      invoke (Trade-Result_Frame-2)
}

        Параметры Фрейма 2 из 6-и Транзакции Trade-Result:
         

Псевдокод Trade-Result_Frame-2: Обновление активов клиента по покупке или продаже.

{
               // Local Frame Variables
               Declare hold_id IDENT_T
               Declare hold_price S_PRICE_T
               Declare hold_qty S_QTY_T
               Declare needed_qty S_QTY_T
               get_current_dts ( trade_dts )

               // Initialize variables
               buy_value = 0.0
               sell_value = 0.0
               needed_qty = trade_qty

               select
                     broker_id   = CA_B_ID,
                     cust_id       = CA_C_ID,
                     tax_status = CA_TAX_ST
              from
                     CUSTOMER_ACCOUNT
              where
                     CA_ID = acct_id

             // Determine if sell or buy order
             if (type_is_sell) then {

               if (hs_qty == 0) then // no prior holdings exist, but one will be inserted
                 insert into
                    HOLDING_SUMMARY (
                        HS_CA_ID,
                        HS_S_SYMB,
                        HS_QTY
                     )
                values (
                            acct_id,
                            symbol,
                            -trade_qty
                             )
               else
                  if (hs_qty != trade_qty) then
                   update
                         HOLDING_SUMMARY
               set
                   HS_QTY = hs_qty – trade_qty
                where
                    HS_CA_ID = acct_id and
                    HS_S_SYMB = symbol

             // Sell Trade:

             // First look for existing holdings, H_QTY > 0
             if (hs_qty > 0) {
             if (is_lifo) then {
               // Could return 0, 1 or many rows
                 declare hold_list cursor for
              select
                  H_T_ID,
                  H_QTY,
                  H_PRICE
              from
                  HOLDING
              where
                  H_CA_ID = acct_id and
                  H_S_SYMB = symbol
              order by
                  H_DTS desc
              } else {
          // Could return 0, 1 or many rows
          declare hold_list cursor for
          select
               H_T_ID,
               H_QTY,
               H_PRICE
          from
               HOLDING
          where
               H_CA_ID = acct_id and
               H_S_SYMB = symbol
          order by
               H_DTS asc
            }
              // Liquidate existing holdings. Note that more than
             // 1 HOLDING record can be deleted here since customer
            // may have the same security with differing prices.
               open hold_list
              do until (needed_qty = 0 or end_of_hold_list) {
               fetch from
                  hold_list
               into
                  hold_id,
                  hold_qty,
                  hold_price
              if (hold_qty > needed_qty) then {
                //Selling some of the holdings
               insert into
                 HOLDING_HISTORY (
                 HH_H_T_ID,
                 HH_T_ID,
                 HH_BEFORE_QTY,
                 HH_AFTER_QTY
                )
               values (
                       hold_id,                                  // H_T_ID of original trade
                       trade_id,                                // T_ID current trade
                       hold_qty,                               // H_QTY now
                       hold_qty - needed_qty         // H_QTY after update
                       )

               update
                   HOLDING
               set
                   H_QTY = hold_qty - needed_qty
               where
                    current of hold_list

                buy_value += needed_qty * hold_price
                sell_value += needed_qty * trade_price
                needed_qty = 0

             } else {
                // Selling all holdings
              insert into
                HOLDING_HISTORY (
                HH_H_T_ID,
                HH_T_ID,
                HH_BEFORE_QTY,
                HH_AFTER_QTY
             )
             values (
                hold_id, // H_T_ID original trade
                trade_id, // T_ID current trade
                hold_qty, // H_QTY now
                0 // H_QTY after delete
                )

            delete from
              HOLDING
            where
              current of hold_list

              buy_value += hold_qty * hold_price
              sell_value += hold_qty * trade_price
              needed_qty = needed_qty - hold_qty
             }
           }
              close hold_list
          }

             // Sell Short:
           // If needed_qty > 0 then customer has sold all existing
            // holdings and customer is selling short. A new HOLDING
            // record will be created with H_QTY set to the negative
             // number of needed shares.
              if (needed_qty > 0) then {
              insert into
              HOLDING_HISTORY (
              HH_H_T_ID,
              HH_T_ID,
              HH_BEFORE_QTY,
              HH_AFTER_QTY
              )
           values (
                    trade_id, // T_ID current is original trade
                    trade_id, // T_ID current trade
                    0, // H_QTY before
                   (-1) * needed_qty // H_QTY after insert
           )

           insert into
             HOLDING (
                  H_T_ID,
                  H_CA_ID,
                  H_S_SYMB,
                  H_DTS,
                  H_PRICE,
                  H_QTY
           )
           values (
             trade_id, // H_T_ID
             acct_id, // H_CA_ID
             symbol, // H_S_SYMB
             trade_dts, // H_DTS
             trade_price, // H_PRICE
            (-1) * needed_qty //* H_QTY
                      )
            else
            if (hs_qty = trade_qty) then
            delete from
              HOLDING_SUMMARY
            where
              HS_CA_ID = acct_id and
              HS_S_SYMB = symbol
             }
           } else { // The trade is a BUY
               if (hs_qty == 0) then // no prior holdings exist, but one will be inserted
                insert into
                   HOLDING_SUMMARY (
                   HS_CA_ID,
                   HS_S_SYMB,
                   HS_QTY
                 )
               values (
                   acct_id,
                   symbol,
                   trade_qty
                   )
                else // hs_qty != 0
                 if (-hs_qty != trade_qty) then
              update
                 HOLDING_SUMMARY
               set
                 HS_QTY = hs_qty + trade_qty
                where
                HS_CA_ID = acct_id and
                HS_S_SYMB = symbol

             // Short Cover:
             // First look for existing negative holdings, H_QTY < 0,
             // which indicates a previous short sell. The buy trade
             // will cover the short sell.
              if (hs_qty < 0) then {
              if (is_lifo) then {
              // Could return 0, 1 or many rows
              declare hold_list cursor for
              select
                 H_T_ID,
                 H_QTY,
                 H_PRICE
             from
                 HOLDING
            where
                 H_CA_ID = acct_id and
                 H_S_SYMB = symbol
            order by
                 H_DTS desc
            } else {
            // Could return 0, 1 or many rows
            declare hold_list cursor for
           select
               H_T_ID,
               H_QTY,
               H_PRICE
           from
               HOLDING
           where
               H_CA_ID = acct_id and
               H_S_SYMB = symbol
           order by
               H_DTS asc
             }
           // Buy back securities to cover a short position.
           open hold_list
           do until (needed_qty = 0 or end_of_hold_list) {
           fetch from
             hold_list
           into
             hold_id,
             hold_qty,
             hold_price
           if (hold_qty + needed_qty < 0) then {
           // Buying back some of the Short Sell
            insert into
            HOLDING_HISTORY (
            HH_H_T_ID,
            HH_T_ID,
            HH_BEFORE_QTY,
            HH_AFTER_QTY
            )
            values (
               hold_id, // H_T_ID original trade
               trade_id, // T_ID current trade
               hold_qty, // H_QTY now
               hold_qty + needed_qty // H_QTY after update
            )

          update
              HOLDING
           set
              H_QTY = hold_qty + needed_qty
          where
              current of hold_list

              sell_value += needed_qty * hold_price
              buy_value += needed_qty * trade_price
              needed_qty = 0
          } else {
          // Buying back all of the Short Sell
           insert into
              HOLDING_HISTORY (
              HH_H_T_ID,
              HH_T_ID,
              HH_BEFORE_QTY,
              HH_AFTER_QTY
          )
           values (
             hold_id, // H_T_ID original trade
             trade_id, // T_ID current trade
             hold_qty, // H_QTY now
            0 // H_QTY after delete
          )

           delete from
              HOLDING
          where
              current of hold_list

           // Make hold_qty positive for easy calculations
            hold_qty = -hold_qty
            sell_value += hold_qty * hold_price
            buy_value += hold_qty * trade_price
            needed_qty = needed_qty - hold_qty
         }
       }
            close hold_list
       }

             // Buy Trade:
            // If needed_qty > 0, then the customer has covered all
            // previous Short Sells and the customer is buying new
           // holdings. A new HOLDING record will be created with
          // H_QTY set to the number of needed shares.
          if (needed_qty > 0) then {
          insert into
             HOLDING_HISTORY (
             HH_H_T_ID,
             HH_T_ID,
             HH_BEFORE_QTY,
             HH_AFTER_QTY
            )
          values (
            trade_id, // T_ID current is original trade
            trade_id, //* T_ID current trade
            0, // H_QTY before
            needed_qty // H_QTY after insert
            )

           insert into
              HOLDING (
              H_T_ID,
              H_CA_ID,
              H_S_SYMB,
              H_DTS,
              H_PRICE,
              H_QTY
             )
           values (
               trade_id         // H_T_ID
               acct_id,          // H_CA_ID
               symbol,         // H_S_SYMB
               trade_dts,    // H_DTS
               trade_price, // H_PRICE
               needed_qty // H_QTY
           )
         }
         else
           if (-hs_qty = trade_qty) then
          delete from
            HOLDING_SUMMARY
          where
            HS_CA_ID = acct_id and
            HS_S_SYMB = symbol
         }
}


3.3.8.5 Фрейм 3 из 6-и Транзакции Trade-Result
Третий Фрейм предназначен для расчета объемов налоговых вычетов с прибыли, полученной клиентом в результате торгов. Фрейм 3 выполняется только в том случае, если клиент избавляется от существующих активов, и эта ликвидация принесла прибыль, и значение налогового статуса клиента равно 1 или 2. Объем налоговых сборов записывается в таблицу TRADE.

Примечание: параметр tax_amount используется EGenTxnHarness для расчета значения параметра se_amount непосредственно перед Фреймом 6. Таким образом, параметр tax_amount инициализирован в нулевое значение, и передается в и из Фрейма 3.
 

Методы доступа к базе данных, используемые во Фрейме 3 - это References and Modifies.
EGenTxnHarness управляет выполнением Фрейма 3 следующим образом:

{
                tax_amount = 0.00
                if ((tax_status == 1 or tax_status == 2)
                  and (sell_value > buy_value)) then
              {
                  invoke (Trade-Result_Frame-3)
                  if (tax_amount <= 0.00) then
                {
                  status = -831
                }
              }
}


    Параметры Фрейма 3 из 6-и Транзакции Trade-Result:
    


Псевдокод Trade-Result_Frame-3: Подсчет и запись налоговой ответственности

{
         // Local Frame variables
         Declare tax_rates S_PRICE_T
         select
            tax_rates = sum(TX_RATE)
         from
            TAXRATE
         where
            TX_ID in ( select
            CX_TX_ID
         from
            CUSTOMER_TAXRATE
        where
            CX_C_ID = cust_id)

        tax_amount = (sell_value – buy_value) * tax_rates

          update
            TRADE
          set
            T_TAX = tax_amount
          where
             T_ID = trade_id
}


3.3.8.6   Trade-Result Transaction Frame 4 of 6
Четвертый Фрейм предназначен для расчета комиссии брокера, выполнившего торги.
Методы доступа к базе данных, используемые во Фрейме 4 - это Reference.

EGenTxnHarness управляет выполнением Фрейма 4 следующим образом:
{
       invoke (Trade-Result_Frame-4)
       if (comm_rate <= 0.00) then
        {
          status = -841
        }
}

     Параметры Фрейма 4 из 6-и Транзакции Trade-Result Frame 4 of 6 Parameters:



Псевдокод Trade-Result_Frame-4: Расчет и запись брокерской комиссии

{
          select
             s_ex_id = S_EX_ID,
             s_name = S_NAME
          from
             SECURITY
          where
             S_SYMB = symbol

          select
             c_tier = C_TIER
          from
             CUSTOMER
          where
             C_ID = cust_id

            // Only want 1 commission rate row
            select first 1 row
              comm_rate = CR_RATE
            from
              COMMISSION_RATE
           where
              CR_C_TIER = c_tier and
              CR_TT_ID = type_id and
              CR_EX_ID = s_ex_id and
              CR_FROM_QTY <= trade_qty and
              CR_TO_QTY >= trade_    
}

3.3.8.7   Trade-Result Transaction Frame 5 of 6

Пятый Фрейм предназначен для записи результатов торгов и брокерской комиссии.
Методы доступа к базе данных, используемые во Фрейме 5 - это сочетание Modify, Add и Remove.
EGenTxnHarness управляет выполнением Фрейма 5 следующим образом:
{
        comm_amount = (comm_rate / 100) * (trade_qty * trade_price)
        invoke (Trade-Result_Frame-5)
 }

   Параметры Фрейма 5 из 6-и Транзакции Trade-Result:
  


Псевдокод Trade-Result_Frame-5: Записать результат торгов и брокерскую комиссию.

{
            update
               TRADE
            set
               T_COMM            = comm_amount,
               T_DTS                = trade_dts,
               T_ST_ID             = st_completed_id,
               T_TRADE_PRICE = trade_price
            where
               T_ID = trade_id

            insert into
               TRADE_HISTORY (
               TH_T_ID,
               TH_DTS,
                TH_ST_ID
            )
             values (
                trade_id,
                trade_dts,
                st_completed_id
             )

               update
                 BROKER
               set
                 B_COMM_TOTAL = B_COMM_TOTAL + comm_amount,
                 B_NUM_TRADES = B_NUM_TRADES + 1
              where
                 B_ID = broker_id
}

3.3.8.8   Фрейм 6 из 6-и Транзакции Trade-Result

Шестой Фрейм предназначен для выравнивания торгов.
Методы доступа к базе данных, используемые во Фрейме 6 - это сочетание Add и Modify.

EGenTxnHarness управляет выполнением Фрейма 6 следующим образом:
{
     due_date = (trade_date + 2 days)
      if (type_is_sell) then
    {
        se_amount = (trade_qty * trade_price) – charge – comm_amount
    } else {
        se_amount = -((trade_qty * trade_price) + charge + comm_amount)
     }
          if (tax_status == 1) then
     {
         se_amount = se_amount – tax_amount
     }
       invoke (Trade-Result_Frame-6)
}

   Параметры Фрейма 6 из 6-и Транзакции Trade-Result:
  


Псевдокод Trade-Result_Frame-6: урегулировать торги

{
        // Local Frame Variables
        Declare cash_type char(40)
        if (trade_is_cash) then
           cash_type = “Cash Account”
        else
           cash_type = “Margin”

        insert into
          SETTLEMENT (
            SE_T_ID,
            SE_CASH_TYPE,
            SE_CASH_DUE_DATE,
            SE_AMT
           )
         values (
               trade_id,
              cash_type,
              due_date,
              se_amount
            )

          if (trade_is_cash) then {
         update
            CUSTOMER_ACCOUNT
         set
           CA_BAL = CA_BAL + se_amount
        where
           CA_ID = acct_id

        insert into
           CASH_TRANSACTION (
           CT_DTS,
           CT_T_ID,
           CT_AMT,
           CT_NAME
         )
       values (
           trade_dts,
           trade_id,
           se_amount,
           type_name + " " + trade_qty + " shares of " + s_name
          )
     }

      select
        acct_bal = CA_BAL
      from
        CUSTOMER_ACCOUNT
      where
        CA_ID = acct_id

      commit transaction
}


3.3.9   Транзакция Trade-Status
 
Транзакция Trade-Status предназначена для имитации процесса обновления статуса конкретного набора торгов. Это является представлением клиента, просматривающего информацию по недавней торговой деятельности для одного из счетов.
Trade-Status вызывается EGenDriverCE. Она состоит из единственного Фрейма. Для заданного идентификатора счета Trade-Status возвращает идентификаторы торгов и статусы 50 последних торгов.

3.3.9.1  Параметры Транзакции Trade-Status

Входные данные Транзакции Trade-Status генерируются кодом EGenDriverCE в CETxnInputGenerator.cpp, и структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров.
   
   Trade-Status Transaction Parameters:
   

3.3.9.2  Слепок базы данных Транзакции Trade-Status

Слепок базы данных Транзакции Trade-Status представлен следующим образом:
 

3.3.9.3   Фрейм 1 из 1-го Транзакции Trade-Status

Методы доступа к базе данных, используемые во Фрейме 1 - это Return.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:
{
invoke (Trade-Status_Frame-1)
}

   Параметры Фрейма 1 из 1-го Транзакции Trade-Status:
  




Псевдокод Trade-Status_Frame-1: Получить информацию по 50 последним торгам.

{
         start transaction
         // Only want 50 rows, the 50 most recent trades for this customer account
         select first 50 row
              trade_id[]        = T_ID,
              trade_dts[]      = T_DTS,
              status_name[] = ST_NAME,
              type_name[]    = TT_NAME,
              symbol[]           = T_S_SYMB,
              trade_qty[]       = T_QTY,
              exec_name[]    = T_EXEC_NAME,
              charge[]           = T_CHRG,
              s_name[]         = S_NAME,
              ex_name[]       = EX_NAME
        from
              TRADE,
              STATUS_TYPE,
              TRADE_TYPE,
              SECURITY,
              EXCHANGE
        where
              T_CA_ID = acct_id and
              ST_ID = T_ST_ID and
              TT_ID = T_TT_ID and
              S_SYMB = T_S_SYMB and
              EX_ID = S_EX_ID
        order by
              T_DTS desc

         if (row_count != 50)
        {
            status = -911
        }

         select
          cust_l_name = C_L_NAME,
          cust_f_name = C_F_NAME,
          broker_name = B_NAME
         from
           CUSTOMER_ACCOUNT,
           CUSTOMER,
           BROKER
        where
          CA_ID = acct_id and
          C_ID = CA_C_ID and
          B_ID = CA_B_ID

        commit transaction
}

3.3.10   Транзакция Trade-Update
Транзакция Trade-Update предназначена для имитации процесса внесения незначительных изменений или обновлений в набор торгов. Это является аналогом того, как клиент или брокер, просматривая набор торгов, обнаруживает необходимость внесения незначительных редакционных изменений. Различные виды торгов выбраны таким образом, чтобы работа представляла собой:
  • просмотр основных тенденций рынка
  • обзор торгов за период времени, предшествующий последней выписке из счета
  • просмотр последних событий по конкретным ценным бумагам
Trade-Update вызывается EGenDriverCE. Она состоит из трех взаимно исключающих Фреймов. Каждый Фрейм применяет различную технику поиска исторических данных торгов. В полученные данные вносятся минимальные исправления.
Фрейм 1 принимает список идентификаторов торгов. Возвращается информация по каждым торгам в списке. Изменяется имя исполнителя для каждых торгов.

Фрейм 2 принимает в качестве входных данных идентификатор счета клиента, начальный момент времени, конечный момент времени и количество торгов (N). Фрейм возвращает информацию по первым N торгам на заданном счете клиента между начальным и конечным моментами времени включительно. Изменяется тип наличного расчета по каждым торгам.

Фрейм 3 принимает в качестве входных переменных символ ценных бумаг, начальный момент времени, конечный момент времени и количество торгов (N). Фрейм возвращает информацию о первых N торгах по заданным ценным бумагам прошедшим между начальным и конечным моментами времени (включительно). В случае торгов за наличные средства изменяется описание Транзакции.

3.3.10.1 Параметры Транзакции Trade-Update

Входные данные для Транзакции Trade-Update генерируются кодом EGenDriverCE в CETxnInputGenerator.cpp. Структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров.


   Параметры Транзакции Trade-Update:


3.3.10.2 Слепок базы данных Транзакции Trade-Update

Слепок базы данных Транзакции Trade-Update представлен следующим образом:
 

3.3.10.3 Фрейм 1 из 3-х Транзакции Trade-Update
 
Первый Фрейм предназначен для получения информации об указанном массиве идентификаторов торгов и изменении некоторых данных из таблицы TRADE.
EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:
{
             if( frame_to_execute == 1 )
            {
              invoke (Trade-Update_Frame-1)
              if (num_found != max_trades) or (num_updated != max_updates) then
              {
              status = -1011
              }
              frame_executed = 1
            }
[...]


       Параметры Фрейма 1 из 3-х Транзакции Trade-Update:
      


Псевдокод Trade-Update_Frame-1: Получить информацию по торгам по каждому идентификатору торгов в массиве trade_id и изменить некоторые ряды таблицы TRADE.

{
               declare i int
               declare ex_name char(49)
               start transaction

                 num_found = 0
                 num_updated = 0

               for (i = 0; i++; i < max_trades) do {
                // Get trade information
                  if (num_updated < max_updates) then {
                   // Modify the TRADE row for this trade.

                select
                 ex_name = T_EXEC_NAME
                from
                 TRADE
               where
                 T_ID = trade_id[i]

                 num_found = num_found + row_count

                 if (ex_name like “% X %”) then
                   select ex_name = REPLACE (ex_name, “ X “, “ “)
                 else
                   select ex_name = REPLACE (ex_name, “ “, “ X “)

                 update
                   TRADE
                 set
                   T_EXEC_NAME = ex_name
                 where
                   T_ID = trade_id[i]
 
                 num_updated = num_updated + row_count
                }

                 // Will only return one row for each trade
                   select
                       bid_price[i] = T_BID_PRICE,
                       exec_name[i] = T_EXEC_NAME,
                       is_cash[i] = T_IS_CASH,
                       is_market[i] = TT_IS_MRKT,
                       trade_price[i] = T_TRADE_PRICE
                   from
                       TRADE,
                       TRADE_TYPE
                   where
                       T_ID = trade_id[i] and
                       T_TT_ID = TT_ID

                  // Get settlement information
                 // Will only return one row for each trade
                   select
                     settlement_amount[i] = SE_AMT,
                     settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
                     settlement_cash_type[i] = SE_CASH_TYPE
                   from
                     SETTLEMENT
                   where
                     SE_T_ID = trade_id[i]

               // get cash information if this is a cash transaction
              // Will only return one row for each trade that was a cash transaction
                  if (is_cash[i]) then {
                  select
                    cash_transaction_amount[i] = CT_AMT,
                    cash_transaction_dts[i] = CT_DTS,
                    cash_transaction_name[i] = CT_NAME
                  from
                    CASH_TRANSACTION
                  where
                     CT_T_ID = trade_id[i]
                   }
                  // read trade_history for the trades
                  // Will return 2 or 3 rows per trade
                  select first 3 rows
                    trade_history_dts[i][] = TH_DTS,
                    trade_history_status_id[i][] = TH_ST_ID
                 from
                     TRADE_HISTORY
                 where
                     TH_T_ID = trade_id[i]
                 order by
                     TH_DTS
                 } // end for loop

              commit transaction
}


3.3.10.4 Фрейм 2 из 3-х Транзакции Trade-Update
Второй Фрейм возвращает информацию о первых N торгах, совершенных на указанном счете клиента между заданными начальным и конечным моментами времени, и изменяет ряд SETTLEMENT по всем возвращаемым торгам. Если заданное время начала слишком близко к заданному времени окончания, тогда возможен возврат и изменение менее торгов N.

EGenTxnHarness управляет выполнением Фрейма 2 следующим образом:

[...]
          else if( frame_to_execute == 2 )
           {
                 invoke (Trade-Update_Frame-2)
                 if (num_updated != num_found) or (num_updated < 0) then
                {
                   status = -1021
                }
                  else if (num_updated == 0) then
                {
                  status = +1021
                }
                  frame_executed = 2
           }
[...]


  Параметры Фрейма 2 из 3-х Транзакции Trade-Update:
 


Псевдокод Trade-Update_Frame-2: Получить торговую информацию по первым N торгам на заданном счете клиента от указанного момента времени и изменить некоторые из рядов таблицы SETTLEMENT.

{
           declare i int
           declare cash_type char(40)
           start transaction

          // Get trade information
          // Will return between 0 and max_trades rows
          select first max_trades rows
             bid_price[] = T_BID_PRICE,
             exec_name[] = T_EXEC_NAME,
             is_cash[] = T_IS_CASH,
             trade_list[] = T_ID,
             trade_price[] = T_TRADE_PRICE
          from
              TRADE
          where
              T_CA_ID = acct_id and
              T_DTS >= start_trade_dts and
              T_DTS <= end_trade_dts
          order by
              T_DTS asc

           num_found = row_count
           num_updated = 0

       // Get extra information for each trade in the trade list.
          for (i = 0; i < num_found; i++) {
           if (num_updated < max_updates) then {
        // Modify the SETTLEMENT row for this trade.
        select
          cash_type = SE_CASH_TYPE
        from
          SETTLEMENT
        where
          SE_T_ID = trade_list[i]

         if (is_cash[i]) then {
         if (cash_type == “Cash Account”) then
            cash_type = “Cash”
         else
            cash_type = “Cash Account”
           }
         else
         if (cash_type == “Margin Account”) then
          cash_type = “Margin”
         else
          cash_type = “Margin Account”
           }

        update
          SETTLEMENT
        set
           SE_CASH_TYPE = cash_type
        where
           SE_T_ID = trade_list[i]

           num_updated = num_updated + row_count
         }

         // Get settlement information
         // Will return only one row for each trade
         select
            settlement_amount[i] = SE_AMT,
            settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
            settlement_cash_type[i] = SE_CASH_TYPE
         from
            SETTLEMENT
         where
            SE_T_ID = trade_list[i]

          // get cash information if this is a cash transaction
         // Should return only one row for each trade that was a cash transaction
         if (is_cash[i]) then {
         select
          cash_transaction_amount[i] = CT_AMT,
          cash_transaction_dts[i] = CT_DTS
          cash_transaction_name[i] = CT_NAME
         from
           CASH_TRANSACTION
         where
           CT_T_ID = trade_list[i]
          }

        // read trade_history for the trades
        // Will return 2 or 3 rows per trade
        select first 3 rows
            trade_history_dts[i][] = TH_DTS,
            trade_history_status_id[i][] = TH_ST_ID
        from
            TRADE_HISTORY
        where
            TH_T_ID = trade_list[i]
        order by
            TH_DTS

        } // end for loop

        commit transaction
}


3.3.10.5   Фрейм 3 из 3-х Транзакции Trade-Update
Третий Фрейм возвращает информацию по первым N торгам по заданным ценным бумагам между начальным и конечным моментами времени и изменяет соответствующие ряды CASH_TRANSACTION для каждого из возвращаемых рядов. Если заданный момент времени начала слишком близок к заданному моменту окончанию, то возможно, что может быть возвращено менее N торгов и изменено рядов CASH_TRANSACTION.
.
EGenTxnHarness управляет выполнением Фрейма 3 следующим образом:
[...]
             else if( frame_to_execute == 3 )
             {
                invoke (Trade-Update_Frame-3)
                if (num_found == 0) then
               {
                status = +1031
                }
                 frame_executed = 3
             }
}

   Параметры Фрейма 3 из 3-х Транзакции Trade-Update:
  


Псевдокод Trade-Update_Frame-3: Получить список N торгов, совершенных по заданным ценным бумагам, начиная с указанном момента времени и изменить некоторые из рядов таблицы CASH_TRANSACTION.

{
           declare i int
           declare ct_name char(100)
           start transaction
           // Will return between 0 and max_trades rows.
           select first max_trades rows
               acct_id[]        = T_CA_ID,
               exec_name[] = T_EXEC_NAME,
               is_cash[]       = T_IS_CASH,
               price[]           = T_TRADE_PRICE,
               quantity[]     = T_QTY,
               s_name[]      = S_NAME,
               trade_dts[]   = T_DTS,
               trade_list[]    = T_ID,
               trade_type[] = T_TT_ID,
               type_name[] = TT_NAME
           from
               TRADE,   
               TRADE_TYPE,
               SECURITY
          where
               T_S_SYMB = symbol and
               T_DTS >= start_trade_dts and
               T_DTS <= end_trade_dts and
               TT_ID = T_TT_ID and
               S_SYMB = T_S_SYMB
             // The max_acct_id “where” clause is a hook used for engineering purposes
            // only and is not required for benchmark publication purposes.
           // and
          //T_CA_ID <= max_acct_id
           order by
             T_DTS asc

             num_found = row_count
             num_updated = 0

            // Get extra information for each trade in the trade list.
            for (i = 0; i < num_found; i++) {
            // Get settlement information
           // Will return only one row for each trade
           select
              settlement_amount[i] = SE_AMT,
              settlement_cash_due_date[i] = SE_CASH_DUE_DATE,
              settlement_cash_type[i] = SE_CASH_TYPE
           from
              SETTLEMENT
           where
              SE_T_ID = trade_list[i]

          // get cash information if this is a cash transaction
          // Will return only one row for each trade that was a cash transaction
          if (is_cash[i]) then {
          if (num_updated < max_updates) then {
          // Modify the CASH_TRANSACTION row for this trade.
          select
             ct_name = CT_NAME
          from
             CASH_TRANSACTION
          where
              CT_T_ID = trade_list[i]

          if (ct_name like “% shares of %”) then
            ct_name = type_name[i] + “ “ + quantity[i] + “ Shares of “ + s_name[i]
          else
            ct_name = type_name[i] + “ “ + quantity[i] + “ shares of “ + s_name[i]

         update
           CASH_TRANSACTION
         set
           CT_NAME = ct_name
        where
           CT_T_ID = trade_list[i]

           num_updated = num_updated + row_count
       }
 
          select
            cash_transaction_amount[i] = CT_AMT,
            cash_transaction_dts[i] = CT_DTS
            cash_transaction_name[i] = CT_NAME
          from
                 CASH_TRANSACTION
         where
                 CT_T_ID = trade_list[i]
         }

            // read trade_history for the trades
           // Will return 2 or 3 rows per trade
           select first 3 rows
                trade_history_dts[i][] = TH_DTS,
                trade_history_status_id[i][] = TH_ST_ID
          from
                TRADE_HISTORY
          where
               TH_T_ID = trade_list[i]
          order by
               TH_DTS asc

        } // end for loop

      commit transaction
}


3.3.11 Транзакция Data-Maintenance
Транзакция Data-Maintenance предназначена для имитации периодических изменений в данных, которые являются в основном неизменными и используются для ссылок. Это аналогично обновлению адреса электронной почты клиента или иных данных, которые редко меняются.
Data-Maintenance вызывается EGenDriverDM. Она состоит из одного Фрейма. Эта Транзакция выполняется раз в минуту. Она имитирует периодические изменения в таблицах данных, которые обычно используются для организации ссылок другими Транзакциями. В качестве входных данных Драйвер предоставляет название таблицы, которая должна быть изменена Транзакцией.
При каждом запуске этой Транзакции Драйвер изменяет содержимое следующей таблицы в списке. Это означает, что каждая таблица в списке будет изменяться только один раз в каждые двенадцать минут.
Ниже приведен список названий таблиц, которые могут быть переданы в качестве аргументов в эту Транзакцию:
  • ACCOUNT_PERMISSION
  • ADDRESS
  • COMPANY
  • CUSTOMER
  • CUSTOMER_TAXRATE
  • DAILY_MARKET
  • EXCHANGE
  • FINANCIAL
  • NEWS_ITEM
  • SECURITY
  • TAXRATE
  • WATCH_ITEM
Транзакция Data-Maintenance состоит из единственного Фрейма.
Назначением данной Транзакции является изменение таблиц данных, в которых не осуществляются записи способами контрольного тестирования. Во время каждого выполнения Транзакции EGenTxnHarness будет выбирать следующую таблицу из списка.
Ниже приведено описание того, какие изменения вносятся в каждую из таблиц при её выборе:

1. ACCOUNT_PERMISSION -EGenTxnHarness будете передавать в Транзакцию Data-Maintenance идентификатор счета клиента. Каждому счету клиента будет соответствовать по меньшей мере один ряд таблицы ACCOUNT_PERMISSION. Будет найден первый ряд таблицы ACCOUNT_PERMISSION, соответствующий клиенту (Организатор может решать, какой из рядов – первый). Этот ряд таблицы ACCOUNT_PERMISSION Будет иметь Список контроля доступа (Access Control List (AP_ACL)). Этот список контроля доступа будет обновлен до значения 1111, если еще не является таковым. Если список контроля доступа уже 1111, ему будет присвоено значение 0011.

2. ADDRESS – 67% времени EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор клиента. Остальные 33% времени EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор компании. Будет изменяться ADDRESS этой компании или клиента. AD_LINE2 будет присвоено значение«Apt. 10C» или «Apt. 22», если оно уже равно «Apt. 10C».

3. COMPANY – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор компании. Кредитный рейтинг «Standard and Poor» этой компании будет изменен на «ABA» или «AAA», если он уже установлен равным «ABA».

4. CUSTOMER – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор клиента. Часть, соответствующая имени домена, на котором располагается второй e-mail клиента (C_EMAIL_2) будет обновлен до «@mindspring.com» или «@earthlink.com», если он уже «@mindspring.com».

5. CUSTOMER_TAXRATE – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор клиента. Налоговая ставка страны будет циклически изменяться к следующей ставке в наборе {«US1», «US2», «US3», «US4», «US5»} или наборе {«CN1», «CN2», «CN3», «CN4»}, В зависимости от страны клиента.

6. DAILY_MARKET – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance символ ценных бумаг, день месяца и случайное число (положительное или отрицательное). Вся ряды в таблице DAILY_MARKET с соответствующими символами и днями месяца будут обновлены путем добавления случайного числа к DM_VOL.

7. EXCHANGE – EGenTxnHarness не будет передавать в Транзакцию Data-Maintenance дополнительную информацию. В таблице EXCHANGE существуют только четыре ряда. В каждом ряду будет обновлено значение EX_DESC. Если EX_DESC еще не заканчивается «LAST UPDATED » и датой и временем, то эта строка будет добавлена в конце EX_DESC. В противном случае дата и время в конце EX_DESC примут значение текущих даты и времени.

8. FINANCIAL – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор компании. Значения FI_QTR_START_DATE будут обновлены до второго из месяцев или до первого из месяцев, если даты уже принадлежали второму из месяцев.

9. NEWS_ITEM – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор компании. На один день будут обновлены параметры NI_DTS, соответствующие новостным сюжетам о компании.

10. SECURITY – EGenTxnHarness будет передавать символ ценных бумаг. Значение S_EXCH_DATE ценных бумаг увеличится на один день.

11. TAXRATE – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор налоговой ставки. Параметр налоговой ставки TX_NAME будет обновлен таким образом, что будет подстрока будет переключаться между «Tax» и «tax».

12. WATCH_ITEM – EGenTxnHarness будет передавать в Транзакцию Data-Maintenance идентификатор клиента. Будет выбран средний элемент из списка клиента WATCH_ITEM. Ему будет присвоено значение следующего символа из таблицы SECURITY, который еще не находится в списке клиента WATCH_ITEM.

3.3.11.1 Параметры Транзакции.

Входные данные Транзакции Data-Maintenance генерируются EGenDriverDM в DM.cpp. Структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров..
 
  Параметры Транзакции Data-Maintenance:
 

3.3.11.2  Слепок базы данных Транзакции Data-Maintenance

Эта Транзакция включает в себя сочетание операций Reference, Modify, Remove и Add. Для реализации Транзакции может понадобится доступ к следующим таблицам и колонкам базы данных.
 

3.3.11.3 Фрейм 1 из 1-го Транзакции Data-Maintenance

EGenTxnHarness управляет выполнением Фрейма 1 следующим образом:
{
invoke (Data-Maintenance_Frame-1)
}

   Параметры Фрейма 1 из 1-го Транзакции Data-Maintenance:
  


Псевдокод Data-Maintenance Frame 1: Обновить таблицу

             /* Check which table is to be updated. */
             if (strcmp(table_name, “ACCOUNT_PERMISSION”)==0) {

                  //ACCOUNT_PERMISSION
                 //Update the AP_ACL to “1111” or “0011” in rows for a
                //customer account of c_id.

            acl = NULL

            select first 1 row
               acl = AP_ACL
            from
               ACCOUNT_PERMISSION
           where
               AP_CA_ID = acct_id
           order by
               AP_ACL DESC

           if (acl != “1111”) then {
          update 
              ACCOUNT_PERMISSION
           set
             AP_ACL=”1111”
          where
            AP_CA_ID = acct_id and
            AP_ACL = acl
          } else { /*ACL is “1111” change it to “0011” */
          update
            ACCOUNT_PERMISSION
          set
           AP_ACL = ”0011”
         where
           AP_CA_ID = acct_id and
           AP_ACL = acl
         }
         } else if (strcmp(table_name,”ADDRESS”)==0) {

          // ADDRESS
          // Change AD_LINE2 in the ADDRESS table for
         // the CUSTOMER with C_ID of c_id or the COMPANY with CO_ID of co_id.

        line2 = NULL
        ad_id = 0
         // Customer ID provided
         if (c_id != 0) {
         select
            line2 = AD_LINE2,
            ad_id = AD_ID
          from
            ADDRESS, CUSTOMER
         where
            AD_ID = C_AD_ID and
            C_ID = c_id
          }
          // Company ID provided
          else {
          select
            line2 = AD_LINE2,
            ad_id = AD_ID
           from
            ADDRESS, COMPANY
          where
            AD_ID = CO_AD_ID and
            CO_ID = co_id
         }
          if (strcmp(line2, “Apt. 10C”) != 0) {
          update
            ADDRESS
          set
            AD_LINE2 = “Apt. 10C”
          where
            AD_ID = ad_id
           } else {
         update
           ADDRESS
         set
           AD_LINE2 = “Apt. 22”
         where
           AD_ID = ad_id
         }
         } else if (strcmp(table_name,”COMPANY”)==0) {
         // COMPANY
         // Update a row in the COMPANY table identified
          // by co_id, set the company’s Standard and Poor
         // credit rating to “ABA” or to “AAA”.
           sprate = NULL
           select
           sprate = CO_SP_RATE
       from
           COMPANY
       where
           CO_ID = co_id
       if (strcmp(sprate, “ABA”) != 0) {
       update
          COMPANY
       set
          CO_SP_RATE = “ABA”
        where
           CO_ID = co_id
        } else {
        update
           COMPANY
        set
           CO_SP_RATE = “AAA”
        where
           CO_ID = co_id
         }
          } else if (strcmp(table_name, “CUSTOMER”) == 0) {
          // CUSTOMER
           // Update the second email address of a CUSTOMER
          // identified by c_id. Set the ISP part of the customer’s
          // second email address to “@mindspring.com”
          // or “@earthlink.com”.
            email2 = NULL
            len = 0
            lenMindspring = strlen(“@mindspring.com)
         select
            email2 = C_EMAIL_2
         from
           CUSTOMER
          where
            C_ID = c_id
            len = strlen(email2)
          if ( ((len – lenMindspring) > 0) and
             (strcmp(substr(email2,len-lenMindspring,
              lenMindspring),”@mindspring.com”) == 0) ) {
           update
               CUSTOMER
            set
               C_EMAIL_2 = substring(C_EMAIL_2, 1,
               charindex(“@”,C_EMAIL_2) ) + ‘earthlink.com’
            where
                C_ID = c_id
            } else { /* set to @mindspring.com */
            update
                CUSTOMER
            set
                C_EMAIL_2 = substring(C_EMAIL_2, 1,
                charindex(“@”,C_EMAIL_2) ) + ‘mindspring.com’
            where
                 C_ID = c_id
           }
            } else if (strcmp(table_name, “CUSTOMER_TAXRATE”) == 0) {

                // CUSTOMER_TAXRATE
                // Find the customer’s current country tax rate code.
                // Calculate cyclically the next tax rate code for the customer’s country.
               // Update to the new country tax rate code.
               declare old_tax_rate char(3),
               new_tax_rate char(3),
               tax_num int

           select
             old_tax_rate = CX_TX_ID
            from
             CUSTOMER_TAXRATE
           where
             CX_C_ID = c_id and
             (CX_TX_ID like “US%” or CX_TX_ID like “CN%”)

              if (left(old_tax_rate,2) = “US”) {
              if (old_tax_rate = “US5”) {
                new_tax_rate = “US1”
            }
              else { // Change string US to US
                tax_num = CODE(right(old_tax_rate,1)) – CODE(“0”) + 1
                new_tax_rate = “US” + CHAR(tax_num + CODE(“0”))
             }
              else {
              if (old_tax_rate = “CN4”) {
                new_tax_rate = “CN1”
             }
              else { // Change string CN to CN
                  tax_num = CODE(right(old_tax_rate,1)) – CODE(“0”) + 1
                  new_tax_rate = “CN” + CHAR(tax_num + CODE(“0”))
             }
          }

             update
               CUSTOMER_TAXRATE
             set
               CX_TX_ID = new_tax_rate
            where
               CX_C_ID = c_id and
               CX_TX_ID = old_tax_rate

            } else if (strcmp(table_name, “DAILY_MARKET”) == 0) {
            // DAILY_MARKET
            // A security symbol, a day in the month and a
            // random positive or negative number are passed into
            // the Data-Maintenance function, when table_name
           // is DAILY_MARKET. The DM_VOL column in the DAILY_MARKET
            // table will be updated by adding the random positive or
            // negative number.
           // The rows to be updated are those for the security
           // whose symbol was passed in, and for that day in the
           // month that was passed in.
          update
              DAILY_MARKET
          set
              DM_VOL = DM_VOL + vol_incr
          where
              DM_S_SYMB = symbol
          and substring ((convert(char(8),DM_DATE,3),1,2) = day_of_month
          } else if (strcmp(table_name, “EXCHANGE”) == 0) {
          // EXCHANGE
          // Other than the table_name, no additional
         // parameters are used when the table_name is EXCHANGE.
         // There are only four rows in the EXCHANGE table. Every
         // row will have its EX_DESC updated. If EX_DESC does not
         // already end with “LAST UPDATED “ and a date and time,
         // that string will be appended to EX_DESC. Otherwise the
         // date and time at the end of EX_DESC will be updated
          // to the current date and time.

        rowcount = 0

        select
           rowcount = count(*)
         from
            EXCHANGE
        where
            EX_DESC like “%LAST UPDATED%”

          if (rowcount == 0) {
          update
              EXCHANGE
          set
              EX_DESC = EX_DESC + “ LAST UPDATED “ + getdatetime()
          } else {
          update
              EXCHANGE
          set
              EX_DESC = substring(EX_DESC,1,
              len(EX_DESC)-len(getdatetime())) + getdatetime()
           }
           } else if (strcmp(table_name,”FINANCIAL”) == 0) {
               // FINANCIAL
              // Update the FINANCIAL table for a company identified by
             // co_id. That company’s FI_QTR_START_DATEs will be
            // updated to the second of the month or to the first of
           // the month if the dates were already the second of the
          // month.

           rowcount = 0
          select
            rowcount = count(*)
          from
              FINANCIAL
          where
               FI_CO_ID = co_id and
               substring(convert(char(8),
                FI_QTR_START_DATE,2),7,2) = “01”
           if (rowcount > 0) {
           update
              FINANCIAL
           set
                FI_QTR_START_DATE = FI_QTR_START_DATE + 1 day
           where
                FI_CO_ID = co_id
           } else {
                update
                   FINANCIAL
                set
                   FI_QTR_START_DATE = FI_QTR_START_DATE – 1 day
                where
                    FI_CO_ID = co_id
                }
                } else if (strcmp(table_name, “NEWS_ITEM”) == 0) {
               // NEWS_ITEM
              // Update the news items for a specified company.
             // Change the NI_DTS by 1 day.
               update
                 NEWS_ITEM
               set
                 NI_DTS = NI_DTS + 1day
               where
                  NI_ID = (
                select
                  NX_NI_ID
                from
                   NEWS_XREF
                 where
                   NX_CO_ID = @co_id)
                   } else if (strcmp(table_name,”SECURITY”) == 0) {
                  // SECURITY
                  // Update a security identified symbol, increment
                 // S_EXCH_DATE by 1 day.
             update
                SECURITY
             set
                 S_EXCH_DATE = S_EXCH_DATE + 1day
             where
                 S_SYMB = symbol
                 } else if strcmp(table_name,”TAXRATE”) == 0) {
                // TAXRATE
                // Update a TAXRATE identified by tx_id. The tax rate’s
                // TX_NAME will have a substring modified from “ Tax ” to “ tax ”
                // or from “ tax ” to “ Tax ”, depending on the current value.

                tx_name = NULL

                select
                   tx_name = TX_NAME
                from
                  TAXRATE
               where
                   TX_ID = tx_id

                if (tx_name like “% Tax %”) {
                     tx_name = replace(tx_name, “ Tax “, “ tax “)
                } else {
                      tx_name = replace(tx_name, “ tax “, “ Tax “)
                }

               update
                   TAXRATE
                set
                    TX_NAME = tx_name
                where
                    TX_ID = tx_id

                } else if (strcmp(table_name,”WATCH_ITEM”) == 0) {
                   // WATCH_ITEM
                  // Find the “middle” symbol in the current watch list.
                 // Find the next symbol in the SECURITY table that is not already in the
                // current watch list. Update the middle symbol in the current watch
               // list with the new symbol.

             declare cnt int,
             old_symbol char(15),
             new_symbol char(15)

             select
                cnt = count(*) // number of rows is [50..150]
             from
                 WATCH_ITEM,
                 WATCH_LIST
             where
                 WL_C_ID = c_id and
                 WI_WL_ID = WL_ID

           cnt = (cnt + 1)/2 // calculate “middle” row index

           // select “middle” row current symbol
         select
            old_symbol = WI_S_SYMB
         from
           ( select 
                 ROWNUM,
                WI_S_SYMB
         from
               WATCH_ITEM,
               WATCH_LIST
        where
               WL_C_ID = c_id and
               WI_WL_ID = WL_ID and
         order by
                WI_S_SYMB asc
        )
           where
             rownum = cnt

              select first 1
               new_symbol = S_SYMB
           from
               SECURITY
          where
               S_SYMB > old_symbol and
               S_SYMB not in (
          select 
               WI_S_SYMB
          from
               WATCH_ITEM,
                WATCH_LIST
          where
                WL_C_ID = c_id and
                WI_WL_ID = WL_ID
          )
           order by
                S_SYMB asc

                update
                  WATCH_ITEM
                set
                   WI_S_SYMB = new_symbol
         from
               WATCH_LIST
         where
               WL_C_ID = c_id and
               WI_WL_ID = WL_ID and
               WI_S_SYMB = old_symbol

            }
           commit transaction
}



3.3.12 Транзакция Trade-Cleanup

Транзакция Trade-Cleanup используется для отмены любых ожидающих или подтвержденных торгов из базы данных
Для вызова Trade-Cleanup Организатор может использовать EGenTxnHarness или осуществлять вызовы Транзакции другими тестами.
 
Trade-Cleanup используется для приведения базы данных к известному состоянию перед началом Выполнения Теста.

Транзакция Trade-Cleanup состоит из единственного Фрейма. Транзакция Trade-Cleanup может быть реализована с использованием более, чем одной Транзакции базы данных..

3.3.12.1 Параметры ТранзакцииTrade-Cleanup

Входные данные для Транзакции Trade-Cleanup предоставляются организатором. Структуры данных, определенные в TxnHarnessStructs.h, должны быть использованы для связи входных и выходных параметров.
 

         Параметры Транзакции Trade-Cleanup:

 

3.3.12.2 Слепок базы данных Транзакции Trade-Cleanup

 Слепок базы данных Транзакции Trade-Cleanup представлен следующим образом:
 

3.3.12.3 Фрейм 1 из 1-го Транзакции Trade-Cleanup
Методы доступа к базе данных, используемые во Фрейме 1 - это Reference, Modify, Remove и Add.

Если EGenTxnHarness используется для вызова Фрейма, он управляет выполнением Фрейма 1 следующим образом:
{
   invoke (Trade-Cleanup_Frame-1)
}

  Параметры Фрейма 1 из 1-го Транзакции Trade-Cleanup:
  


Псевдокод Trade-Cleanup_Frame-1: Отменить ожидающие и отправленные торги.

{
          start transaction

          Declare t_id         TRADE_T
          Declare tr_t_id    TRADE_T
          Declare now_dts DATETIME

          /* Find pending trades from TRADE_REQUEST */

          declare pending_list for
          select
              TR_T_ID
          from
              TRADE_REQUEST
          order by
              TR_T_ID

          open pending_list

          /* Insert a submitted followed by canceled record into TRADE_HISTORY, mark the trade canceled and delete the pending trade */

         do until (end_of_pending_list) {
         fetch from
          pending_list
         into
          tr_t_id

          get_current_dts ( now_dts )

        insert into
           TRADE_HISTORY (
           TH_T_ID, TH_DTS, TH_ST_ID
            )
        values (
            tr_t_id, // TH_T_ID
            now_dts, // TH_DTS
            st_submitted_id // TH_ST_ID
            )

        update
           TRADE
        set
           T_ST_ID = st_canceled_id,
           T_DTS = now_dts
       where
           T_ID = tr_t_id

       insert into
           TRADE_HISTORY (
                 TH_T_ID, TH_DTS, TH_ST_ID
           )
           values (
               tr_t_id, // TH_T_ID
               now_dts, // TH_DTS
               st_canceled_id // TH_ST_ID
           )

          } //end of pending_list

           /* Remove all pending trades */
          delete
          from
             TRADE_REQUEST

          /* Find submitted trades, change the status to canceled and insert a canceled record into TRADE_HISTORY*/
         declare submit_list for
         select
            T_ID
         from
            TRADE
         where
            T_ID >= trade_id and
            T_ST_ID = st_submitted_id

         open submit_list

         do until (end_of_submit_list) {
         fetch from 
           submit_list
         into
            t_id

         get_current_dts ( now_dts )

         /* Mark the trade as canceled, and record the time */
         update
            TRADE
         set
            T_ST_ID = st_canceled_id
            T_DTS = now_dts
         where
            T_ID = t_id

         insert into
            TRADE_HISTORY (
                    TH_T_ID, TH_DTS, TH_ST_ID
            )
            values (
                     t_id, // TH_T_ID
                     now_dts, // TH_DTS
                     st_canceled_id // TH_ST_ID
                     )

           } //end of submit_list

         commit transaction
}