Files
email-tracker/external/duckdb/third_party/tpce-tool/main/CETxnInputGenerator.cpp
2025-10-24 19:21:19 -05:00

961 lines
38 KiB
C++

/*
* 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<int>(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<int>(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<int>(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<int>(sizeof(TxnReq.symbol)));
} else {
// Submit the company name
m_pCompanies.CreateName(m_pSecurities.GetCompanyIndex(iFlatFileSymbIndex), TxnReq.co_name,
static_cast<int>(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<int>(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);
}
}