# Pair trading based on cointegration - equity line

I'm preparing a project at my Uni where I have to make a simple pair trading strategy using cointegration between two stocks.

I'm stuck on the equity line calculation. I have prepared opening and closing signals but still have to prepare a plot of equity line but I don't know how to calculate it.

There are some details:

-long position in undervalued stock and short in overvalued

-short selling allowed without boundaries, with the deposit of 100% of the short sell value

-when opening the position, we assume equal shares of short and long positions

-open/close signals are defined by the close price, positions are opened/closed by the next day open price

-transaction fee are 0,1% of position value (at the open and the close)

Yes, that can be really sophisticated even using such nice tools as pandas. But the basic idea is to find position enters & exits to derive cashflow.

Here is my code to derive all that stuff from generated signals (in my backtester signals are fractions of 2 stocks in portfolio for each moment). I hope I've found all bugs here, but no warranties. Total_invested variable is used to calculate total number of shares in portfolio using only initial capital.

Actually, this code is part of my backtest engine that I'm gonna open-source in a few months. It also deals with spreads and fixed commissions, so you may skip this part. It will require adaptation to your conditions, but hope that helps!

Also take a look at articles by Mike Halls-Moore. This site helped me a lot!

def get_portfolio(self, signals, prices):
time_index = prices.index
end = time_index[-1]
# Assets prices
x_prices = prices[self.sym1]
y_prices = prices[self.sym2]
# Assets weights in portfolio
x_weights = signals.map(lambda sig:sig[self.sym1])
y_weights = signals.map(lambda sig:sig[self.sym2])
# Total number of invested shares
total_invested = pd.Series(index = signals.index)
# Need trade enters to calculate portfolio size
enter_points = x_weights.diff().fillna(0)!=0
# Index magic here:
# We need to delete position exits, we suppose there are separate enters/exits
enter_points[enter_points[enter_points].index[1::2]] = False
# capital = w₁⋅total⋅p₁ + w₂⋅total⋅p₂ (cover position)
total_invested[enter_points] = (self.initial_capital
/(x_weights.abs()[enter_points]*x_prices[enter_points]
+ y_weights.abs()[enter_points]*y_prices[enter_points]))
# Zero for right initial open and final close
total_invested.iloc = 0; total_invested.iloc[-1] = 0;
total_invested.fillna(method='ffill', inplace=True)
# Positions rounded to lot sizes
x_positions = (total_invested*x_weights//self.lot1*self.lot1).fillna(0)
y_positions = (total_invested*y_weights//self.lot2*self.lot2).fillna(0)
long_pos = x_positions.copy(); long_pos[long_pos<0] = 0
short_pos = x_positions.copy(); short_pos[short_pos>0] = 0
x_pos_diff = x_positions.diff().fillna(0)
y_pos_diff = y_positions.diff().fillna(0)

# Tribute to the market-makers: spread
# Binary divide because we count twice: enter & exit
# Cashflow & Turnover: not the same!
cashflow = -x_pos_diff*x_prices - y_pos_diff*y_prices
turnover = abs(x_pos_diff)*x_prices + abs(y_pos_diff)*y_prices
# Commission from turnover
commission = turnover * self.commission
commission[cashflow!=0] += self.fixed_commission
portfolio = pd.DataFrame(index=time_index, columns=['EQ','holdings',
'x_positions','y_positions'])
# Value of shares
portfolio['holdings'] = x_positions*x_prices + y_positions*y_prices
# Value of cash, paid commission on each transaction
portfolio['cash'] = self.initial_capital + (cashflow
- commission - tribute).cumsum()
# Equity is the sum of both
portfolio['EQ'] = portfolio['cash'] + portfolio['holdings']
portfolio['turnover'] = turnover