=================================================== STOCK.H ========================================================
#ifndef HASHTABLE_STOCK_H
#define HASHTABLE_STOCK_H
#include <iostream>
#include <vector>
/**
* 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 <fstream>
#include <sstream>
#include <cstring>
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 <string.h>
#include <math.h>
#include <fstream>
#include <sstream>
#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 <iostream>
#include <sstream>
#include <array>
#include <iomanip>
#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<int, entries> 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<int>& in) {
for (auto& i : in) std::cout << i;
std::cout << std::endl;
};
plot_numbers(std::vector <int>{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 <int>{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;
}
Comments