Stock Market Simulator main e8c3612
A game that provides a realistic stock buying experience with unpredictable trends to test investment strategies.
Loading...
Searching...
No Matches
stock.cpp
Go to the documentation of this file.
1/// @file stock.cpp
2/// Implementation of the Stock class.
3/*
4This program is free software: you can redistribute it and/or modify it under the
5terms of the GNU Lesser General Public License as published by the Free Software
6Foundation, either version 3 of the License, or (at your option) any later version.
7
8This program is distributed in the hope that it will be useful, but WITHOUT ANY
9WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11
12You should have received a copy of the GNU Lesser General Public License along with this
13program. If not, see <https://www.gnu.org/licenses/>.
14*/
15#include "stock.h"
16
17#include "file_io.h"
18#include "format.h"
19#include "names.h"
20#include "random_price.h"
21
22#include <algorithm>
23#include <cassert>
24#include <fstream>
25#include <iostream>
26
27const int INVALID_OPERATION = -1;
28
32 /** The distribution of initial stock price will be consistent across the same
33 * categories.
34 * Note that the value '3' is because currently init_stock_price has 3
35 * possible input values.
36 */
38 quantity = 0;
43 split_count = 0;
45}
46
47void Stock::save(const std::string & playerName, int i) {
48 std::string filesave;
49 std::ofstream fout;
50 filesave = SAVE_FOLDER_PREFIX + playerName + "/" + std::to_string(i) + "" +
51 SAVE_FILE_EXTENSION_TXT; // creating the file path
52 fout.open(filesave.c_str());
53 fout << *this; // use operator<< to save the Stock object
54 fout.close();
55}
56
57void Stock::load(const std::string & playerName, int i) {
58 std::string fileToBeLoaded;
59 std::ifstream fin;
60 fileToBeLoaded = SAVE_FOLDER_PREFIX + playerName + "/" + std::to_string(i) + "" +
62 std::cout << "Loading " << fileToBeLoaded << " ... ";
63 fin.open(fileToBeLoaded.c_str());
64 // get the first line, which is category
65 fin >> *this; // use operator>> to load the Stock object
66 fin.close();
67 assert(price <= STOCK_PRICE_LIMIT && "Price exceed the limit");
68 std::cout << "done" << std::endl;
69}
70
71std::ostream & operator<<(std::ostream & fout, const Stock & stock) {
72 fout << stock.category
73 << std::endl; // literally load everything into class into file
74 fout << stock.name << std::endl;
75 for (unsigned int index = 0; index < stock.history.size(); index++) {
76 fout << stock.history[index] << " ";
77 }
78 fout << -1 << std::endl; // -1 is the stop code for vector<float> history in
79 // filesave
80 fout << stock.quantity << std::endl;
81 fout << stock.attributes.at(standard_deviation) << " ";
82 fout << stock.attributes.at(mean) << " ";
83 fout << stock.attributes.at(lower_limit) << " ";
84 fout << stock.attributes.at(upper_limit) << std::endl;
85 fout << stock.split_count << std::endl << std::endl;
86
87 // Save the ongoing events, separated by std::endl
88 for (Stock_event event : stock.events) {
89 fout << event << std::endl;
90 }
91 return fout;
92}
93
94std::istream & operator>>(std::istream & fin, Stock & stock) {
95 fin >> stock.category; // line 1
96 assert(stock.category < category_list_size && "Invalid category");
97 // line 2 is entirely the stock name
98 std::getline(fin >> std::ws, stock.name);
99 float loadedPrice;
100 fin >> loadedPrice;
101 // Erase the history vector and load the new history
102 stock.history.clear();
103 while (loadedPrice != -1) {
104 stock.history.emplace_back(loadedPrice);
105 fin >> loadedPrice; // line 3
106 }
107 // Set the price
108 stock.price = stock.history.back();
109 fin >> stock.quantity; // line 4
110 fin >> stock.attributes[standard_deviation]; // line 5
111 fin >> stock.attributes[mean];
112 fin >> stock.attributes[lower_limit];
113 fin >> stock.attributes[upper_limit];
114 fin >> stock.split_count; // line 6
115 // Clear the events list
116 stock.events.clear();
117 // Skip 2 empty lines
118 std::string emptyLine;
119 std::getline(fin >> std::ws, emptyLine);
120 std::getline(fin >> std::ws, emptyLine);
121 std::string loadedEventString;
122 while (std::getline(fin, loadedEventString)) {
123 Stock_event loadedEvent;
124 std::istringstream(loadedEventString) >> loadedEvent;
125 // Check the loaded event is valid
126 if (loadedEvent.event_id == getStockSplitEvent().event_id) {
127 stock.add_event(loadedEvent);
128 continue;
129 }
130 assert(
131 loadedEvent.event_id < all_stock_events.size() && "Invalid event loaded");
132 Stock_event comparedEvent = all_stock_events[loadedEvent.event_id];
133 assert(loadedEvent == comparedEvent && "Invalid event loaded");
134 stock.add_event(loadedEvent);
135 }
136 return fin;
137}
138
140 float & balance, unsigned int amount, float trading_fees_percent) {
141 float total_cost = price * amount * (1 + trading_fees_percent);
142 // Check if the player has enough balance to buy the stock
143 if (total_cost > balance && price <= 0) {
144 return INVALID_OPERATION;
145 }
146 // Update the balance, quantity, and money_spent
147 balance -= total_cost;
148 quantity += amount;
149 return total_cost;
150}
151
152float Stock::sell(float & balance, unsigned int amount, float trading_fees_percent) {
153 // Check if the player has enough stocks to sell
154 if (quantity < amount && price <= 0) {
155 return INVALID_OPERATION;
156 }
157 // Calculate the total revenue
158 float total_revenue = price * amount * (1 - trading_fees_percent);
159 balance += total_revenue;
160 quantity -= amount;
161 return total_revenue;
162}
163
164std::string Stock::category_name(void) const { return category_list[category]; }
165
167 float balance, float trading_fees_percent) const {
168 float value = balance / (price * (1 + trading_fees_percent));
169 return value < 0 ? 0 : static_cast<unsigned int>(value);
170}
171
173 /** We use vector now! */
174 history.emplace_back(price);
175}
176
177std::vector<float> Stock::return_most_recent_history(unsigned int rounds) {
178 std::vector<float> recent_history;
179 if (rounds >= history.size()) {
180 return history;
181 }
182 for (unsigned int i = history.size() - rounds; i < history.size(); i++) {
183 recent_history.emplace_back(history[i]);
184 }
185 return recent_history;
186}
187
189 // Stock prices are stored in the history array
190 if (history.size() < 2) {
191 // If there are less than two prices in the history array, return 0
192 return 0;
193 }
194 // Return the change of the last two prices
195 return history[history.size() - 1] - history[history.size() - 2];
196}
197
199 if (history.size() < 2 || history[history.size() - 1] < 0 ||
200 history[history.size() - 2] < 0) {
201 /** If there are less than two prices in the history array, return 0
202 * If the last two prices are negative, return 0, as it is not possible to
203 * calculate the percentage change
204 */
205 return 0;
206 }
207 return delta_price() / history[history.size() - 2];
208}
209
210void Stock::add_event(const Stock_event & event) {
211 if (!can_add_event(event)) {
212 // If the event is mutually exclusive with ongoing events,
213 // ignore it and do nothing.
214 return;
215 }
216 // If the event does not exist, add it to the std::list of events
217 // Otherwise, update the duration of the event by deleting the old one and add the
218 // new one.
219 std::list<Stock_event>::iterator event_itr = events.begin();
220 while (event_itr != events.end()) {
221 if (*event_itr == event) {
222 event_itr = events.erase(event_itr);
223 }
224 else {
225 event_itr++;
226 }
227 }
228 events.emplace_back(event);
229}
230
232 std::list<Stock_event>::iterator event_itr = events.begin();
233 while (event_itr != events.end()) {
234 if (!event_itr->mutually_exclusive_events.empty()) {
235 for (unsigned int i = 0; i < event_itr->mutually_exclusive_events.size();
236 i++) {
237 if (event_itr->mutually_exclusive_events[i] == event.event_id) {
238 return false;
239 }
240 }
241 }
242 event_itr++;
243 }
244 return true;
245}
246
248 std::list<Stock_event>::iterator event_itr = events.begin();
249 while (event_itr != events.end()) {
250 if (event_itr->duration <= 0) {
251 event_itr = events.erase(event_itr);
252 }
253 else {
254 event_itr++;
255 }
256 }
257}
258
260 float sum = 0;
261 std::list<Stock_event>::iterator event_itr = events.begin();
262 while (event_itr != events.end()) {
263 sum += event_itr->modifiers[attribute];
264 event_itr++; // Bug fix: infinite loop
265 }
266 return sum;
267}
268
270 Stock_event event_copy = getStockSplitEvent();
271 event_copy.text = name + event_copy.text;
272 event_copy.category = category;
273 return event_copy;
274}
275
277 /** Update the price of the stock.
278 * If the price is less than 1000, the price will increase or decrease by a random
279 * percentage. If the price is more than 1000, the price will be halved and the
280 * quantity will be doubled.
281 */
282 float price_diff = percentage_change_price(*this) / 100;
283 // Reduce all events duration by one.
284 std::list<Stock_event>::iterator event_itr = events.begin();
285 while (event_itr != events.end()) {
286 if (event_itr->duration > durationDecreaseMultiplier) {
287 event_itr->duration -= durationDecreaseMultiplier;
288 }
289 else {
290 event_itr->duration = 0;
291 }
292 event_itr++;
293 }
294 if (!(price * (1 + price_diff) >= STOCK_PRICE_LIMIT)) {
295 price *= (1 + price_diff);
296 }
297 else {
298 price /= 2;
299 quantity *= 2;
300 split_count++;
302 }
305}
306
307std::vector<unsigned int> Stock::get_event_ids(void) {
308 std::vector<unsigned int> event_ids;
309 std::list<Stock_event>::iterator event_itr = events.begin();
310 while (event_itr != events.end()) {
311 event_ids.emplace_back(event_itr->event_id);
312 event_itr++;
313 }
314 return event_ids;
315}
316
318 return attributes[attribute] + get_event_attribute(attribute);
319}
320
321void sortStocksList(std::vector<Stock> & stocks_list, SortingMethods sortMethod,
322 SortingDirections sortDirection) {
323 switch (sortMethod) {
324 case by_name:
325 std::sort(stocks_list.begin(), stocks_list.end(),
326 [](Stock a, Stock b) { return a.get_name() < b.get_name(); });
327 break;
328 case by_category:
329 std::sort(stocks_list.begin(), stocks_list.end(),
330 [](Stock a, Stock b) { return a.get_category() < b.get_category(); });
331 break;
332 case by_price:
333 std::sort(stocks_list.begin(), stocks_list.end(),
334 [](Stock a, Stock b) { return a.get_price() < b.get_price(); });
335 break;
336 case by_quantity:
337 std::sort(stocks_list.begin(), stocks_list.end(),
338 [](Stock a, Stock b) { return a.get_quantity() < b.get_quantity(); });
339 break;
340 case by_sd:
341 std::sort(stocks_list.begin(), stocks_list.end(), [](Stock a, Stock b) {
342 return a.get_total_attribute(standard_deviation) <
343 b.get_total_attribute(standard_deviation);
344 });
345 break;
346 case by_mean:
347 std::sort(stocks_list.begin(), stocks_list.end(), [](Stock a, Stock b) {
348 return a.get_total_attribute(mean) < b.get_total_attribute(mean);
349 });
350 break;
351 case by_lower_limit:
352 std::sort(stocks_list.begin(), stocks_list.end(), [](Stock a, Stock b) {
353 return a.get_total_attribute(lower_limit) <
354 b.get_total_attribute(lower_limit);
355 });
356 break;
357 case by_upper_limit:
358 std::sort(stocks_list.begin(), stocks_list.end(), [](Stock a, Stock b) {
359 return a.get_total_attribute(upper_limit) <
360 b.get_total_attribute(upper_limit);
361 });
362 break;
363 default:
364 break;
365 }
366 if (sortDirection == descending) {
367 std::reverse(stocks_list.begin(), stocks_list.end());
368 }
369}
370
372 return price * quantity * (1 - trading_fees_percent);
373}
374
A class that represents a stock object in the game.
Definition stock.h:55
std::string category_name(void) const
Return the name of the category the stock belongs to.
Definition stock.cpp:164
unsigned int split_count
Contains the spliting count of a stock.
Definition stock.h:296
float sell(float &balance, unsigned int amount, float trading_fees_percent)
Sell a given number of stocks.
Definition stock.cpp:152
float calculateStockValue(const float &trading_fees_percent) const
Calculate the total value of the stocks the player is holding.
Definition stock.cpp:371
void add_event(const Stock_event &event)
Add an event to the stock.
Definition stock.cpp:210
unsigned int num_stocks_affordable(float balance, float trading_fees_percent) const
Definition stock.cpp:166
std::vector< float > history
Contains the stock price history.
Definition stock.h:293
std::map< stock_modifiers, float > attributes
Stores the initial value of the stock_modifiers (e.g.
Definition stock.h:289
unsigned int category
Use numbers to represent the category of the stock.
Definition stock.h:282
float price
Current price of the stock.
Definition stock.h:273
float delta_price(void)
Return the change of stock price using the most recent price and the current price.
Definition stock.cpp:188
std::string name
Name of the stock that we assigned to it.
Definition stock.h:270
bool can_add_event(const Stock_event &event)
Check if we can add the event to the stock.
Definition stock.cpp:231
float delta_price_percentage(void)
Return the percentage of change of stock price.
Definition stock.cpp:198
std::list< Stock_event > events
Stores all the events that will apply to this stock specifically.
Definition stock.h:285
void update_history(void)
Update the history array with the current price.
Definition stock.cpp:172
void next_round(void)
Call this when the game proceed to next round.
Definition stock.cpp:276
std::vector< float > return_most_recent_history(unsigned int rounds)
Get the stock price of recent rounds.
Definition stock.cpp:177
unsigned int quantity
Number of stocks the player has purchased.
Definition stock.h:276
void save(const std::string &playerName, int i)
Save the stock from a file.
Definition stock.cpp:47
void remove_obselete_event(void)
Remove obselete events from the list events that durations are less than/equal to 0 (In other words,...
Definition stock.cpp:247
Stock(void)
Constructor of class Stock.
Definition stock.cpp:29
void load(const std::string &playerName, int i)
Load the stock from a file.
Definition stock.cpp:57
float calculateTradingFeesLost(const float &trading_fees_percent) const
Calculate the amount of money player lost due to trading fees.
Definition stock.cpp:375
std::vector< unsigned int > get_event_ids(void)
Get the event ids of all the events that will apply to this stock specifically.
Definition stock.cpp:307
float get_total_attribute(stock_modifiers attribute)
Sums up get_base_attribute() and get_event_attribute().
Definition stock.cpp:317
float purchase(float &balance, unsigned int amount, float trading_fees_percent)
Purchase a given number of stocks.
Definition stock.cpp:139
float get_event_attribute(stock_modifiers attribute)
Get the total change of attribute of the stock due to events only.
Definition stock.cpp:259
Stock_event setup_STOCK_SPLIT_EVENT(void)
Set up a getStockSplitEvent() with proper values.
Definition stock.cpp:269
Stock_event getStockSplitEvent(void)
Definition events.cpp:1453
const std::vector< Stock_event > all_stock_events
The list of all events that can be applied to the stocks.
Definition events.cpp:49
stock_modifiers
The attributes of a stock that Events will modify are hardcoded here.
Definition events.h:30
@ upper_limit
The upper limit of the stock price percentage change.
Definition events.h:48
@ standard_deviation
Amount of variation of the stock price percentage change.
Definition events.h:32
@ mean
The expectation of the stock price percentage change.
Definition events.h:36
@ lower_limit
The lower limit of the stock price percentage change.
Definition events.h:42
const float defaultUpperLimit
Default upper limit.
Definition events.h:67
const float defaultLowerLimit
Default lower limit.
Definition events.h:64
constexpr float defaultMean
Default mean.
Definition events.h:70
const unsigned int durationDecreaseMultiplier
Rate of decrease of duration.
Definition events.h:73
Header files for file operation functions related to the game.
const std::string SAVE_FOLDER_PREFIX
Definition file_io.h:45
const std::string SAVE_FILE_EXTENSION_TXT
Definition file_io.h:48
Header file for the ANSI Escape code related functions.
const float trading_fees_percent
/ 100 means charging % more/portion of the money involved in stock operations.
Definition main.cpp:65
float balance
Player's balance.
Definition main.cpp:68
std::string playerName
Player's name.
Definition main.cpp:73
vector< string > generate_name(unsigned int category, unsigned int num)
Generates a set of unique stock names based on the specified category and quantity.
Definition names.cpp:37
string const category_list[category_list_size]
List of stock categories.
Definition names.cpp:22
Declaration of the name generating function.
const int category_list_size
The size of the category list.
Definition names.h:27
float init_stock_price(int price_profile)
Initialize starting stock price.
float percentage_change_price(Stock stock)
Calculate the percentage change of the stock price.
unsigned int random_integer(unsigned int max_integer)
python randint like function
float init_sd(void)
Initialize the standard deviation of the stock price.
Header file for random related functions.
std::ostream & operator<<(std::ostream &fout, const Stock &stock)
Definition stock.cpp:71
const int INVALID_OPERATION
Definition stock.cpp:27
void sortStocksList(std::vector< Stock > &stocks_list, SortingMethods sortMethod, SortingDirections sortDirection)
Sorts the stocks.
Definition stock.cpp:321
std::istream & operator>>(std::istream &fin, Stock &stock)
Definition stock.cpp:94
Declaration of the Stock class.
const float STOCK_PRICE_LIMIT
The upper limit of the stock price.
Definition stock.h:34
SortingMethods
Definition stock.h:308
@ by_upper_limit
Definition stock.h:313
@ by_mean
Definition stock.h:315
@ by_price
Definition stock.h:310
@ by_quantity
Definition stock.h:312
@ by_category
Definition stock.h:311
@ by_lower_limit
Definition stock.h:314
@ by_sd
Definition stock.h:316
@ by_name
Definition stock.h:309
SortingDirections
Definition stock.h:319
@ descending
Definition stock.h:319
The data structure of an event that will be applied to the stocks.
Definition events.h:104
unsigned int category
Definition events.h:129
std::string text
The text that will be displayed to the player.
Definition events.h:116
unsigned int event_id
The id of the event.
Definition events.h:110