/* * 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 */ /* * Class that generates trades and holdings for a given set * of customers. It maintains the proper holding information * for every customer while the trades are being generated. * * TRADE, TRADE_HISTORY, CASH_TRANSACTION, SETTLEMENT, * HOLDING, HOLDING_HISTORY rows are generated by this class. * */ #ifndef TRADE_GEN_H #define TRADE_GEN_H #include #include "utilities/EGenStandardTypes.h" #include "utilities/Money.h" #include "MEESecurity.h" #include "CustomerAccountsAndPermissionsTable.h" #include "AddressTable.h" #include "CustomerTable.h" #include "CustomerTaxRateTable.h" #include "CustomerSelection.h" #include "HoldingsAndTradesTable.h" #include "Brokers.h" #include "SecurityTable.h" #include "Person.h" #include "input/DataFileManager.h" #include "StatusTypeIDs.h" using namespace std; namespace TPCE { // Maximum number of HOLDING_HISTORY rows that can be output // for one completed trade. // Determined by the maximum number of holdings that a trade // can modify. The maximum number would be a trade with // the biggest possible quantity modifying holdings each having // the smallest possible quantity. // const int iMaxHoldingHistoryRowsPerTrade = 800 / 100; // Incomplete trade information generated // at Trade Order time. // typedef struct TTradeInfo { TTrade iTradeId; eTradeTypeID eTradeType; // integer representation of the TRADE row T_TT_ID eStatusTypeID eTradeStatus; // integer representation of the TRADE row T_ST_ID double PendingTime; // seconds from StartTime; only for limit orders double SubmissionTime; // seconds from StartTime double CompletionTime; // seconds from StartTime TIdent iSymbolIndex; // stock symbol index in the input flat file UINT iSymbolIndexInAccount; // stock symbol index in the account basket int iTradeQty; // number of shares in the trade CMoney fBidPrice; // bid price for market orders or limit price for limit ones CMoney fTradePrice; // price that the trade completed at TIdent iCustomer; // customer executing this trade eCustomerTier iCustomerTier; // customer tier for the customer executing this trade TIdent iCustomerAccount; // customer account in which the trade executes bool bIsLifo; // needed to update holdings } * PTradeInfo; // Information about completed trade that is generated once // for performance typedef struct TAdditionalTradeInfo { // Current value of trade's positions that are being closed // CMoney fBuyValue; // Value of trade's positions when they were opened // CMoney fSellValue; // Broker id of the account for the current completed trade // TIdent iCurrentBrokerId; eTaxStatus eAccountTaxStatus; // These fields are needed for correcteness (pricing consistency). // They need to be kept in CMoney and only converted to double // before copying them into table row structures. // CMoney Commission; CMoney Charge; CMoney Tax; CMoney SettlementAmount; } * PAdditionalTradeInfo; // Customer holding information // to be able to generate HOLDING table after all trades // have been generated. // typedef struct THoldingInfo { TTrade iTradeId; int iTradeQty; CMoney fTradePrice; CDateTime BuyDTS; TIdent iSymbolIndex; // stock symbol index in the input flat file - stored // for performance } * PHoldingInfo; // Trade-related table rows. // HOLDING row is ommitted because it is contained in // a separate variable. // typedef struct TTradeRow { TRADE_ROW m_Trade; // for the Trade table TRADE_REQUEST_ROW m_TradeRequest; // for the Trade Requests table TRADE_HISTORY_ROW m_TradeHistory[3]; // for the Trade History table SETTLEMENT_ROW m_Settlement; // for the Settlement table CASH_TRANSACTION_ROW m_CashTransaction; // for the Cash Transaction table HOLDING_HISTORY_ROW m_HoldingHistory[iMaxHoldingHistoryRowsPerTrade]; } * PTradeRow; // Container to store holdings // typedef list THoldingList; typedef THoldingList TCustomerHoldingArray[iMaxSecuritiesPerAccount]; class CTradeGen { // RNG class for generation of row data // CRandom m_rnd; // Class used to get address information for a customer // to properly calculate tax on a trade // CAddressTable m_AddressTable; // Class used to select a random customer for whom to perform a trade. // CCustomerSelection m_CustomerSelection; // Class used to get CUSTOMER table information for a specific customer // CCustomerTable m_CustomerTable; // Class used to calculate T_TAX for the TRADE table // CCustomerTaxRateTable m_CustTaxrateTable; // Class used to get customer account information. // CCustomerAccountsAndPermissionsTable m_CustomerAccountTable; // Class used in determining the basket of securities for an account // CHoldingsAndTradesTable m_HoldingTable; // Class used to generate BROKER table (with consistent YTD columns) // CBrokersTable m_BrokerTable; // Class used to get S_NAME for cash transaction descriptions // CSecurityTable m_SecurityTable; // Class to get the first and last names of a customer // CPerson m_Person; // Input files for character data generation. // const CCompanyFile &m_CompanyFile; const CSecurityFile &m_SecurityFile; const ChargeDataFile_t &m_ChargeFile; // CHARGE table from the flat file const CommissionRateDataFile_t &m_CommissionRateFile; // COMMISSION_RATE table from the flat file const StatusTypeDataFile_t &m_StatusTypeFile; // STATUS_TYPE table from the flat file const TradeTypeDataFile_t &m_TradeTypeFile; // TRADE_TYPE table from the flat file const ExchangeDataFile_t &m_ExchangeFile; // EXCHANGE table from the flat file // The first customer to generate for this class instance // TIdent m_iStartFromCustomer; // First account of the StartFromCustomer // TIdent m_iStartFromAccount; // Number of customers for this class instance // TIdent m_iCustomerCount; // Total number of customers in the database // TIdent m_iTotalCustomers; // Number of customers in one load unit // int m_iLoadUnitSize; // Number of accounts for customers in one load unit // int m_iLoadUnitAccountCount; // Number of customers for 1 tpsE // int m_iScaleFactor; // Number of hours of initial trades to generate // int m_iHoursOfInitialTrades; // Average number of seconds between two consecutive trades // double m_fMeanTimeBetweenTrades; // Mean delay between Pending and Submission times // for an immediatelly triggered (in-the-money) limit order. // double m_fMeanInTheMoneySubmissionDelay; // Time at which to start trade timestamps (time 0 or StartTime). // Not changed during the class lifetime. // // This is the submission (or pending) time of the first trade. // CDateTime m_StartTime; // Current Trade Order time in the simulated // time sequence (seconds from StartTime). // When this time is further than // the priority queue's front, incomplete trades // are removed from the priority queue and completed. // // If this time is before the priority queue front // time, new incomplete trades are placed on the queue // and this time is incremented. // double m_CurrentSimulatedTime; // Priority queue that contains incomplete trades // ordered by their completion time. The queue's // front contains trade with the earliest completion // time. // // Template default is to return the biggest value, // but we need the smallest (earliest) one. This is // why we specify greater<> for the template comparison // parameter instead of the default less<> priority_queue, greater> m_CurrentTrades; // Number of trades completed up to now. // Does not include aborted trades. // TTrade m_iCurrentCompletedTrades; // Number of total trades needed to generate. // Does not include aborted trades. // TTrade m_iTotalTrades; // Number of trades initiated up to now. Includes aborted // trades. // Needed to calculate when to abort a trade at Trade Order time. // TTrade m_iCurrentInitiatedTrades; // Number of trades in an 8-hour workday. // Needed to know when to move trading time to the next day. // int m_iTradesPerWorkDay; // 3-dimensional array of double-linked lists each containing // one customer holding information. // // The array is indexed as follows: // [AccountId][SecurityIndexWithinAccount] // // There is no need to index on customer id since the account // id is unique across the universe of all customers // TCustomerHoldingArray *m_pCustomerHoldings; // Structure to contain incomplete, but essential // trade information generated at Trade Order time. // TTradeInfo m_NewTrade; // Structure to contain trade non-essential information // frequently used at Trade Result time. // TAdditionalTradeInfo m_CompletedTradeInfo; // Structure to contain current trade and holding // table rows. // Filled in GenerateNextTrade() for trade-related // tables and in GenerateNextHolding for // holding-related tables. // TTradeRow m_TradeRow; HOLDING_ROW m_HoldingRow; // Structure to contain HOLDING_SUMMARY rows. // Filled in GenerateNextHoldingSummaryRow. HOLDING_SUMMARY_ROW m_HoldingSummaryRow; // Number of Trade History rows for the current trade in m_TradeRow. // int m_iTradeHistoryRowCount; // Number of Cash Transaction rows for the current trade in m_TradeRow. // int m_iCashTransactionRowCount; // Number of Settlement rows for the current trade in m_TradeRow. // int m_iSettlementRowCount; // Number of Holding History rows. May be more than one // if the trade modifies more than one holding. // int m_iHoldingHistoryRowCount; // Security price emulation CMEESecurity m_MEESecurity; // Account, security index, and security holding // to use in GenerateNextHolding() to return the next holding. // int m_iCurrentAccountForHolding; int m_iCurrentSecurityForHolding; // index within the account (not input // file) list::iterator m_pCurrentSecurityHolding; // Account index and security index, // used in GenerateNextHoldingSummaryRecord(). // int m_iCurrentAccountForHoldingSummary; // index int m_iCurrentSecurityForHoldingSummary; // index // Trade ID for the last generated trade. // Positioned at the correct trade id at start. // TTrade m_iCurrentTradeId; // Current load unit number // int m_iCurrentLoadUnit; /////////////////////////////////////////////////// // Functions /////////////////////////////////////////////////// // Generate enough trade information to put into // the priority queue. // void GenerateNewTrade(); // Take the incoplete trade information and // generate all the trade-related rows in internal // row structures. // void GenerateCompleteTrade(); // Generate a random delay (in seconds) between // two consecutive trades. // inline double GenerateDelayBetweenTrades(); // Return the list of holdings to modify // by the most recently generated complete trade // inline THoldingList *GetHoldingListForCurrentTrade(); // Return position before the first or the last element // in the holding list (depending on IsLifo flag) // list::iterator PositionAtHoldingList(THoldingList *pHoldingList, int IsLifo); // Update holding information for the customer and trade // contained in the internal trade row structure. // Set internal buy and sell values. // void UpdateHoldings(); // Position internal iterator at the next non-empty holding. // Update internal customer/account/security counters as required. // // Return whether a non-empty holding exists. // bool FindNextHolding(); // Position internal indexes to next non-empty list of holdings // Return whether non-empty holding list exists. // bool FindNextHoldingList(); // Generate a new trade id // TTrade GenerateNextTradeId(); // Generate a random trade type // eTradeTypeID GenerateTradeType(); // Generate some common fields for the completed trade. // Those fields are used more than once so they are stored // in a separate structure. // void GenerateCompletedTradeInfo(); // Generate TRADE row // void GenerateTradeRow(); void GenerateTradeCharge(); void GenerateTradeCommission(); void GenerateTradeTax(); // Generate settlement amount for SE_AMT and CT_AMT // void GenerateSettlementAmount(); // Generate TRADE_HISTORY rows // void GenerateTradeHistoryRow(); // Generate CASH_TRANSACTION row // void GenerateCashTransactionRow(); // Generate SETTLEMENT row // void GenerateSettlementRow(); // Generate HOLDING_HISTORY row // void GenerateHoldingHistoryRow(TTrade iHoldingTradeID, // trade id of the original trade TTrade iTradeTradeID, // trade id of the modifying trade int iBeforeQty, // holding qty now int iAfterQty); // holding qty after modification // Helper function to get the current customer id TIdent GetCurrentCustID() { return m_NewTrade.iCustomer; } // Helper function to get the current customer tier int GetCurrentCustTier() { return m_NewTrade.iCustomerTier; } // Helper function to get the current account id TIdent GetCurrentAccID() { return m_NewTrade.iCustomerAccount; } // Helper function to get the current trade id TTrade GetCurrentTradeID() { return m_NewTrade.iTradeId; } // Helper function to get the current trade bid price CMoney GetCurrentBidPrice() { return m_NewTrade.fBidPrice; } // Helper function to get the current trade execution price CMoney GetCurrentTradePrice() { return m_NewTrade.fTradePrice; } // Helper function to get the current trade quantity int GetCurrentTradeQty() { return m_NewTrade.iTradeQty; } // Helper function to get the current trade type eTradeTypeID GetCurrentTradeType() { return m_NewTrade.eTradeType; } // Helper function to get the current trade status eStatusTypeID GetCurrentTradeStatus() { return m_NewTrade.eTradeStatus; } // Helper function to get whether the current trade is cash int GetCurrentTradeIsCash() { return m_TradeRow.m_Trade.T_IS_CASH; } // Helper function to get the current security symbol index TIdent GetCurrentSecurityIndex() { return m_NewTrade.iSymbolIndex; } // Helper function to get the current security index in the account's basket // (1-25) UINT GetCurrentSecurityAccountIndex() { return m_NewTrade.iSymbolIndexInAccount; } // Helper function to get the current trade pending time CDateTime GetCurrentTradePendingTime() { CDateTime ReturnTime = m_StartTime; int iDays, iMs; // submit days separately to avoid int32 overflow in ms after 25 days iDays = (int)(m_NewTrade.PendingTime / SecondsPerDay); iMs = (int)((m_NewTrade.PendingTime - iDays * SecondsPerDay) * MsPerSecond); ReturnTime.Add(iDays, iMs, true); // add days and msec and adjust for weekend return ReturnTime; } // Helper function to get the current trade submission time CDateTime GetCurrentTradeSubmissionTime() { CDateTime ReturnTime = m_StartTime; int iDays, iMs; // submit days separately to avoid int32 overflow in ms after 25 days iDays = (int)(m_NewTrade.SubmissionTime / SecondsPerDay); iMs = (int)((m_NewTrade.SubmissionTime - iDays * SecondsPerDay) * MsPerSecond); ReturnTime.Add(iDays, iMs, true); // add days and msec and adjust for weekend return ReturnTime; } // Helper function to get the current trade completion time CDateTime GetCurrentTradeCompletionTime() { CDateTime ReturnTime = m_StartTime; int iDays, iMs; // submit days separately to avoid int32 overflow in ms after 25 days iDays = (int)(m_NewTrade.CompletionTime / SecondsPerDay); iMs = (int)((m_NewTrade.CompletionTime - iDays * SecondsPerDay) * MsPerSecond); ReturnTime.Add(iDays, iMs, true); // add days and msec and adjust for weekend return ReturnTime; } // Helper function to get the current trade's is_lifo flag bool GetCurrentTradeIsLifo() { return m_NewTrade.bIsLifo; } // Helper function to get the current trade's sell value CMoney GetCurrentTradeSellValue() { return m_CompletedTradeInfo.fSellValue; } // Helper function to get the current trade's buy value CMoney GetCurrentTradeBuyValue() { return m_CompletedTradeInfo.fBuyValue; } // Helper function to get the current account broker id TIdent GetCurrentBrokerId() { return m_CompletedTradeInfo.iCurrentBrokerId; } // Helper function to get the current account tax status eTaxStatus GetCurrentTaxStatus() { return m_CompletedTradeInfo.eAccountTaxStatus; } // Helper function to get the current trade's charge amount CMoney GetCurrentTradeCharge() { return m_CompletedTradeInfo.Charge; } // Helper function to get the current trade's commission amount CMoney GetCurrentTradeCommission() { return m_CompletedTradeInfo.Commission; } // Helper function to get the current trade's tax amount CMoney GetCurrentTradeTax() { return m_CompletedTradeInfo.Tax; } // Helper function to get the current trade's settlement amount CMoney GetCurrentSettlementAmount() { return m_CompletedTradeInfo.SettlementAmount; } public: // Constructor // CTradeGen(const DataFileManager &dfm, TIdent iCustomerCount, TIdent iStartFromCustomer, TIdent iTotalCustomers, UINT iLoadUnitSize, UINT iScaleFactor, UINT iHoursOfInitialTrades, bool bCacheEnabled = false); // Destructor // ~CTradeGen(); // Generate one Trade Result and return the // resulting trade. This function will generate // a new incomplete trade (Trade Order) if needed // and put it onto the priority queue. // It will also update the holding information // as needed. // // Returns whether there is another trade to return. // bool GenerateNextTrade(); // Generate next HOLDING_SUMMARY record. // Returns whether there is another HOLDING_SUMMARY record to return. // bool GenerateNextHoldingSummaryRow(); // Generate next holding row. // This function will check internal state and // throw an exception if not all trades // have been generated. // // Returns whether there is another HOLDING row to return. // bool GenerateNextHolding(); // Initialize next load unit and prepare it for // GenerateNextTrade/GenerateNextHolding calls. // The first load unit doesn't have to be initialized. // // Return whether the next load unit exists // bool InitNextLoadUnit(); // Accessors for internal row structures. // const TRADE_ROW &GetTradeRow() { return m_TradeRow.m_Trade; } int GetTradeHistoryRowCount() { return m_iTradeHistoryRowCount; } const TRADE_HISTORY_ROW &GetTradeHistoryRow(int i) { return m_TradeRow.m_TradeHistory[i]; } int GetSettlementRowCount() { return m_iSettlementRowCount; } const SETTLEMENT_ROW &GetSettlementRow() { return m_TradeRow.m_Settlement; } int GetCashTransactionRowCount() { return m_iCashTransactionRowCount; } const CASH_TRANSACTION_ROW &GetCashTransactionRow() { return m_TradeRow.m_CashTransaction; } const HOLDING_ROW &GetHoldingRow() { return m_HoldingRow; } int GetHoldingHistoryRowCount() { return m_iHoldingHistoryRowCount; } const HOLDING_HISTORY_ROW &GetHoldingHistoryRow(int i) { return m_TradeRow.m_HoldingHistory[i]; } const HOLDING_SUMMARY_ROW &GetHoldingSummaryRow() { return m_HoldingSummaryRow; } bool GenerateNextBrokerRecord() { return m_BrokerTable.GenerateNextRecord(); } const BROKER_ROW &GetBrokerRow() { return m_BrokerTable.GetRow(); } }; } // namespace TPCE #endif // TRADE_GEN_H