1/*
2 * Legal Notice
3 *
4 * This document and associated source code (the "Work") is a part of a
5 * benchmark specification maintained by the TPC.
6 *
7 * The TPC reserves all right, title, and interest to the Work as provided
8 * under U.S. and international laws, including without limitation all patent
9 * and trademark rights therein.
10 *
11 * No Warranty
12 *
13 * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
14 * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
15 * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
16 * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
17 * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
18 * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
19 * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
20 * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
21 * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
22 * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
23 * WITH REGARD TO THE WORK.
24 * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
25 * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
26 * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
27 * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
28 * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
29 * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
30 * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
31 * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * Contributors
34 * - Sergey Vasilevskiy, Doug Johnson, Matt Emmerton
35 */
36
37#include "main/CETxnInputGenerator.h"
38#include "main/DailyMarketTable.h"
39#include "main/TradeTypeIDs.h"
40
41using namespace TPCE;
42
43/*
44 * Constructor - no partitioning by C_ID.
45 *
46 * PARAMETERS:
47 * IN dfm - Data file manager
48 * IN iConfiguredCustomerCount - number of configured customers in
49 * the database IN iActiveCustomerCount - number of active customers in
50 * the database IN iScaleFactor - scale factor (number of
51 * customers per 1 tpsE) of the database IN iHoursOfInitialTrades -
52 * number of hours of the initial trades portion of the database IN pLogger -
53 * reference to parameter logging object IN pDriverCETxnSettings -
54 * initial transaction parameter settings
55 *
56 * RETURNS:
57 * not applicable.
58 */
59CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
60 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades,
61 CBaseLogger *pLogger,
62 const PDriverCETxnSettings pDriverCETxnSettings)
63 : m_rnd(RNGSeedBaseTxnInputGenerator) // initialize with a default seed
64 ,
65 m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount),
66 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
67 m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
68 m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()),
69 m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()),
70 m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()),
71 m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger),
72 m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount),
73 m_iMyStartingCustomerId(iDefaultStartFromCustomer), m_iMyCustomerCount(iActiveCustomerCount),
74 m_iPartitionPercent(100), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) {
75 Initialize();
76}
77
78/*
79 * Constructor - no partitioning by C_ID, RNG seed provided.
80 *
81 * RNG seed is for testing/engineering work allowing repeatable transaction
82 * parameter stream. This constructor is NOT legal for a benchmark publication.
83 *
84 * PARAMETERS:
85 * IN dfm - Data file manager
86 * IN iConfiguredCustomerCount - number of configured customers in
87 * the database IN iActiveCustomerCount - number of active customers in
88 * the database IN iScaleFactor - scale factor (number of
89 * customers per 1 tpsE) of the database IN iHoursOfInitialTrades -
90 * number of hours of the initial trades portion of the database IN RNGSeed -
91 * initial seed for random number generator IN pLogger -
92 * reference to parameter logging object IN pDriverCETxnSettings -
93 * initial transaction parameter settings
94 *
95 * RETURNS:
96 * not applicable.
97 */
98CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
99 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades,
100 RNGSEED RNGSeed, CBaseLogger *pLogger,
101 const PDriverCETxnSettings pDriverCETxnSettings)
102 : m_rnd(RNGSeed) // to be predictable
103 ,
104 m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount),
105 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
106 m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
107 m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()),
108 m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()),
109 m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()),
110 m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger),
111 m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount),
112 m_iMyStartingCustomerId(iDefaultStartFromCustomer), m_iMyCustomerCount(iActiveCustomerCount),
113 m_iPartitionPercent(100), m_iScaleFactor(iScaleFactor), m_iHoursOfInitialTrades(iHoursOfInitialTrades) {
114 Initialize();
115}
116
117/*
118 * Constructor - partitioning by C_ID.
119 *
120 * PARAMETERS:
121 * IN dfm - Data file manager
122 * IN iConfiguredCustomerCount - number of configured customers in
123 * the database IN iActiveCustomerCount - number of active customers in
124 * the database IN iScaleFactor - scale factor (number of
125 * customers per 1 tpsE) of the database IN iHoursOfInitialTrades -
126 * number of hours of the initial trades portion of the database IN
127 * iMyStartingCustomerId - first customer id (1-based) of the partition
128 * for this instance IN iMyCustomerCount - number of customers in
129 * the partition for this instance IN iPartitionPercent - the
130 * percentage of C_IDs generated within this instance's partition IN pLogger -
131 * reference to parameter logging object IN pDriverCETxnSettings -
132 * initial transaction parameter settings
133 *
134 * RETURNS:
135 * not applicable.
136 */
137CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
138 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades,
139 TIdent iMyStartingCustomerId, TIdent iMyCustomerCount,
140 INT32 iPartitionPercent, CBaseLogger *pLogger,
141 const PDriverCETxnSettings pDriverCETxnSettings)
142 : m_rnd(RNGSeedBaseTxnInputGenerator) // initialize with a default seed
143 ,
144 m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount,
145 iPartitionPercent, iMyStartingCustomerId, iMyCustomerCount),
146 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
147 m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
148 m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()),
149 m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()),
150 m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()),
151 m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger),
152 m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount),
153 m_iMyStartingCustomerId(iMyStartingCustomerId), m_iMyCustomerCount(iMyCustomerCount),
154 m_iPartitionPercent(iPartitionPercent), m_iScaleFactor(iScaleFactor),
155 m_iHoursOfInitialTrades(iHoursOfInitialTrades) {
156 Initialize();
157}
158
159/*
160 * Constructor - partitioning by C_ID, RNG seed provided.
161 *
162 * RNG seed is for testing/engineering work allowing repeatable transaction
163 * parameter stream. This constructor is NOT legal for a benchmark publication.
164 *
165 * PARAMETERS:
166 * IN dfm - Data file manager
167 * IN iConfiguredCustomerCount - number of configured customers in
168 * the database IN iActiveCustomerCount - number of active customers in
169 * the database IN iScaleFactor - scale factor (number of
170 * customers per 1 tpsE) of the database IN iHoursOfInitialTrades -
171 * number of hours of the initial trades portion of the database IN
172 * iMyStartingCustomerId - first customer id (1-based) of the partition
173 * for this instance IN iMyCustomerCount - number of customers in
174 * the partition for this instance IN iPartitionPercent - the
175 * percentage of C_IDs generated within this instance's partition IN pLogger -
176 * reference to parameter logging object IN pDriverCETxnSettings -
177 * initial transaction parameter settings
178 *
179 * RETURNS:
180 * not applicable.
181 */
182CCETxnInputGenerator::CCETxnInputGenerator(const DataFileManager &dfm, TIdent iConfiguredCustomerCount,
183 TIdent iActiveCustomerCount, INT32 iScaleFactor, INT32 iHoursOfInitialTrades,
184 TIdent iMyStartingCustomerId, TIdent iMyCustomerCount,
185 INT32 iPartitionPercent, RNGSEED RNGSeed, CBaseLogger *pLogger,
186 const PDriverCETxnSettings pDriverCETxnSettings)
187 : m_rnd(RNGSeed) // to be predictable
188 ,
189 m_Person(dfm, 0, false), m_CustomerSelection(&m_rnd, iDefaultStartFromCustomer, iActiveCustomerCount,
190 iPartitionPercent, iMyStartingCustomerId, iMyCustomerCount),
191 m_AccsAndPerms(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
192 m_Holdings(dfm, iDefaultLoadUnitSize, iActiveCustomerCount, iDefaultStartFromCustomer),
193 m_Brokers(dfm, iActiveCustomerCount, iDefaultStartFromCustomer), m_pCompanies(dfm.CompanyFile()),
194 m_pSecurities(dfm.SecurityFile()), m_pIndustries(dfm.IndustryDataFile()), m_pSectors(dfm.SectorDataFile()),
195 m_pStatusType(dfm.StatusTypeDataFile()), m_pTradeType(dfm.TradeTypeDataFile()),
196 m_pDriverCETxnSettings(pDriverCETxnSettings), m_pLogger(pLogger),
197 m_iConfiguredCustomerCount(iConfiguredCustomerCount), m_iActiveCustomerCount(iActiveCustomerCount),
198 m_iMyStartingCustomerId(iMyStartingCustomerId), m_iMyCustomerCount(iMyCustomerCount),
199 m_iPartitionPercent(iPartitionPercent), m_iScaleFactor(iScaleFactor),
200 m_iHoursOfInitialTrades(iHoursOfInitialTrades) {
201 Initialize();
202}
203
204/*
205 * Perform initialization common to all constructors.
206 *
207 * PARAMETERS:
208 * IN pDriverCETxnSettings - initial transaction parameter
209 * settings
210 *
211 * RETURNS:
212 * none.
213 */
214void CCETxnInputGenerator::Initialize() {
215 m_iActiveCompanyCount = m_pCompanies.GetActiveCompanyCount();
216 m_iActiveSecurityCount = m_pSecurities.GetActiveSecurityCount();
217 m_iIndustryCount = m_pIndustries.size();
218 m_iSectorCount = m_pSectors.size();
219 m_iStartFromCompany = m_pCompanies.GetCompanyId(0); // from the first company
220
221 // In order for this computation to overflow an INT64, assuming that all
222 // multiplications are executed before divisions and the default value
223 // for ITD is used, the active customer count must be greater than 2.1e10
224 // (21 billion customers). I hope we never get to that point.
225 // NOTE: (iAbortTrade / 100) = 1.01, which is compensation for rollbacks.
226
227 m_iMaxActivePrePopulatedTradeID = m_iHoursOfInitialTrades;
228 m_iMaxActivePrePopulatedTradeID *= SecondsPerHour;
229 m_iMaxActivePrePopulatedTradeID *= m_iActiveCustomerCount;
230 m_iMaxActivePrePopulatedTradeID /= m_iScaleFactor;
231 m_iMaxActivePrePopulatedTradeID *= iAbortTrade;
232 m_iMaxActivePrePopulatedTradeID /= 100;
233
234 // Set the start time (time 0) to the base time
235 m_StartTime.Set(InitialTradePopulationBaseYear, InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay,
236 InitialTradePopulationBaseHour, InitialTradePopulationBaseMinute, InitialTradePopulationBaseSecond,
237 InitialTradePopulationBaseFraction);
238
239 // UpdateTunables() is called from CCE constructor (Initialize)
240}
241
242/*
243 * Return internal random number generator seed.
244 *
245 * PARAMETERS:
246 * none.
247 *
248 * RETURNS:
249 * current random number generator seed.
250 */
251RNGSEED CCETxnInputGenerator::GetRNGSeed(void) {
252 return (m_rnd.GetSeed());
253}
254
255/*
256 * Set internal random number generator seed.
257 *
258 * PARAMETERS:
259 * IN RNGSeed - new random number generator seed
260 *
261 * RETURNS:
262 * none.
263 */
264void CCETxnInputGenerator::SetRNGSeed(RNGSEED RNGSeed) {
265 m_rnd.SetSeed(RNGSeed);
266}
267
268/*
269 * Refresh internal information from the external transaction parameters.
270 * This function should be called anytime the external transaction
271 * parameter structure changes.
272 *
273 * PARAMETERS:
274 * none.
275 *
276 * RETURNS:
277 * none.
278 */
279void CCETxnInputGenerator::UpdateTunables(void) {
280 INT64 secondsOfInitialTrades = (INT64)m_iHoursOfInitialTrades * SecondsPerHour;
281
282 m_iTradeLookupFrame2MaxTimeInMilliSeconds =
283 (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame2)) *
284 MsPerSecond;
285
286 m_iTradeLookupFrame3MaxTimeInMilliSeconds =
287 (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame3)) *
288 MsPerSecond;
289
290 m_iTradeLookupFrame4MaxTimeInMilliSeconds =
291 (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TL_settings.cur.BackOffFromEndTimeFrame4)) *
292 MsPerSecond;
293
294 m_iTradeUpdateFrame2MaxTimeInMilliSeconds =
295 (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TU_settings.cur.BackOffFromEndTimeFrame2)) *
296 MsPerSecond;
297
298 m_iTradeUpdateFrame3MaxTimeInMilliSeconds =
299 (INT64)(secondsOfInitialTrades - ((INT64)m_pDriverCETxnSettings->TU_settings.cur.BackOffFromEndTimeFrame3)) *
300 MsPerSecond;
301
302 // Set the completion time of the last initial trade.
303 // 15 minutes are added at the end of hours of initial trades for pending
304 // trades.
305 m_EndTime = m_StartTime;
306 m_EndTime.AddWorkMs((INT64)(secondsOfInitialTrades + 15 * SecondsPerMinute) * MsPerSecond);
307
308 // Based on 10 * Trade-Order transaction mix percentage.
309 // This is currently how the mix levels are set, so use that.
310 m_iTradeOrderRollbackLimit = m_pDriverCETxnSettings->TxnMixGenerator_settings.cur.TradeOrderMixLevel;
311 m_iTradeOrderRollbackLevel = m_pDriverCETxnSettings->TO_settings.cur.rollback;
312
313 // Log Tunables
314 m_pLogger->SendToLogger(m_pDriverCETxnSettings->BV_settings);
315 m_pLogger->SendToLogger(m_pDriverCETxnSettings->CP_settings);
316 m_pLogger->SendToLogger(m_pDriverCETxnSettings->MW_settings);
317 m_pLogger->SendToLogger(m_pDriverCETxnSettings->SD_settings);
318 m_pLogger->SendToLogger(m_pDriverCETxnSettings->TL_settings);
319 m_pLogger->SendToLogger(m_pDriverCETxnSettings->TO_settings);
320 m_pLogger->SendToLogger(m_pDriverCETxnSettings->TU_settings);
321}
322
323/*
324 * Generate Non-Uniform customer ID.
325 *
326 * PARAMETERS:
327 * OUT iCustomerId - generated C_ID
328 * OUT iCustomerTier - generated C_TIER
329 *
330 * RETURNS:
331 * none.
332 */
333inline void CCETxnInputGenerator::GenerateNonUniformRandomCustomerId(TIdent &iCustomerId,
334 eCustomerTier &iCustomerTier) {
335 m_CustomerSelection.GenerateRandomCustomer(iCustomerId, iCustomerTier);
336}
337
338/*
339 * Generate customer account ID (uniformly distributed).
340 *
341 * PARAMETERS:
342 * none.
343 *
344 * RETURNS:
345 * CA_ID uniformly distributed across all load units.
346 */
347TIdent CCETxnInputGenerator::GenerateRandomCustomerAccountId() {
348 TIdent iCustomerId;
349 TIdent iCustomerAccountId;
350 eCustomerTier iCustomerTier;
351
352 m_CustomerSelection.GenerateRandomCustomer(iCustomerId, iCustomerTier);
353 iCustomerAccountId = m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier);
354
355 return (iCustomerAccountId);
356}
357
358/*
359 * Generate a trade id to be used in Trade-Lookup / Trade-Update Frame 1.
360 *
361 * PARAMETERS:
362 * IN AValue - parameter to NURAND function
363 * IN SValue - parameter to NURAND function
364 *
365 * RETURNS:
366 * T_ID, distributed non-uniformly.
367 */
368TTrade CCETxnInputGenerator::GenerateNonUniformTradeID(INT32 AValue, INT32 SValue) {
369 TTrade TradeId;
370
371 TradeId = m_rnd.NURnd(1, m_iMaxActivePrePopulatedTradeID, AValue, SValue);
372
373 // Skip over trade id's that were skipped over during load time.
374 if (m_Holdings.IsAbortedTrade(TradeId)) {
375 TradeId++;
376 }
377
378 TradeId += iTTradeShift; // shift trade id to 64-bit value
379
380 return (TradeId);
381}
382
383/*
384 * Generate a trade timestamp to be used in Trade-Lookup / Trade-Update.
385 *
386 * PARAMETERS:
387 * OUT dts - returned timestamp
388 * IN MaxTimeInMilliSeconds - time interval (from the first initial
389 * trade) in which to generate the timestamp IN AValue -
390 * parameter to NURAND function IN SValue - parameter to
391 * NURAND function
392 *
393 * RETURNS:
394 * none.
395 */
396void CCETxnInputGenerator::GenerateNonUniformTradeDTS(TPCE::TIMESTAMP_STRUCT &dts, INT64 MaxTimeInMilliSeconds,
397 INT32 AValue, INT32 SValue) {
398 CDateTime TradeTime(InitialTradePopulationBaseYear, InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay,
399 InitialTradePopulationBaseHour, InitialTradePopulationBaseMinute,
400 InitialTradePopulationBaseSecond,
401 InitialTradePopulationBaseFraction); // NOTE: Interpretting Fraction as
402 // milliseconds,
403 // probably 0 anyway.
404 INT64 TradeTimeOffset;
405
406 // Generate random number of seconds from the base time.
407 //
408 TradeTimeOffset = m_rnd.NURnd(1, MaxTimeInMilliSeconds, AValue, SValue);
409
410 // The time we have is an offset into the initial pre-populated trading
411 // time. This needs to be converted into a "real" time taking into account 8
412 // hour business days, etc.
413
414 TradeTime.AddWorkMs(TradeTimeOffset);
415 TradeTime.GetTimeStamp(&dts);
416}
417
418/*
419 * Generate Broker-Volume transaction input.
420 *
421 * PARAMETERS:
422 * OUT TxnReq - input parameter structure filled in
423 * for the transaction.
424 *
425 * RETURNS:
426 * the number of brokers generated.
427 */
428void CCETxnInputGenerator::GenerateBrokerVolumeInput(TBrokerVolumeTxnInput &TxnReq) {
429 INT32 iNumBrokers;
430 INT32 iCount, i;
431 TIdent B_ID[max_broker_list_len];
432 INT32 iSectorIndex;
433
434 // Make sure we're starting with a clean object.
435 TxnReq.Clear();
436
437 // Select the range of brokers, honoring partitioning by CID settings.
438 // iBrokersStart = iStartingBrokerID;
439 // iBrokersCount = m_iActiveCustomerCount / iBrokersDiv;
440 iNumBrokers = m_rnd.RndIntRange(min_broker_list_len,
441 max_broker_list_len); // 20..40 brokers
442 // Small databases (<=4LUs) may contain less than the chosen number of
443 // brokers. Broker names for Broker Volume are unique, so need to re-adjust
444 // or be caught in an infinite loop below.
445 if (iNumBrokers > m_Brokers.GetBrokerCount()) {
446 iNumBrokers = (INT32)m_Brokers.GetBrokerCount(); // adjust for small databases
447 }
448
449 iCount = 0;
450 do {
451 // select random broker ID (from active customer range)
452 B_ID[iCount] = m_Brokers.GenerateRandomBrokerId(&m_rnd);
453
454 for (i = 0; (i < iCount) && (B_ID[i] != B_ID[iCount]); ++i) {
455 };
456
457 if (i == iCount) // make sure brokers are distinct
458 {
459 // put the broker name into the input parameter
460 m_Brokers.GenerateBrokerName(B_ID[iCount], TxnReq.broker_list[iCount],
461 static_cast<int>(sizeof(TxnReq.broker_list[iCount])));
462 ++iCount;
463 }
464
465 } while (iCount < iNumBrokers);
466
467 // select sector name
468 iSectorIndex = m_rnd.RndIntRange(0, m_iSectorCount - 1);
469
470 strncpy(TxnReq.sector_name, m_pSectors[iSectorIndex].SC_NAME_CSTR(), sizeof(TxnReq.sector_name));
471}
472
473/*
474 * Generate Customer-Position transaction input.
475 *
476 * PARAMETERS:
477 * OUT TxnReq - input parameter structure filled in
478 * for the transaction.
479 *
480 * RETURNS:
481 * none.
482 */
483void CCETxnInputGenerator::GenerateCustomerPositionInput(TCustomerPositionTxnInput &TxnReq) {
484 TIdent iCustomerId;
485 eCustomerTier iCustomerTier;
486
487 // Make sure we're starting with a clean object.
488 TxnReq.Clear();
489
490 GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier);
491
492 if (m_rnd.RndPercent(m_pDriverCETxnSettings->CP_settings.cur.by_tax_id)) {
493 // send tax id instead of customer id
494 m_Person.GetTaxID(iCustomerId, TxnReq.tax_id);
495 } else {
496 // send customer id and not the tax id
497 TxnReq.cust_id = iCustomerId;
498 }
499
500 TxnReq.get_history = m_rnd.RndPercent(m_pDriverCETxnSettings->CP_settings.cur.get_history);
501 if (TxnReq.get_history) {
502 TxnReq.acct_id_idx = m_rnd.RndIntRange(0, m_AccsAndPerms.GetNumberOfAccounts(iCustomerId, iCustomerTier) - 1);
503 } else {
504 TxnReq.acct_id_idx = -1;
505 }
506}
507
508/*
509 * Generate Market-Watch transaction input.
510 *
511 * PARAMETERS:
512 * OUT TxnReq - input parameter structure filled in
513 * for the transaction.
514 *
515 * RETURNS:
516 * none.
517 */
518void CCETxnInputGenerator::GenerateMarketWatchInput(TMarketWatchTxnInput &TxnReq) {
519 TIdent iCustomerId;
520 eCustomerTier iCustomerTier;
521 INT32 iThreshold;
522 INT32 iWeek;
523 INT32 iDailyMarketDay;
524 CDateTime StartDate(iDailyMarketBaseYear, iDailyMarketBaseMonth, iDailyMarketBaseDay, iDailyMarketBaseHour,
525 iDailyMarketBaseMinute, iDailyMarketBaseSecond, iDailyMarketBaseMsec);
526
527 // Make sure we're starting with a clean object.
528 TxnReq.Clear();
529
530 iThreshold = m_rnd.RndGenerateIntegerPercentage();
531
532 // have some distribution on what inputs to send
533 if (iThreshold <= m_pDriverCETxnSettings->MW_settings.cur.by_industry) {
534 // send industry name
535 strncpy(TxnReq.industry_name, m_pIndustries[m_rnd.RndIntRange(0, m_iIndustryCount - 1)].IN_NAME_CSTR(),
536 sizeof(TxnReq.industry_name));
537
538 if (iBaseCompanyCount < m_iActiveCompanyCount) {
539 TxnReq.starting_co_id = m_rnd.RndInt64Range(
540 m_iStartFromCompany, m_iStartFromCompany + m_iActiveCompanyCount - (iBaseCompanyCount - 1));
541 TxnReq.ending_co_id = TxnReq.starting_co_id + (iBaseCompanyCount - 1);
542 } else {
543 TxnReq.starting_co_id = m_iStartFromCompany;
544 TxnReq.ending_co_id = m_iStartFromCompany + m_iActiveCompanyCount - 1;
545 }
546 } else {
547 if (iThreshold <= (m_pDriverCETxnSettings->MW_settings.cur.by_industry +
548 m_pDriverCETxnSettings->MW_settings.cur.by_watch_list)) {
549 // Send customer id
550 GenerateNonUniformRandomCustomerId(TxnReq.c_id, iCustomerTier);
551 } else {
552 // Send account id
553 GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier);
554 m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier, &TxnReq.acct_id, NULL);
555 }
556 }
557
558 // Set start_day for both cases of the 'if'.
559 //
560 iWeek = (INT32)m_rnd.NURnd(0, 255, 255, 0) + 5; // A = 255, S = 0
561 // Week is now between 5 and 260.
562 // Select a day within the week.
563 //
564 iThreshold = m_rnd.RndGenerateIntegerPercentage();
565 if (iThreshold > 40) {
566 iDailyMarketDay = iWeek * DaysPerWeek + 4; // Friday
567 } else // 1..40 case
568 {
569 if (iThreshold <= 20) {
570 iDailyMarketDay = iWeek * DaysPerWeek; // Monday
571 } else {
572 if (iThreshold <= 27) {
573 iDailyMarketDay = iWeek * DaysPerWeek + 1; // Tuesday
574 } else {
575 if (iThreshold <= 33) {
576 iDailyMarketDay = iWeek * DaysPerWeek + 2; // Wednesday
577 } else {
578 iDailyMarketDay = iWeek * DaysPerWeek + 3; // Thursday
579 }
580 }
581 }
582 }
583
584 // Go back 256 weeks and then add our calculated day.
585 //
586 StartDate.Add(iDailyMarketDay, 0);
587
588 StartDate.GetTimeStamp(&TxnReq.start_day);
589}
590
591/*
592 * Generate Security-Detail transaction input.
593 *
594 * PARAMETERS:
595 * OUT TxnReq - input parameter structure filled in
596 * for the transaction.
597 *
598 * RETURNS:
599 * none.
600 */
601void CCETxnInputGenerator::GenerateSecurityDetailInput(TSecurityDetailTxnInput &TxnReq) {
602 CDateTime StartDate(iDailyMarketBaseYear, iDailyMarketBaseMonth, iDailyMarketBaseDay, iDailyMarketBaseHour,
603 iDailyMarketBaseMinute, iDailyMarketBaseSecond, iDailyMarketBaseMsec);
604 INT32 iStartDay; // day from the StartDate
605
606 // Make sure we're starting with a clean object.
607 TxnReq.Clear();
608
609 // random symbol
610 m_pSecurities.CreateSymbol(m_rnd.RndInt64Range(0, m_iActiveSecurityCount - 1), TxnReq.symbol,
611 static_cast<int>(sizeof(TxnReq.symbol)));
612
613 // Whether or not to access the LOB.
614 TxnReq.access_lob_flag = m_rnd.RndPercent(m_pDriverCETxnSettings->SD_settings.cur.LOBAccessPercentage);
615
616 // random number of financial rows to return
617 TxnReq.max_rows_to_return = m_rnd.RndIntRange(iSecurityDetailMinRows, iSecurityDetailMaxRows);
618
619 iStartDay = m_rnd.RndIntRange(0, iDailyMarketTotalRows - TxnReq.max_rows_to_return);
620
621 // add the offset
622 StartDate.Add(iStartDay, 0);
623
624 StartDate.GetTimeStamp(&TxnReq.start_day);
625}
626
627/*
628 * Generate Trade-Lookup transaction input.
629 *
630 * PARAMETERS:
631 * OUT TxnReq - input parameter structure filled in
632 * for the transaction.
633 *
634 * RETURNS:
635 * none.
636 */
637void CCETxnInputGenerator::GenerateTradeLookupInput(TTradeLookupTxnInput &TxnReq) {
638 INT32 iThreshold;
639
640 // Make sure we're starting with a clean object.
641 TxnReq.Clear();
642
643 iThreshold = m_rnd.RndGenerateIntegerPercentage();
644
645 if (iThreshold <= m_pDriverCETxnSettings->TL_settings.cur.do_frame1) {
646 // Frame 1
647 TxnReq.frame_to_execute = 1;
648 TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame1;
649
650 // Generate list of unique trade id's
651 int ii, jj;
652 bool Accepted;
653 TTrade TID;
654
655 for (ii = 0; ii < TxnReq.max_trades; ii++) {
656 Accepted = false;
657 while (!Accepted) {
658 TID = GenerateNonUniformTradeID(TradeLookupAValueForTradeIDGenFrame1,
659 TradeLookupSValueForTradeIDGenFrame1);
660 jj = 0;
661 while (jj < ii && TxnReq.trade_id[jj] != TID) {
662 jj++;
663 }
664 if (jj == ii) {
665 // We have a unique TID for this batch
666 TxnReq.trade_id[ii] = TID;
667 Accepted = true;
668 }
669 }
670 }
671 } else if (iThreshold <=
672 m_pDriverCETxnSettings->TL_settings.cur.do_frame1 + m_pDriverCETxnSettings->TL_settings.cur.do_frame2) {
673 // Frame 2
674 TxnReq.frame_to_execute = 2;
675 TxnReq.acct_id = GenerateRandomCustomerAccountId();
676 TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame2;
677
678 GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame2MaxTimeInMilliSeconds,
679 TradeLookupAValueForTimeGenFrame2, TradeLookupSValueForTimeGenFrame2);
680
681 // Set to the end of initial trades.
682 m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts);
683 } else if (iThreshold <= m_pDriverCETxnSettings->TL_settings.cur.do_frame1 +
684 m_pDriverCETxnSettings->TL_settings.cur.do_frame2 +
685 m_pDriverCETxnSettings->TL_settings.cur.do_frame3) {
686 // Frame 3
687 TxnReq.frame_to_execute = 3;
688 TxnReq.max_trades = m_pDriverCETxnSettings->TL_settings.cur.MaxRowsFrame3;
689
690 m_pSecurities.CreateSymbol(m_rnd.NURnd(0, m_iActiveSecurityCount - 1, TradeLookupAValueForSymbolFrame3,
691 TradeLookupSValueForSymbolFrame3),
692 TxnReq.symbol, static_cast<int>(sizeof(TxnReq.symbol)));
693
694 GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame3MaxTimeInMilliSeconds,
695 TradeLookupAValueForTimeGenFrame3, TradeLookupSValueForTimeGenFrame3);
696
697 // Set to the end of initial trades.
698 m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts);
699
700 TxnReq.max_acct_id = m_AccsAndPerms.GetEndingCA_ID(m_iActiveCustomerCount);
701 } else {
702 // Frame 4
703 TxnReq.frame_to_execute = 4;
704 TxnReq.acct_id = GenerateRandomCustomerAccountId();
705 GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeLookupFrame4MaxTimeInMilliSeconds,
706 TradeLookupAValueForTimeGenFrame4, TradeLookupSValueForTimeGenFrame4);
707 }
708}
709
710/*
711 * Generate Trade-Order transaction input.
712 *
713 * PARAMETERS:
714 * OUT TxnReq - input parameter structure filled in
715 * for the transaction. OUT TradeType - integer representation of
716 * generated trade type (as eTradeTypeID enum). OUT bExecutorIsAccountOwner -
717 * whether Trade-Order frame 2 should (FALSE) or shouldn't (TRUE) be called.
718 *
719 * RETURNS:
720 * none.
721 */
722void CCETxnInputGenerator::GenerateTradeOrderInput(TTradeOrderTxnInput &TxnReq, INT32 &iTradeType,
723 bool &bExecutorIsAccountOwner) {
724 TIdent iCustomerId; // owner
725 eCustomerTier iCustomerTier;
726 TIdent CID_1, CID_2;
727 bool bMarket;
728 INT32 iAdditionalPerms;
729 UINT iSymbIndex;
730 TIdent iFlatFileSymbIndex;
731 eTradeTypeID eTradeType;
732
733 // Make sure we're starting with a clean object.
734 TxnReq.Clear();
735
736 // Generate random customer
737 //
738 GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier);
739
740 // Generate random account id and security index
741 //
742 m_Holdings.GenerateRandomAccountSecurity(iCustomerId, iCustomerTier, &TxnReq.acct_id, &iFlatFileSymbIndex,
743 &iSymbIndex);
744
745 // find out how many permission rows there are for this account (in addition
746 // to the owner's)
747 iAdditionalPerms = m_AccsAndPerms.GetNumPermsForCA(TxnReq.acct_id);
748 // distribution same as in the loader for now
749 if (iAdditionalPerms == 0) { // select the owner
750 m_Person.GetFirstLastAndTaxID(iCustomerId, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id);
751
752 bExecutorIsAccountOwner = true;
753 } else {
754 // If there is more than one permission set on the account,
755 // have some distribution on whether the executor is still
756 // the account owner, or it is one of the additional permissions.
757 // Here we must take into account the fact that we've excluded
758 // a large portion of customers that don't have any additional
759 // executors in the above code (iAdditionalPerms == 0); the
760 // "exec_is_owner" percentage implicity includes such customers
761 // and must be factored out here.
762
763 int exec_is_owner =
764 (m_pDriverCETxnSettings->TO_settings.cur.exec_is_owner - iPercentAccountAdditionalPermissions_0) * 100 /
765 (100 - iPercentAccountAdditionalPermissions_0);
766
767 if (m_rnd.RndPercent(exec_is_owner)) {
768 m_Person.GetFirstLastAndTaxID(iCustomerId, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id);
769
770 bExecutorIsAccountOwner = true;
771 } else {
772 if (iAdditionalPerms == 1) {
773 // select the first non-owner
774 m_AccsAndPerms.GetCIDsForPermissions(TxnReq.acct_id, iCustomerId, &CID_1, NULL);
775
776 m_Person.GetFirstLastAndTaxID(CID_1, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id);
777 } else {
778 // select the second non-owner
779 m_AccsAndPerms.GetCIDsForPermissions(TxnReq.acct_id, iCustomerId, &CID_1, &CID_2);
780 // generate third account permission row
781 m_Person.GetFirstLastAndTaxID(CID_2, TxnReq.exec_f_name, TxnReq.exec_l_name, TxnReq.exec_tax_id);
782 }
783
784 bExecutorIsAccountOwner = false;
785 }
786 }
787
788 // Select either stock symbol or company from the securities flat file.
789 //
790
791 // have some distribution on the company/symbol input preference
792 if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.security_by_symbol)) {
793 // Submit the symbol
794 m_pSecurities.CreateSymbol(iFlatFileSymbIndex, TxnReq.symbol, static_cast<int>(sizeof(TxnReq.symbol)));
795 } else {
796 // Submit the company name
797 m_pCompanies.CreateName(m_pSecurities.GetCompanyIndex(iFlatFileSymbIndex), TxnReq.co_name,
798 static_cast<int>(sizeof(TxnReq.co_name)));
799
800 strncpy(TxnReq.issue, m_pSecurities.GetRecord(iFlatFileSymbIndex).S_ISSUE_CSTR(), sizeof(TxnReq.issue));
801 }
802
803 TxnReq.trade_qty = cTRADE_QTY_SIZES[m_rnd.RndIntRange(0, cNUM_TRADE_QTY_SIZES - 1)];
804 TxnReq.requested_price = m_rnd.RndDoubleIncrRange(fMinSecPrice, fMaxSecPrice, 0.01);
805
806 // Determine whether Market or Limit order
807 bMarket = m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.market);
808
809 // Determine whether Buy or Sell trade
810 if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.buy_orders)) {
811 if (bMarket) {
812 // Market Buy
813 eTradeType = eMarketBuy;
814 } else {
815 // Limit Buy
816 eTradeType = eLimitBuy;
817 }
818
819 // Set margin or cash for Buy
820 TxnReq.type_is_margin = m_rnd.RndPercent(
821 // type_is_margin is specified for all orders, but used only for
822 // buys
823 m_pDriverCETxnSettings->TO_settings.cur.type_is_margin * 100 /
824 m_pDriverCETxnSettings->TO_settings.cur.buy_orders);
825 } else {
826 if (bMarket) {
827 // Market Sell
828 eTradeType = eMarketSell;
829 } else {
830 // determine whether the Limit Sell is a Stop Loss
831 if (m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.stop_loss)) {
832 // Stop Loss
833 eTradeType = eStopLoss;
834 } else {
835 // Limit Sell
836 eTradeType = eLimitSell;
837 }
838 }
839
840 TxnReq.type_is_margin = false; // all sell orders are cash
841 }
842 iTradeType = eTradeType;
843
844 // Distribution of last-in-first-out flag
845 TxnReq.is_lifo = m_rnd.RndPercent(m_pDriverCETxnSettings->TO_settings.cur.lifo);
846
847 // Copy the trade type id from the flat file
848 strncpy(TxnReq.trade_type_id, m_pTradeType[eTradeType].TT_ID_CSTR(), sizeof(TxnReq.trade_type_id));
849
850 // Copy the status type id's from the flat file
851 strncpy(TxnReq.st_pending_id, m_pStatusType[ePending].ST_ID_CSTR(), sizeof(TxnReq.st_pending_id));
852 strncpy(TxnReq.st_submitted_id, m_pStatusType[eSubmitted].ST_ID_CSTR(), sizeof(TxnReq.st_submitted_id));
853
854 TxnReq.roll_it_back = (m_iTradeOrderRollbackLevel >= m_rnd.RndIntRange(1, m_iTradeOrderRollbackLimit));
855
856 // Need to address logging more comprehensively.
857 // return eTradeType;
858}
859
860/*
861 * Generate Trade-Status transaction input.
862 *
863 * PARAMETERS:
864 * OUT TxnReq - input parameter structure filled in
865 * for the transaction.
866 *
867 * RETURNS:
868 * none.
869 */
870void CCETxnInputGenerator::GenerateTradeStatusInput(TTradeStatusTxnInput &TxnReq) {
871 TIdent iCustomerId;
872 eCustomerTier iCustomerTier;
873
874 // Make sure we're starting with a clean object.
875 TxnReq.Clear();
876
877 // select customer id first
878 GenerateNonUniformRandomCustomerId(iCustomerId, iCustomerTier);
879
880 // select random account id
881 m_AccsAndPerms.GenerateRandomAccountId(m_rnd, iCustomerId, iCustomerTier, &TxnReq.acct_id, NULL);
882}
883
884/*
885 * Generate Trade-Update transaction input.
886 *
887 * PARAMETERS:
888 * OUT TxnReq - input parameter structure filled in
889 * for the transaction.
890 *
891 * RETURNS:
892 * none.
893 */
894void CCETxnInputGenerator::GenerateTradeUpdateInput(TTradeUpdateTxnInput &TxnReq) {
895 INT32 iThreshold;
896
897 // Make sure we're starting with a clean object.
898 TxnReq.Clear();
899
900 iThreshold = m_rnd.RndGenerateIntegerPercentage();
901
902 if (iThreshold <= m_pDriverCETxnSettings->TU_settings.cur.do_frame1) {
903 // Frame 1
904 TxnReq.frame_to_execute = 1;
905 TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame1;
906 TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame1;
907
908 // Generate list of unique trade id's
909 int ii, jj;
910 bool Accepted;
911 TTrade TID;
912
913 for (ii = 0; ii < TxnReq.max_trades; ii++) {
914 Accepted = false;
915 while (!Accepted) {
916 TID = GenerateNonUniformTradeID(TradeUpdateAValueForTradeIDGenFrame1,
917 TradeUpdateSValueForTradeIDGenFrame1);
918 jj = 0;
919 while (jj < ii && TxnReq.trade_id[jj] != TID) {
920 jj++;
921 }
922 if (jj == ii) {
923 // We have a unique TID for this batch
924 TxnReq.trade_id[ii] = TID;
925 Accepted = true;
926 }
927 }
928 }
929 } else if (iThreshold <=
930 m_pDriverCETxnSettings->TU_settings.cur.do_frame1 + m_pDriverCETxnSettings->TU_settings.cur.do_frame2) {
931 // Frame 2
932 TxnReq.frame_to_execute = 2;
933 TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame2;
934 TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame2;
935 TxnReq.acct_id = GenerateRandomCustomerAccountId();
936
937 GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeUpdateFrame2MaxTimeInMilliSeconds,
938 TradeUpdateAValueForTimeGenFrame2, TradeUpdateSValueForTimeGenFrame2);
939
940 // Set to the end of initial trades.
941 m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts);
942 } else {
943 // Frame 3
944 TxnReq.frame_to_execute = 3;
945 TxnReq.max_trades = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsFrame3;
946 TxnReq.max_updates = m_pDriverCETxnSettings->TU_settings.cur.MaxRowsToUpdateFrame3;
947
948 m_pSecurities.CreateSymbol(m_rnd.NURnd(0, m_iActiveSecurityCount - 1, TradeUpdateAValueForSymbolFrame3,
949 TradeUpdateSValueForSymbolFrame3),
950 TxnReq.symbol, static_cast<int>(sizeof(TxnReq.symbol)));
951
952 GenerateNonUniformTradeDTS(TxnReq.start_trade_dts, m_iTradeUpdateFrame3MaxTimeInMilliSeconds,
953 TradeUpdateAValueForTimeGenFrame3, TradeUpdateSValueForTimeGenFrame3);
954
955 // Set to the end of initial trades.
956 m_EndTime.GetTimeStamp(&TxnReq.end_trade_dts);
957
958 TxnReq.max_acct_id = m_AccsAndPerms.GetEndingCA_ID(m_iActiveCustomerCount);
959 }
960}
961