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 | |
41 | using 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 | */ |
59 | CCETxnInputGenerator::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 | */ |
98 | CCETxnInputGenerator::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 | */ |
137 | CCETxnInputGenerator::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 | */ |
182 | CCETxnInputGenerator::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 | */ |
214 | void 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 | */ |
251 | RNGSEED 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 | */ |
264 | void 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 | */ |
279 | void 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 | */ |
333 | inline 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 | */ |
347 | TIdent 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 | */ |
368 | TTrade 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 | */ |
396 | void 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 | */ |
428 | void 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 | */ |
483 | void 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 | */ |
518 | void 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 | */ |
601 | void 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 | */ |
637 | void 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 | */ |
722 | void 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 | */ |
870 | void 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 | */ |
894 | void 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 | |