Revisions: Nov 14,
2007: Added sample code link to to sample code compiled with Visual C++ 2005
Express Edition compiler
In this assignment we will model BankAccounts, Stocks and containers that use STL-style iterators. We will also model actions on stocks and bank accounts as "trigger" objects that are based on the Observer Programming Pattern. Notice that many details have been left up to you to design.
Part1) The containers
Create a class called OrderedCollection
with the following interface:
int size(void) //answer
the number of elements
add(T &e) //add
an element to the end of the collection
addFirst(T & e)
//add an element to the front of the collection
addLast(T & e) //add
an element to the end of the collection
T & removeFirst()
//answer and remove the first element
T & removeLast()
//answer and remove the last element
remove(T &e) //remove
e from the collection if it exists
bool includes(T &e)
//answer whether the collection includes e
OrderedIterator<T>
& begin()
//answer
an iterator pointing at the first element
OrderedIterator<T>
& end()
//answer
an iterator pointing a the last element
Create an iterator class OrderedIterator<T> which is a friend of OrderedCollection<T>, and supports the following methods
operator++ //increment
the iterator to the next element
operator* //de-reference
the iterator to get the element
//notice iterators work like pointers
bool operator==(OrderedIterator<T>
& i)
//answer whether iterator *this and i refer to the
//same element
bool operator!=(OrderedIterator<T>
& i)
//answer whether iterator *this and i don't refer to the
//same element
Example of iterator use
OrderedCollection<BankAccount>
s;
//add some bank accounts
to s
for (OrderedIterator<BankAccount>
i = s.begin(); i != s.end(); i++ )
cout <<
*i;
For this part you need to model BankAccounts, some Stock objects, and a customer's Portfolio
The BankAccount
class should include methods (you can add others)
void withdraw(Float
amount)
void deposit(Float amount)
Float balance() //answer
the balance
Create a class Stock
which represents a holding of a stock on the stock market. For example
the stock NASDAQ ENTU 100 $29.23 represents 100 shares of the stock for
Entrust Technologies trading on the NASDAQ exchange whose current marked
value is $29.23.
A stock should have the following properties ( you can
add additional ones if you like): exchange
(string representing the stock exchange), symbol
(string representing the trading symbol, e.g. "ENTU"), a marketValue
which is a float representing the current market value of the stock, and
integer shares which is the number
of shares of the stock.
Create a class Portfolio
that represents a customers trading account and the stocks they currently
own. A Portfolio should have the following properities:
owner (String
representing the customer)
portfolioAccountNumber
(int representing unique portfolio id)
account (instance
of BankAccount from which stock purchases and sales are made)
stocks (an OrderdCollection
of the stocks currently owned by the portfolio owner)
actions (an OrderedCollection
of current actions pending against accounts or stocks -see below).
A portfolio should include the following methods, but
you can add more:
buy(Stock s, int ns)
//purchase ns shares
of stock s from account in the portfolio
sell(Stock s, int ns)
//sell ns shares of
stock s and deposit the money in account in portfolio
addAction(Action a)
//add an action object
to the current actions of the portfolio
removeAction(Action
a)
//remove the action
a from the portfolio
priceChange(char * symbol,
Float price)
//set the current
market value of stock symbol to price
print(ostream &o)
//print the porfolio
A $30.00 service charge should applied to any buy or sell transaction in a portfolio. Place this service charge in a class variable so it can be adjusted from time to time (probably raised). The portfolio printout should include all the stocks held and the balance of the account and finally the current value of the portfolio. The current value is the balance of the account and the value of each stock owned times the number of shares owned.
Part 3 Stock and Account Actions
Suppose you want to buy a particular stock and sell when,
the purchase price rises above a certain amount. Someone could watch the
stock to see when the event in question happens.
An alternative is to have an Action
object that will watch for the event and then react to it. Such Action
objects can be based on the Observer programming pattern (that will be
discussed in class).
In this assignment you have to create Action objects
that are capable of watching Stock objects. To do so Stock classes
must implement the subject protocol. We will do this by having the Stock
class inherit from an abstract class Subject.
Class Action will inherit from abstract class Observer.
Class Subject
should have the following methods
attach(Observer * obs)
//attach an observer
dettach(Observer * obs)
//dettach an observer
notify() //notify
all observers by invoking their update() method
Class Observer
should have the following protocol
update(Subject *sub)
//react to a change in the subject sub
You can implmement class Action any way you like but it
must follow the Observer pattern and inherit from class Observer.
If a portfolio customer wants to purchase some stock or sell some stock
when it hits a certain value, an Action object should be created and it
should attach itself to the stock. Whenever the stock's price changes,
the action object should have a chance to react to the change and if necessary
sell or buy stock on behalf of the portfolio. (You should purchase stock
at current market value using Action objects as well which do not
specify a specific price -you need to decide how to implement this). When
an Action object "fires" it should print a message about the details of
the transaction to cout.
Testing:
Test your code with a main program and a file that works
as follows.
You need a file, that you create, to simulate stock prices.
The file should have individual lines that represent the stock symbol and
the current market value. For example.
entu 43.00
ibm 53.00
nt 117.00
entu 44.00
ibm 51.00
nt 119.00
entu 47.00
nt 120.00
...
Create a main program that does the following.
create a bank account and deposit $10.000
create a portfollio using the above account
create action objects to purchase some shares of some stocks at market value (purchase $10.000 worth of stock)
create some action objects to buy and sell stocks at a specific values.
read the simulation file
each action object that fires should print out the shares and amount etc.
at the end of the simulation file print out the portfolio, which should show all stocks, number of shares, market value, bank account balance and total portfolio value.
print out a final statement showing profit or loss (based on original bankaccount balance)
Class OrderedCollection and its Iterator
#include <iostream.h>
template <class T>
class OrderedIterator;
template <class T>
class OrderedCollection {
// =================
friend class OrderedIterator<T>;
const int capacity_;
int size_; //number of elements
const T **buffer;
public:
OrderedCollection(int size = 100) : capacity_(size),
buffer(new const T*[size]), size_(0){}
OrderedCollection(const OrderedCollection<T> & c):
capacity_(c.capacity_), size_(c.size_), buffer(new const T*[c.capacity_])
{
for(int i = 0; i < capacity_; i ++)
buffer[i] = c.buffer[i];
}
~OrderedCollection() {delete [] buffer; }
typedef OrderedIterator<T> iterator;
int size() {return size_;}; //answer number of elements
void add(const T & element);
void addLast(const T & element);
void addFirst(const T & element);
T & removeLast();
T & removeFirst();
int remove(const T & element);
iterator begin(void) {return OrderedIterator<T>(*this);}
iterator end(void) {return OrderedIterator<T>(*this, size());}
void printOn(ostream & out) {
for (int i = 0; i < size_; i++)
cout << *buffer[i] << "\n";
}
};
template <class T>
void OrderedCollection<T>::add(const T & element){
if(size_ < capacity_)
buffer[size_++] = &element;
}
template <class T>
void OrderedCollection<T>::addLast(const T & element){
add(&element);
}
template <class T>
void OrderedCollection<T>::addFirst(const T & element){
if(size_ < capacity_){
for (int i = size_; i>0; i--)
buffer[i] = buffer[i-1];
buffer[0] = &element;
size_++;
}
}
template <class T>
T & OrderedCollection<T>::removeLast(){
return * (T*) (buffer[size_--]);
}
template <class T>
T & OrderedCollection<T>::removeFirst(){
T* temp = buffer[0];
for(int i = 0; i<size_ - 1; i++)
buffer[i] = buffer[i + 1];
size_--;
return * (T*) temp;
}
template <class T>
int OrderedCollection<T>::remove(const T & item){
//remove first occurence of element == item
//return true if element was found and removed
int found = 0;
for(int i = 0; i<size_; i++) {
if((*buffer[i] == item) && !found) found = 1;
buffer[i] = buffer[i + found];
}
size_ -= found;
return found;
}
template <class T>
ostream & operator<<(ostream & out, OrderedCollection<T> & collection) {
collection.printOn(out);
return out;
}
template <class T>
class OrderedIterator {
// ===============
int index;
OrderedCollection<T> & s;
public:
OrderedIterator(OrderedCollection<T> & set, int position = 0) :
s(set), index(position){}
T & operator*() {return *(T*)(s.buffer[index]);};
OrderedIterator<T> & operator++(int) {index++; return *this;};
bool operator==(OrderedIterator<T> & iter)
{return (&(this->s) == &(iter.s))&&(this->index == iter.index);};
bool operator!=(OrderedIterator<T> & iter) {return !(*this == iter);};
};
BankAccount Class
#include <iostream.h>
#include <string.h>
class BankAccount {
// ===========
static int nextAccountNumber;
int accountNumber;
float balance_;
public:
BankAccount(float amount = 0.0):
balance_(amount), accountNumber(nextAccountNumber++) {}
void printOn(ostream & out) {
out << "acct#" <<accountNumber << " $" << balance_;
}
void deposit(float amount) {balance_ += amount;}
void withdraw(float amount) {balance_ -= amount;}
float balance() const {return balance_;}
};
ostream & operator<< (ostream & out, BankAccount & b) {
b.printOn(out);
return out;
}
int BankAccount::nextAccountNumber = 1000;
Observer Class
#include <iostream.h>
#include <string.h>
class Subject;
class Observer {
public:
virtual void update(Subject * subject)= 0;
virtual void printOn(ostream & out) const = 0;
int operator==(const Observer & obs) const {
return this == & obs;
}
};
ostream & operator<<(ostream & out, const Observer & obs) {
obs.printOn(out);
return out;
}
Subject and Stock Class
#include <iostream.h>
#include <string.h>
class Subject {
// =======
OrderedCollection<Observer> observers;
public:
void attach(Observer * obs) {
observers.add(*obs);
}
void dettach(Observer * obs) {
observers.remove(*obs);
}
void notify() {
//Note: observer collection is copied and the copy
//iterated over so that observers can dettach
//when they are being notified (i.e. double buffering)
OrderedCollection<Observer> observers_copy = observers;
for(OrderedCollection<Observer>::iterator itr = observers_copy.begin();
itr != observers_copy.end(); itr++) {
(*itr).update((Subject*) this);
}
}
};
class Stock :public Subject {
// =====
char * exchange; //not used for this assignment
char * symbol;
int shares;
float market_value;
public:
Stock(char * sym = "ACME", float price = 0.0, int num_shares = 0, char *
xch = "NASDAQ" ):
shares(num_shares), market_value(price) {
exchange = new char[strlen(xch) + 1];
strcpy(exchange,xch);
symbol = new char[strlen(sym) + 1];
strcpy(symbol,sym);
}
Stock (const Stock & s) : shares(s.shares), market_value(s.market_value)
{
exchange = new char [strlen(s.exchange) + 1];
strcpy(exchange, s.exchange);
symbol = new char [strlen(s.symbol) + 1];
strcpy(symbol, s.symbol);
}
Stock & operator=(const Stock & s)
{
if (this != &s) {
delete [] exchange;
delete [] symbol;
market_value = s.market_value;
shares = s.shares;
exchange = new char [strlen(s.exchange) + 1];
strcpy(exchange, s.exchange);
symbol = new char [strlen(s.symbol) + 1];
strcpy(symbol, s.symbol);
}
return *this;
}
~Stock(void) {
delete exchange;
delete symbol;
}
void printOn(ostream & out) const {
out << symbol << " " << shares << " $" << market_value;
}
int operator==(const Stock & s) const {
return strcmp(symbol,s.symbol) == 0;}
void setMarketValue(float newprice) {
market_value = newprice;
notify();
}
float getMarketValue() {return market_value;}
void setShares(int n) { shares = n; }
int getShares(void) {return shares;}
char * getSymbol() {return symbol;}
};
ostream & operator<< (ostream & out, const Stock & s) {
s.printOn(out);
return out;
}
Portfolio Class
#include <iostream.h>
#include <string.h>
class Portfolio {
// =========
char * owner;
static int next_portfolio_id;
static float service_charge;
int portfolio_id;
BankAccount & account;
OrderedCollection<Stock> stocks;
//portfolio assignment not allowed hence private
Portfolio & operator=(const Portfolio & p){}
public:
Portfolio(char * customer, BankAccount & acct):
account(acct), portfolio_id(next_portfolio_id++) {
owner = new char [strlen(customer) + 1];
strcpy(owner, customer);
}
Portfolio (const Portfolio & p) : account(p.account),
portfolio_id(next_portfolio_id++)
{
owner = new char [strlen(p.owner) + 1];
strcpy(owner, p.owner);
OrderedCollection<Stock> & p_stocks = (OrderedCollection<Stock>)
p.stocks;
for(OrderedCollection<Stock>::iterator itr = p_stocks.begin(); itr !=
p_stocks.end(); itr++)
stocks.add(*itr);
}
~Portfolio(void) {
delete owner;
}
void priceChange(char * stock_symbol, float price) {
//change the price of any stock with symbol stock_symbol
for(OrderedCollection<Stock>::iterator itr = stocks.begin(); itr !=
stocks.end(); itr++)
if(strcmp((*itr).getSymbol(),stock_symbol)==0) {
(*itr).setMarketValue(price);
}
}
float market_value() {
float value = account.balance();
for(OrderedCollection<Stock>::iterator itr = stocks.begin(); itr !=
stocks.end(); itr++)
value += ((*itr).getMarketValue() * (*itr).getShares());
return value;
}
void printOn(ostream & out) {
out << "Portfolio#" << portfolio_id << " "<< account << "\n";
for(OrderedCollection<Stock>::iterator itr = stocks.begin(); itr !=
stocks.end(); itr++)
out << *itr << "\n";
out << "portfolio value $" << market_value() << "\n";
}
void add(Stock &s) {stocks.add(s);}
void remove(Stock & s) {stocks.remove(s);}
void buy(Stock & s, int ns) {
//buy ns shares of stock s owned by portfolio
int found = 0;
for(OrderedCollection<Stock>::iterator itr = stocks.begin(); itr !=
stocks.end(); itr++)
if(((*itr) == s) && !found) {
found = 1;
account.withdraw((*itr).getMarketValue() * ns);
account.withdraw(service_charge);
(*itr).setShares((*itr).getShares() + ns);
cout << "TRANSACTION: BUY " << ns << " shares of " << s << " portfolio
$" << market_value() << "\n";
file << "TRANSACTION: BUY " << ns << " shares of " << s << " portfolio
$" << market_value() << "\n";
}
}
void sell(Stock & s, int ns) {
//sell ns shares of stock s owned by portfolio
int found = 0;
for(OrderedCollection<Stock>::iterator itr = stocks.begin(); itr !=
stocks.end(); itr++)
if(((*itr) == s) && !found) {
found = 1;
account.deposit((*itr).getMarketValue() * ns);
account.withdraw(service_charge);
(*itr).setShares((*itr).getShares() - ns);
cout << "TRANSACTION: SELL " << ns << " shares of " << s << "
portfolio $" << market_value() <<"\n";
file << "TRANSACTION: SELL " << ns << " shares of " << s << "
portfolio $" << market_value() <<"\n";
}
}
};
ostream & operator<< (ostream & out, Portfolio & p) {
p.printOn(out);
return out;
}
int Portfolio::next_portfolio_id = 100;
float Portfolio::service_charge = 30.00;
Action classes
#include <iostream.h>
#include <string.h>
class Action :public Observer {
// =======
protected:
Stock & subject;
Portfolio & portfolio;
float action_price;
int num_shares;
public:
Action(Stock & stock, Portfolio & p, int num, float price = 0.0) :
subject(stock), portfolio(p), num_shares(num), action_price(price) {
stock.attach(this);
}
virtual void update(Subject * stock) {cout << "Action::update()";}
virtual void printOn(ostream & out) const {
out << "Action " << this << "\n";}
};
ostream & operator<<(ostream & out, Action & act) {
act.printOn(out);
return out;
}
class BuyAction :public Action {
// ==========
public:
BuyAction(Stock & stock, Portfolio & p, int num, float price = 0.0) :
Action(stock, p, num, price) {}
virtual void update(Subject * stock){
if(action_price <= 0.0) {
portfolio.buy(*(Stock *)stock, num_shares);
stock->dettach(this);
}
else if (((Stock *)stock)->getMarketValue() <= action_price) {
portfolio.buy(*(Stock *)stock, num_shares);
stock->dettach(this);
}
}
};
class SellAction :public Action {
// ===========
public:
SellAction(Stock & stock, Portfolio & p, int num, float price = 0.0) :
Action(stock, p, num, price) {}
virtual void update(Subject * stock){
if(action_price <= 0.0) {
portfolio.sell(*(Stock *)stock, num_shares);
stock->dettach(this);
}
else if (((Stock *)stock)->getMarketValue() >= action_price) {
portfolio.sell(*(Stock *)stock, num_shares);
stock->dettach(this);
}
}
};
Sample main routine
#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
ofstream file ("simulation.txt"); //file to write simulation to
#include "ordcollection.cpp"
#include "bankaccount.cpp"
#include "observer.h"
#include "stock.cpp"
#include "portfolio.cpp"
#include "action.cpp"
int main() {
BankAccount account;
Portfolio portfolio("Lou", account);
account.deposit(10000.00); //opening balance
//create stocks we are interested in
Stock s1("entu", 43.0);
Stock s2("nortel", 44.0);
Stock s3("newbridge", 47.0);
Stock s4("xerox", 49.0);
//add stocks we want to trade to portfolio
portfolio.add(s1);
portfolio.add(s2);
portfolio.add(s3);
portfolio.add(s4);
//print portfolio at start
file << portfolio << "\n";
//create buy and sell actions to buy and sell stocks
//when appropriate. actions with price of 0.0 are traded
//at the current market value of the stock
BuyAction * buy1 = new BuyAction(s1, portfolio, 20);
BuyAction * buy2 = new BuyAction(s2, portfolio, 30);
BuyAction * buy3 = new BuyAction(s3, portfolio, 30);
BuyAction * buy4 = new BuyAction(s1, portfolio, 20, 18.0 );
BuyAction * buy5 = new BuyAction(s2, portfolio, 40, 20.0);
SellAction * sell1 = new SellAction(s1, portfolio, 40, 98.0);
SellAction * sell2 = new SellAction(s2, portfolio, 40, 75);
//read stock market data simulation file and
//react to stock price changes
ifstream infile("stockdata.txt", ios::in);
if (!infile) {
cerr << "file could not be opened" << endl;
exit(1);
}
char stockSymbol[80];
float stockValue;
while (infile >> stockSymbol >> stockValue) {
cout << stockSymbol << " $" << stockValue << "\n";
file << stockSymbol << " $" << stockValue << "\n";
portfolio.priceChange(stockSymbol, stockValue);
}
//output final portfolio value
file << "\n";
file << portfolio;
infile.close();
file.close();
return 0;
}
Sample input file
nortel 55.0
nortel 54.0
nortel 53.0
nortel 15.0
xerox 35.0
newbridge 53.0
nortel 35.0
entu 43.0
entu 15.0
entu 65.0
nortel 75.0
entu 85.0
entu 95.0
nortel 30.0
entu 100.0
Sample Output
Portfolio#100 acct#1000 $10000
entu 0 $43
nortel 0 $44
newbridge 0 $47
xerox 0 $49
portfolio value $10000
nortel $55
TRANSACTION: BUY 30 shares of nortel 30 $55 portfolio $9970
nortel $54
nortel $53
nortel $15
TRANSACTION: BUY 40 shares of nortel 70 $15 portfolio $8740
xerox $35
newbridge $53
TRANSACTION: BUY 30 shares of newbridge 30 $53 portfolio $8710
nortel $35
entu $43
TRANSACTION: BUY 20 shares of entu 20 $43 portfolio $10080
entu $15
TRANSACTION: BUY 20 shares of entu 40 $15 portfolio $9490
entu $65
nortel $75
TRANSACTION: SELL 40 shares of nortel 30 $75 portfolio $14260
entu $85
entu $95
nortel $30
entu $100
TRANSACTION: SELL 40 shares of entu 0 $100 portfolio $14280
Portfolio#100 acct#1000 $11790
entu 0 $100
nortel 30 $30
newbridge 30 $53
xerox 0 $35
portfolio value $14280