# Calculate Average Price, Cost, (Un)Realized P&L of a position based on executed trades

We have built an algorithmic trading software and need to calculate the following parameters for each position in our portfolio.

• Average Price
• Cost
• Realized Profit & Loss
• Unrealized Profit & Loss

These values can be calculated by going through all prior fills for that security. But in a trading system that potentially has thousands of trades for a single security this might take too long, especially if this calculation has to be done every time one needs those values. So I assume that it is much quicker to calculate those values based on prior values and the last fill received for that security.

Any help is appreciated!

• Move closed trades into a different collection, simple as that.By the way, you should re-calculate an average price each time you get a fill, in that sense you can store and retrieve the avg price (or for that matter any other metric) at any time without additional computational overhead. (unless of course you query or utilize avg price much more seldom than you receive fills). – Matt Sep 25 '13 at 14:42
• Thanks Matt. I believe I understand what you are saying. Store all those values with the Position and whenever a new Fill comes in calculate the new values based on the old values plus qty and price from the new Fill? You are right, this way one would not have to go through the entire collection each time. Do you have any idea where to find an example of those calculations, e.g. new unrealized P/L = f(old unrealized P/L, new Fill)? – Andy Flury Sep 25 '13 at 14:58
• Sorry dont have, but its a trivial calculation, weigh the average price by the previous size underlying the old avg price and the fill size and fill price. – Matt Sep 25 '13 at 15:24
• Thanks Matt. Let me try to come up with those formulas and maybe I can paste them here as an answer to my own question, if that makes sense – Andy Flury Sep 26 '13 at 8:04

We actually managed to come up with the answer to this question ourselves but wanted to share the answer since it might be relevant to others as well.

The calculation depends on what method is used to calculate the cost. There is the FIFO, LIFO and the average cost method, see: http://www.accounting-basics-for-students.com/fifo-method.html

If FIFO or LIFO are used, there is no other way than going through each fill every time.

However for the average cost method one only needs the prior values of the position (quantity, cost and realized P/L) and the latest fill (qty and price).

These are the calculations (in shortened Java code):

closingQty = sign(oldQty) != sign(fillQty) ? min(Math.abs(oldQty), abs(fillQty)) * sign(fillQty) : 0
openingQty = sign(oldQty) == sign(fillQty) ? fillQty : fillQty - closingQty

newQty = oldQty + fillQty
newCost = oldCost + openingQty * fillPrice + closingQty * oldCost / oldQty
newRealizedPL = oldRealizedPL + closingQty * (oldCost / oldQty - fillPrice)


The other values can now be derived:

averagePrice = cost / qty
marketValue = qty * currentPrice
unrealizedPL = cost - marketValue


Thanks to everyone. Any feedback?

• I thought your closingQty was assuming that the position was not being flipped but now that I've written lots of test cases, it handles all of them ! Thank-you ! – user1016736 Jan 19 '14 at 16:25
• C# implementation with test cases: here – user1016736 Jan 19 '14 at 18:49
• The calculation fails for the following test case, which the expected result is 54.0 for realized profit, and the calculated is 52.0: pos.addFill(1, 80.0); pos.addFill(-3, 102.0); pos.addFill(-2, 98.0); pos.addFill(3, 90.0); pos.addFill(-2, 100.0); – Alexandre Verri Mar 28 '14 at 17:06
• This algorithm is pretty standard for calculation of UPL/RPL but it's order dependent. ie.( +100@10, - 50@15, +100@12 will produce different result from +100@10, +100@12, - 50@15 ). This could lead to values that are very difficult to explain – Kozyarchuk Apr 15 '15 at 22:21
• Did you choose the average cost method because of its computational efficiency or another reason? My understanding is that FIFO is the most commonly technique used in finance. – Morten Jul 6 '15 at 15:33

Using Andy Flury answer and bit polishing it gives following Python class for PnL calculator:

class PnLCalculator:
def __init__(self):
self.quantity = 0
self.cost = 0.0
self.market_value = 0.0
self.r_pnl = 0.0
self.average_price = 0.0

def fill(self, n_pos, exec_price):
pos_change = n_pos - self.quantity
direction = np.sign(pos_change)
prev_direction = np.sign(self.quantity)
qty_closing = min(abs(self.quantity), abs(pos_change)) * direction if prev_direction != direction else 0
qty_opening = pos_change if prev_direction == direction else pos_change - qty_closing

new_cost = self.cost + qty_opening * exec_price
if self.quantity != 0:
new_cost += qty_closing * self.cost / self.quantity
self.r_pnl += qty_closing * (self.cost / self.quantity - exec_price)

self.quantity = n_pos
self.cost = new_cost

def update(self, price):
if self.quantity != 0:
self.average_price = self.cost / self.quantity
else:
self.average_price = 0
self.market_value = self.quantity * price
return self.market_value - self.cost


