| 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, Cecil Reames, Matt Emmerton, Doug Johnson |
| 35 | */ |
| 36 | |
| 37 | /* |
| 38 | * Class representing the Financial table. |
| 39 | */ |
| 40 | #ifndef FINANCIAL_TABLE_H |
| 41 | #define FINANCIAL_TABLE_H |
| 42 | |
| 43 | #include "EGenTables_common.h" |
| 44 | #include "CompanyTable.h" |
| 45 | #include "utilities/Money.h" |
| 46 | |
| 47 | #include "input/DataFileManager.h" |
| 48 | |
| 49 | namespace TPCE { |
| 50 | |
| 51 | const int iYearsForFins = 5; |
| 52 | const int iQuartersInYear = 4; |
| 53 | const int iFinsPerCompany = iYearsForFins * iQuartersInYear; // 5 years of 4 quaters each year |
| 54 | |
| 55 | // multiplier to get the diluted number of shares from outstanding |
| 56 | const double fDilutedSharesMultiplier = 1.1; |
| 57 | |
| 58 | // Multipliers for previous quarter to get the current quarter data |
| 59 | const double fFinDataDownMult = 0.9; |
| 60 | const double fFinDataUpMult = 1.15; |
| 61 | const double fFinDataIncr = 0.00000000000001; |
| 62 | |
| 63 | const double fFinancialRevenueMin = 100000.00; |
| 64 | const double fFinancialRevenueMax = 16000000000.00; |
| 65 | |
| 66 | const double fFinancialEarningsMin = -300000000.00; |
| 67 | const double fFinancialEarningsMax = 3000000000.00; |
| 68 | |
| 69 | const INT64 iFinancialOutBasicMin = 400000; |
| 70 | const INT64 iFinancialOutBasicMax = INT64_CONST(9500000000); |
| 71 | |
| 72 | const double fFinancialInventMin = 0.00; |
| 73 | const double fFinancialInventMax = 2000000000.00; |
| 74 | |
| 75 | const double fFinancialAssetsMin = 100000.00; |
| 76 | const double fFinancialAssetsMax = 65000000000.00; |
| 77 | |
| 78 | const double fFinancialLiabMin = 100000.00; |
| 79 | const double fFinancialLiabMax = 35000000000.00; |
| 80 | |
| 81 | // Number of RNG calls to skip for one row in order |
| 82 | // to not use any of the random values from the previous row. |
| 83 | // |
| 84 | const int iRNGSkipOneRowFinancial = 6 + iFinsPerCompany * 6; |
| 85 | |
| 86 | typedef struct FINANCIAL_GEN_ROW { |
| 87 | FINANCIAL_ROW m_financials[iFinsPerCompany]; |
| 88 | } * PFINANCIAL_GEN_ROW; |
| 89 | |
| 90 | class CFinancialTable : public TableTemplate<FINANCIAL_GEN_ROW> { |
| 91 | CCompanyTable m_CompanyTable; |
| 92 | int m_iFinYear; // first year to generate financials |
| 93 | int m_iFinQuarter; // first quarter to generate financials (0-based) |
| 94 | // Number of times GenerateNextRecord() was called for the current company |
| 95 | // data. Needed to decide when to generate next company's data. |
| 96 | int m_iRowsGeneratedPerCompany; |
| 97 | // Stores whether there is another company(s) for which to |
| 98 | // generate financial data. |
| 99 | bool m_bMoreCompanies; |
| 100 | TIdent m_iFinancialCountForOneLoadUnit; |
| 101 | |
| 102 | // |
| 103 | // Generate the financial data for the next company. |
| 104 | // |
| 105 | // Return whether there are more companies to generate data for. |
| 106 | // |
| 107 | bool GenerateFinancialRows() { |
| 108 | TIdent FI_CO_ID; |
| 109 | int iFinYear, iFinQuarter; |
| 110 | int i; |
| 111 | CMoney fRev, fEarn, fInvent, fAssets, fLiab, fBasicEPS, fDilutEPS, fMargin; |
| 112 | INT64 iOutBasic, iOutDilut; |
| 113 | |
| 114 | // Set starting values for financial values |
| 115 | FI_CO_ID = m_CompanyTable.GetCurrentCO_ID(); |
| 116 | iFinYear = m_iFinYear; |
| 117 | iFinQuarter = m_iFinQuarter; |
| 118 | |
| 119 | fRev = m_rnd.RndDoubleIncrRange(fFinancialRevenueMin, fFinancialRevenueMax, 0.01); |
| 120 | fEarn = m_rnd.RndDoubleIncrRange( |
| 121 | fFinancialEarningsMin, fRev < fFinancialEarningsMax ? fRev.DollarAmount() : fFinancialEarningsMax, 0.01); |
| 122 | iOutBasic = m_rnd.RndInt64Range(iFinancialOutBasicMin, iFinancialOutBasicMax); |
| 123 | iOutDilut = 0; |
| 124 | fInvent = m_rnd.RndDoubleIncrRange(fFinancialInventMin, fFinancialInventMax, 0.01); |
| 125 | fAssets = m_rnd.RndDoubleIncrRange(fFinancialAssetsMin, fFinancialAssetsMax, 0.01); |
| 126 | fLiab = m_rnd.RndDoubleIncrRange(fFinancialLiabMin, fFinancialLiabMax, 0.01); |
| 127 | fBasicEPS = 0.00; |
| 128 | fDilutEPS = 0.00; |
| 129 | fMargin = 0.00; |
| 130 | |
| 131 | for (i = 0; i < iFinsPerCompany; ++i) { |
| 132 | // Compute values for this quarter |
| 133 | fRev = fRev * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr); |
| 134 | fEarn = fEarn * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr); |
| 135 | if (fEarn >= fRev) { // earnings cannot be greater than the revenue |
| 136 | fEarn = fEarn * fFinDataDownMult; |
| 137 | } |
| 138 | iOutBasic = |
| 139 | (INT64)((double)iOutBasic * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr)); |
| 140 | iOutDilut = (INT64)((double)iOutBasic * fDilutedSharesMultiplier); |
| 141 | fInvent = fInvent * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr); |
| 142 | fAssets = fAssets * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr); |
| 143 | fLiab = fLiab * m_rnd.RndDoubleIncrRange(fFinDataDownMult, fFinDataUpMult, fFinDataIncr); |
| 144 | fBasicEPS = fEarn / (double)iOutBasic; |
| 145 | fDilutEPS = fEarn / (double)iOutDilut; |
| 146 | fMargin = fEarn / fRev.DollarAmount(); |
| 147 | |
| 148 | // Assign values for this quarter |
| 149 | m_row.m_financials[i].FI_CO_ID = FI_CO_ID; |
| 150 | m_row.m_financials[i].FI_YEAR = iFinYear; |
| 151 | m_row.m_financials[i].FI_QTR = iFinQuarter + 1; |
| 152 | m_row.m_financials[i].FI_QTR_START_DATE.Set(iFinYear, iFinQuarter * 3 + 1, 1); |
| 153 | m_row.m_financials[i].FI_REVENUE = fRev.DollarAmount(); |
| 154 | m_row.m_financials[i].FI_NET_EARN = fEarn.DollarAmount(); |
| 155 | m_row.m_financials[i].FI_OUT_BASIC = iOutBasic; |
| 156 | m_row.m_financials[i].FI_OUT_DILUT = iOutDilut; |
| 157 | m_row.m_financials[i].FI_INVENTORY = fInvent.DollarAmount(); |
| 158 | m_row.m_financials[i].FI_ASSETS = fAssets.DollarAmount(); |
| 159 | m_row.m_financials[i].FI_LIABILITY = fLiab.DollarAmount(); |
| 160 | m_row.m_financials[i].FI_BASIC_EPS = fBasicEPS.DollarAmount(); |
| 161 | m_row.m_financials[i].FI_DILUT_EPS = fDilutEPS.DollarAmount(); |
| 162 | m_row.m_financials[i].FI_MARGIN = fMargin.DollarAmount(); |
| 163 | |
| 164 | // Increment quarter |
| 165 | iFinQuarter++; |
| 166 | if (iFinQuarter == iQuartersInYear) { // reached the last quarter in the year |
| 167 | iFinQuarter = 0; // start from the first quarter |
| 168 | ++iFinYear; // increment year |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | return m_CompanyTable.GenerateNextCO_ID(); |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | * Reset the state for the next load unit. |
| 177 | * |
| 178 | * PARAMETERS: |
| 179 | * none. |
| 180 | * |
| 181 | * RETURNS: |
| 182 | * none. |
| 183 | */ |
| 184 | void InitNextLoadUnit() { |
| 185 | m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedTableDefault, (RNGSEED)m_iLastRowNumber * iRNGSkipOneRowFinancial)); |
| 186 | |
| 187 | ClearRecord(); // this is needed for EGenTest to work |
| 188 | } |
| 189 | |
| 190 | public: |
| 191 | CFinancialTable(const DataFileManager &dfm, TIdent iCustomerCount, TIdent iStartFromCustomer) |
| 192 | : TableTemplate<FINANCIAL_GEN_ROW>(), m_CompanyTable(dfm, iCustomerCount, iStartFromCustomer), |
| 193 | m_iRowsGeneratedPerCompany(iFinsPerCompany), m_bMoreCompanies(true) { |
| 194 | // Start year to generate financials. |
| 195 | // Count by quaters |
| 196 | m_iFinYear = iDailyMarketBaseYear; // first financial year |
| 197 | m_iFinQuarter = iDailyMarketBaseMonth / 3; // first financial quarter in the year (0-based) |
| 198 | |
| 199 | m_bMoreRecords = true; // initialize once |
| 200 | |
| 201 | m_iFinancialCountForOneLoadUnit = |
| 202 | dfm.CompanyFile().CalculateCompanyCount(iDefaultLoadUnitSize) * iFinsPerCompany; |
| 203 | |
| 204 | m_iLastRowNumber = dfm.CompanyFile().CalculateStartFromCompany(iStartFromCustomer) * iFinsPerCompany; |
| 205 | }; |
| 206 | |
| 207 | bool GenerateNextRecord() { |
| 208 | // Reset RNG at Load Unit boundary, so that all data is repeatable. |
| 209 | // |
| 210 | if (m_iLastRowNumber % m_iFinancialCountForOneLoadUnit == 0) { |
| 211 | InitNextLoadUnit(); |
| 212 | } |
| 213 | |
| 214 | ++m_iLastRowNumber; |
| 215 | |
| 216 | ++m_iRowsGeneratedPerCompany; |
| 217 | |
| 218 | if (m_iRowsGeneratedPerCompany >= iFinsPerCompany) { |
| 219 | if (m_bMoreCompanies) { |
| 220 | // All rows for the current company have been returned |
| 221 | // therefore move on to the next company |
| 222 | m_bMoreCompanies = GenerateFinancialRows(); |
| 223 | |
| 224 | m_iRowsGeneratedPerCompany = 0; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | // Return false when generated the last row of the last company |
| 229 | if (!m_bMoreCompanies && (m_iRowsGeneratedPerCompany == iFinsPerCompany - 1)) { |
| 230 | m_bMoreRecords = false; |
| 231 | } |
| 232 | |
| 233 | return MoreRecords(); |
| 234 | } |
| 235 | |
| 236 | const FINANCIAL_ROW &GetRow() { |
| 237 | return m_row.m_financials[m_iRowsGeneratedPerCompany]; |
| 238 | } |
| 239 | }; |
| 240 | |
| 241 | } // namespace TPCE |
| 242 | |
| 243 | #endif // FINANCIAL_TABLE_H |
| 244 | |