/* * Legal Notice * * This document and associated source code (the "Work") is a part of a * benchmark specification maintained by the TPC. * * The TPC reserves all right, title, and interest to the Work as provided * under U.S. and international laws, including without limitation all patent * and trademark rights therein. * * No Warranty * * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES, * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE. * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT * WITH REGARD TO THE WORK. * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT, * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY, * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. * * Contributors * - Sergey Vasilevskiy, Doug Johnson, Matt Emmerton */ #include "main/CETxnInputGenerator.h" #include "main/DailyMarketTable.h" #include "main/TradeTypeIDs.h" using namespace TPCE; /* * Constructor - no partitioning by C_ID. * * PARAMETERS: * IN dfm - Data file manager * IN iConfiguredCustomerCount - number of configured customers in * the database IN iActiveCustomerCount - number of active customers in * the database IN iScaleFactor - scale factor (number of * customers per 1 tpsE) of the database IN iHoursOfInitialTrades - * number of hours of the initial trades portion of the database IN pLogger - * reference to parameter logging object IN pDriverCETxnSettings - * initial transaction parameter settings * * RETURNS: * not applicable. */ CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount, TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades, CBaseLogger *pLogger, const PDriverCETxnSettings pDriverCETxnSettings) : m_rnd(RNGSeedBaseTxnInputGenerator) // initialize with a default seed , m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount), m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()), m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()), m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()), m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger), m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount), m_iMyStartingCustomerId(iDefaultStartFromCustomer), m_iMyCustomerCount(iActiveCustomerCount), m_iPartitionPercent(100), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) { Initialize(); } /* * Constructor - no partitioning by C_ID, RNG seed provided. * * RNG seed is for testing/engineering work allowing repeatable transaction * parameter stream. This constructor is NOT legal for a benchmark publication. * * PARAMETERS: * IN dfm - Data file manager * IN iConfiguredCustomerCount - number of configured customers in * the database IN iActiveCustomerCount - number of active customers in * the database IN iScaleFactor - scale factor (number of * customers per 1 tpsE) of the database IN iHoursOfInitialTrades - * number of hours of the initial trades portion of the database IN RNGSeed - * initial seed for random number generator IN pLogger - * reference to parameter logging object IN pDriverCETxnSettings - * initial transaction parameter settings * * RETURNS: * not applicable. */ CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount, TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades, RNGSEED RNGSeed, CBaseLogger *pLogger, const PDriverCETxnSettings pDriverCETxnSettings) : m_rnd(RNGSeed) // to be predictable , m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount), m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()), m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()), m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()), m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger), m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount), m_iMyStartingCustomerId(iDefaultStartFromCustomer), m_iMyCustomerCount(iActiveCustomerCount), m_iPartitionPercent(100), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) { Initialize(); } /* * Constructor - partitioning by C_ID. * * PARAMETERS: * IN dfm - Data file manager * IN iConfiguredCustomerCount - number of configured customers in * the database IN iActiveCustomerCount - number of active customers in * the database IN iScaleFactor - scale factor (number of * customers per 1 tpsE) of the database IN iHoursOfInitialTrades - * number of hours of the initial trades portion of the database IN * iMyStartingCustomerId - first customer id (1-based) of the partition * for this instance IN iMyCustomerCount - number of customers in * the partition for this instance IN iPartitionPercent - the * percentage of C_IDs generated within this instance's partition IN pLogger - * reference to parameter logging object IN pDriverCETxnSettings - * initial transaction parameter settings * * RETURNS: * not applicable. */ CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount, TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades, TIdent iMyStartingCustomerId, TIdent iMyCustomerCount, INT32 iPartitionPercent, CBaseLogger *pLogger, const PDriverCETxnSettings pDriverCETxnSettings) : m_rnd(RNGSeedBaseTxnInputGenerator) // initialize with a default seed , m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount, iPartitionPercent, iMyStartingCustomerId, iMyCustomerCount), m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()), m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()), m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()), m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger), m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount), m_iMyStartingCustomerId(iMyStartingCustomerId), m_iMyCustomerCount(iMyCustomerCount), m_iPartitionPercent(iPartitionPercent), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) { Initialize(); } /* * Constructor - partitioning by C_ID, RNG seed provided. * * RNG seed is for testing/engineering work allowing repeatable transaction * parameter stream. This constructor is NOT legal for a benchmark publication. * * PARAMETERS: * IN dfm - Data file manager * IN iConfiguredCustomerCount - number of configured customers in * the database IN iActiveCustomerCount - number of active customers in * the database IN iScaleFactor - scale factor (number of * customers per 1 tpsE) of the database IN iHoursOfInitialTrades - * number of hours of the initial trades portion of the database IN * iMyStartingCustomerId - first customer id (1-based) of the partition * for this instance IN iMyCustomerCount - number of customers in * the partition for this instance IN iPartitionPercent - the * percentage of C_IDs generated within this instance's partition IN pLogger - * reference to parameter logging object IN pDriverCETxnSettings - * initial transaction parameter settings * * RETURNS: * not applicable. */ CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount, TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades, TIdent iMyStartingCustomerId, TIdent iMyCustomerCount, INT32 iPartitionPercent, RNGSEED RNGSeed, CBaseLogger *pLogger, const PDriverCETxnSettings pDriverCETxnSettings) : m_rnd(RNGSeed) // to be predictable , m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount, iPartitionPercent, iMyStartingCustomerId, iMyCustomerCount), m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer), m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()), m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()), m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()), m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger), m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount), m_iMyStartingCustomerId(iMyStartingCustomerId), m_iMyCustomerCount(iMyCustomerCount), m_iPartitionPercent(iPartitionPercent), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) { Initialize(); } /* * Perform initialization common to all constructors. * * PARAMETERS: * IN pDriverCETxnSettings - initial transaction parameter * settings * * RETURNS: * none. */ void CCETxnInputGenerator::Initialize() { m_iActiveCompanyCount = m_pCompanies.GetActiveCompanyCount(); m_iActiveSecurityCount = m_pSecurities.GetActiveSecurityCount(); m_iIndustryCount = m_pIndustries.size(); m_iSectorCount = m_pSectors.size(); m_iStartFromCompany = m_pCompanies.GetCompanyId(0); // from the first company // In order for this computation to overflow an INT64, assuming that all // multiplications are executed before divisions and the default value // for ITD is used, the active customer count must be greater than 2.1e10 // (21 billion customers). I hope we never get to that point. // NOTE: (iAbortTrade / 100) = 1.01, which is compensation for rollbacks. m_iMaxActivePrePopulatedTradeID = m_iHoursOfInitialTrades; m_iMaxActivePrePopulatedTradeID *= SecondsPerHour; m_iMaxActivePrePopulatedTradeID *= m_iActiveCustomerCount; m_iMaxActivePrePopulatedTradeID /= m_iScaleFactor; m_iMaxActivePrePopulatedTradeID *= iAbortTrade; m_iMaxActivePrePopulatedTradeID /= 100; // Set the start time (time 0) to the base time m_StartTime.Set(InitialTradePopulationBaseYear, InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay, InitialTradePopulationBaseHour, InitialTradePopulationBaseMinute, InitialTradePopulationBaseSecond, InitialTradePopulationBaseFraction); // UpdateTunables() is called from CCE constructor (Initialize) } /* * Return internal random number generator seed. * * PARAMETERS: * none. * * RETURNS: * current random number generator seed. */ RNGSEED CCETxnInputGenerator::GetRNGSeed(void) { return (m_rnd.GetSeed()); } /* * Set internal random number generator seed. * * PARAMETERS: * IN RNGSeed - new random number generator seed * * RETURNS: * none. */ void CCETxnInputGenerator::SetRNGSeed(RNGSEED RNGSeed) { m_rnd.SetSeed(RNGSeed); } /* * Refresh internal information from the external transaction parameters. * This function should be called anytime the external transaction * parameter structure changes. * * PARAMETERS: * none. * * RETURNS: * none. */ void CCETxnInputGenerator::UpdateTunables(void) { INT64 secondsOfInitialTrades = (INT64)m_iHoursOfInitialTrades * SecondsPerHour; m_iTradeLookupFrame2MaxTimeInMilliSeconds = (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame2)) * MsPerSecond; m_iTradeLookupFrame3MaxTimeInMilliSeconds = (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame3)) * MsPerSecond; m_iTradeLookupFrame4MaxTimeInMilliSeconds = (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame4)) * MsPerSecond; m_iTradeUpdateFrame2MaxTimeInMilliSeconds = (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TU_settings.cur.BackOffFromEndTimeFrame2)) * MsPerSecond; m_iTradeUpdateFrame3MaxTimeInMilliSeconds = (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TU_settings.cur.BackOffFromEndTimeFrame3)) * MsPerSecond; // Set the completion time of the last initial trade. // 15 minutes are added at the end of hours of initial trades for pending // trades. m_EndTime = m_StartTime; m_EndTime.AddWorkMs((INT64)(secondsOfInitialTrades + 15 * SecondsPerMinute) * MsPerSecond); // Based on 10 * Trade-Order transaction mix percentage. // This is currently how the mix levels are set, so use that. m_iTradeOrderRollbackLimit = m_pDriverCETxnSettings->TxnMixGenerator_settings.cur.TradeOrderMixLevel; m_iTradeOrderRollbackLevel = m_pDriverCETxnSettings->TO_settings.cur.rollback; // Log Tunables m_pLogger->SendToLogger(m_pDriverCETxnSettings->BV_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->CP_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->MW_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->SD_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->TL_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->TO_settings); m_pLogger->SendToLogger(m_pDriverCETxnSettings->TU_settings); } /* * Generate Non-Uniform customer ID. * * PARAMETERS: * OUT iCustomerId - generated C_ID * OUT iCustomerTier - generated C_TIER * * RETURNS: * none. */ inline void CCETxnInputGenerator::GenerateNonUniformRandomCustomerId(TIdent &iCustomerId, eCustomerTier &iCustomerTier) { m_CustomerSelection.GenerateRandomCustomer(iCustomerId, iCustomerTier); } /* * Generate customer account ID (uniformly distributed). * * PARAMETERS: * none. * * RETURNS: * CA_ID uniformly distributed across all load units. */ TIdent CCETxnInputGenerator::GenerateRandomCustomerAccountId() { TIdent iCustomerId; TIdent iCustomerAccountId; eCustomerTier iCustomerTier; m_CustomerSelection.GenerateRandomCustomer(iCustomerId, iCustomerTier); iCustomerAccountId = m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier); return (iCustomerAccountId); } /* * Generate a trade id to be used in Trade-Lookup / Trade-Update Frame 1. * * PARAMETERS: * IN AValue - parameter to NURAND function * IN SValue - parameter to NURAND function * * RETURNS: * T_ID, distributed non-uniformly. */ TTrade CCETxnInputGenerator::GenerateNonUniformTradeID(INT32 AValue, INT32 SValue) { TTrade TradeId; TradeId = m_rnd.NURnd(1, m_iMaxActivePrePopulatedTradeID, AValue, SValue); // Skip over trade id's that were skipped over during load time. if (m_Holdings.IsAbortedTrade(TradeId)) { TradeId++; } TradeId += iTTradeShift; // shift trade id to 64-bit value return (TradeId); } /* * Generate a trade timestamp to be used in Trade-Lookup / Trade-Update. * * PARAMETERS: * OUT dts - returned timestamp * IN MaxTimeInMilliSeconds - time interval (from the first initial * trade) in which to generate the timestamp IN AValue - * parameter to NURAND function IN SValue - parameter to * NURAND function * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateNonUniformTradeDTS(TPCE::TIMESTAMP_STRUCT &dts, INT64 MaxTimeInMilliSeconds, INT32 AValue, INT32 SValue) { CDateTime TradeTime(InitialTradePopulationBaseYear, InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay, InitialTradePopulationBaseHour, InitialTradePopulationBaseMinute, InitialTradePopulationBaseSecond, InitialTradePopulationBaseFraction); // NOTE: Interpretting Fraction as // milliseconds, // probably 0 anyway. INT64 TradeTimeOffset; // Generate random number of seconds from the base time. // TradeTimeOffset = m_rnd.NURnd(1, MaxTimeInMilliSeconds, AValue, SValue); // The time we have is an offset into the initial pre-populated trading // time. This needs to be converted into a "real" time taking into account 8 // hour business days, etc. TradeTime.AddWorkMs(TradeTimeOffset); TradeTime.GetTimeStamp(&dts); } /* * Generate Broker-Volume transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * the number of brokers generated. */ void CCETxnInputGenerator::GenerateBrokerVolumeInput(TBrokerVolumeTxnInput &TxnReq) { INT32 iNumBrokers; INT32 iCount, i; TIdent B_ID[max_broker_list_len]; INT32 iSectorIndex; // Make sure we're starting with a clean object. TxnReq.Clear(); // Select the range of brokers, honoring partitioning by CID settings. // iBrokersStart = iStartingBrokerID; // iBrokersCount = m_iActiveCustomerCount / iBrokersDiv; iNumBrokers = m_rnd.RndIntRange(min_broker_list_len, max_broker_list_len); // 20..40 brokers // Small databases (<=4LUs) may contain less than the chosen number of // brokers. Broker names for Broker Volume are unique, so need to re-adjust // or be caught in an infinite loop below. if (iNumBrokers > m_Brokers.GetBrokerCount()) { iNumBrokers = (INT32)m_Brokers.GetBrokerCount(); // adjust for small databases } iCount = 0; do { // select random broker ID (from active customer range) B_ID[iCount] = m_Brokers.GenerateRandomBrokerId(&m_rnd); for (i = 0; (i < iCount) && (B_ID[i] != B_ID[iCount]); ++i) { }; if (i == iCount) // make sure brokers are distinct { // put the broker name into the input parameter m_Brokers.GenerateBrokerName(B_ID[iCount], TxnReq.broker_list[iCount], static_cast(sizeof(TxnReq.broker_list[iCount]))); ++iCount; } } while (iCount < iNumBrokers); // select sector name iSectorIndex = m_rnd.RndIntRange(0, m_iSectorCount - 1); strncpy(TxnReq.sector_name, m_pSectors[iSectorIndex].SC_NAME_CSTR(), sizeof(TxnReq.sector_name)); } /* * Generate Customer-Position transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateCustomerPositionInput(TCustomerPositionTxnInput &TxnReq) { TIdent iCustomerId; eCustomerTier iCustomerTier; // Make sure we're starting with a clean object. TxnReq.Clear(); GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier); if (m_rnd.RndPercent(m_pDriverCETxnSettings->CP_settings.cur.by_tax_id)) { // send tax id instead of customer id m_Person.GetTaxID(iCustomerId, TxnReq.tax_id); } else { // send customer id and not the tax id TxnReq.cust_id = iCustomerId; } TxnReq.get_history = m_rnd.RndPercent(m_pDriverCETxnSettings->CP_settings.cur.get_history); if (TxnReq.get_history) { TxnReq.acct_id_idx = m_rnd.RndIntRange(0, m_AccsAndPerms.GetNumberOfAccounts(iCustomerId, iCustomerTier) - 1); } else { TxnReq.acct_id_idx = -1; } } /* * Generate Market-Watch transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateMarketWatchInput(TMarketWatchTxnInput &TxnReq) { TIdent iCustomerId; eCustomerTier iCustomerTier; INT32 iThreshold; INT32 iWeek; INT32 iDailyMarketDay; CDateTime StartDate(iDailyMarketBaseYear, iDailyMarketBaseMonth, iDailyMarketBaseDay, iDailyMarketBaseHour, iDailyMarketBaseMinute, iDailyMarketBaseSecond, iDailyMarketBaseMsec); // Make sure we're starting with a clean object. TxnReq.Clear(); iThreshold = m_rnd.RndGenerateIntegerPercentage(); // have some distribution on what inputs to send if (iThreshold <= m_pDriverCETxnSettings->MW_settings.cur.by_industry) { // send industry name strncpy(TxnReq.industry_name, m_pIndustries[m_rnd.RndIntRange(0, m_iIndustryCount - 1)].IN_NAME_CSTR(), sizeof(TxnReq.industry_name)); if (iBaseCompanyCount < m_iActiveCompanyCount) { TxnReq.starting_co_id = m_rnd.RndInt64Range( m_iStartFromCompany, m_iStartFromCompany + m_iActiveCompanyCount - (iBaseCompanyCount - 1)); TxnReq.ending_co_id = TxnReq.starting_co_id + (iBaseCompanyCount - 1); } else { TxnReq.starting_co_id = m_iStartFromCompany; TxnReq.ending_co_id = m_iStartFromCompany + m_iActiveCompanyCount - 1; } } else { if (iThreshold <= (m_pDriverCETxnSettings->MW_settings.cur.by_industry + m_pDriverCETxnSettings->MW_settings.cur.by_watch_list)) { // Send customer id GenerateNonUniformRandomCustomerId(TxnReq.c_id, iCustomerTier); } else { // Send account id GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier); m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier, &TxnReq.acct_id, NULL); } } // Set start_day for both cases of the 'if'. // iWeek = (INT32)m_rnd.NURnd(0, 255, 255, 0) + 5; // A = 255, S = 0 // Week is now between 5 and 260. // Select a day within the week. // iThreshold = m_rnd.RndGenerateIntegerPercentage(); if (iThreshold > 40) { iDailyMarketDay = iWeek * DaysPerWeek + 4; // Friday } else // 1..40 case { if (iThreshold <= 20) { iDailyMarketDay = iWeek * DaysPerWeek; // Monday } else { if (iThreshold <= 27) { iDailyMarketDay = iWeek * DaysPerWeek + 1; // Tuesday } else { if (iThreshold <= 33) { iDailyMarketDay = iWeek * DaysPerWeek + 2; // Wednesday } else { iDailyMarketDay = iWeek * DaysPerWeek + 3; // Thursday } } } } // Go back 256 weeks and then add our calculated day. // StartDate.Add(iDailyMarketDay, 0); StartDate.GetTimeStamp(&TxnReq.start_day); } /* * Generate Security-Detail transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateSecurityDetailInput(TSecurityDetailTxnInput &TxnReq) { CDateTime StartDate(iDailyMarketBaseYear, iDailyMarketBaseMonth, iDailyMarketBaseDay, iDailyMarketBaseHour, iDailyMarketBaseMinute, iDailyMarketBaseSecond, iDailyMarketBaseMsec); INT32 iStartDay; // day from the StartDate // Make sure we're starting with a clean object. TxnReq.Clear(); // random symbol m_pSecurities.CreateSymbol(m_rnd.RndInt64Range(0, m_iActiveSecurityCount - 1), TxnReq.symbol, static_cast(sizeof(TxnReq.symbol))); // Whether or not to access the LOB. TxnReq.access_lob_flag = m_rnd.RndPercent(m_pDriverCETxnSettings->SD_settings.cur.LOBAccessPercentage); // random number of financial rows to return TxnReq.max_rows_to_return = m_rnd.RndIntRange(iSecurityDetailMinRows, iSecurityDetailMaxRows); iStartDay = m_rnd.RndIntRange(0, iDailyMarketTotalRows - TxnReq.max_rows_to_return); // add the offset StartDate.Add(iStartDay, 0); StartDate.GetTimeStamp(&TxnReq.start_day); } /* * Generate Trade-Lookup transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateTradeLookupInput(TTradeLookupTxnInput &TxnReq) { INT32 iThreshold; // Make sure we're starting with a clean object. TxnReq.Clear(); iThreshold = m_rnd.RndGenerateIntegerPercentage(); if (iThreshold <= m_pDriverCETxnSettings->TL_settings.cur.do_frame1) { // Frame 1 TxnReq.frame_to_execute = 1; TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame1; // Generate list of unique trade id's int ii, jj; bool Accepted; TTrade TID; for (ii = 0; ii < TxnReq.max_trades; ii++) { Accepted = false; while (!Accepted) { TID = GenerateNonUniformTradeID(TradeLookupAValueForTradeIDGenFrame1, TradeLookupSValueForTradeIDGenFrame1); jj = 0; while (jj < ii && TxnReq.trade_id[jj] != TID) { jj++; } if (jj == ii) { // We have a unique TID for this batch TxnReq.trade_id[ii] = TID; Accepted = true; } } } } else if (iThreshold <= m_pDriverCETxnSettings->TL_settings.cur.do_frame1 + m_pDriverCETxnSettings->TL_settings.cur.do_frame2) { // Frame 2 TxnReq.frame_to_execute = 2; TxnReq.acct_id = GenerateRandomCustomerAccountId(); TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame2; GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame2MaxTimeInMilliSeconds, TradeLookupAValueForTimeGenFrame2, TradeLookupSValueForTimeGenFrame2); // Set to the end of initial trades. m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts); } else if (iThreshold <= m_pDriverCETxnSettings->TL_settings.cur.do_frame1 + m_pDriverCETxnSettings->TL_settings.cur.do_frame2 + m_pDriverCETxnSettings->TL_settings.cur.do_frame3) { // Frame 3 TxnReq.frame_to_execute = 3; TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame3; m_pSecurities.CreateSymbol(m_rnd.NURnd(0, m_iActiveSecurityCount - 1, TradeLookupAValueForSymbolFrame3, TradeLookupSValueForSymbolFrame3), TxnReq.symbol, static_cast(sizeof(TxnReq.symbol))); GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame3MaxTimeInMilliSeconds, TradeLookupAValueForTimeGenFrame3, TradeLookupSValueForTimeGenFrame3); // Set to the end of initial trades. m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts); TxnReq.max_acct_id = m_AccsAndPerms.GetEndingCA_ID(m_iActiveCustomerCount); } else { // Frame 4 TxnReq.frame_to_execute = 4; TxnReq.acct_id = GenerateRandomCustomerAccountId(); GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame4MaxTimeInMilliSeconds, TradeLookupAValueForTimeGenFrame4, TradeLookupSValueForTimeGenFrame4); } } /* * Generate Trade-Order transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. OUT TradeType - integer representation of * generated trade type (as eTradeTypeID enum). OUT bExecutorIsAccountOwner - * whether Trade-Order frame 2 should (FALSE) or shouldn't (TRUE) be called. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateTradeOrderInput(TTradeOrderTxnInput &TxnReq, INT32 &iTradeType, bool &bExecutorIsAccountOwner) { TIdent iCustomerId; // owner eCustomerTier iCustomerTier; TIdent CID_1, CID_2; bool bMarket; INT32 iAdditionalPerms; UINT iSymbIndex; TIdent iFlatFileSymbIndex; eTradeTypeID eTradeType; // Make sure we're starting with a clean object. TxnReq.Clear(); // Generate random customer // GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier); // Generate random account id and security index // m_Holdings.GenerateRandomAccountSecurity(iCustomerId, iCustomerTier, &TxnReq.acct_id, &iFlatFileSymbIndex, &iSymbIndex); // find out how many permission rows there are for this account (in addition // to the owner's) iAdditionalPerms = m_AccsAndPerms.GetNumPermsForCA(TxnReq.acct_id); // distribution same as in the loader for now if (iAdditionalPerms == 0) { // select the owner m_Person.GetFirstLastAndTaxID(iCustomerId, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id); bExecutorIsAccountOwner = true; } else { // If there is more than one permission set on the account, // have some distribution on whether the executor is still // the account owner, or it is one of the additional permissions. // Here we must take into account the fact that we've excluded // a large portion of customers that don't have any additional // executors in the above code (iAdditionalPerms == 0); the // "exec_is_owner" percentage implicity includes such customers // and must be factored out here. int exec_is_owner = (m_pDriverCETxnSettings->TO_settings.cur.exec_is_owner - iPercentAccountAdditionalPermissions_0) * 100 / (100 - iPercentAccountAdditionalPermissions_0); if (m_rnd.RndPercent(exec_is_owner)) { m_Person.GetFirstLastAndTaxID(iCustomerId, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id); bExecutorIsAccountOwner = true; } else { if (iAdditionalPerms == 1) { // select the first non-owner m_AccsAndPerms.GetCIDsForPermissions(TxnReq.acct_id, iCustomerId, &CID_1, NULL); m_Person.GetFirstLastAndTaxID(CID_1, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id); } else { // select the second non-owner m_AccsAndPerms.GetCIDsForPermissions(TxnReq.acct_id, iCustomerId, &CID_1, &CID_2); // generate third account permission row m_Person.GetFirstLastAndTaxID(CID_2, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id); } bExecutorIsAccountOwner = false; } } // Select either stock symbol or company from the securities flat file. // // have some distribution on the company/symbol input preference if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.security_by_symbol)) { // Submit the symbol m_pSecurities.CreateSymbol(iFlatFileSymbIndex, TxnReq.symbol, static_cast(sizeof(TxnReq.symbol))); } else { // Submit the company name m_pCompanies.CreateName(m_pSecurities.GetCompanyIndex(iFlatFileSymbIndex), TxnReq.co_name, static_cast(sizeof(TxnReq.co_name))); strncpy(TxnReq.issue, m_pSecurities.GetRecord(iFlatFileSymbIndex).S_ISSUE_CSTR(), sizeof(TxnReq.issue)); } TxnReq.trade_qty = cTRADE_QTY_SIZES[m_rnd.RndIntRange(0, cNUM_TRADE_QTY_SIZES - 1)]; TxnReq.requested_price = m_rnd.RndDoubleIncrRange(fMinSecPrice, fMaxSecPrice, 0.01); // Determine whether Market or Limit order bMarket = m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.market); // Determine whether Buy or Sell trade if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.buy_orders)) { if (bMarket) { // Market Buy eTradeType = eMarketBuy; } else { // Limit Buy eTradeType = eLimitBuy; } // Set margin or cash for Buy TxnReq.type_is_margin = m_rnd.RndPercent( // type_is_margin is specified for all orders, but used only for // buys m_pDriverCETxnSettings->TO_settings.cur.type_is_margin * 100 / m_pDriverCETxnSettings->TO_settings.cur.buy_orders); } else { if (bMarket) { // Market Sell eTradeType = eMarketSell; } else { // determine whether the Limit Sell is a Stop Loss if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.stop_loss)) { // Stop Loss eTradeType = eStopLoss; } else { // Limit Sell eTradeType = eLimitSell; } } TxnReq.type_is_margin = false; // all sell orders are cash } iTradeType = eTradeType; // Distribution of last-in-first-out flag TxnReq.is_lifo = m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.lifo); // Copy the trade type id from the flat file strncpy(TxnReq.trade_type_id, m_pTradeType[eTradeType].TT_ID_CSTR(), sizeof(TxnReq.trade_type_id)); // Copy the status type id's from the flat file strncpy(TxnReq.st_pending_id, m_pStatusType[ePending].ST_ID_CSTR(), sizeof(TxnReq.st_pending_id)); strncpy(TxnReq.st_submitted_id, m_pStatusType[eSubmitted].ST_ID_CSTR(), sizeof(TxnReq.st_submitted_id)); TxnReq.roll_it_back = (m_iTradeOrderRollbackLevel >= m_rnd.RndIntRange(1, m_iTradeOrderRollbackLimit)); // Need to address logging more comprehensively. // return eTradeType; } /* * Generate Trade-Status transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateTradeStatusInput(TTradeStatusTxnInput &TxnReq) { TIdent iCustomerId; eCustomerTier iCustomerTier; // Make sure we're starting with a clean object. TxnReq.Clear(); // select customer id first GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier); // select random account id m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier, &TxnReq.acct_id, NULL); } /* * Generate Trade-Update transaction input. * * PARAMETERS: * OUT TxnReq - input parameter structure filled in * for the transaction. * * RETURNS: * none. */ void CCETxnInputGenerator::GenerateTradeUpdateInput(TTradeUpdateTxnInput &TxnReq) { INT32 iThreshold; // Make sure we're starting with a clean object. TxnReq.Clear(); iThreshold = m_rnd.RndGenerateIntegerPercentage(); if (iThreshold <= m_pDriverCETxnSettings->TU_settings.cur.do_frame1) { // Frame 1 TxnReq.frame_to_execute = 1; TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame1; TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame1; // Generate list of unique trade id's int ii, jj; bool Accepted; TTrade TID; for (ii = 0; ii < TxnReq.max_trades; ii++) { Accepted = false; while (!Accepted) { TID = GenerateNonUniformTradeID(TradeUpdateAValueForTradeIDGenFrame1, TradeUpdateSValueForTradeIDGenFrame1); jj = 0; while (jj < ii && TxnReq.trade_id[jj] != TID) { jj++; } if (jj == ii) { // We have a unique TID for this batch TxnReq.trade_id[ii] = TID; Accepted = true; } } } } else if (iThreshold <= m_pDriverCETxnSettings->TU_settings.cur.do_frame1 + m_pDriverCETxnSettings->TU_settings.cur.do_frame2) { // Frame 2 TxnReq.frame_to_execute = 2; TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame2; TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame2; TxnReq.acct_id = GenerateRandomCustomerAccountId(); GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeUpdateFrame2MaxTimeInMilliSeconds, TradeUpdateAValueForTimeGenFrame2, TradeUpdateSValueForTimeGenFrame2); // Set to the end of initial trades. m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts); } else { // Frame 3 TxnReq.frame_to_execute = 3; TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame3; TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame3; m_pSecurities.CreateSymbol(m_rnd.NURnd(0, m_iActiveSecurityCount - 1, TradeUpdateAValueForSymbolFrame3, TradeUpdateSValueForSymbolFrame3), TxnReq.symbol, static_cast(sizeof(TxnReq.symbol))); GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeUpdateFrame3MaxTimeInMilliSeconds, TradeUpdateAValueForTimeGenFrame3, TradeUpdateSValueForTimeGenFrame3); // Set to the end of initial trades. m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts); TxnReq.max_acct_id = m_AccsAndPerms.GetEndingCA_ID(m_iActiveCustomerCount); } }