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 | * - Doug Johnson |
35 | */ |
36 | |
37 | /****************************************************************************** |
38 | * Description: Implementation of the MEETickerTape class. |
39 | * See MEETickerTape.h for a description. |
40 | ******************************************************************************/ |
41 | |
42 | #include "main/MEETickerTape.h" |
43 | #include "main/StatusTypeIDs.h" |
44 | |
45 | using namespace TPCE; |
46 | |
47 | const int CMEETickerTape::LIMIT_TRIGGER_TRADE_QTY = 375; |
48 | const int CMEETickerTape::RANDOM_TRADE_QTY_1 = 325; |
49 | const int CMEETickerTape::RANDOM_TRADE_QTY_2 = 425; |
50 | |
51 | RNGSEED CMEETickerTape::GetRNGSeed(void) { |
52 | return (m_rnd.GetSeed()); |
53 | } |
54 | |
55 | void CMEETickerTape::SetRNGSeed(RNGSEED RNGSeed) { |
56 | m_rnd.SetSeed(RNGSeed); |
57 | } |
58 | |
59 | void CMEETickerTape::Initialize(void) { |
60 | // Set up status and trade types for Market-Feed input |
61 | // |
62 | // Submitted |
63 | strncpy(m_TxnInput.StatusAndTradeType.status_submitted, m_StatusType[eSubmitted].ST_ID_CSTR(), |
64 | sizeof(m_TxnInput.StatusAndTradeType.status_submitted)); |
65 | // Limit-Buy |
66 | strncpy(m_TxnInput.StatusAndTradeType.type_limit_buy, m_TradeType[eLimitBuy].TT_ID_CSTR(), |
67 | sizeof(m_TxnInput.StatusAndTradeType.type_limit_buy)); |
68 | // Limit-Sell |
69 | strncpy(m_TxnInput.StatusAndTradeType.type_limit_sell, m_TradeType[eLimitSell].TT_ID_CSTR(), |
70 | sizeof(m_TxnInput.StatusAndTradeType.type_limit_sell)); |
71 | // Stop-Loss |
72 | strncpy(m_TxnInput.StatusAndTradeType.type_stop_loss, m_TradeType[eStopLoss].TT_ID_CSTR(), |
73 | sizeof(m_TxnInput.StatusAndTradeType.type_stop_loss)); |
74 | } |
75 | |
76 | // Constructor - use default RNG seed |
77 | CMEETickerTape::CMEETickerTape(CMEESUTInterface *pSUT, CMEEPriceBoard *pPriceBoard, CDateTime *pBaseTime, |
78 | CDateTime *pCurrentTime, const DataFileManager &dfm) |
79 | : m_pSUT(pSUT), m_pPriceBoard(pPriceBoard), m_BatchIndex(0), m_BatchDuplicates(0), m_rnd(RNGSeedBaseMEETickerTape), |
80 | m_Enabled(true), m_pBaseTime(pBaseTime), m_pCurrentTime(pCurrentTime), m_StatusType(dfm.StatusTypeDataFile()), |
81 | m_TradeType(dfm.TradeTypeDataFile()) { |
82 | Initialize(); |
83 | } |
84 | |
85 | // Constructor - RNG seed provided |
86 | CMEETickerTape::CMEETickerTape(CMEESUTInterface *pSUT, CMEEPriceBoard *pPriceBoard, CDateTime *pBaseTime, |
87 | CDateTime *pCurrentTime, RNGSEED RNGSeed, const DataFileManager &dfm) |
88 | : m_pSUT(pSUT), m_pPriceBoard(pPriceBoard), m_BatchIndex(0), m_BatchDuplicates(0), m_rnd(RNGSeed), m_Enabled(true), |
89 | m_pBaseTime(pBaseTime), m_pCurrentTime(pCurrentTime), m_StatusType(dfm.StatusTypeDataFile()), |
90 | m_TradeType(dfm.TradeTypeDataFile()) { |
91 | Initialize(); |
92 | } |
93 | |
94 | CMEETickerTape::~CMEETickerTape(void) { |
95 | } |
96 | |
97 | bool CMEETickerTape::DisableTicker(void) { |
98 | m_Enabled = false; |
99 | return (!m_Enabled); |
100 | } |
101 | |
102 | bool CMEETickerTape::EnableTicker(void) { |
103 | m_Enabled = true; |
104 | return (m_Enabled); |
105 | } |
106 | |
107 | void CMEETickerTape::AddEntry(PTickerEntry pTickerEntry) { |
108 | if (m_Enabled) { |
109 | AddToBatch(pTickerEntry); |
110 | AddArtificialEntries(); |
111 | } |
112 | } |
113 | |
114 | void CMEETickerTape::PostLimitOrder(PTradeRequest pTradeRequest) { |
115 | eTradeTypeID eTradeType; |
116 | double CurrentPrice = -1.0; |
117 | PTickerEntry pNewEntry = new TTickerEntry; |
118 | |
119 | eTradeType = ConvertTradeTypeIdToEnum(pTradeRequest->trade_type_id); |
120 | |
121 | pNewEntry->price_quote = pTradeRequest->price_quote; |
122 | strncpy(pNewEntry->symbol, pTradeRequest->symbol, sizeof(pNewEntry->symbol)); |
123 | pNewEntry->trade_qty = LIMIT_TRIGGER_TRADE_QTY; |
124 | |
125 | CurrentPrice = m_pPriceBoard->GetCurrentPrice(pTradeRequest->symbol).DollarAmount(); |
126 | |
127 | if (((eTradeType == eLimitBuy || eTradeType == eStopLoss) && CurrentPrice <= pTradeRequest->price_quote) || |
128 | ((eTradeType == eLimitSell) && CurrentPrice >= pTradeRequest->price_quote)) { |
129 | // Limit Order is in-the-money. |
130 | pNewEntry->price_quote = CurrentPrice; |
131 | // Make sure everything is up to date. |
132 | m_LimitOrderTimers.ProcessExpiredTimers(); |
133 | // Now post the incoming entry. |
134 | m_InTheMoneyLimitOrderQ.push(pNewEntry); |
135 | } else { |
136 | // Limit Order is not in-the-money. |
137 | pNewEntry->price_quote = pTradeRequest->price_quote; |
138 | double TriggerTimeDelay; |
139 | double fCurrentTime = *m_pCurrentTime - *m_pBaseTime; |
140 | |
141 | // GetSubmissionTime returns a value relative to time 0, so we |
142 | // need to substract off the value for the current time to get |
143 | // the delay time relative to now. |
144 | TriggerTimeDelay = |
145 | m_pPriceBoard->GetSubmissionTime(pNewEntry->symbol, fCurrentTime, pNewEntry->price_quote, eTradeType) - |
146 | fCurrentTime; |
147 | m_LimitOrderTimers.StartTimer(TriggerTimeDelay, this, &CMEETickerTape::AddLimitTrigger, pNewEntry); |
148 | } |
149 | } |
150 | |
151 | void CMEETickerTape::AddLimitTrigger(PTickerEntry pTickerEntry) { |
152 | m_InTheMoneyLimitOrderQ.push(pTickerEntry); |
153 | } |
154 | |
155 | void CMEETickerTape::AddArtificialEntries(void) { |
156 | TIdent SecurityIndex; |
157 | TTickerEntry TickerEntry; |
158 | int TotalEntryCount = 0; |
159 | static const int PaddingLimit = |
160 | (max_feed_len / 10) - 1; // NOTE: 10 here represents the ratio of TR to MF transactions |
161 | static const int PaddingLimitForAll = PaddingLimit; // MAX (trigger+artificial) entries |
162 | static const int PaddingLimitForTriggers = PaddingLimit; // MAX (triggered) entries |
163 | |
164 | while (TotalEntryCount < PaddingLimitForTriggers && !m_InTheMoneyLimitOrderQ.empty()) { |
165 | PTickerEntry pEntry = m_InTheMoneyLimitOrderQ.front(); |
166 | AddToBatch(pEntry); |
167 | delete pEntry; |
168 | m_InTheMoneyLimitOrderQ.pop(); |
169 | TotalEntryCount++; |
170 | } |
171 | |
172 | while (TotalEntryCount < PaddingLimitForAll) { |
173 | TickerEntry.trade_qty = (m_rnd.RndPercent(50)) ? RANDOM_TRADE_QTY_1 : RANDOM_TRADE_QTY_2; |
174 | |
175 | SecurityIndex = m_rnd.RndInt64Range(0, m_pPriceBoard->m_iNumberOfSecurities - 1); |
176 | TickerEntry.price_quote = (m_pPriceBoard->GetCurrentPrice(SecurityIndex)).DollarAmount(); |
177 | m_pPriceBoard->GetSymbol(SecurityIndex, TickerEntry.symbol, static_cast<INT32>(sizeof(TickerEntry.symbol))); |
178 | |
179 | AddToBatch(&TickerEntry); |
180 | TotalEntryCount++; |
181 | } |
182 | } |
183 | |
184 | void CMEETickerTape::AddToBatch(PTickerEntry pTickerEntry) { |
185 | // Check to see if this symbol already exists in the batch |
186 | for (int i = 0; i < m_BatchIndex; i++) { |
187 | if (strncmp(pTickerEntry->symbol, m_TxnInput.Entries[i].symbol, cSYMBOL_len) == 0) { |
188 | m_BatchDuplicates++; |
189 | break; |
190 | } |
191 | } |
192 | |
193 | // Add the ticker to the batch |
194 | m_TxnInput.Entries[m_BatchIndex++] = *pTickerEntry; |
195 | |
196 | // Buffer is full, time for Market-Feed. |
197 | if (max_feed_len == m_BatchIndex) { |
198 | m_TxnInput.unique_symbols = (max_feed_len - m_BatchDuplicates); |
199 | m_pSUT->MarketFeed(&m_TxnInput); |
200 | m_BatchIndex = 0; |
201 | m_BatchDuplicates = 0; |
202 | } |
203 | } |
204 | |
205 | eTradeTypeID CMEETickerTape::ConvertTradeTypeIdToEnum(char *pTradeType) { |
206 | // Convert character trade type to enumeration |
207 | switch (pTradeType[0]) { |
208 | case 'T': |
209 | switch (pTradeType[1]) { |
210 | case 'L': |
211 | switch (pTradeType[2]) { |
212 | case 'B': |
213 | return (eLimitBuy); |
214 | case 'S': |
215 | return (eLimitSell); |
216 | default: |
217 | break; |
218 | } |
219 | break; |
220 | case 'M': |
221 | switch (pTradeType[2]) { |
222 | case 'B': |
223 | return (eMarketBuy); |
224 | case 'S': |
225 | return (eMarketSell); |
226 | default: |
227 | break; |
228 | } |
229 | break; |
230 | case 'S': |
231 | switch (pTradeType[2]) { |
232 | case 'L': |
233 | return (eStopLoss); |
234 | default: |
235 | break; |
236 | } |
237 | break; |
238 | default: |
239 | break; |
240 | } |
241 | break; |
242 | default: |
243 | break; |
244 | } |
245 | |
246 | // Throw exception - should never get here |
247 | assert(false); // this should never happen |
248 | |
249 | return eMarketBuy; // silence compiler warning about not all control paths |
250 | // returning a value |
251 | } |
252 | |