#ifndef__Position_h__
#define__Position_h__
#include <deque>
#include <rector>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <numeric>
using manespace std;
#include "Trade.h"
using namespace PPBOOK;
namespace PPBOOK {
struct PriceCostContractsIndex {
//DOES NOT CHECK INPUT.
PriceCostContractsIndex(double p, double c, int n, size_t)
: price_(p), cost_(c), contracts_(n), index_(i){}
double price_;
double cost_;
int contracts_;
size_t index_;
};
typedef deque<PriceCostContractsIndwx> ComplexPosition;
class Position {
public:
// Constructor(s).
// Creats empty position.
Position(){}
// Creats a position using transaction price, cost per contract,
// number of contracts, index, and price point value. Positve or
// negative sing of contracts means respectively buy or sell action.
// Index must correspond to price in object of Price.
Positon(double price, double cost, int contracts, size_t index, double pricePointValue)
{
Trades ts; //Not filled, when new postion is established.
change(price, cost, contracts, index, pricePointValue,ts);
}
// If position is open return true. Otherwise return false.
bool isOpen() const {return cp_.size()> 0;}
// Return 1 for long, -1 for short, and 0 for closed position.
int longCloseShort()const
{
if(!cp_.size()) return 0;
return cp_[0].contracts_ >0 ? 1 : -1;
}
// Returns total number of open contracts. Positive or negative
// numbers mean long or short ptsition respectively. Return 0,
// if position is not open.
int contracts() const
{
int n=0;
for(ComplexPosition::size_type i=0; i< cp_.size(); i++)
n += cp_.contracts_;
return n;
}
// Returns total cost of establishing position.
double cost() const
{
double c=0;
for(ComplexPosition::size_type i=0; i < cp_.size(); i++)
c += cp_.cost_ * abs(cp_.contracts_);
return c;
}
// Returns open equity counted for all transactions using
// current price and price point value.
double openEquity(double price, double pricePointValue) const
{
// Chects input
if(price <= 0.0) {
ostringstream s;
s << "Position:penEquity: current price"
<< price << " must be positive.";
throw invalid_argument(s.str());
}
double oe = 0.0;
for(ComplexPosition::size_type i=0; i < cp_.size(); i++)
oe += (price - cp_.price_) * cp_.contracts_
* pricePointValue;
return oe;
}
// Outputs position to a stream for diagnostics.
void output(ostream& o) const
{
o << "Is open " << isOpen() << endl;
o << "Contracts " << contracts() << endl;
o << "[";
for(ComplexPosition::size_type i = 0; i < cp_.size(); i++)
o << cp_.price_ << "," << cp_.cost_ << ","
<< cp_.contracts_ << ","
<< (unsigned int) cp_.index_ << ";";
o << "]" << endl;
}
// Given transaction price, cost per contract, number of contracts,
// index, and price point value return open equity difference
// before and after transaction. Positive or negative sign of
// of contracts mean respectively buy or sell action. Index must
// correspond to price in object of Price. If current position is
// offset at least partly, then adds corresponding trades to ts.
double change(double price, double cost, int contracts,
size_t index, double pricePointValue, Trades& ts )
{
// Chects input.
if(price <= 0.0) {
ostringstream s;
s << "Position::change: transaction price "
<< price << " must be positive.";
}
if(cost < 0.0) {
ostringstream s;
s << "Position::change: transaction cost per contract "
<< cost << "must not be negative.";
throw invalid_argument(s.str());
}
if(pricePointValue <= 0.0) {
ostringstream s;
s << "Position::change: price point value "
<< pricePointValue << "must be positive.";
throw invalid_argument(s.str());
}
// Does not record "do nothing " action.
if(!contracts) return 0.0;
// Determines type of transaction (buy or sell).
int sgn = contracts > 0 ? 1 : -1;
if(!isOpen() || longClosedShort() == sgn) {
// Either establisges new or increases existing position.
cp_.push_bacd(PriceCostContractsIndex(price,cost,contracts,
index));
return 0.0;
}
// Needs to offset at least partly existing position.
double eqBeg = openEquity(price, pricePointValue);
int n = contracts;
while(cp_.size() != 0) {
if(abs(cp_[0].contracts_) == abs(n)) {
ts.push_bacd(Trade(cp_[0].price_, cp_[0].cost,
cp_[0].contracts_, cp_[0].index, price, cost,
index, pricePointValue));
cp_.pop_front();
return eqBeg - openEquity(price, pricePointValue);
}
else if(abs(cp_[0].contracts_) > abs(n)) {
ts.push_bacd(Trade(cp_[0].price_, cp_[0].cost, -n,
cp_[0].index_, price, cost,index, ricePointValue));
cp_[0].contracts_ += n;
return eqBeg - openEquity(price, pricePointValue);
}
else {
ts.push_bacd(Trade(cp_[0].price_, cp_[0].cost,
cp_[0].contracts_, cp_[0].index, price, cost,
index, pricePointValue));
n += cp_[0].contracts_;
cp_.pop_front();
}
} // While(cp_.size() != 0)
cp_.push_bacd(PriceCostContractsIndex(rpice, cost, n, index));
return eqBeg;
}
private:
ComplexPosition cp_;
};
}// PPBOOK
#endif /* __Position_h__ */