and using it :

positions = np.array([200, 100, -100, 150, 50, 0])
exec_prices = np.array([50.0, 51.0, 49.0, 51.0, 53.0, 52.0])
pnls = []
print('Pos\t|\tR.P&L\t|\tU P&L\t|\tAvgPrc')
print('-' * 55)
pos = PnLCalculator()
pnls = []
for (p,e) in zip(positions, exec_prices):
pos.fill(p, e)
u_pnl = pos.update(e)
print('%+d\t|\t%.1f\t|\t%.1f\t|\t[%.1f]' % (pos.quantity, pos.r_pnl, u_pnl, pos.average_price))
pnls.append(u_pnl + pos.r_pnl)
print('-' * 55)
print(pnls)


This is a partial answer. It shows how to simply calculate Total P&L, which is sum of Realized and UnRealized. From my experience, I didn't really need to split it. Also, It doesn't calculate Average Price, but you can add this functionality if needed.

So, here is the simplest implementation (Java)

public class PNL {
int position = 0;
double money = 0.0;

public void on_execution(double price, int quantity) {
position += quantity;
money -= quantity * price;
}

public double get_pnl(double current_price){
double pnl = money + position * current_price;
return pnl;
}
}


Usage:

• Whenever execution occurs, call on_execution(), where price is execution price, and quantity is execution size. Note, that quantity is signed, i.e. it must be negative in case of SELL.

• Whenever you need the total P&L, call the get_pnl() with current price. The price is up to you to decide. It may be last price, midprice, position liquidation price, etc.

Explanation: The idea here is very intuitive: you change money into position and vice versa. You P&L is sum of money and the value of position. Signed quantity makes it consistent for any direction of trade.

• This method only calculates TPL and does not provide Average Price, Cost, UPL/RPL – Kozyarchuk Apr 15 '15 at 21:04

an implementation in c++ with slightly different signatures:

#ifndef PNL_CALCULATOR_H
#define PNL_CALCULATOR_H

class pnl_calc{

public:

/**
* @brief Default Ctor. Sets everything to 0.0
*/
pnl_calc();

/**
* @brief Call this method every time there is a fill.
* @param fill_qty signed (negative for sold) amount of shares in the most recent transaction
* @param price the price (taken or received) for the transaction
*/
void on_fill(const int& fill_qty, const double& price);

/**
* @brief Call this method every time there is a market price movement.
* @param price the most up-to-date price of an instrument.
*/
void on_price(const double& price);

/**
* @brief get the realized pnl
* @return realized pnl
*/
const double& get_rpnl() const;

/**
* @brief get the average price (never negative because cost and qty are always the same sign)
* @return the average price
*/
const double& get_avg_price() const;

/**
* @brief get the current quantity of shares owned (or sold if negative)
* @return the number of shares as an integer
*/
const int& get_qty() const;

private:
int m_qty; // this is signed
double m_cost; // total dollar amount invested (negative for short)
double m_mkt_val; // total dollar amount currently worth
double m_rlzd_pnl; // realized profit and loss
double m_avg_price; // cost / qty
int sgn(const double& val);
};

#endif // PNL_CALCULATOR_H


and

#include "pnl_calculator.h"

#include <algorithm> // min

pnl_calc::pnl_calc() : m_qty(0), m_cost(0.0), m_mkt_val(0.0), m_rlzd_pnl(0.0), m_avg_price(0.0)
{
}

void pnl_calc::on_fill(const int& fill_qty, const double& price)
{
int direction = sgn(fill_qty);
int prev_direction = sgn(m_qty);

int qty_opening, qty_closing;
if(prev_direction == direction){
qty_closing = 0;
qty_opening = fill_qty;
}else{
qty_closing = std::min(std::abs(m_qty), std::abs(fill_qty)) * direction;  // first case is reversal, second is a partial closeout
qty_opening = fill_qty - qty_closing;
}

double new_cost = m_cost + qty_opening*price;
if(m_qty != 0){
new_cost += qty_closing*m_cost/m_qty;
m_rlzd_pnl += qty_closing*(m_cost/m_qty - price);
}

m_qty += fill_qty;
m_cost = new_cost;

if(m_qty != 0){
m_avg_price = m_cost / m_qty;
}else{
m_avg_price = 0.0;
}

}

void pnl_calc::on_price(const double& price)
{
m_mkt_val = m_qty * price;
}

int pnl_calc::sgn(const double& val)
{
return (0.0 < val) - (val < 0.0);
}

const double& pnl_calc::get_rpnl() const
{
return m_rlzd_pnl;
}

const double& pnl_calc::get_avg_price() const
{
return m_avg_price;
}

const int& pnl_calc::get_qty() const
{
return m_qty;
}