eFinancialPlanner  V1.0 (proof of concept)
Personal Financial Planning based on Maslowian Portfolio Theory
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
investment_problem.class.cpp
Go to the documentation of this file.
1 
15 class investment_problem : public investor, public portfolio
16 {
17 public:
18 //inherited: int investor_id;
20  void solve();
21  int get_nbr_goals();
22  std::map<int, aGOAL> goalZ;
24  void javaGraph(int g,string xtra_var = "", string xtra_label = "", int followup_mnth = 0);
25  void prepare_javaVars_colors(int g, int followup_mnth);
26  void parse_javaGraph(int g, string xtra_var = "", string xtra_label = "");
27 
28 protected:
29  std::map<int, portfolio> portfolios;
30  void set_followup_color_prae(float Vlow, float Vmed, float Vhigh, int g);
31  void set_followup_color_post(float V, int g);
32 
33 private:
34 
35  std::map<int, float> means;
36  std::map<int, float> means_left;
37  std::map<int, float> means_used;
38  std::map<int, float> means_block;
39  std::map<int, float> means_tmp;
40 
42  //inherited: age; // the age of the investor TODAY
43  int nbr_goals;
44  int nbr_assets = 0;
45  int nbr_cfs;
46 
47  void set_assets();
48  void set_cfs();
49  void set_goals();
50  void set_means_goal(int g);
51  void expand_cf(float amount, string freq = "M", string fromStr="", string tillStr="", int goal_nbr = 0);
52  void set_portfolios();
53  float get_optimal_portfolio(int g);
54  float calc_alpha(int priority, int monthNbr);
55  void set_priorityLimits();
56  float goal_seek_means(int g, int p);
57  void goal_seek_tmp_means(float *perc, int g, int p);
58  float calc_risk(int g,int p) ;
59  float calc_V_high(int g, int p = 0);
60  void set_goal_color(int g, float opt_perc);
61  void set_goal_remarks(int g);
62  void allocate_to_unallocated_goal(int unallocated_goal_nbr);
63  int get_portfolio_safest();
65  bool set_unallocated_goal();
66  //bool* portfolio_suitable = NULL;
67  std::map<int, bool> portfolio_suitable;
68 
69 
70 // float get_risk(const char* riskFunction, int theGoal, int thePortfolio);
71 // float ExpectedShortfall_normDist(int theGoal, int thePortfolio);
74  /*
75  std::map<int, asset> assets; // set of asset_objects
76  std::map<int, cf> cfs; // set of CF-objects
77  std::map<int, goal> goals; // set of goal-objects
78 */
79 
80 };
81 
86  // : market(investor) ///< note: parent class constructur in the initializer list in order to pass the parameter
87 {
88  if (load_from_db(to_string(investor)) <= 0 ) { /*TODO : errorhandling*/ }
90  for (int i=0; i <= months2simulate(); i++)
91  {
92  means.insert (std::pair<int,float>(i, 0.0) );
93  means_left.insert (std::pair<int,float>(i, 0.0) );
94  means_used.insert (std::pair<int,float>(i, 0.0) );
95  means_block.insert(std::pair<int,float>(i, 0.0) );
96  means_tmp.insert (std::pair<int,float>(i, 0.0) );
97  } // initialize means ...
99  set_assets(); // adds assets to means[]
100  set_cfs(); // adds cash flows to means[]
101 
102  set_goals(); // adds goals to goalZ[] in the right order(!)
103 
105  //market(investor_id); ///< re-execute the constructor with the right user-id now ... DOES NOT WORK (changes investor_id into a pointer to market)
108  set_portfolios(); // sets nbr_portfolios, the map portfolios and the portfolio_suitable map (executes set_mu() and set_sigma, using the ER van covar)
109 
111  if (nbr_goals == 0) {error_message = error_message + t_errMsg["no_goals"];}
112  if (nbr_assets + nbr_cfs == 0) {error_message = error_message + t_errMsg["no_assets"];}
113 
114 }
115 
123 {
124  string s, the_curr = "";
125  float theSum = 0;
126  cls_currency oCurr;
127  s = "SELECT amount, currency FROM " + oConfig.tbl_prefix + "_assets WHERE investor = " + std::to_string(investor_id) + ";";
128 
129  db.res = db.stmt->executeQuery(s);
130  while (db.res->next())
131  {
132  the_curr = db.res->getString("currency");
133  if (oCurr.set_curr(the_curr))
134  {
135  theSum += oCurr.to_curr(db.getFloat("amount"), this->currency);
136  //theSum += db.getFloat("amount");
137  nbr_assets++;
138  }
139  else
140  {
141  error_message = error_message + "<li> ERRN3400: invalid currency</li>";
142  theSum += db.getFloat("amount");
143  }
144 // cout << " || the " << nbr_assets << " first assets are " << theSum << this->currency << " worth. XDB<BR>";
145  }
146 // cout << "<BR>the number of assets=" << nbr_assets;
147  this->means.at(0) = theSum;
148  }
149 
155  void investment_problem::expand_cf(float amount, string freq, string fromStr, string tillStr, int goal_nbr)
156  {
157  int m, step;
158  int startMnth;
159  int endMnth = this->months2simulate();
160  struct tm tm1; struct tm tm2;
161  if (freq == "M") step = 1;
162  else if (freq == "A") step = 12;
163  else if (freq == "Q") step = 3;
164  else if (freq == "S") step = 6;
165  else if (freq == "W")
166  {
167  amount *= 30.4375/7; // note: 30.4375 = 365.25/
168  step = 1;
169  }
170  else if (freq == "D")
171  {
172  amount *= 30.4375; // note: 30.4375 = 365.25/
173  step = 1;
174  }
175  else step = 1;
176  tm1 = get_tm();
177  dateStr2tm(fromStr, &tm2);
178  if (is_valid_dateStr(fromStr) && (difftime(mktime(&tm1), mktime(&tm2)) < 0)) {startMnth = dateStr2Mnbr(fromStr);} else {startMnth = 0;}
179  if (is_valid_dateStr(tillStr)) {endMnth = dateStr2Mnbr(tillStr);} else {endMnth = this->months2simulate();}
180  m = startMnth;
181  while (m <= endMnth && m <= this->months2simulate()) //just in case endMnth > months2simulate
182  {
183  if (goal_nbr == 0)
184  {
185  means.at(m) += amount;
186  }
187  else
188  {
189  goalZ[goal_nbr].means_goal.at(m) += amount;
190  }
191  m += step;
192  }
193 // cout << "<BR>expand_cf: from=" << startMnth << " | to_m=" << m << " | add_to_means=" << add_to_means<< " | step=" << step;
194  }
195 
203  {
204  string s = "", d1, d2, the_curr;
205  float amnt;
206  cls_currency oCurr;
207  s = "SELECT * FROM " + oConfig.tbl_prefix + "_cash_flows WHERE investor = " + std::to_string(this->investor_id) + ";";
208  db.res = db.stmt->executeQuery(s);
209  while (db.res->next())
210  {
211  d1 = db.res->getString("from_date");
212  d2 = db.res->getString("till_date");
213  the_curr = db.res->getString("currency");
214  oCurr.set_curr(the_curr);
215  amnt = oCurr.to_curr(atof(db.res->getString("amount").c_str()), this->currency);
216 
217  expand_cf(amnt, db.res->getString("frequency").c_str(), d1, d2);
218  nbr_cfs++; // increment the number of cash flows so that at the end this reflects the number of cash flows
219  }
220 }
221 
226 {
227  string s = "";
228  int nbr = 0;
229  s = "SELECT * FROM " + oConfig.tbl_prefix + "_goals WHERE investor = " + to_string(this->investor_id) + " ORDER BY priority ASC;";
230  this->set_priorityLimits();
231  db.res = db.stmt->executeQuery(s);
232 #ifdef DEBUG
233  debug_info = debug_info + "<BR>goal_type_s2i[\"amount@date\"] = " + to_string(goal_type_s2i["amount@date"]);
234  debug_info = debug_info + "<BR>goal_type_s2i[\"income from/to\"] = " + to_string(goal_type_s2i["income from/to"]);
235 #endif
236  while (db.res->next())
237  {
238  nbr++;
239 // this->goalZ[nbr] = aGOAL(investor_id); //create new and run constructor
240  this->goalZ.insert(pair<int, aGOAL>(nbr, aGOAL(investor_id)));
241  this->goalZ[nbr].set_from_db();
242 #ifdef DEBUG
243  debug_info = debug_info + "<BR>---goal: " + to_string(nbr);
244  debug_info = debug_info + "<BR>goal_type = " + to_string(goalZ[nbr].goal_type);
245 #endif
246 
247 //cout << "<br>g=" << to_string(nbr) << " amount=" << goalZ[nbr].amount;
248  //GOAL_TYPES: (4, "amount asap"),
250  if (goalZ[nbr].goal_type == goal_type_s2i["unallocated"]) //(0, "unallocated"),
251  {
252  goalZ[nbr].realization_monthNbr = months2simulate();
253  goalZ[nbr].target_amount = 0;
254  }
255  else if (goalZ[nbr].goal_type == goal_type_s2i["amount@date"]) //(1, "amount@date")
256  {
257  goalZ[nbr].realization_monthNbr = age2monthNbr(goalZ[nbr].realization_age);
258  goalZ[nbr].target_amount = goalZ[nbr].amount;
259  }
260  else if (goalZ[nbr].goal_type == goal_type_s2i["income from/to"]) // (2, "income from/to")
261  {
262  goalZ[nbr].realization_monthNbr = dateStr2Mnbr(goalZ[nbr].till_date);
263  goalZ[nbr].target_amount = 0;
264 // debug_info = debug_info + "<BR>goalZ[nbr].realization_monthNbr" + to_string(goalZ[nbr].realization_monthNbr);
265 // debug_info = debug_info + "<BR>goalZ[nbr].target_amount" + to_string(goalZ[nbr].target_amount);
266  }
267  else if (goalZ[nbr].goal_type == goal_type_s2i["rainy day savings"]) // (3, "rainy day savings")
268  {
269  goalZ[nbr].realization_monthNbr = RAINY_DAY_MONTH_NBR;
270  goalZ[nbr].target_amount = goalZ[nbr].amount;
271  }
272  else if (goalZ[nbr].goal_type == goal_type_s2i["amount asap"]) // (4, "amount asap")
273  {
274  goalZ[nbr].realization_monthNbr = months2simulate();
275  goalZ[nbr].target_amount = goalZ[nbr].amount;
276  }
277  else // assume that it is an amount@date type of goal
278  {
279  goalZ[nbr].realization_monthNbr = age2monthNbr(goalZ[nbr].realization_age);
280  goalZ[nbr].target_amount = goalZ[nbr].amount;
281  }
282  this->goalZ[nbr].alpha = calc_alpha(this->goalZ[nbr].priority, this->goalZ[nbr].realization_monthNbr);
283  // cout << "<br>goalZ[" << nbr<<"].alpha = " << goalZ[nbr].alpha;
284 
285  set_means_goal(nbr);
286 
289  if ( goalZ[nbr].realization_monthNbr > months2simulate()) goalZ[nbr].realization_monthNbr = months2simulate();
290  }
291  this->nbr_goals = nbr;
292 }
293 
294 
301 {
302  string s = "";
303  s = "SELECT MIN(priority) as theMin, MAX(priority) as theMax FROM " + oConfig.tbl_prefix + "_goals WHERE investor = " + to_string(this->investor_id) + " AND goal_type != " + to_string(goal_type_s2i["unallocated"]) + ";";
304  db.res = db.stmt->executeQuery(s);
305  while (db.res->next())
306  {
307  this->priorityMax = atoi(db.res->getString("theMax").c_str());
308  this->priorityMin = atoi(db.res->getString("theMin").c_str());
309  }
310 }
311 
312 
318 inline float investment_problem::calc_alpha(int priority, int monthNbr)
319 {
320  float x;
321  if (priorityMin != priorityMax)
322  {
324  }
325  else
326  {
327  x = 0.01;
328  }
329 //xx cout << "[" << x;
330  if (x < ALPHA_UPPER_LIMIT) x += (ALPHA_UPPER_LIMIT - x) * (1 - exp(- monthNbr / 12 / 35));
331 //xx cout << " --> " << x ;
332  if (x > ALPHA_LOWER_LIMIT) x -= (x - ALPHA_LOWER_LIMIT) * exp(- monthNbr / 12 / 5);
333 //xx cout << " --> " << x << "]" ;
334  return x;
335 }
336 
337 
342 {
343  int nbr = 0, count = 0, p, ac;
344  bool is_suitable;
345  string s = "SELECT portfolio_id FROM " + oConfig.tbl_prefix + "_portfolios ORDER BY portfolio_id;";
346  db.res = db.stmt->executeQuery(s);
347  while (db.res->next())
348  {
349  nbr = db.res->getInt("portfolio_id");
350  if (this->portfolios[nbr].get_portf_from_db(nbr)) //success retrieving info
351  {
352  this->portfolios[nbr].set_mu(this->assetClass_mu); //sets pMu
353  this->portfolios[nbr].set_sigma(this->assetClass_covar); // sets pSigma
354  //xxx cout << "<br>portf[" << nbr << "] ER=" << exp(12 * portfolios[nbr].pMu) - 1 << " S=" << sqrt(12) * portfolios[nbr].pSigma;
355  count++;
356  }
357  }
359 /* not needed any more because portfolio_suitable is a C++ map now and not a C array any longer
360  bool* new_block = NULL;
361  new_block = (bool*) realloc(portfolio_suitable, nbr_portfolios * sizeof(bool));
362  if (new_block != NULL)
363  {
364  portfolio_suitable = new_block;
365  }
366  else
367  {
368  free(portfolio_suitable);
369 #ifdef DEBUG
370  debug_info = debug_info + "<br/>realloc() failed in portfolio_suitable()";
371 #endif
372  }
373  */
374 
375  // set the number of portfolios (note: already used in the next lines!)
376  this->nbr_portfolios = count;
377 
378  // now set the portfolio_suitable map
379  load_preferences(); // to set the map set_max_exposure (inherited from the investor class)
380  for (p =1; p <= nbr_portfolios; p++)
381  {
382  is_suitable = true;
383  for (ac = 1; ac <= NBR_ASSET_CLASSES; ac++)
384  {
385  //(portfolios[p].weights[ac-1] <= max_exposure[ac])?portfolio_suitable[p-1] = true : portfolio_suitable[p-1] = false;
386  if (portfolios[p].weights[ac-1] > max_exposure[ac]) is_suitable = false;
387  }
388  portfolio_suitable[p] = is_suitable;
389  }
390 
391 }
392 
397 {
398  int g = 1,m, k, freeFrom, unallocated_goal_nbr = 0;
399  float opt_perc, amnt_used, currency_conversion;
400  cls_currency g_currency;
401 
403  //cout << " ### months2simulate=" << to_string(months2simulate());
404  //cout << " ### goalZ[g].realization_monthNbr=" << to_string(goalZ[g].realization_monthNbr);
405 
406 
407  for(m=0;m<=goalZ[g].realization_monthNbr;m++)
408  {
409  means_left.at(m) = means.at(m);
410  //cout << " | means.at(" << m << ")=" << means.at(m);
411  }
412 
413  for (g = 1; g <= this->nbr_goals; g++)
414  {
415 
416  /*
417  //TODO: prepare covar, E_R and eventually portfolios for the relevant goal-currency
418  set_mu(goalZ[g].currency);
419  set_covar(goalZ[g].currency);
420  set_portfolios(goalZ[g].currency);
421  */
422 
423  // convert all relevant means_left to the goal-currency
424  g_currency.set_curr(this->currency);
425  currency_conversion = g_currency.to_curr(1.0, goalZ[g].currency);
426  if (currency_conversion != 0)
427  {
428  for(m=0;m<=goalZ[g].realization_monthNbr;m++)
429  {
430  means_left.at(m) = means_left.at(m) * currency_conversion;
431  }
432  }
433  else
434  { // if the currency_conversion equals zero, then we convert it to one (to avoid dividing by 0 later)
435  currency_conversion = 1;
436  }
437 
438  if (goalZ[g].goal_type == goal_type_s2i["unallocated"])
439  {
440  unallocated_goal_nbr = g;
441  continue;
442  }
443  freeFrom = get_max_month_for_lower_goals(g);
444 
445 
446 /* TODO: refine the allocation for from/to goals
447  if (goalZ[g].goal_type == goal_type_s2i["income from/to"]
448  {
450 
452  }
453  */
455  for(m=0; m<=goalZ[g].realization_monthNbr; m++)
456  {
457  means_used[m] = 0;
458  }
459 
460 
461 //xx set_means_goal(g);/// calculate the means that are implied by the goal (eg as income "from/till"
463  if ((goalZ[g].goal_type == goal_type_s2i["amount asap"]) || (goalZ[g].goal_type == goal_type_s2i["rainy day savings"]))
464  {
465  //for (k = 0; k < months2simulate(); k++) means_block[k] = 0;
466  k = 0;
467 
468  do
469  {
470  means_block[k] = means_left[k];
471  goalZ[g].realization_monthNbr = k;
472  if (k > 0)
473  {
474  means_used[k-1] = means_block[k-1];
475  means_block[k-1] = 0;
476  }
477  opt_perc = get_optimal_portfolio(g);
478  } while ((opt_perc > 1 - PRECISSION) && (k < months2simulate()) );
479 
480 /*
481  means_block[0] = means_left[0];
482  goalZ[g].realization_monthNbr = 0;
483  opt_perc = get_optimal_portfolio(g);
484  for (k = 1; (k < months2simulate()) && (opt_perc > 1 - PRECISSION); k++) //realization_monthNbr = months2simulate()-1
485  {
486  goalZ[g].realization_monthNbr = k;
487  means_used[k-1] = means_block[k-1];
488  means_block[k-1] = 0;
489  means_block[k] = means_left[k];
490  opt_perc = get_optimal_portfolio(g);
491  }
492 */
493  }
494  else
495  {
496  for (k = freeFrom; k <= goalZ[g].realization_monthNbr; k++) means_block[k] = means_left[k];
497  opt_perc = get_optimal_portfolio(g);
498 
499  if (opt_perc > 1 - PRECISSION)
500  {
502  //means_used = means_block since we're only here if opt_perc == 1
503  for (k = freeFrom; k <= goalZ[g].realization_monthNbr; k++)
504  {
505  means_used[k] = means_block[k];
506  means_block[k] = 0;
507  }
508  for (k = 0; k < freeFrom;k++) means_block[k] = means_left[k];
509  //xx cout << "<br>===[GOAL " << g << "]====<br>";
510  opt_perc = get_optimal_portfolio(g);
511  //xx cout << "<br>===[end]===<br>";
512  }
513  }
514 
515 
517  for (k = 0; k <= goalZ[g].realization_monthNbr; k++)
518  {
519  amnt_used = means_used[k] + (means_block[k] * opt_perc);
520  // if(amnt_used > 0)
521  // {
522  means_left[k] = (means_left[k] - amnt_used) / currency_conversion;
523  goalZ[g].saving_plan[k] = amnt_used;
524 
525  // }
526  }
528  for (k = 1; k <= NBR_ASSET_CLASSES; k++)
529  {
530  goalZ[g].benchmark[k] = portfolios[goalZ[g].optimal_portf].weights[k-1];
531  }
532  set_goal_color(g, opt_perc);
533  set_goal_remarks(g);
534 
535  //goalZ.save_results(); //TODO
536  } //(g = 1; g <= this->nbr_goals; g++)
537 
539  allocate_to_unallocated_goal(unallocated_goal_nbr);
540 }
541 
542 
546 void investment_problem::set_goal_color(int g, float opt_perc)
547 {
548 if (opt_perc < 1 - PRECISSION)
549  {
550  goalZ[g].success = true;
552  if (flSum(&means_left, goalZ[g].realization_monthNbr) > 0.1 * flSum(&goalZ[g].saving_plan, goalZ[g].realization_monthNbr))
553  {
554  goalZ[g].remarks = t_feedback["brightgreen"];
555  goalZ[g].color = "brightgreen";
556  }
557  else
558  {
559  goalZ[g].remarks = t_feedback["green"];
560  goalZ[g].color = "green";
561  }
562  }
563  else // opt_perc = 1
564  {
565  goalZ[g].success = false;
566  //cout << "<br>flSum(&goalZ["<<g<<"].saving_plan, goalZ[g].realization_monthNbr)="<<flSum(&goalZ[g].saving_plan, goalZ[g].realization_monthNbr);
567  if (flSum(&goalZ[g].saving_plan, goalZ[g].realization_monthNbr) > 0)
568  {
569  goalZ[g].remarks = t_feedback["red"];
570  goalZ[g].color = "red";
571  }
572  else
573  {
574  goalZ[g].remarks = t_feedback["darkred"];
575  goalZ[g].color = "darkred";
576  }
577  if (calc_V_high(g) >= goalZ[g].amount - goalZ[g].max_shortfall)
578  {
579  goalZ[g].remarks = t_feedback["amber"];
580  goalZ[g].color = "amber";
581  }
582  }
583 }
584 
589 {
590  goalZ[g].remarks = "<u>" + goalZ[g].remarks + "</u>"
591  + "<br>The portoflio corresponding to this benchmark is called " + portfolios[goalZ[g].optimal_portf].description + "."
592  + "<br>The shortfall of this portfolio with the given savings plan is estimated to be "
593  + curr_format(goalZ[g].realized_shortfall, currency) + " with a probability of "
594  + to_string((int)((1-goalZ[g].alpha)*10000)/100) + "%."
595  + "<br>The sum of all savings (not discounted) is " +
596  curr_format(flSum(&goalZ[g].saving_plan, goalZ[g].realization_monthNbr), currency) + ".";
597 }
598 
605 {
606  int k, optimal_portf;
607  if (unallocated_goal_nbr == 0) // if it was not encountered above, then create it
608  {
609  unallocated_goal_nbr = ++nbr_goals;
610  this->goalZ.insert(pair<int, aGOAL>(nbr_goals, aGOAL(investor_id)));
611  goalZ[nbr_goals].description = "Unallocated Resources";
612  }
613 
614  if (set_unallocated_goal())
615  {
616  // set the saving_plan:
617  for (k = 0; k <= months2simulate(); k++)
618 //x.x.x for (k = 1; k <= 10; k++)
619  {
620  goalZ[unallocated_goal_nbr].saving_plan[k] = means_left[k];
621  }
622  // set the optimal portfolio
623  optimal_portf = get_portfolio_riskiest();
624 
625  // set optimal_portf and alpha
626  goalZ[unallocated_goal_nbr].optimal_portf = optimal_portf;
627  goalZ[unallocated_goal_nbr].alpha = (MAX_ALPHA + MIN_ALPHA) / 2;
628 
629  // set the benchmark
630  for (k = 1; k <= NBR_ASSET_CLASSES; k++)
631  {
632  goalZ[unallocated_goal_nbr].benchmark[k] = portfolios[optimal_portf].weights[k-1];
633  }
634  //set color and comments
635  goalZ[unallocated_goal_nbr].remarks = goalZ[unallocated_goal_nbr].remarks + "This is not really a &quot;goal&quot."
636  + "This is simply all the assets that are not or cannot be used by other goals.<br>"
637  + "The non-discounted sum of this savings is: "
638  + curr_format(flSum(&goalZ[unallocated_goal_nbr].saving_plan, months2simulate()), currency) ;
639  goalZ[unallocated_goal_nbr].color = "brightgreen";
640  }
641  else
642  {
643  error_message = error_message + "<li>Failed to create the unallocated goal, so after all the goals mentioned here, some means might be left</li>";
644  }
645 }
646 
655 {
656  int m;
657  // for ...: goalZ[g].means_goal.insert (std::pair<int,float>(i, 0.0) );
658  for (m = 0; m <= goalZ[g].realization_monthNbr; m++) goalZ[g].means_goal[m] = 0;
659  if (goalZ[g].goal_type == goal_type_s2i["income from/to"]) // only for "income from/till"
660  {
662  expand_cf(goalZ[g].amount, goalZ[g].frequency, goalZ[g].from_date, goalZ[g].till_date, g);
663  }
668 }
669 
670 
678 {
679  int p, optimal_portf = 0;
680  float opt_perc = 1; // initalize to one to make sure it is replaced
681  float* perc_bloc_used = NULL;
682  float* new_block = NULL;
683  new_block = (float*) realloc(perc_bloc_used, nbr_portfolios * sizeof(float));
684  if (new_block != NULL)
685  {
686  perc_bloc_used = new_block;
687  }
688  else
689  {
690  free(perc_bloc_used);
691 #ifdef DEBUG
692  debug_info = debug_info + "<br/>realloc() failed in get_optimal_portfolio()";
693 #endif
694  return false;
695  }
696 
698  for (p =1; p <= nbr_portfolios; p++)
699  {
700  // do this only for suitable portfolios
701  if (portfolio_suitable[p])
702  {
703  perc_bloc_used[p-1] = goal_seek_means(g, p);
704  }
705  else
706  {
707  perc_bloc_used[p-1] = opt_perc + 1; // in order to exclude this portfolio automatically in the next lines
708  }
709  }
710 
712  for (p =1; p <= nbr_portfolios; p++)
713  {
714 //xx cout << "<br>portf="<<p<<" , opt_perc: " << opt_perc << " | perc_bloc_used[" << p-1 << "] :" << perc_bloc_used[p-1];
715  if (perc_bloc_used[p-1] <= opt_perc)
716  {
717  opt_perc = perc_bloc_used[p-1];
718  optimal_portf = p;
719  }
720  }
721 if (goalZ[g].realization_monthNbr <= MAX_MONTHS_TO_SAFEST)
722 {
723  goalZ[g].optimal_portf = get_portfolio_safest();
724 }
725 else
726 {
727  goalZ[g].optimal_portf = optimal_portf;
728 }
729 
730 //cout << "<br>g="<<to_string(g)<< " optimal_portf="<<to_string(goalZ[g].optimal_portf);
731 
732 goalZ[g].realized_shortfall = calc_risk(g, optimal_portf);
733 return opt_perc;
734 }
735 
746  int g,
747  int p
748  )
749 {
750  int m;
751  float perc = 0.5; // the perecentage used of this block
752 
754  for(m = 0; m <= goalZ[g].realization_monthNbr; m++) means_tmp[m] = 0;
755  if ((calc_risk(g, p) <= goalZ[g].max_shortfall) || (goalZ[g].realization_monthNbr < 0))
756  {
757  return 0.0;
758  }
759 
761  for(m= 0; m<=goalZ[g].realization_monthNbr; m++) means_tmp[m] = means_block[m];
762  if (calc_risk(g, p) >= goalZ[g].max_shortfall)
763  {
764  return 1.0;
765  }
766 
768 
770 
771 //xx for(m=0;m<=goalZ[g].realization_monthNbr;m++) means_tmp[m] = perc * means_block[m];
772  goal_seek_tmp_means(&perc, g, p);
773  return perc;
774 }
775 
779 inline void investment_problem::goal_seek_tmp_means(float *perc, int g, int p)
780 {
781  int k, m;
782  for (k = 2; k <= NBR_ITERATIONS; k++)
783  {
784  if ((goalZ[g].goal_type == goal_type_s2i["amount asap"]) || (goalZ[g].goal_type == goal_type_s2i["rainy day savings"]))
785  {
786  means_tmp[goalZ[g].realization_monthNbr] = (*perc) * means_block[goalZ[g].realization_monthNbr];
787  }
788  else
789  {
790  for(m = 0; m <= goalZ[g].realization_monthNbr; m++) means_tmp[m] = (*perc) * means_block[m];
791  }
792 // for(m=1;m<=goalZ[g].realization_monthNbr;m++) cout << " ["<< m << "]" << means_tmp[m];
793 // cout << "<BR>perc=" << to_string(*perc) << " | calc_risk(g, p)=" << to_string(calc_risk(g, p)) << " | goalZ[g].max_shortfall" << to_string(goalZ[g].max_shortfall);
794  if (calc_risk(g, p) > goalZ[g].max_shortfall)
795  {*perc += pow(2,-k);}
796  else
797  {*perc -= pow(2,-k);}
798  }
799 }
800 
801 
810  int g,
811  int p
812  )
813 {
814  float V_min,
815  V,
816  delta,
817  s = 0,
818  mnt_avg = 0;
819  float const my_errf = erfinv(2 * goalZ[g].alpha - 1);
820  int m;
821 
822  V_min = V = delta = means_used[0] + means_tmp[0] - goalZ[g].means_goal[0];
823  s = portfolios[p].pSigma;
824  for (m = 1; m <= goalZ[g].realization_monthNbr; m++)
825  {
826  delta = means_used[m] + means_tmp[m] - goalZ[g].means_goal[m];
827  mnt_avg++;
828  if (abs(V) + abs(delta) != 0)
829  {
830  mnt_avg = (abs(V) * (mnt_avg) + abs(delta) * 1) / (abs(V) + abs(delta));
831  }
832  V = V * exp(portfolios[p].pLogR + pow(s, 2) / 2) + delta;
833  V_min = V_min * exp(portfolios[p].pLogR +sqrt(2) * s * (sqrt(mnt_avg) - sqrt(mnt_avg-1)) * my_errf) + delta;
834  }
835 
836 if (oConfig.riskFunction == "VaR") {return (goalZ[g].target_amount - V_min);}
837 else {return (goalZ[g].target_amount - V_min);}
838 }
839 
840 
841 /* =====not used any more ========
842  * turns the relevant risk measure for given goal and portfolio for means_block
843  *
844  * riskFunction = the risk function to use : ES_normdist
845  */
846 /*
847 inline float investment_problem::get_risk(const char* riskFunction, int theGoal, int thePortfolio)
848 {
849  if (strcmp(riskFunction,"ES_normdist") == 0) return ExpectedShortfall_normDist(theGoal, thePortfolio);
850  //else if (
851  else return 0;
852 }
853 */
854 /*float portfolio::get_risk(
855  float alpha, //!< the confidence level (small)
856  float (*riskFunction)(float alpha, float (*AssetClass_mu), float (*AssetClass_varCov)), //!< pointer to the risk function to use
857  float (*AssetClass_mu), ///< pointer to the array of E[R] of the asset classes
858  float (*AssetClass_varCov)) ///< pointer to the two dimensional array of sigma[n][m]
859 {
860  return (*riskFunction) (alpha, AssetClass_mu, AssetClass_varCov);
861 }
862 */
863 
864 /* TODO: improve the previous as follows:
865  * td::function<bool()> my_fun;
866 
867 if (condition1)
868  my_fun = std::bind(&MyClass::function_one, my_class);
869 else if (condition2)
870  my_fun = std::bind(&MyClass::function_two, my_class, a, b);
871 else if (condition3)
872  my_fun = std::bind(&MyClass::function_three, my_class, a, b, c);
873 else if (condition4)
874  my_fun = std::bind(&MyClass::function_four, my_class, a, b, c, d);
875 
876 while (my_fun())
877 { ... }
878 */
879 
880 /* OR:
881  * or the sake of interest, there's also a simple lo-tech solution from the C world that as far as it goes, works in C++. Instead of allowing arbitrary parameters, define the function as void (*func)(void*), and make "params" void*. It's then the caller's job to define some struct that will contain the parameters, and manage its lifecycle. Usually the caller would also write a simple wrapper to the function that's really needed to be called:
882 
883 void myfunc(int, float); // defined elsewhere
884 
885 typedef struct {
886  int foo;
887  float bar;
888 } myfunc_params;
889 
890 void myfunc_wrapper(void *userdata) {
891  myfunc_params *params = (myfunc_params *)p;
892  myfunc(p->foo, p->bar);
893 }
894 
895 int main() {
896  myfunc_params x = {1, 2};
897  AddTimer(23, 5, myfunc_wrapper, &x);
898  sleep(23*5 + 1);
899 }*/
900 
901 /* ==============[not used any more]===========
902  * returns the expected shortfall for the GAUSSIAN distribution for given alpha using
903  *
904  * ES = mu + a sigma
905  *
906  * with
907  *
908  * a = (1/alpha sqrt(2 Pi) exp {-[errfinv(2 alpha -1)]^2})
909  */
910 /*
911 float investment_problem::ExpectedShortfall_normDist(int theGoal, int thePortfolio)
912 {
913  int k = 1;
914  float EV, Sigma, a;
915  EV = means_block[k] + means_used[k];
916  Sigma = portfolios[thePortfolio].pSigma * EV;
917  while (k <= this->goalZ[theGoal].realization_monthNbr)
918  {
919  EV = EV * (1 + portfolios[thePortfolio].pMu) + means_block[k] + means_used[k];
920  Sigma = sqrt( 2 * Sigma * Sigma + pow((means_block[k] + means_used[k]) * portfolios[thePortfolio].pSigma, 2));
921  k++;
922  }
923 
924  // calculate a:
925  a = fast_erfinv(2 * goalZ[theGoal].alpha - 1);
926  a = exp(- pow(a,2));
927  a = (1 / (2 * goalZ[theGoal].alpha * pow(Pi,0.5))) * a;
928 
929  return (- EV + a * Sigma);
930 }
931 */
932 
937 {
938  return nbr_goals;
939 }
940 
946 {
947  int k, max_month = 0;
948  if (g < nbr_goals)
949  {
950  for (k = g + 1; k <= this->nbr_goals; k++)
951  {
953  if (goalZ[k].goal_type != 0 && goalZ[k].realization_monthNbr > max_month) {max_month = goalZ[k].realization_monthNbr;}
954  }
955  }
956  return max_month;
957 }
958 
970 void investment_problem::prepare_javaVars_colors(int g, int followup_mnth)
971 {
972  int k;
973  string s1, s2, s3, s4, comma;
974  float Vlow, Vhigh, Vmed, Vexp, Vexp_evol,
975  sigma, the_diff, age_now = age(0), age_at_cutoff, diff_cum, erf_low, erf_high, erf_med, age_at_k,
976  mnt_avg = 0,
977  mnth_max = (goal_type_i2s[goalZ[g].goal_type] == "rainy day savings") ? months2simulate() : goalZ[g].realization_monthNbr;
978  int p = goalZ[g].optimal_portf;
979  s1 = s2 = s3 = s4 = "";
980  sigma = portfolios[p].pSigma ;
981  erf_low = erfinv(2 * goalZ[g].alpha - 1);
982  erf_high = erfinv(2 * (1-goalZ[g].alpha) - 1);
983  erf_med = erfinv(0);
984  set_means_goal(g);
985 
986  if (followup_mnth == 0)
987  { // in this case we are making a feedback or a Simulation, thus the tricolor graph starts from month 0, independent from the simulation
988  Vlow = Vhigh = Vmed = diff_cum = Vexp = goalZ[g].saving_plan[0] - goalZ[g].means_goal[0];
989  }
990  else // in this case we are producing the Feedback screen and hence we start the tricolor plot at the end of the simulation
991  {
992  Vlow = Vhigh = Vmed = diff_cum = Vexp = goalZ[g].saving_plan[followup_mnth] - goalZ[g].means_goal[followup_mnth] + goalZ[g].simulation_endvalue;
993  }
994  age_at_cutoff = age_now + (float)followup_mnth / 12;
995 // cout << "<br> goalZ[" << to_string(g) << "].saving_plan[0] " << to_string(goalZ[g].saving_plan[0]) << " -- goalZ[g].means_goal[0] = " << to_string(goalZ[g].means_goal[0]);
996  if ( followup_mnth < mnth_max)
997  {
998  s1 = "[" + to_string(age_at_cutoff) + ", " + to_string(Vexp) + "]";
999  s2 = "[" + to_string(age_at_cutoff) + ", " + to_string(Vexp) + "]";
1000  s3 = "[" + to_string(age_at_cutoff) + ", " + to_string(Vexp) + "]";
1001  }
1002  else
1003  {
1004  s1 = s2 = s3 = "[]";
1005  }
1007 
1008  for (k=followup_mnth + 1; k <= mnth_max; k++)
1009  {
1010 // Vexp_sign = (Vexp >= 0) ? 1.0 : -1.0;
1011 // Vexp = Vexp * Vexp_sign; // ==> is now always positive
1012  Vexp_evol = Vexp * exp(portfolios[p].pLogR + pow(portfolios[p].pSigma, 2) / 2);
1013 // sigma = sqrt(pow(sigma, 2) + pow(portfolios[p].pSigma * Vexp,2));
1014  the_diff = goalZ[g].saving_plan[k] - goalZ[g].means_goal[k];
1015  diff_cum += the_diff;
1016 // Vexp = Vexp_sign * Vexp_evol + the_diff; //set back to positive or negative
1017  Vexp = Vexp_evol + the_diff; //set back to positive or negative
1018  mnt_avg++;
1019  if (abs(Vexp) + abs(the_diff) != 0)
1020  {
1021  mnt_avg = (abs(Vexp) * (mnt_avg) + abs(the_diff) * 1) / (abs(Vexp) + abs(the_diff));
1022  }
1023 // cout << "<br>VLow=" << to_string(Vlow) << " -- sigma=" << to_string(sigma) <<"-- exp(portfolios[" << to_string(p) << "].pLogR)= " << to_string(exp(portfolios[p].pLogR)) << " -- exp...=" << exp(portfolios[p].pLogR +sqrt(2) * (sqrt(mnt_avg) - sqrt(mnt_avg-1)) * sigma * erf_low);
1024 
1025  Vlow = Vlow * exp(portfolios[p].pLogR +sqrt(2) * (sqrt(mnt_avg) - sqrt(mnt_avg-1)) * sigma * erf_low) + the_diff;
1026  Vmed = Vmed * exp(portfolios[p].pLogR +sqrt(2) * (sqrt(mnt_avg) - sqrt(mnt_avg-1)) * sigma * erf_med) + the_diff;
1027  Vhigh = Vhigh * exp(portfolios[p].pLogR +sqrt(2) * (sqrt(mnt_avg) - sqrt(mnt_avg-1)) * sigma * erf_high) + the_diff;
1028  Vexp = Vexp_evol + the_diff; //set back to positive or negative
1029  age_at_k = age_now + (float)k / 12;
1030  s1 = s1 + ", [" + to_string(age_at_k) + ", " + to_string(Vlow) + "]";
1031 #ifdef SHOW_Vexp_not_Vmed
1032  s2 = s2 + ", [" + to_string(age_at_k) + ", " + to_string(Vexp) + "]";
1033 #else
1034  s2 = s2 + ", [" + to_string(age_at_k) + ", " + to_string(Vmed) + "]";
1035 #endif
1036  s3 = s3 + ", [" + to_string(age_at_k) + ", " + to_string(Vhigh) + "]";
1037  }
1038  //s4: for the rainy day savings a line, for all other goals a big dot
1039  if (goalZ[g].goal_type == goal_type_s2i["rainy day savings"])
1040  {
1041  s4 = s4 + "[" + to_string(age_now) + ", " + to_string(goalZ[g].target_amount) + "]";
1042  for (k=1; k <= mnth_max; k++)
1043  {
1044  age_at_k = age_now + (float)k / 12;
1045  s4 = s4 + ", [" + to_string(age_at_k) + ", " + to_string(goalZ[g].target_amount) + "]";
1046  }
1047  }
1048  else
1049  {
1050  s4 = "[" + to_string(age_now + ((float)goalZ[g].realization_monthNbr)/12) + "," + to_string(goalZ[g].target_amount) + "]";
1051  }
1052  // cout << "<div class=\"jqplot-target\" id=\"xchart" << g << "\" style=\"height: 300px; width: 500px; position: relative;\">";
1053  // cout << "<script class=\"code\" type=\"text/javascript\">$(document).ready(function(){var plot1 = $.jqplot ('xchart" << g << "', [[3,7,9,1,5,3,8,2,5]]);});</script>";
1055 
1057  goalZ[g].s_low = s1;
1058  goalZ[g].s_exp = s2;
1059  goalZ[g].s_high = s3;
1060  goalZ[g].s_goal = s4;
1061 
1062  if (followup_mnth > 0)
1063  { // in this case we are in the "Follow-Up screen"
1064  if (followup_mnth + 1 > goalZ[g].realization_monthNbr)
1065  {
1066  // if the previous for-loop was not executed, so we are before
1067  set_followup_color_post(Vexp, g);
1068  }
1069  else
1070  {
1071  set_followup_color_prae(Vlow, Vexp, Vhigh, g);
1072  }
1073 
1074  }
1075 }
1076 
1077 
1078 
1089 void investment_problem::javaGraph(int g, string xtra_var, string xtra_label, int followup_mnth)
1090 {
1091  prepare_javaVars_colors(g, followup_mnth);
1092 
1093  parse_javaGraph( g, xtra_var, xtra_label);
1094 }
1095 
1103 void investment_problem::parse_javaGraph(int g, string xtra_var, string xtra_label)
1104 {
1105  string xtra_var_name;
1106  cout << "<div id=\"chartOverview"<<g<<"\" style=\"height:400px; width:700px;\"></div>";
1107  cout << "<script class=\"code\" type=\"text/javascript\">$(document).ready(function(){ \n";
1108  cout << "var l1 = [" + this->goalZ[g].s_low + "]; \n";
1109  cout << "var l2 = [" + this->goalZ[g].s_exp + "]; \n";
1110  cout << "var l3 = [" + this->goalZ[g].s_high + "]; \n";
1111  cout << "var l4 = [" + this->goalZ[g].s_goal + "]; \n";
1112  if (xtra_var != "")
1113  {
1114  cout << "var l5 = [" + xtra_var + "]; ";
1115  xtra_var_name = ", l5";
1116  }
1117 
1118  /* cout << "var l1 = [[1,3],[2.5,4],[3,5],[5,7]]; \n";
1119  cout << "var l2 = [[1,3],[2.5,6],[3,6],[5,6]]; \n";
1120  cout << "var l3 = [[1,3],[2.5,3],[3,4],[5,6]]; \n";
1121  cout << "var l4 = [[1,3]]; \n";*/
1122  cout << "var overviewPlot" << g << " = var" << g << " = $.jqplot ('chartOverview" << g << "', [l1, l2, l3, l4" << xtra_var_name << "] ";
1123  cout << ", {";
1124  cout << "seriesDefaults: {";
1125  cout << "showMarker: false ,";
1126  cout << "rendererOptions: { smooth: false },";
1127  cout << "markerOptions: { style:\"o\", size:5 }, ";
1128  cout << "lineWidth:7 ";
1129  cout << "},";
1130  cout << "legend: {show: true, location: 'e', fontSize: '2em', placement: 'outside', marginRight: \"600px\",";
1131  cout << "labels:['"<<t_plotlabels_evol[1]<<"', '"<<t_plotlabels_evol[2]<<"', '"<<t_plotlabels_evol[3]<<"', '"<<t_plotlabels_evol[4]<<g<<"'";
1132  if (xtra_var != "") cout << ", '" << xtra_label << "'";
1133  cout << "]},";
1134 // cout << "markerOptions: { style:\"o\", size:5 }, lineWidth:1}";
1135 
1136  /*/ ///////////////////
1137  if (goalZ[g].goal_type != goal_type_s2i["rainy day savings"])
1138  { // for the goals the special big dot
1139  cout << "{markerOptions: { show: true, style: 'circle', size: 12, shadow: false, shadowDepth: 6, shadowAlpha: 0.07, shapeRenderer: new $.jqplot.customMarkerRenderer() }}"; // old markerOptions: style:\"circle\", size:17
1140  }
1141  else
1142  { // except for the rainy day savings: the simple black line
1143  cout << "{showMarker: false}";
1144  }
1145  if (xtra_var != "") cout << ", {markerOptions: { style:\"o\", size:5 }, lineWidth:1}";
1146  cout << "],";
1148 
1149  cout << "series: [{}, {}, {}, "; // for the goal: something special=
1150  if (goalZ[g].goal_type != goal_type_s2i["rainy day savings"])
1151  { // the typical presentation of the goal:
1152  cout << "{showMarker: true, markerOptions: { style:\"filledCircle\", size:17}, shadowDepth: 6, shadowAlpha: 0.07, shapeRenderer: new $.jqplot.customMarkerRenderer() }";
1153  }
1154  else
1155  {
1156  cout << "{showMarker: false}";
1157  }
1158  if (xtra_var != "")
1159  {// if there is a simulation to be added, provide here the customization of the plot
1160  cout << ", {showMarker: true, markerOptions: {style:\"filledCircle\", size:15 }, lineWidth:3}";
1161  }
1162  cout << "], ";
1163 
1164  cout << "seriesColors: " << hh.seriesColorsGoalPlot << ", ";
1165  cout << "axesDefaults: {labelRenderer: $.jqplot.CanvasAxisLabelRenderer},";
1166  //cout << "axes: {xaxis: {label: \"age\" }, yaxis: {label: \"" << currency << "\"}, {tickOptions: {formatter:tickFormatter}}}"; // , pad: 0
1167  cout << "axes: {xaxis: {label: \"age\" }, yaxis: {label: \"" << goalZ[g].currency << "\"}}"; // , pad: 0
1168 
1169  cout << "}";
1170  cout << "); });";
1171  cout << "</script>";
1172  return;
1173 
1174 //150215 cout << "var plot" << g << " = $.jqplot('chartOverview" << g << "', [l1, l2, l3, l4" << xtra_var_name << "], {";
1175 
1176 
1177  // axesDefaults: {
1178 // pad: 1.05
1179  // },
1180 /* //////
1181  // Use the fillBetween option to control fill between two
1182  // lines on a plot.
1184  fillBetween: {
1185  // series1: Required, if missing won't fill.
1186  series1: 1,
1187  // series2: Required, if missing won't fill.
1188  series2: 2,
1189  // color: Optional, defaults to fillColor of series1.
1190  color: "rgba(227, 167, 111, 0.7)",
1191  // baseSeries: Optional. Put fill on a layer below this series
1192  // index. Defaults to 0 (first series). If an index higher than 0 is
1193  // used, fill will hide series below it.
1194  baseSeries: 0,
1195  // fill: Optional, defaults to true. False to turn off fill.
1196  fill: true
1197  },*/
1198  cout << "seriesDefaults: {rendererOptions: { smooth: false }},";
1199  cout << "legend: {show: true, location: 'e', placement: 'outside', marginRight: \"600px\",";
1200  cout << "labels:['negative scenario', 'expected evolution', 'good scenario', 'YOUR GOAL #"<<g<<"'";
1201  if (xtra_var != "") cout << ", '" << xtra_label << "'";
1202  cout << "]},";
1203 // cout << "seriesDefaults: {showMarker: false}, ";
1204 
1205 
1206  cout << "series:[{showMarker: false},{showMarker:false,lineWidth:5},{showMarker: false},";
1207 
1208 
1209 
1210  if (goalZ[g].goal_type != goal_type_s2i["rainy day savings"])
1211  { // for the goals the special big dot
1212  cout << "{markerOptions: { show: true, style: 'circle', size: 12, shadow: false, shadowDepth: 6, shadowAlpha: 0.07, shapeRenderer: new $.jqplot.customMarkerRenderer() }}"; // old markerOptions: style:\"circle\", size:17
1213  }
1214  else
1215  { // except for the rainy day savings: the simple black line
1216  cout << "{showMarker: false}";
1217  }
1218  if (xtra_var != "") cout << ", {markerOptions: { style:\"o\", size:5 }, lineWidth:1}";
1219  cout << "],";
1220 
1222  cout << "seriesColors: " << hh.seriesColorsGoalPlot << ", ";
1223  cout << "axesDefaults: {labelRenderer: $.jqplot.CanvasAxisLabelRenderer},";
1224  //cout << "axes: {xaxis: {label: \"age\" }, yaxis: {label: \"" << currency << "\"}, {tickOptions: {formatter:tickFormatter}}}"; // , pad: 0
1225  cout << "axes: {xaxis: {label: \"age\" }, yaxis: {label: \"" << goalZ[g].currency << "\"}}"; // , pad: 0
1226  cout << " } ); }); </script>";
1227 }
1228 
1234 inline void investment_problem::set_followup_color_prae(float Vlow, float Vmed, float Vhigh, int g)
1235 {
1236  //NOTE Vhigh is not used now ...
1237  if (Vlow > this->goalZ[g].target_amount) this->goalZ[g].color_followup = "green";
1238  else if (Vmed > this->goalZ[g].target_amount) this->goalZ[g].color_followup = "amber";
1239  else this->goalZ[g].color_followup = "red";
1240 }
1241 
1247 {
1248  if (V > this->goalZ[g].target_amount) this->goalZ[g].color_followup = "green";
1249  else if (V > this->goalZ[g].target_amount * (1 - MIN_ALPHA)) this->goalZ[g].color_followup = "amber";
1250  else this->goalZ[g].color_followup = "red";
1251 }
1252 
1253 
1261 {
1262  int k;
1263  float V0, Vhigh,sigma, logR, Vexp;
1264  if (p == 0) p = goalZ[g].optimal_portf;
1265  Vhigh = Vexp = V0 = goalZ[g].saving_plan[0] - goalZ[g].means_goal[0];//rm 1;
1266  sigma = portfolios[p].pSigma * V0;
1267 
1268  for (k=1; k <= goalZ[g].realization_monthNbr; k++)
1269  {
1270  sigma = sqrt(pow(sigma, 2) + pow(portfolios[p].pSigma * Vexp,2));
1271  Vexp = Vexp * exp(portfolios[p].pLogR + pow(portfolios[p].pSigma, 2) / 2) + goalZ[g].saving_plan[k] - goalZ[g].means_goal[k];
1272  logR = log(Vexp / V0);
1273  Vhigh = V0 * exp(logR + sigma / Vexp * norminv(ALPHA_PLOT_HIGH));
1274  }
1275  return Vhigh;
1276 }
1277 
1278 
1279 
1286 {
1287  bool success = true;
1288  aGOAL unalloc_goal(investor_id);
1289  // check if an unallocated goal already exists
1290  string s = "SELECT * FROM " + oConfig.tbl_prefix + "_goals WHERE investor = " + to_string(investor_id)
1291  + " AND goal_type = " + to_string(goal_type_s2i["unallocated"]) + ";";
1292  try
1293  {
1294  db.res = db.stmt->executeQuery(s);
1295  if (db.res->next())
1296  {
1297 // db.res->previous();
1298 // while (res->next())
1299 // {
1300  unalloc_goal.set_from_db();
1301 // }
1302  }
1303  else
1304  {
1306 // this->goal_id = res->getInt("goal_id");
1307 //done in the constructor: this->investor = investor_id;
1308  unalloc_goal.amount = 0;
1309  unalloc_goal.goal_type = goal_type_s2i["unallocated"];
1310  unalloc_goal.description = "unallocated means";
1311  unalloc_goal.realization_age = simulate_till_age;
1312  unalloc_goal.currency = currency;
1313  unalloc_goal.priority = 99;
1314  unalloc_goal.from_date = "";
1315  unalloc_goal.till_date = "";
1316  unalloc_goal.frequency = "O";
1317  unalloc_goal.max_shortfall = 0;
1318  if (!unalloc_goal.add_to_db())
1319  {
1320  error_message = error_message + "<li>Failed to save the new unallocated goal.</li>";
1321  success = false;
1322  }
1323  }
1324  }
1325  catch (sql::SQLException &e)
1326  {
1327  #ifdef DEBUG
1328  debug_info = "<br>" + s + "<br>";
1329  debug_info = debug_info + "# ERR: SQLException in " + __FILE__ + "(" + __FUNCTION__
1330  + ") on line " + to_string(__LINE__) + "<br># ERR: " + e.what()
1331  + " (MySQL error code: " + to_string(e.getErrorCode())
1332  + ", SQLState: " + e.getSQLState() + " )<br>";
1333  #endif
1334  error_message = error_message + "<li>Sorry, I failed to load a goal.</li>";
1335  success = false;
1336  }
1337  return success;
1338 }
1339 
1340 
1341 
1346 {
1347  int p, the_portfolio = 1;
1348  float sigma = portfolios[1].pSigma;
1349  for (p =1; p <= nbr_portfolios; p++)
1350  {
1351  if (portfolio_suitable[p] && portfolios[p].pSigma <= sigma)
1352  {
1353  sigma = portfolios[p].pSigma;
1354  the_portfolio = p;
1355  }
1356  }
1357  return the_portfolio;
1358 }
1359 
1364 {
1365  int p, the_portfolio = 1;
1366  float sigma = portfolios[1].pSigma;
1367  for (p =1; p <= nbr_portfolios; p++)
1368  {
1369  if (portfolio_suitable[p] && portfolios[p].pSigma >= sigma)
1370  {
1371  sigma = portfolios[p].pSigma;
1372  the_portfolio = p;
1373  }
1374  }
1375  return the_portfolio;
1376 }
int nbr_portfolios
the number of standard portfolios
#define RAINY_DAY_MONTH_NBR
the artificial horizon in months for the "rainy day goal"
Definition: efp.cpp:73
void load_covar(int person, char person_type= 'i')
bool is_valid_dateStr(string theDate)
float pLogR
the MONTHLY log-return
type norminv(type p)
Definition: normdist.h:73
void set_followup_color_post(float V, int g)
bool add_to_db()
#define ALPHA_UPPER_LIMIT
the upper limit for all alpha's to be used
Definition: efp.cpp:69
const string seriesColorsGoalPlot
string currency
the default currency for that customer
unordered_map< string, string > t_feedback
Definition: texts_Eng_UK.h:140
float age(int Mnbr=0)
sql::ResultSet * res
string from_date
int nbr_goals
the total number of goals
std::map< int, float > means
sum of cash flows and assets per month (not to be changed)
float calc_V_high(int g, int p=0)
calculates the 1-alpha quantile portfolio for the goal alpha at realization_monthNbr ...
int goal_type
(0, "unallocated"), (1, "amount@date"), (2, "income from/to"), (3, "rainy day savings"), (4, "amount asap");
float amount
void expand_cf(float amount, string freq="M", string fromStr="", string tillStr="", int goal_nbr=0)
float weights[NBR_ASSET_CLASSES]
the weights of the asset classes (ordered as the asset classes)
unordered_map< int, string > t_plotlabels_evol
Definition: texts_Eng_UK.h:199
#define MIN_ALPHA
= (1 - confidence_level) for the most important goal
Definition: efp.cpp:67
bool get_portf_from_db(int id)
float getFloat(string s)
unordered_map< int, string > goal_type_i2s
Definition: efp.cpp:168
sql::Statement * stmt
#define ALPHA_PLOT_HIGH
the high alpha to plot
Definition: efp.cpp:72
std::map< int, portfolio > portfolios
the standard portfolios
investment_problem(int investor)
Constructor.
#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 * assetClass_covar
void prepare_javaVars_colors(int g, int followup_mnth)
float simulate_till_age
float pSigma
the MONTHLY volatility
int age2monthNbr(float theAge)
const string tbl_prefix
tables start with "" + oConfig.tbl_prefix + "_" if the prefix is eg. "tbl" then we have "tbl_invesotr...
std::map< int, bool > portfolio_suitable
string frequency
#define PRECISSION
equals roundup (1 / 2^NBR_ITERATIONS)
Definition: efp.cpp:78
tm get_tm(int monthNbr=0)
global functions
int get_portfolio_safest()
returns the portfolio id of the safest acceptable portfolio
string curr_format(float dv, string the_curr="")
double erfinv(double x)
Definition: normdist.h:182
float realization_age
std::map< int, float > means_left
the percentage left to be invested of each cash-flow (carried over to next goal)
int get_portfolio_riskiest()
returns the portfolio id of the riskiest acceptable portfolio
#define ALPHA_LOWER_LIMIT
the lower limit for all alpha's to be used
Definition: efp.cpp:70
void set_from_db()
void solve()
allocates means (with a benchmark) to goals
html_helper hh
own c++ classes
Definition: efp.cpp:180
void set_goal_color(int g, float opt_perc)
allocates a color to each goal after the benchmark is found
float max_shortfall
#define NBR_ITERATIONS
number of iterations in goalseek procedures
Definition: efp.cpp:77
void set_goal_remarks(int g)
adds remarks about the benchmark afther the benchmark is found
std::map< int, float > means_used
the means already used for THIS particular goal
string riskFunction
Math.
db_helper db
Definition: efp.cpp:183
bool set_curr(string the_curr)
#define MAX_MONTHS_TO_SAFEST
the maximum number of months for realization_monthNbr to be forced to the safest portfolio ...
Definition: efp.cpp:87
string description
void load_ER(int person=0, char person_type= 'i')
void set_priorityLimits()
sets priorityMax and priorityMin
float calc_alpha(int priority, int monthNbr)
estimates $$
std::map< int, float > means_block
next block of means to be used for a certain percentage
float assetClass_mu[(NBR_ASSET_CLASSES+1)]
note: index 0 not used
int dateStr2Mnbr(string dStr)
void set_means_goal(int g)
set the cash flows that are implied by the goal (eg. regular income from portfolio) ...
void javaGraph(int g, string xtra_var="", string xtra_label="", int followup_mnth=0)
std::map< int, float > means_tmp
copy of block for goal-seek
std::map< int, float > max_exposure
the maximum exposure per asset class
float get_optimal_portfolio(int g)
finds the portfolio with minimal investment
void goal_seek_tmp_means(float *perc, int g, int p)
finds the minimal percentage needed of tmp_means
unordered_map< string, string > t_errMsg
Definition: texts_Eng_UK.h:86
void dateStr2tm(string dStr, tm *target_tm)
void set_followup_color_prae(float Vlow, float Vmed, float Vhigh, int g)
#define MAX_ALPHA
= (1 - confidence_level) for the least important goal
Definition: efp.cpp:68
float to_curr(float amnt, string the_curr)
int priority
void allocate_to_unallocated_goal(int unallocated_goal_nbr)
if necessary create an unallocated goal and put the means_left there
float calc_risk(int g, int p)
calculate the risk
void load_preferences()
sets the experience, knowledge and desirability vectors
void set_assets()
add the assets to means[1]
config oConfig
mysql connection mysql connector from dev.mysql.com
Definition: efp.cpp:149
int load_from_db(string investorID)
string till_date
std::map< int, aGOAL > goalZ
map containing all goals
int nbr_cfs
the total number of cash flows
void parse_javaGraph(int g, string xtra_var="", string xtra_label="")
plots the chartOverview
string currency
float flSum(std::map< int, float > *theMap, int N)
int nbr_assets
the total number of assets
void set_portfolios()
sets the portfolios
unordered_map< string, int > goal_type_s2i
Global lists.
Definition: efp.cpp:160
int months2simulate()
float goal_seek_means(int g, int p)
finds the minimal means needed (first free, then remaining, etc); sets tmp_means and calls the next f...