Глава 3 - Транзакции |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Содержание: 3.2. Правила реализации транзакций Ядро каждой транзакции 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 Каждый Слепок базы данных представлен в табличном формате, в котором колонки представляют следующее:
3.1.2.3 Следующая таблица является примером Слепка базы данных Транзакции.
Rollback
Слово «Commit» указывает, что соответствующий Фрейм содержит управляющую операцию, которая подтверждает Транзакцию базы данных. Commit: Контрольная операция в СУБД, которая делает временные изменения, внесенные транзакцией в данные, постоянными
Примечание: В одном Фрейме могут возникнуть несколько операций управления Транзакцией. Например, Транзакция, состоящая из одного Фрейма, будет содержать и «Start» и «Commit» в ее колонке Слепка базы данных, связанной с Фреймом 1.
Примечание 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. Могут быть исполнены любые дополнительные методы по отношению к любому Определенному пользователем объекту. 3.2.1.7 Минимальной точностью для каждого расчета, выполняемого как часть Фрейма, должна быть максимальная точность всех отдельных элементов в этом расчете. 3.2.1.8 Каждый Фрейм и Транзакция имеют выходной параметр статуса, используемый для обозначения статуса исполнения Фрейма или Транзакции. Значение статуса 0 обозначает успешное выполнение. Отрицательное значение статуса обозначает ошибку, которая нарушит Выполнение Теста. Положительное ненулевое целое значение статуса обозначает предупреждение. Предупреждения означают, что был создан неожиданный результат, и Организатору и Аудитору следует исследовать неожиданный результат. Неожиданный результат может быть следствием редких, но корректных условий, или использования некорректной реализации, или ошибки выполнения. Если причиной предупреждения является последнее, оно должно рассматриваться как ошибка, нарушающая Выполнение теста. 3.2.1.9 Если используется монитор обработки транзакций (здесь и далее называемый TM), он должен быть коммерчески доступным программным продуктом, предоставляющим следующие возможности/функции:
Администрирование/Обслуживание - TM должен иметь предопределенную возможность производить централизованное, непрограммируемое (т.е должно быть реализовано в стандартном продукте и не требовать дополнительного программирования) и динамическое управление конфигурацией ресурсов TM, включая оборудование, сети, службы (одиночные и групповые), правила установки приоритетов в управлении очередями, и т.д. Восстановление - TM также должен иметь возможность:
Прозрачность приложений – контекст(ы) сообщений, существующий между клиентской и серверной прикладными программами, должен управляться исключительно при помощи TM. Клиентская и серверная прикладные программы не должны иметь никаких сведений о контексте сообщения или нижележащем механизме обмена сообщениями, который обеспечивает этот контекст. Примечание 1: ниже приведены примеры реализация, не соответствующих требованиям Прозрачности приложений. Когда количество очередей или равнозначный структур данных, используемых ТМ для обслуживания контекста сообщений между клиентской и серверной прикладными программами, меняется администрацией ТМ, требуется изменение и/или рекомпиляция клиентской и/или серверной прикладной программы.
3.2.2 Разделение Клиентов и создание входных данных Транзакций. 3.2.2.1 Если используется разделение клиентов, и Фрейм Вызывается Клиентом, EGenDriverCE будет применять следующие правила при любом создании идентификатора клиента, идентификатора счета или налогового идентификатора клиента:
Если разделение клиентов не используется, или Фрейм не Вызывается Клиентом, EGenDriverCE будет создавать идентификаторы клиентов, идентификаторы счетов и налоговые идентификаторы клиентов из всего диапазона клиентов. 3.3 Транзакции Одной из ключевых характеристик производительности системы базы данных – это соотношение операций чтения и записи, создаваемых объемом нагрузки. Для моделирования подобного соотношения, TPC-E определило Транзакции с характеристиками только для чтения, равно как транзакции с характеристиками чтения и записи. Дополнительно, Транзакции осуществляют различную нагрузку на процессор. Транзакции в сочетании могут быть сгруппированы по трем категориям:
Следующая сводная таблица описывает базовые характеристики транзакций: 3.3.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. { Параметрые Фрейма 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 следующим образом: { Параметры Фрейма 1 из 3-х Транзакции Customer-Position:
Псевдокод Customer-Position_Frame-1: Получение информации по всем активам клиента
{ from } 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 следующим образом: { Параметры Фрейма 2 из 3-х Транзакции Customer-Position: Псевдокод Customer-Position_Frame-2: Получение истории торгов клиента { 3.3.2.5 Фрейм 3 из 3-х Транзакции Customer-Position Этот Фрейм исполняется только если для входного параметра get_history установлено значение FALSE. Этот Фрейм подтверждает Транзакцию, начатую во Фрейме 1, и возвращает статус. {
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 Используя записи из списка табло, Фрейм предназначается для:
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 дней рыночных данных, загруженных во время начального наполнения базы данных. Расчет выполнятся путем рассмотрения цены закрытия в выбранный день всех ценных бумаг в списке и умножения ее на количество торгуемых акций. Этот результат добавляется к промежуточной сумме капитализации закрывающегося рынка выбранного дня. Дополнительно, текущая стоимость всех ценных бумаг в списке умножается на число торгуемых пакетов акций. Этот результат добавляется к промежуточной сумме текущей рыночной капитализации. Возвращается разница между общей рыночной капитализации на момент закрытия выбранного дня к общей текущей, выраженная в процентах. Транзакция обеспечивает эти расчеты рыночного наблюдения по группе ценных бумаг, выбранных по следующему списку критериев:
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,
fromfin[].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 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 предназначена для имитации изъятия информации либо клиентом, либо брокером для получения ответов на их вопросы, касающиеся торгов. Различные виды торгов выбраны таким образом, чтобы работа представляла собой:
Фрейм 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 предназначена для имитации процесса внесения незначительных изменений или обновлений в набор торгов. Это является аналогом того, как клиент или брокер, просматривая набор торгов, обнаруживает необходимость внесения незначительных редакционных изменений. Различные виды торгов выбраны таким образом, чтобы работа представляла собой:
Фрейм 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. Она состоит из одного Фрейма. Эта Транзакция выполняется раз в минуту. Она имитирует периодические изменения в таблицах данных, которые обычно используются для организации ссылок другими Транзакциями. В качестве входных данных Драйвер предоставляет название таблицы, которая должна быть изменена Транзакцией. При каждом запуске этой Транзакции Драйвер изменяет содержимое следующей таблицы в списке. Это означает, что каждая таблица в списке будет изменяться только один раз в каждые двенадцать минут. Ниже приведен список названий таблиц, которые могут быть переданы в качестве аргументов в эту Транзакцию:
Назначением данной Транзакции является изменение таблиц данных, в которых не осуществляются записи способами контрольного тестирования. Во время каждого выполнения Транзакции 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 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 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 }
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||