=================================================== STOCK.H ======================================================== #ifndef HASHTABLE_STOCK_H #define HASHTABLE_STOCK_H #include #include /** * Represents price data of a stock for a single day */ class PriceData { std::string date; double open, high, low, close, adj_close; int volume; public: /** * Creates price data for a single day * @param date Date of given price data * @param open Open value of given day * @param high High value of given day * @param low Low value of given day * @param close Close value of given day * @param volume Volume of given day * @param adj_close Adjusted close value of given day */ PriceData(std::string date, double open, double high, double low, double close, int volume, double adj_close); /** * Returns the date of this PriceData * @return a string containing the date */ std::string getDate(); /** * Returns the open value of this PriceData * @return a double containing the open value */ double getOpen(); /** * Returns the high value of this PriceData * @return a double containing the high value */ double getHigh(); /** * Returns the low value of this PriceData * @return a double containing the low value */ double getLow(); /** * Returns the close value of this PriceData * @return a double containing the close value */ double getClose(); /** * Returns the volume value of this PriceData * @return an int containing the volume value */ int getVolume(); /** * Returns the adjusted close value of this PriceData * @return a double containing the adjusted close value */ double getAdjClose(); }; /** * Represents a stock with a name, member code, security identification number and price data of last 30 days */ class Stock { std::string name; std::string member_code; // Security Identification Number int sin; PriceData* price_data[30]; public: /** * Creates an empty stock */ Stock(); /** * Creates a new stock * @param name Stock name * @param member_code Short name of stock * @param sin Security Identification Number */ Stock(std::string name, std::string member_code, int sin); /** * Import price data of last 30 days from a csv file * @param filepath path to csv file (including filename + ending) */ void import_price_data(std::string filepath); /** * Returns the name of the stock * @return a string containing the name */ std::string getName(); /** * Returns the member code of the stock * @return a string containing the member code */ std::string getMemberCode(); /** * Returns the security identification number of the stock * @return an int containing the sin */ int getSIN(); /** * Returns the PriceData Array of the stock * @return an array of PriceData Pointer of length 30 */ PriceData** getPriceData(); /** * Sets the PriceData Array * @param data an array of PriceData Pointer of length 30 */ void setPriceData(PriceData** data); }; #endif //HASHTABLE_STOCK_H =================================================== STOCK.CPP ====================================================== #include "stock.h" #include #include #include PriceData::PriceData(std::string date, double open, double high, double low, double close, int volume, double adj_close) : date(date), open(open), high(high), low(low), close(close), volume(volume), adj_close(adj_close) { } std::string PriceData::getDate() { return date; } double PriceData::getOpen() { return open; } double PriceData::getHigh() { return high; } double PriceData::getLow() { return low; } double PriceData::getClose() { return close; } int PriceData::getVolume() { return volume; } double PriceData::getAdjClose() { return adj_close; } Stock::Stock(std::string name, std::string member_code, int sin) : name(name), member_code(member_code), sin(sin) { for (int i = 0; i < 30; i++) { price_data[i] = nullptr; } } Stock::Stock() { name = nullptr; member_code = nullptr; sin = -1; } void Stock::import_price_data(std::string filepath) { std::ifstream file(filepath, std::ios::in); std::string line; int line_numbers = 0; for (; std::getline(file, line); line_numbers++); std::string date, open, high, low, close, volume, adj_close; double open_d, high_d, low_d, close_d, adj_close_d; int volume_d; std::ifstream datei; //open file with correct Filepath of Input datei.open(filepath, std::ios::in); //read first line without values to get to second line getline(datei, date, '\n'); for (int i = 0; i < 30 && i < line_numbers-1; ++i) { //read the line of the file and get the values into the correct variables getline(datei, date, ','); getline(datei, open, ','); getline(datei, high, ','); getline(datei, low, ','); getline(datei, close, ','); getline(datei, volume, ','); getline(datei, adj_close, '\n'); //prepare stringstreams to get the values from string into double std::stringstream open_s(open); std::stringstream high_s(high); std::stringstream low_s(low); std::stringstream close_s(close); std::stringstream volume_s(volume); std::stringstream adj_close_s(adj_close); //convert stringstreams in doubles open_s >> open_d; high_s >> high_d; low_s >> low_d; close_s >> close_d; adj_close_s >> adj_close_d; volume_s >> volume_d; if(!open_s.fail() && !high_s.fail() && !low_s.fail() && !close_s.fail() && !adj_close_s.fail() && !volume_s.fail()) { //erstelle neues Objekt und übergebe die daten if(price_data[i] != nullptr) { delete price_data[i]; } price_data[i] = new PriceData(date, open_d, high_d, low_d, close_d, volume_d, adj_close_d); } } } std::string Stock::getName() { return name; } std::string Stock::getMemberCode() { return member_code; } int Stock::getSIN() { return sin; } PriceData** Stock::getPriceData() { return price_data; } void Stock::setPriceData(PriceData **data) { for(int i = 0; i < 30; i++){ price_data[i] = data[i]; } } =================================================== HASHTABLE.H ==================================================== #ifndef HASHTABLE_HASHTABLE_H #define HASHTABLE_HASHTABLE_H #include "stock.h" /** * Represents a HashTable for saving stock information */ class HashTable { const static int array_size = 1999; // Data format to store stocks in Stock* stocks[array_size]; public: const static int HASH_BY_NAME = 0; const static int HASH_BY_CODE = 1; /** * Creates a new HashTable */ HashTable(); /** * Hash function, which creates an integer value from a string * @param str string to be hashed * @return an integer value representing a hashed value of the given string */ int hash(std::string str); /** * Puts a stock into the HashTable * @param stock Stock to be inserted * @param hash_by HASH_BY_NAME or HASH_BY_CODE */ void add(Stock* stock, int hash_by); /** * Removes a stock from the HashTable * @param name Name of stock to be removed * @param hash_by HASH_BY_NAME or HASH_BY_CODE */ void remove(std::string name, int hash_by); /** * Searches a stock in the HashTable and returns it if found * @param name Name of wanted stock * @param hash_by HASH_BY_NAME or HASH_BY_CODE * @return Wanted stock, if found. Else it will return null */ Stock* search(std::string name, int hash_by); /** * Saves the complete HashTable into a file * @param filepath the path (+filename) where it should be saved */ void saveToFile(std::string filepath); /** * Reads a complete HashTable from a file * @param filepath the path (+filename) from where it should be read */ void readFromFile(std::string filepath); }; #endif //HASHTABLE_HASHTABLE_H =================================================== HASHTABLE.CPP ================================================== #include #include #include #include #include "hashtable.h" HashTable::HashTable() { for(int i = 0; i < array_size; i++){ stocks[i] = nullptr; } } int HashTable::hash(std::string str) { int intLength = str.length() / 4; long sum = 0; for (int j = 0; j < intLength; j++) { char c[5]; std::string tmp = str.substr(j * 4, (j * 4) + 4); strcpy(c, tmp.c_str()); long mult = 1; for (int k = 0; k < 5; k++) { sum += c[k] * mult; mult *= 256; } } int lengthMax = str.length() % 4; char c[lengthMax]; std::string tmp = str.substr(intLength * 4); strcpy(c, tmp.c_str()); long mult = 1; for (int k = 0; k < lengthMax; k++) { sum += c[k] * mult; mult *= 256; } return(sum % array_size); } void HashTable::add(Stock* stock, int hash_by) { int hashed = 0; if(hash_by == HASH_BY_NAME) { hashed = hash(stock->getName()); }else{ hashed = hash(stock->getMemberCode()); } //look in the list if the hashed position for stock is empty if(stocks[hashed] == nullptr){ stocks[hashed] = stock; }else{ //if not empty start the search algorithm for empty position int plus = 1; int next_pos = 0; for(int i = 1; i <= array_size;){ int x = (int)pow(i,2); //function to take the numbers of square always negative and positive if(!plus){ x = (-1) * x; i++; } plus = (plus+1)%2; //calculation to get the correct value always as a positive integer next_pos = ((hashed+x)% array_size + array_size) % array_size ; if(stocks[next_pos] == nullptr){ stocks[next_pos] = stock; break; } } } } void HashTable::remove(std::string name, int hash_by) { int hashed = hash(name); //look in the list if correct stock from the input is on the hashed position if((hash_by == HASH_BY_NAME && stocks[hashed] != nullptr && stocks[hashed]->getName() == name) || (hash_by == HASH_BY_CODE && stocks[hashed] != nullptr && stocks[hashed]->getMemberCode() == name)){ delete stocks[hashed]; stocks[hashed] = nullptr; }else{ int plus = 1; int next_pos = 0; for(int i = 1; i <= array_size;){ int x = (int)pow(i,2); //function to take the numbers of square always negative and positive if(!plus){ x = (-1) * x; i++; } plus = (plus+1)%2; //calculation to get the correct value always as a positive integer next_pos = ((hashed+x) % array_size + array_size) % array_size ; if((hash_by == HASH_BY_NAME && stocks[next_pos] != nullptr && stocks[next_pos]->getName() == name) || (hash_by == HASH_BY_CODE && stocks[next_pos] != nullptr && stocks[next_pos]->getMemberCode() == name)){ delete stocks[next_pos]; stocks[next_pos] = nullptr; break; } } } } Stock* HashTable::search(std::string name, int hash_by) { int hashed = hash(name); //look in the list if correct stock from the input is on the hashed position if((hash_by == HASH_BY_NAME && stocks[hashed] != nullptr && stocks[hashed]->getName() == name) || (hash_by == HASH_BY_CODE && stocks[hashed] != nullptr && stocks[hashed]->getMemberCode() == name)){ return stocks[hashed]; }else{ //if not on the hashed position start with the search algorithm int plus = 1; int next_pos = 0; for(int i = 1; i <= array_size;){ int x = (int)pow(i,2); //function to take the numbers of square always negative and positive if(!plus){ x = (-1) * x; i++; } plus = (plus+1)%2; //calculation to get the correct value always as a positive integer next_pos = ((hashed+x) % array_size + array_size) % array_size ; if(hash_by == HASH_BY_NAME && stocks[next_pos] != nullptr && stocks[next_pos]->getName() == name || hash_by == HASH_BY_CODE && stocks[next_pos] != nullptr && stocks[next_pos]->getMemberCode() == name){ return stocks[next_pos]; } } } return nullptr; } void HashTable::saveToFile(std::string filepath) { int count_pricedata; std::ofstream file; file.open(filepath, std::ios::out); for(int i = 0; i < array_size; i++){ if(stocks[i] != nullptr){ // Write stock information file << i << " " << stocks[i]->getName() << " " << stocks[i]->getMemberCode() << " " << stocks[i]->getSIN(); count_pricedata = 0; for(int j = 0; j < 30; j++){ if(stocks[i]->getPriceData()[j] != nullptr){ count_pricedata++; } } file << " " << count_pricedata << "\n"; // Write price data for(int j = 0; j < 30; j++){ if(stocks[i]->getPriceData()[j] != nullptr){ file << j << " " << stocks[i]->getPriceData()[j]->getDate(); file << " " << stocks[i]->getPriceData()[j]->getOpen(); file << " " << stocks[i]->getPriceData()[j]->getHigh(); file << " " << stocks[i]->getPriceData()[j]->getLow(); file << " " << stocks[i]->getPriceData()[j]->getClose(); file << " " << stocks[i]->getPriceData()[j]->getVolume(); file << " " << stocks[i]->getPriceData()[j]->getAdjClose() << "\n"; } } } } // End of File file << "eof" << " \n"; file.close(); } void HashTable::readFromFile(std::string filepath) { std::string in, name, membercode, sin_s, date; int count_pricedata, sin, index, volume, pdindex; double open, high, low, close, adjclose; std::ifstream file; file.open(filepath, std::ios::in); for(int i = 0; i < array_size; i++){ getline(file, in, ' '); // If not end of file if(in != "eof"){ // Read stock information getline(file, name, ' '); getline(file, membercode, ' '); getline(file, sin_s, ' '); std::stringstream sin_stream(sin_s); sin_stream >> sin; std::stringstream index_stream(in); index_stream >> index; // Insert stock into hashtable Stock* stock = new Stock(name, membercode, sin); stocks[index] = stock; // Read price data getline(file, in, '\n'); std::stringstream pricedata_stream(in); pricedata_stream >> count_pricedata; PriceData* data[30]; for(int j = 0; j < 30; j++){ data[j] = nullptr; } for(int j = 0; j < count_pricedata; j++){ getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> pdindex; getline(file, date, ' '); } getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> open; } getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> high; } getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> low; } getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> close; } getline(file, in, ' '); { std::stringstream in_stream(in); in_stream >> volume; } getline(file, in, '\n'); { std::stringstream in_stream(in); in_stream >> adjclose; } PriceData* priceData = new PriceData(date, open, high, low, close, volume, adjclose); data[pdindex] = priceData; } stocks[index]->setPriceData(data); }else{ break; } } file.close(); } =================================================== MAIN.CPP ======================================================== #include #include #include #include #include "hashtable.h" Stock* searchStock(std::string name, HashTable* table_names, HashTable* table_codes){ Stock *s = nullptr; if(name.length() > 4) { s = table_names->search(name, HashTable::HASH_BY_NAME); }else{ s = table_codes->search(name, HashTable::HASH_BY_CODE); } if(s == nullptr){ if(name.length() > 4) { s = table_codes->search(name, HashTable::HASH_BY_CODE); }else{ s = table_names->search(name, HashTable::HASH_BY_NAME); } } return s; } void printMenuInfo(){ std::cout << "\n\n"; std::cout << "==============================" << std::endl; std::cout << "1 ... Add stock" << std::endl; std::cout << "2 ... Search stock" << std::endl; std::cout << "3 ... Delete stock" << std::endl; std::cout << "4 ... Import price data from file" << std::endl; std::cout << "5 ... Plot price data of a stock" << std::endl; std::cout << "6 ... Save hashtable to file" << std::endl; std::cout << "7 ... Load hashtable from file" << std::endl; std::cout << "8 ... Quit program" << std::endl; std::cout << "------------------------------" << std::endl; } int main() { std::string in = ""; HashTable *table_names = new HashTable(); HashTable *table_codes = new HashTable(); // QUIT if input is 8 while(in.compare("8") != 0){ printMenuInfo(); std::cin >> in; if(in.compare("1") == 0){ // ADD std::string name, member_code, sin_s; int sin; std::cout << "Name: "; std::cin >> name; std::cout << "Member Code: "; std::cin >> member_code; int fail = 0; do { std::cout << "Security Identification Number: "; std::cin >> sin_s; std::stringstream s(sin_s); s >> sin; if(s.fail()){ fail = 1; }else{ fail = 0; } }while(fail); Stock *stock = new Stock(name, member_code, sin); table_names->add(stock, HashTable::HASH_BY_NAME); table_codes->add(stock, HashTable::HASH_BY_CODE); }else if(in.compare("3") == 0){ // DELETE std::string name; std::cout << "Name/Member Code: "; std::cin >> name; Stock *s = searchStock(name, table_names, table_codes); if(s != nullptr) { table_names->remove(s->getName(), HashTable::HASH_BY_NAME); table_codes->remove(s->getMemberCode(), HashTable::HASH_BY_CODE); std::cout << name << " successfully removed!" << std::endl; }else{ std::cout << "Could not delete stock! (Not found)"; } }else if(in.compare("4") == 0){ // IMPORT std::string name; std::cout << "Name/Member Code: "; std::cin >> name; Stock* s = searchStock(name, table_names, table_codes); if(s != nullptr) { std::string filepath; std::cout << "Filepath: "; std::cin >> filepath; s->import_price_data(filepath); std::cout << "Import successful!" << std::endl; }else{ std::cout << "Could not find stock!" << std::endl; } }else if(in.compare("2") == 0){ // SEARCH std::string name; std::cout << "Name/Member Code: "; std::cin >> name; Stock* s = searchStock(name, table_names, table_codes); if(s != nullptr) { std::cout << "NAME: " << s->getName() << std::endl; std::cout << "MEMBER CODE: " << s->getMemberCode() << std::endl; std::cout << "SIN: " << s->getSIN() << std::endl; PriceData* data = s->getPriceData()[0]; if(data != nullptr) { std::cout << "High: " << data->getHigh() << std::endl; }else{ std::cout << "No price data found" << std::endl; } }else{ std::cout << "Could not find stock!"; } }else if(in.compare("5") == 0){ // PLOT std::string name; std::cout << "Name/Member Code: "; std::cin >> name; Stock* s = searchStock(name, table_names, table_codes); //check if the stock from input is available if(s != nullptr) { //define the size of the Plotting window constexpr size_t entries = 30; constexpr size_t steps = 25; //the array/vector to put the values of the stock in it std::array arr; double max = 0; PriceData* data = nullptr; //get the max value of the chosen stock for (int i = 0; i < entries; ++i) { data = s->getPriceData()[i]; if (data != nullptr) max = std::max(max, data->getHigh()); } //write every value of the last 30 days in the correct position of the array/vector auto adjust = max / steps; for (int i = 0; i < entries; ++i) { data = s->getPriceData()[i]; arr[i] = (data != nullptr) ? data->getHigh() / adjust : 0; } // plot the graph of the stock std::cout << "\n" << std::endl; // clear new line... for (int j = steps; j > 0; j--) { for (int i = 0; i < entries; ++i) if (arr[i] >= j) std::cout << "#"; else std::cout << " "; std::cout << " " << j*adjust << std::endl; } //function to add the correct numbers of day in under my plotted graph auto plot_numbers = [&](const std::vector& in) { for (auto& i : in) std::cout << i; std::cout << std::endl; }; plot_numbers(std::vector {0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3}); plot_numbers(std::vector {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0}); }else{ std::cout << "Could not find stock!"; } }else if(in.compare("6") == 0){ // SAVE std::cout << "Saving to file..." << std::endl; table_names->saveToFile("hashtable_names.txt"); table_codes->saveToFile("hashtable_codes.txt"); std::cout << "Saved!" << std::endl; }else if(in.compare("7") == 0){ // LOAD std::cout << "Reading from file..." << std::endl; table_names->readFromFile("hashtable_names.txt"); table_codes->readFromFile("hashtable_codes.txt"); std::cout << "Finished!" << std::endl; } } std::cout << "Exiting program..." << std::endl; std::cout << "Good Bye!" << std::endl; return 0; }