#include #include #include #include "standaard.h" #include "beurs.h" #include "dag.h" using namespace std; //**************************************************************************** // Reset de waardes van de opzet voor een beurs // Alle private variabelen op -1 void Beurs::resetBeursOpzet() { tw = -1; n = -1; provisie = -1; b0 = -1; aantalDagen = -1; } // Beurs::resetBeursOpzet //************************************************************************* // Default constructor Beurs::Beurs () { resetBeursOpzet(); } // Beurs::Beurs //**************************************************************************** // Leest de waardes voor een nieuwe ozpet voor een beurs in // Open file met 'invoernaam' als dit kan en leest hieruit // de waardes voor een beurs bool Beurs::leesIn (const char* invoernaam) { ifstream invoer; invoer.open(invoernaam, ios::in); if(invoer.fail()) { cout << "File kan niet geopend worden." << endl; return false; } // Checkt of file te openen is invoer >> tw; aantalDagen = tw + 1; invoer >> n; if(!integerInBereik("tw", tw, 1, 100) && !integerInBereik("n", n, 1, 8)) { resetBeursOpzet(); return false; } // Checkt of de n en tw binnen de grenzen liggen invoer >> provisie; invoer >> b0; for(int k = 0; k < aantalDagen; k++) { Dag dag; dag.setNummer(k); dagen.push_back(dag); } // Maakt alle dagen aan for(int i = 0; i < aantalDagen; i++) { for(int j = 0; j < n; j++) { double koers; invoer >> koers; dagen.at(i).setKoers(j, koers); } } // De koersen van de aandelen voor elke dag for(int l = 0; l < aantalDagen; l++) { double rente; invoer >> rente; dagen.at(l).setRentepercentage(rente); } // De rentes voor elke dag, behalve de laatste dag return true; } // Beurs::leesIn //**************************************************************************** // Drukt, ter controle, de invoer af void Beurs::drukAfInvoer () { cout << "De opzet voor de beurs:" << endl << "tw: " << tw << " dag" << endl << "n: " << n << " aandelen" << endl << "provisie: " << provisie << " procent" << endl << "b0: " << b0 << " beginbedrag" << endl << "aantal dag-objecten: " << dagen.size() << " objecten" << endl << endl; cout << "Wilt u ook specifiek per dag de waardes zien? 1 = ja, 0 = nee" << endl; int keuze; cin >> keuze; if(keuze == 1) { int dagenSize = dagen.size(); for(int i = 0; i < dagenSize; i++) { for(int j = 0; j < n; j++) { cout << i << " - koers " << j << " - " << dagen.at(i).getKoers(j) << endl; } cout << i << " " << dagen.at(i).getNummer() << " - rente - " << dagen.at(i).getRentepercentage() << endl; } } // Voor als de gebruiker ook alle specifieke invoer wilt zien van de dagen } // Beurs::drukAfInvoer //**************************************************************************** // Haalt alle waardes uit transacties en vult transacties // met zoveel vectoren als het aantal dagen. Met de membervariabelen van Beurs gebeurd // verder niks void Beurs::transactiesResetten(vector > > &transacties) const { transacties.clear(); vector> hulp; for(int i = 0; i <= tw; i++) { transacties.push_back(hulp); } } // Beurs::transactiesResetten //**************************************************************************** // Retourneert bedrag dat erbij komt door rente. // Met de membervariabelen van Beurs gebeurd verder niks double Beurs::rente(double const bedrag, int const dag) const { if(dag == 0) { return 0.00; } // de eerste dag heeft geen rente van de vorige dag return (bedrag * (dagen.at(dag - 1).getRentepercentage() * 0.01)); } // Beurs::rente //**************************************************************************** // Retourneert bedrag dat je krijgt bij verkopen. // Met de membervariabelen van Beurs gebeurd verder niks double Beurs::verkopen(int const aandeel, int const dag) const { return (dagen.at(dag).getKoers(aandeel) * (1 - (provisie*0.01))); } // Beurs::verkopen //**************************************************************************** // Retourneert bedrag dat eraf gaat bij kopen. // Met de membervariabelen van Beurs gebeurd verder niks double Beurs::kopen(int const aandeel, int const dag) const { return (dagen.at(dag).getKoers(aandeel) * (1 + (provisie*0.01))); } // Beurs::kopen //**************************************************************************** // Retourneert of het aandeel in de bitstring met combinatie van aandelen zit. // Met de membervariabelen van Beurs gebeurd verder niks bool Beurs::aandeelInCombinatie(int const aandeel, int combinatieAandelen) const { int hulp = combinatieAandelen >> aandeel; // schuiven zodat bit van gegeven aandeel rechts staat if((hulp & 0b1) == 0b1) { return true; } // Kijkt of de bit voor het gegeven aandeel '1' is of '0' return false; } // Beurs::aandeelInCombinatie //**************************************************************************** // Berekent het eindbedrag dat de gebruiker op dag tw zal hebben // na het uitvoeren van de transacties uit de vector en de rentes van elke dag. // Met de membervariabelen van Beurs gebeurd verder niks double Beurs::berekenEindbedrag(vector > > const transacties) const { double saldo = b0; // dit houdt de saldo van de gebruiker bij for(int i = 0; i < aantalDagen; i++) { saldo += rente(saldo, i); // de rente erbij int aantalTransacties = transacties.at(i).size(); // aantal transactie op dag 'i' for(int j = 0; j < aantalTransacties; j++) { if(transacties.at(i).at(j).first) { saldo -= kopen(transacties.at(i).at(j).second, i); } // kopen else { saldo += verkopen(transacties.at(i).at(j).second, i); } // verkopen } // loopt alle transactie op deze dag af } return saldo; } // Beurs::berekenEindbedrag //**************************************************************************** // Berekent het bedrag in kas na het uitvoeren van // een bitstring op een vorige bitstring van de vorige dag. // Met de membervariabelen van Beurs gebeurd verder niks double Beurs::berekenBedrag(double vorigeBedrag, int const vorigeCombinatie, int const nieuweCombinatie, int const dag) const { vorigeBedrag += rente(vorigeBedrag, dag); // eerst rente erbij for(int i = 0; i < n; i++) { bool aandeelInVorig = aandeelInCombinatie(i, vorigeCombinatie); bool aandeelInNieuw = aandeelInCombinatie(i, nieuweCombinatie); if(aandeelInVorig && !aandeelInNieuw) { vorigeBedrag += verkopen(i, dag); } // verkopen if(!aandeelInVorig && aandeelInNieuw) { vorigeBedrag -= kopen(i, dag); } // kopen } // loopt alle aandelen af return vorigeBedrag; } // Beurs::berekenBedrag //**************************************************************************** // Voegt de transacties van de dag van combinatie toe aan de vector met transacties. // Met de membervariabelen van Beurs gebeurd verder niks void Beurs::addTransacties(int combinatie, int combinatieVorige, vector > > &transacties, int const dag) { for(int i = 0; i < n; i++) { bool aandeelInVorig = aandeelInCombinatie(i, combinatieVorige); bool aandeelInVolgend = aandeelInCombinatie(i, combinatie); if(!aandeelInVorig && aandeelInVolgend) { transacties.at(dag).push_back(pair (true, i)); } // koop transactie toevoegen else if(aandeelInVorig && !aandeelInVolgend) { transacties.at(dag).push_back(pair (false, i)); } // verkoop transactie toevoegen } // loopt alle aandelen af } // Beurs::addTransacties //**************************************************************************** // Bepaalt een maximum eindbedrag met bottom up. // Daarna worden de transacties in de meegegeven vector gestopt voor het max bedrag. // Met de membervariabelen van Beurs gebeurt verder niks double Beurs::bepaalMaxBedragBU(vector > > &transacties) { int combinatiesAandelen = berekenMacht(2, n); // alle mogelijke combinaties van aandelen pair bedragenTabel[combinatiesAandelen][aantalDagen - 1]; int combinatieVorige = int(); // een combinatie van aandelen op de vorige dag double maxBedrag = -1; // het maximum bedrag tot nu toe met de huidige combinatie aandelen for(int i = 0; i < aantalDagen; i++) { for(int j = 0; j < combinatiesAandelen; j++) { if(i == 0) { maxBedrag = berekenBedrag(b0, 0, j, i); } // op de eerste dag is er geen vorige dag om het maximum uit te nemen else { for(int k = 0; k < combinatiesAandelen; k++) { if(bedragenTabel[k][i - 1].first >= 0) { double tempBedrag = berekenBedrag(bedragenTabel[k][i - 1].first, k, j, i); if(tempBedrag > maxBedrag) { maxBedrag = tempBedrag; combinatieVorige = k; } // nieuwe max bedrag } // negatieve saldo's worden niet verder mee gerekend } // berekent het maximum bedrag mogelijk met combinatie 'j' op deze dag } if(i == tw) { j = combinatiesAandelen; // uit de loop } // dag is tw, dus we berekenen alleen situatie met 0 aandelen (de rest is onnodig) else { bedragenTabel[j][i].first = maxBedrag; bedragenTabel[j][i].second = combinatieVorige; // zet waardes in tabel maxBedrag = -1; combinatieVorige = int(); // resets } } } // vult de tabel in met steeds het maxbedrag mogelijk met vorige aandelen combinaties transactiesResetten(transacties); addTransacties(0, combinatieVorige, transacties, tw); // de laatste transacties for(int i = tw - 1; i >= 0; i--) { addTransacties(combinatieVorige, bedragenTabel[combinatieVorige][i].second, transacties, i); combinatieVorige = bedragenTabel[combinatieVorige][i].second; } // Voegt de transacties toe in de vector transacties return maxBedrag; } // Beurs::bepaalMaxBedragBU //**************************************************************************** // Kijkt of tempBedrag groter is dan maxBedrag en als dat zo is dan wordt maxBedrag gelijk gesteld aan // tempBedrag. Met tempBedrag gebeurd verder niks en in de klasse verandert ook niks. void Beurs::nieuwMaxBedrag(double const tempBedrag, double &maxBedrag) const { if(tempBedrag > maxBedrag) { maxBedrag = tempBedrag; } } // Beurs::nieuwMaxBedrag //**************************************************************************** // Berekent recursief wat het maximale bedrag is dat je kan krijgen door aandelen te kopen en // verkopen en dan uiteindelijk de combinatie "combinatie" over te houden. De methode is top down // waarbij deelresultaten niet worden opgeslagen. "dag" is de dag waarvoor je het met die aanroep // gaat bereken en "laatsteDag" is de dag waarop je echt het resultaat mee wilt weten en waarmee // voor het eerst de functie wordt aangeroepen. Met de membervariabelen van Beurs gebeurd verder niks double Beurs::berekenRecBedrag(int const dag, int const laatsteDag, int const combinatie) const { int combinatiesAandelen = berekenMacht(2, n); // Alle mogelijke combinaties double maxBedrag = INT_MIN; // Het maximale bedrag dat verkregen kan worden double vorigeBedrag = INT_MIN; // Bedrag van de vorige dag bij een bepaald combinatie double tempBedrag = INT_MIN; // Hulp variabele om het bedrag in op te slaan if(dag == 0) { maxBedrag = berekenBedrag(b0, 0, combinatie, dag); } // Op dag 0 heb je b0 in bezit en nog geen aandelen else { for(int i = 0; i < combinatiesAandelen; i++) { vorigeBedrag = berekenRecBedrag((dag - 1), laatsteDag, i); // Het bedrag dat je de vorige dag // met combinatie i kan hebben if(vorigeBedrag >= 0) { tempBedrag = berekenBedrag(vorigeBedrag, i, combinatie, dag); nieuwMaxBedrag(tempBedrag, maxBedrag); // Kijken of dit een maximaal bedrag } } // Alle combinaties afgaan } return maxBedrag; } // Beurs::berekenRecBedrag //**************************************************************************** // Zet op (aandeelCombinatie, dag) "nieuwBedrag" in de dubbele array "bedrag" en // zet de boolean op die plek op true. Met de membervariabelen van Beurs gebeurd verder niks void Beurs::setBedrag(pair bedrag[MaxAs][MaxTw], double const nieuwBedrag, int const dag, int const aandeelCombinatie) const { bedrag[aandeelCombinatie][dag].second = nieuwBedrag; bedrag[aandeelCombinatie][dag].first = true; } // Beurs::setBedrag //**************************************************************************** // Zet de waarde van de double op -1 en van de boolean op false op plek // (aandeelCombinatie, dag). Met de membervariabelen van Beurs gebeurd verder niks void Beurs::resetBedrag(pair bedrag[MaxAs][MaxTw], int const dag, int const aandeelCombinatie) const { bedrag[aandeelCombinatie][dag].first = false; bedrag[aandeelCombinatie][dag].second = -1; } // Beurs::resetBedrag //**************************************************************************** // Berekent recursief en top down wat het maximale bedrag is wat je op een dag in de kas kan // hebben. Op laatste dag wordt alles verkocht. Er wordt gebruikt gemaakt van een dubbele array // waarin deelresultaten worden opgeslagen. In de klasse Beurs veranderd er niks en dag en // laatsteDag veranderen ook niet double Beurs::berekenRecBedragMemo(pair bedrag[MaxAs][MaxTw], int const dag, int const laatsteDag) const { int combinatiesAandelen = berekenMacht(2, n); double tempBedrag = INT_MIN; // Hulp variable om een bedrag in op te slaan double vorigBedrag = INT_MIN; // Een bedrag van de vorige dag double maxVorigeBedrag = INT_MIN; // Het maximale bedrag dat voor een bitstring verdiend kan worden double maxBedrag = INT_MIN; // Het maximale bedrag dat deze dag verdiend kan worden if(dag == 0) { for(int i = 0; i < combinatiesAandelen; i++) { tempBedrag = berekenBedrag(b0, 0, i, dag); setBedrag(bedrag, tempBedrag, dag, i); nieuwMaxBedrag(tempBedrag, maxBedrag); } } // Als de dag 0 is dan wordt dan gekeken wat het maximale bedrag is // en van bedrag wordt de eerste kolom gevuld else { for(int i = 0; i < combinatiesAandelen; i++) { maxVorigeBedrag = INT_MIN; for(int j = 0; j < combinatiesAandelen; j++) { if(!bedrag[j][dag - 1].first) { vorigBedrag = berekenRecBedragMemo(bedrag, dag - 1, laatsteDag); } // Als het vorige bedrag nog niet in de array staat dan wordt die ingevuld vorigBedrag = bedrag[j][dag - 1].second; if(vorigBedrag >= 0) { tempBedrag = berekenBedrag(vorigBedrag, j, i, dag); nieuwMaxBedrag(tempBedrag, maxVorigeBedrag); } // Als vorigBedrag >= 0 dan wordt gekeken of hiermee een maximaal bedrag // kan worden gemaakt } setBedrag(bedrag, maxVorigeBedrag, dag, i); nieuwMaxBedrag(maxVorigeBedrag, maxBedrag); // Kijken of dit een maximaal bedrag // van de dag is } if(dag == laatsteDag) { maxBedrag = bedrag[0][dag].second; } // Dan wil je alles verkopen } return maxBedrag; } // Beurs::berekenRecBedragMemo //**************************************************************************** // Deze functie roept een hulpfunctie aan die recursief het maximale bedrag berekend // dat je op tw in de kas zou kunnen hebben. Als memo true is wordt een functie aangeroepen die // deelresultaten opslaat en anders een functie die dat niet doet. Het maximale bedrag wordt // geretourneerd. Met de klasse Beurs verandert er niks. double Beurs::bepaalMaxBedragRec (bool memo) { pair bedrag[MaxAs][MaxTw]; // De boolean geeft aan of het bedrag al is ingevuld int combinatiesAandelen = berekenMacht(2, n); for(int i = 0; i < combinatiesAandelen; i++) { for(int j = 0; j < aantalDagen; j++) { resetBedrag(bedrag, j, i); // De dubbele array initialiseren } } if(memo) { return berekenRecBedragMemo(bedrag, tw, tw); // Met deelresultaten opslaan } else { return berekenRecBedrag(tw, tw, 0); // Zonder deelresultaten opslaan } } // Beurs::bepaalMaxBedragRec //**************************************************************************** // Drukt de transacties per dag af die in de vector transacties zitten. Voor de aandelen n // geldt 1 <= n <= 8. Aan het einde wordt ook berekend wat het bedrag is dat je in kas hebt // nadat de transacties zijn uitgevoerd. Met de vector transacties en de klasse Beurs // gebeurd verder niks. void Beurs::drukAfTransacties(vector > > transacties) { int aantalDagen = transacties.size(); int aantalTransacties; double eindBedrag; cout << endl; for(int i = 0; i < aantalDagen; i++) { cout << "Dag " << i << ": " << endl; aantalTransacties = transacties.at(i).size(); if(aantalTransacties == 0) { cout << "Geen transacties deze dag." << endl; } // Als het een lege vector is else { for(int j = 0; j < aantalTransacties; j++) { if(transacties.at(i).at(j).first) { cout << " - Kopen: "; } else { cout << " - Verkopen: "; } cout << transacties.at(i).at(j).second + 1 << endl; } // De transacties afgaan } cout << endl; } // Alle dagen afgaan eindBedrag = berekenEindbedrag(transacties); cout << "Eindbedrag: " << eindBedrag << endl; } // Beurs::drukAfTransacties