eFinancialPlanner  V1.0 (proof of concept)
Personal Financial Planning based on Maslowian Portfolio Theory
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
investor.class.cpp
Go to the documentation of this file.
1 
11 class investor : public market
12 {
13 public:
15  string user_name;
16  string first_name;
17  string last_name;
18  string password;
19  string currency;
20  struct tm birth_date;
22 
23  string get_full_name();
24  float age(int Mnbr = 0);
25  int months2simulate();
26  int load_from_db(string investorID); // NOTE: no password check and does NOT load password
27 
28  //friend ostream& operator<<(ostream& os, const investor& the_investor);
29 
30 
31 protected:
32  int age2monthNbr(float theAge);
33  string dateStr2Age(string the_date);
34  bool save();
35  int get_from_db(string investorID, string password);
36  bool add_to_db(); // for new investors
37  bool exists(int iid);
38 
39  std::map<int, int> experience; // number from 1 to 5 per asset class
40  std::map<int, int> knowledge;
41  std::map<int, int> desirability;
42  std::map<int, float> max_exposure;
43  void load_preferences();
44  bool save_preferences();
45  void set_max_exposure();
46  bool set_scale(string scale_type, int ac, int val);
47 
48 
49 
55 /*this would be used if the experience etc was a vector ... but then we cannot use the simple indices :-( and have to resort to iterators
56  * investor() : experience(NBR_ASSET_CLASSES, DEFAULT_SCALE),
57  knowledge(NBR_ASSET_CLASSES, DEFAULT_SCALE),
58  desirability(NBR_ASSET_CLASSES, DEFAULT_SCALE) {}
59 */
61  {
62  int i;
63  for (i = 1; i <= NBR_ASSET_CLASSES; i++)
64  {
68  max_exposure[i] = 1;
69  }
70  experience[1] = MAX_SCALE;
71  knowledge[1] = MAX_SCALE;
72  }
73 };
74 
75 
82 /*
83 ostream& operator<<(ostream& os, const investor& the_investor)
84 {
85 
86  os << "<h4>" << "the_investor.get_full_name()" << "</h4>"
87  << "<ul>"
88  << "<li>currency: " << the_investor.currency << "</li>"
89  << "<li>birth date: " << tm2DateStr(the_investor.birth_date) << ", age:" << "to_string(the_investor.age())" << "</li>"
90  << "<li>simulate till age: " << to_string(the_investor.simulate_till_age) << "</li>"
91  << "</ul>";
92  return os;
93 }
94 */
95 
96 
102 // usage: const string& s = theInvestor.get_full_name()
103 string investor::get_full_name() {string s; s = first_name + " " + last_name; return s; }
104 
108 inline float investor::age(int Mnbr) {
109 /* time_t age_date;
110  time(&age_date); //set the age date to the current time as unix timestamp
111  //TODO: this is potentially unsafe, if time is not implemented as unix timestamp
112  age_date += Mnbr * 2629800; // 2629800 = 356.25 / 12 * 24 * 60 * 60
113  return (difftime(age_date,mktime(&birth_date)) / 2629800);*/
114 float the_age;
115 tm tmNow = get_tm();
116 the_age = tmNow.tm_year - birth_date.tm_year;
117 the_age = the_age + (tmNow.tm_mon - birth_date.tm_mon) / 12 + Mnbr / 12;
118 return the_age;
119 }
120 
125  return (int) round(ceil(simulate_till_age - this->age(0)) * 12);
126 }
127 
134 int investor::load_from_db(string uid)
135 {
136  string sSQL;
137  sSQL = "SELECT investor_id, user_name, first_name, last_name, birth_date, currency, simulate_till_age FROM " + oConfig.tbl_prefix + "_investors WHERE investor_id = " + uid + ";";
138  try{
139  sql::Driver *driver;
140  sql::Connection *con;
141  sql::Statement *stmt;
142  sql::ResultSet *res;
143  // sql::PreparedStatement *pstmt;
144  // Create a connection
145  driver = get_driver_instance();
146 // con = driver->connect("tcp://127.0.0.1:3306","efp","efp.cger");
147  con = driver->connect(oConfig.db_host,oConfig.db_user,oConfig.db_pwd);
148 // con->setSchema("efp");
149  con->setSchema(db.db);
150 
151  stmt = con->createStatement();
152  res = stmt->executeQuery(sSQL);
153  if (!(res->next()))
154  {error_message = t_errMsg["user not found"] + error_message;}
155  else
156  {
157 // res = stmt->executeQuery(sSQL);
158  res->previous();
159 
160  while (res->next())
161  {
162  investor_id = res->getInt("investor_id");
163  user_name = res->getString("user_name");
164  first_name = res->getString("first_name");
165  last_name = res->getString("last_name");
166  currency = res->getString("currency");
167  simulate_till_age = atof((res->getString("simulate_till_age")).c_str());
168  dateStr2tm(res->getString("birth_date"), &birth_date);
169  }
170  }
171  delete res;
172  delete stmt;
173  delete con;
174 } //try
175 
176  catch (sql::SQLException &e) {
177  error_message = error_message + t_errMsg["retrievingInvestor"];
178 #ifdef DEBUG
179  cout << "# ERR: SQLException in " << __FILE__;
180  cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
181  cout << "# ERR: " << e.what();
182  cout << " (MySQL error code: " << e.getErrorCode();
183  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
184  cout << "[[" << sSQL << "]]*get*";
185 #endif
186  }
187 // return EXIT_SUCCESS;
188  if (EXIT_SUCCESS == 0)
189  {return investor_id;}
190  else
191  {return 0;}
192 }
193 
200 inline int investor::age2monthNbr(float theAge)
201 {
202  return (int) round((theAge - this->age(0)) * 12);
203 }
204 
209 inline string investor::dateStr2Age(string the_date)
210 {
211 // struct tm tm_date;
212 // dateStr2tm(the_date, &tm_date);
213  int month_nbr = dateStr2Mnbr(the_date);
214  return to_string(this->age() + month_nbr / 12);
215 }
216 
221 {
222  string s;
223  s = "UPDATE " + oConfig.tbl_prefix + "_investors SET user_name = '" + user_name + "',";
224  s += " first_name = '" + first_name + "',";
225  s += " last_name = '" + last_name + "', ";
226  s += " simulate_till_age = '" + to_string(simulate_till_age) + "', ";
227  s += " birth_date = '" + tm2DateStr(birth_date) +"', ";
228  s += " currency = '" + currency +"' ";
229  s += " WHERE investor_id = " + to_string(investor_id) + ";";
230 #ifdef DEBUG
231  debug_info += "<br>" + s;
232 #endif
233  if (db.runSQL(s))
234  {
235  investor_id = load_from_db(to_string(investor_id)); // to load other infor than the investor_id
236  return true;
237  }
238  else
239  {
240  error_message = error_message + t_errMsg["errorSavingUser"];
241  return false;
242  }
243 }
244 
249 int investor::get_from_db(string uid, string password) {
250  string sSQL;
251  sSQL = "SELECT investor_id, user_name, first_name, last_name, birth_date, simulate_till_age, currency FROM " + oConfig.tbl_prefix + "_investors WHERE user_name = '" + uid + "' && AES_DECRYPT(password,'" + password + hh.c_salt + "') = '" + password + "';"; try{
252  sql::Driver *driver;
253  sql::Connection *con;
254  sql::Statement *stmt;
255  sql::ResultSet *res;
256  // sql::PreparedStatement *pstmt;
257  // Create a connection
258  driver = get_driver_instance();
259 // con = driver->connect("tcp://127.0.0.1:3306","efp","efp.cger");
260  con = driver->connect(oConfig.db_host,oConfig.db_user,oConfig.db_pwd);
261 // con->setSchema("efp");
262  con->setSchema(db.db);
263 
264  stmt = con->createStatement();
265  res = stmt->executeQuery(sSQL);
266  if (!(res->next()))
267  {error_message = t_errMsg["pwdUserCombination"] + error_message;}
268  else
269  {
270 // res = stmt->executeQuery(sSQL);
271  res->previous();
272  while (res->next())
273  {
274  investor_id = res->getInt("investor_id");
275  user_name = res->getInt("user_name");
276  first_name = res->getString("first_name");
277  last_name = res->getString("last_name");
278  currency = res->getString("currency");
279  simulate_till_age = atoi((res->getString("simulate_till_age")).c_str());
280  dateStr2tm(res->getString("birth_date"), &birth_date);
281  }
282  }
283  delete res;
284  delete stmt;
285  delete con;
286 } //try
287 
288  catch (sql::SQLException &e) {
289  error_message = error_message + t_errMsg["retrievingInvestor"];
290 #ifdef DEBUG
291  cout << "# ERR: SQLException in " << __FILE__;
292  cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
293  cout << "# ERR: " << e.what();
294  cout << " (MySQL error code: " << e.getErrorCode();
295  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
296 #endif
297  }
298 // return EXIT_SUCCESS;
299  if (EXIT_SUCCESS == 0)
300  {
301  return investor_id;}
302  else
303  {return 0;}
304 }
305 
314 {
315  string s;
316  s = "INSERT INTO " + oConfig.tbl_prefix + "_investors (user_name, first_name, last_name, password, birth_date, simulate_till_age, currency) ";
317  s += "value ('" + user_name + "', '" + first_name + "', '" + last_name + "', ";
318  s += "AES_ENCRYPT('" + password + "',CONCAT('" + password + "','" + hh.c_salt + "')),";
319  s += "'" + tm2DateStr(birth_date) +"', " + to_string(simulate_till_age) + ",'" + currency + "');";
320 #ifdef DEBUG
321  debug_info += "<br>" + s;
322 #endif
323  if (db.runSQL(s))
324  {
325  investor_id = get_from_db(user_name, password); //to set the investor_id
326  return true;
327 
328  }
329  else
330  {
331  error_message = error_message + t_errMsg["userNameTaken1"] + user_name + t_errMsg["userNameTaken2"];
332  return false;
333  }
334 }
335 
336 
337 
343 bool investor::exists(int iid)
344 {
345  string s = "SELECT investor_id FROM " + oConfig.tbl_prefix + "_investors WHERE investor_id = " + to_string(iid) + ";";
346  db.res = db.stmt->executeQuery(s);
347  if ((db.res->next()))
348  {
349  return true;
350  }
351  else
352  {
353  return false;
354  }
355 
356 }
357 
364 {
365  int i;
366  float denom, sumExp = 0;
367  denom = (MAX_SCALE + MAX_SCALE) * (MAX_SCALE - 1);
368  for (i = 1; i <= NBR_ASSET_CLASSES; i++)
369  {
370  max_exposure[i] = (experience[i] + knowledge[i]) * (desirability[i] - 1) / denom;;
371  sumExp += max_exposure[i];
372  //error_message = error_message + to_string(max_exposure[i]) + "<BR>";
373  }
374  if (max_exposure[1] < 0.6) max_exposure[1] = 0.6; // safest asset at least 60%
375  if (sumExp <= 1) max_exposure[1] = 1; // too little room --> class
376  if (sumExp <= 1.5) max_exposure[2] = max((float)0.5, (float)max_exposure[2]); // if it was smaller than 1 then also the second class is upgraded
377  if (sumExp <= 2) max_exposure[3] = max((float)0.2, (float)max_exposure[3]); // if it was smaller than 1 then also the
378 }
379 
384 {
385  int ac;
386  string s = "SELECT * FROM " + oConfig.tbl_prefix + "_preferences WHERE investor = " + to_string(this->investor_id) + ";";
387  db.res = db.stmt->executeQuery(s);
388  while (db.res->next())
389  {
390  ac = db.getInt("asset_class");
391  experience[ac] = db.getInt("experience");
392  knowledge[ac] = db.getInt("knowledge");
393  desirability[ac] = db.getInt("desirability");
394  }
396 // TODO this function will break if one would reduce the number of asset classes
397 }
398 
402 bool investor::set_scale(string scale_type, int ac, int val)
403 {
404  if (ac < 1 || ac > NBR_ASSET_CLASSES) return false;
405  if (val < MIN_SCALE) val = MIN_SCALE;
406  if (val > MAX_SCALE) val = MAX_SCALE;
407  if (scale_type == "experience") experience[ac] = val;
408  if (scale_type == "knowledge") knowledge[ac] = val;
409  if (scale_type == "desirability") desirability[ac] = val;
410  return true;
411 }
412 
417 {
418  int i;
419  string s;
420  bool success = true;
421  s = "DELETE FROM " + oConfig.tbl_prefix + "_preferences WHERE investor = " + to_string(investor_id) + ";";
422  if (db.runSQL(s)) {} else {}//{error_message = error_message + "<li>Please contact us. #errno E010</li>";}
423  s = "INSERT INTO " + oConfig.tbl_prefix + "_preferences (investor, asset_class, experience, knowledge, desirability, max_exposure) VALUES ";
424  for(i=1; i <= NBR_ASSET_CLASSES; i++)
425  {
426  if (i > 1) s = s + ", ";
427  s = s + "(" + to_string(investor_id) + ", " + to_string(i) + ", " + to_string(experience[i]) + ", "
428  + to_string(knowledge[i]) + ", " + to_string(desirability[i]) + ", " +
429  to_string(max_exposure[i]) + ")";
430  }
431  s = s + ";";
432  //error_message = error_message + "<br>" + s;
433  if (db.runSQL(s)) {}
434  else
435  {
436  error_message = error_message + "<li>Please contact us. #errno E011</li>";
437  success = false;
438  }
439  //cout << s;
440  return success;
441 }
string get_full_name()
const string db_host
Database.
string dateStr2Age(string the_date)
struct tm birth_date
std::map< int, int > desirability
string currency
the default currency for that customer
float age(int Mnbr=0)
sql::ResultSet * res
const string db_user
const string c_salt
int getInt(string s)
sql::Statement * stmt
std::map< int, int > knowledge
bool add_to_db()
#define NBR_ASSET_CLASSES
the nunmber of asset classes (not dynamically updated!)
Definition: efp.cpp:97
string error_message
global message variables
Definition: efp.cpp:132
float simulate_till_age
int age2monthNbr(float theAge)
string password
const string tbl_prefix
tables start with "" + oConfig.tbl_prefix + "_" if the prefix is eg. "tbl" then we have "tbl_invesotr...
tm get_tm(int monthNbr=0)
global functions
string tm2DateStr(tm tmDate)
void set_max_exposure()
sets the max_exposure vector based on the experience, knowledge and desirability
string last_name
std::map< int, int > experience
html_helper hh
own c++ classes
Definition: efp.cpp:180
#define MIN_SCALE
the minimum of the scale (1) (on a scale from 1 to 5)
Definition: efp.cpp:91
bool runSQL(string s)
string user_name
db_helper db
Definition: efp.cpp:183
bool save_preferences()
sets the experience, knowledge and desirability vectors
int get_from_db(string investorID, string password)
bool set_scale(string scale_type, int ac, int val)
int dateStr2Mnbr(string dStr)
string first_name
std::map< int, float > max_exposure
the maximum exposure per asset class
unordered_map< string, string > t_errMsg
Definition: texts_Eng_UK.h:86
void dateStr2tm(string dStr, tm *target_tm)
const string db_pwd
void load_preferences()
sets the experience, knowledge and desirability vectors
config oConfig
mysql connection mysql connector from dev.mysql.com
Definition: efp.cpp:149
int load_from_db(string investorID)
bool exists(int iid)
#define MAX_SCALE
the maximum value for the scale (5) (on a scale from 1 to 5)
Definition: efp.cpp:90
#define DEFAULT_SCALE
the default value to use for preferences (on a scale from 1 to 5)
Definition: efp.cpp:89
int months2simulate()