Financial Investment Planning¶

Introduction¶

A financial strategy produces orders. These orders are transmitted to a broker. The broker checks the validity of the order and sends each valid order to the market and sends back a transaction. Every time we buy some shares the broker opens a position with the buy price. If we sell some shares this should be related to a position in order to calculate the profit. Therefore the position information is important mainly in order to calculate profit. We call a buy/sell matching a trade. The sum of all positions are called the portfolio.

Assumptions for this notebook¶

• no user account information
• stock market (consisting of 23 symbols),
• only market orders,
• no short positions,
• the price is determined by the historical daily candle data.

TableOfContents¶

Symbol, the price of a symbol¶

Symbols are the financial instrument that we can invest in. At a given point, there is no known price but the price depends on the buyers' and sellers' bid prices. The price of a symbol is calculated by the market for a given order. Therefore the price of a symbol may change constantly. Usually symbols have candle data (5min, 1day) etc.. storing open, close, low and high values.

In [2]:
import pandas as pd
from pandas.tseries.offsets import BDay
import datetime
import warnings
from copy import deepcopy
import numpy as np
%matplotlib inline
from scipy.stats import linregress
import matplotlib.pyplot as plt
from math import sqrt
import scipy.stats as st

/home/can/anaconda2/lib/python2.7/site-packages/pandas/computation/__init__.py:19: UserWarning: The installed version of numexpr 2.4.4 is not supported in pandas and will be not be used

UserWarning)

In [3]:
symbols = ['AEFES.IS', 'AKENR.IS', 'AKSA.IS', 'AKBNK.IS', 'GARAN.IS',
'MGROS.IS', 'THYAO.IS', 'TRKCM.IS', 'ZOREN.IS', 'XU100.IS',
'ALARK.IS', 'CIMSA.IS',  'HALKB.IS', 'TKFEN.IS', 'FROTO.IS',
'DOAS.IS', 'KARSN.IS', 'TMSN.IS', 'YKBNK.IS', 'VAKBN.IS',
'ULKER.IS', 'TCELL.IS', 'SISE.IS', 'EREGL.IS', 'PETKM.IS',
'BJKAS.IS', 'AFYON.IS', 'KOZAL.IS', 'GOODY.IS', 'VAKFN.IS']

start = datetime.datetime(2015,1,1)
end = datetime.datetime.now()

In [4]:
prices = pd.DataFrame()
for symbol in symbols:
f = web.DataReader(symbol, 'yahoo', start, end)
f['symbol'] = symbol
prices = pd.concat([prices, f])
prices;


• cash dividend (d): closing_price - d
• share dividend (x:y): closing_price* (y+x)/x
• share split (x:y): closing_price * y/x
In [5]:
prices = prices.pivot(columns="symbol", values="Adj Close")

In [6]:
prices.tail()

Out[6]:
symbol AEFES.IS AFYON.IS AKBNK.IS AKENR.IS AKSA.IS ALARK.IS BJKAS.IS CIMSA.IS DOAS.IS EREGL.IS ... THYAO.IS TKFEN.IS TMSN.IS TRKCM.IS ULKER.IS VAKBN.IS VAKFN.IS XU100.IS YKBNK.IS ZOREN.IS
Date
2016-09-26 18.70 5.69 7.96 0.94 8.20 3.44 4.58 14.92 9.93 4.28 ... 5.12 7.37 7.51 2.44 21.44 4.43 1.17 76725.7031 3.66 1.57
2016-09-27 18.69 5.72 8.13 0.95 8.20 3.45 4.72 14.98 9.92 4.24 ... 5.13 7.53 7.51 2.43 21.08 4.54 1.17 77160.7031 3.70 1.58
2016-09-28 18.49 5.85 8.31 0.95 8.27 3.52 4.76 15.08 9.97 4.20 ... 5.16 7.49 7.52 2.45 21.24 4.70 1.18 77677.7969 3.76 1.60
2016-09-29 18.40 6.19 8.13 0.96 8.20 3.59 4.41 15.07 9.93 4.19 ... 5.16 7.70 7.56 2.48 21.22 4.62 1.17 77076.7969 3.70 1.60
2016-09-30 18.17 6.30 8.04 0.95 8.16 3.57 4.26 14.89 10.05 4.13 ... 5.14 7.72 7.53 2.49 21.38 4.59 1.18 76488.3984 3.67 1.59

5 rows × 30 columns

In [7]:
dividends_and_splits= pd.DataFrame()

for symbol in symbols:
if len(f) > 0:
f['symbol'] = symbol
dividends_and_splits = pd.concat([dividends_and_splits, f])

In [8]:
Splits = dividends_and_splits[dividends_and_splits["action"] == 'SPLIT']
Dividends = dividends_and_splits[dividends_and_splits["action"] == 'DIVIDEND']
Splits

Out[8]:
action value symbol
2013-06-26 SPLIT 0.869565 THYAO.IS
2011-07-11 SPLIT 0.833333 THYAO.IS
2013-07-03 SPLIT 0.980392 TRKCM.IS
2012-07-16 SPLIT 0.869565 TRKCM.IS
2010-11-25 SPLIT 0.500000 DOAS.IS
2013-07-04 SPLIT 0.961538 SISE.IS
2012-07-10 SPLIT 0.909091 SISE.IS
2011-06-20 SPLIT 0.884956 SISE.IS
2013-04-12 SPLIT 0.884956 EREGL.IS
2012-04-30 SPLIT 0.699301 EREGL.IS
2011-03-15 SPLIT 0.746269 EREGL.IS
2010-07-02 SPLIT 0.250000 PETKM.IS
2010-01-18 SPLIT 0.040000 AFYON.IS
2010-06-16 SPLIT 0.500000 KOZAL.IS
2016-06-01 SPLIT 0.045455 GOODY.IS
2013-07-29 SPLIT 0.925926 VAKFN.IS
2012-06-15 SPLIT 0.833333 VAKFN.IS
2011-07-20 SPLIT 0.500000 VAKFN.IS
In [9]:
Dividends.head()

Out[9]:
action value symbol
2016-05-30 DIVIDEND 0.245 AEFES.IS
2015-05-29 DIVIDEND 0.460 AEFES.IS
2013-05-30 DIVIDEND 0.450 AEFES.IS
2012-05-29 DIVIDEND 0.450 AEFES.IS
2011-05-27 DIVIDEND 0.480 AEFES.IS

OrderAndTransaction¶

TOC

We give an order buy/sell a symbol of some amount of shares to a brocker which accepts this order and transmit to the market. The response of an order is a transaction and it contains the status of the orders, the price and the commissions.

In [10]:
order = {'symbol':'AKBNK.IS',
'shares':100,
'time':'2016-05-12'}

transaction = {'status':'accepted',
'symbol': 'GARAN',
'shares':100,
'price':5.2,
'commision':2,
'time':'2016-05-13'}


In real situation, when we pass the order to a brocker, the brocker responds with a transaction. We will simulate this situation with the following function.

In [11]:
# TODO: check user account's free cash and update it accordingly
def execute_order(order, holdings):
'Simulates the broker/market and creates a transaction.'
transaction = deepcopy(order)
symbol, shares, time = order['symbol'], order['shares'], order['time']

if order['action']=='sell':
if (holdings is None or
not (symbol in holdings.index) or
holdings.loc[symbol]['shares'] < order['shares']):

warnings.warn('Your order ' + str(order) + ' is rejected.')
transaction['status'] = 'rejected'
return transaction

transaction['status'] = 'accepted'
price = get_price(symbol, time)
commision = commision_calculation(order, price)
transaction['price'], transaction['commision'] = price, commision
return transaction

def get_price(symbol, time = None, price_source=prices):
'Returns the last price of the symbol. We assume that prices is a pandas object.'
if time is None:
time = str(datetime.datetime.now())

try:
closest_time = (price_source.index[time >= price_source.index]).sort_values()[-1]
return price_source[symbol].loc[closest_time]
except ValueError:
raise ValueError("We don't have historical data for an order at " + order_time)
except IndexError:
raise IndexError("We don't have historical data for an order at " + order_time)

def commision_calculation(order, price, commission_ratio=0.0001):
'Calculates commision to be paid.'
return order['shares']*price*commission_ratio

def current_time(prices=prices):
'Returns the maximum date from the prices table.'
return max(prices.index).strftime("%Y-%m-%d")

In [12]:
execute_order(order, [])

Out[12]:
{'action': 'buy',
'commision': 0.076999999999999999,
'price': 7.7000000000000002,
'shares': 100,
'status': 'accepted',
'symbol': 'AKBNK.IS',
'time': '2016-05-12'}

TODO: make a real example

Every time we have an accepted buy order we create a position. A trade is a matching of buy/sell transactions of the same symbol. We need these trade objects in order to calculate the current cost of the portfolio and realized profits.

Example¶

Transactions

• $t_1$: (GARAN, buy, 100, 7.02)
• $t_2$: (GARAN, buy, 200, 7.05)
• $t_3$: (GARAN, sell, 150, 7.10)

Cost

• $t_1$: 702
• $t_2$: 702 + 1410
• $t_3$: 702 + 1410 - $x$

In order to calculate $x$, we need to match the sell order at t3 with the buy orders t1 and t2. For the matching we assume first-in first-out rule. We first match the sell order at t3 with the buy order at t1 and then the remaining with the order at t2.

In [13]:
def apply_transaction(transaction, positions, trades):
'Update positions and trades with the transaction.'
if transaction["status"] == "accepted":
symbol, action, shares = transaction["symbol"], transaction["action"], transaction["shares"]
price, time = transaction["price"], transaction['time']
position = {'type':'long',
'symbol':symbol,
'initial_shares':shares,
'shares':shares,
'price': price,
'cost': price*shares,
'time': time}
positions.append(position)
else:

"""We will select the positions with the same symbol and order them according to time desc.
Until we finish the order's volume we match it with a position. If a position is fulfilled,
we continue with the next one in the order. We create a trade, we remove the amount traded
from the position. If the position's volume is empty we remove the position from the list.

Assumption: Since the broker rejects sells orders greater then our holdings,
we assume that transaction.shares <= sum(positions.shares)."""

sorted(positions, key=lambda k: k['time'])
shares, time, symbol = transaction["shares"], transaction["time"], transaction["symbol"]

for position in positions:
if not shares > 0:
break
if position["symbol"] == transaction["symbol"] and position["shares"] > 0:
'time':time,
'sell_price': sell_price,
'profit': profit}

In [14]:
def calculate_portfolio(positions):
if len(positions) == 0:
return []
else:
temp = pd.DataFrame(positions)
return temp.pivot_table(index='symbol', aggfunc='sum', values=["cost", 'shares'])

In [15]:
orders = [
{'symbol':'GARAN.IS', 'shares':120, 'action':'sel', 'time':'2016-05-22 09:50:00'},
{'symbol':'AKBNK.IS', 'shares':200, 'action':'sell', 'time':'2016-05-24 12:00:00'},
{'symbol':'AKBNK.IS', 'shares':110, 'action':'sell', 'time':'2016-05-27 00:00:00'},
{'symbol':'ZOREN.IS', 'shares':50, 'action':'sell', 'time':'2016-05-28 00:00:00'},
]

pd.DataFrame(orders)

Out[15]:
action shares symbol time
0 buy 100 GARAN.IS 2016-05-15 10:00:00
1 buy 100 GARAN.IS 2016-05-20 11:00:00
2 sel 120 GARAN.IS 2016-05-22 09:50:00
3 buy 100 AKBNK.IS 2016-05-20 16:30:00
4 buy 100 AKBNK.IS 2016-05-21 10:57:23
5 buy 220 AKBNK.IS 2016-05-24 10:00:00
6 sell 200 AKBNK.IS 2016-05-24 12:00:00
7 sell 110 AKBNK.IS 2016-05-27 00:00:00
8 sell 50 ZOREN.IS 2016-05-28 00:00:00

Account¶

In [16]:
def execute_orders(orders, transactions, positions, trades):
"""Calls execute_order function for each order in the order list.
"""

portfolio = calculate_portfolio(positions)
for order in orders:
transaction = execute_order(order, portfolio)
transactions.append(transaction)
portfolio = calculate_portfolio(positions)

In [17]:
transactions, positions, trades = [], [], []

/home/can/.local/lib/python2.7/site-packages/ipykernel/__main__.py:12: UserWarning: Your order {'action': 'sell', 'symbol': 'ZOREN.IS', 'shares': 50, 'time': '2016-05-28 00:00:00'} is rejected.

In [18]:
pd.DataFrame(transactions)

Out[18]:
action commision price shares status symbol time
0 buy 0.07510 7.51 100 accepted GARAN.IS 2016-05-15 10:00:00
1 buy 0.07250 7.25 100 accepted GARAN.IS 2016-05-20 11:00:00
2 sel 0.08700 7.25 120 accepted GARAN.IS 2016-05-22 09:50:00
3 buy 0.07500 7.50 100 accepted AKBNK.IS 2016-05-20 16:30:00
4 buy 0.07500 7.50 100 accepted AKBNK.IS 2016-05-21 10:57:23
5 buy 0.17710 8.05 220 accepted AKBNK.IS 2016-05-24 10:00:00
6 sell 0.16100 8.05 200 accepted AKBNK.IS 2016-05-24 12:00:00
7 sell 0.08745 7.95 110 accepted AKBNK.IS 2016-05-27 00:00:00
8 sell NaN NaN 50 rejected ZOREN.IS 2016-05-28 00:00:00
In [19]:
def summary(transactions, positions, trades):
print "***Transactions***".center(70)
print '-' * 70
print pd.DataFrame(transactions)
print ''

print "***Positions***".center(70)
print '-' * 70
print pd.DataFrame(positions)
print ''

print '-' * 70


                          ***Transactions***
----------------------------------------------------------------------
action  commision  price  shares    status    symbol                 time
0    buy    0.07510   7.51     100  accepted  GARAN.IS  2016-05-15 10:00:00
1    buy    0.07250   7.25     100  accepted  GARAN.IS  2016-05-20 11:00:00
2    sel    0.08700   7.25     120  accepted  GARAN.IS  2016-05-22 09:50:00
3    buy    0.07500   7.50     100  accepted  AKBNK.IS  2016-05-20 16:30:00
4    buy    0.07500   7.50     100  accepted  AKBNK.IS  2016-05-21 10:57:23
5    buy    0.17710   8.05     220  accepted  AKBNK.IS  2016-05-24 10:00:00
6   sell    0.16100   8.05     200  accepted  AKBNK.IS  2016-05-24 12:00:00
7   sell    0.08745   7.95     110  accepted  AKBNK.IS  2016-05-27 00:00:00
8   sell        NaN    NaN      50  rejected  ZOREN.IS  2016-05-28 00:00:00

***Positions***
----------------------------------------------------------------------
cost  initial_shares  price  shares    symbol                 time  type
0    0.0             100   7.51       0  GARAN.IS  2016-05-15 10:00:00  long
1  580.0             100   7.25      80  GARAN.IS  2016-05-20 11:00:00  long
2    0.0             100   7.50       0  AKBNK.IS  2016-05-20 16:30:00  long
3    0.0             100   7.50       0  AKBNK.IS  2016-05-21 10:57:23  long
4  885.5             220   8.05     110  AKBNK.IS  2016-05-24 10:00:00  long

----------------------------------------------------------------------
buy_price  profit  sell_price  shares    symbol                 time
0       7.51   -26.0        7.25     100  GARAN.IS  2016-05-22 09:50:00
1       7.25     0.0        7.25      20  GARAN.IS  2016-05-22 09:50:00
2       7.50    55.0        8.05     100  AKBNK.IS  2016-05-24 12:00:00
3       7.50    55.0        8.05     100  AKBNK.IS  2016-05-24 12:00:00
4       8.05   -11.0        7.95     110  AKBNK.IS  2016-05-27 00:00:00


Portfolio¶

TOC

An asset is financial instruments that we own. The assets can be calculated using transaction reports. Market value is the current value of an asset. It represent the value as if we want to sell the asset right now. It is calculated by some estimation of the current price of the corresponding symbol. The collection of assets that we own are called our portfolio.

Portfolio Market Value¶
In [20]:
portfolio = calculate_portfolio(positions)
portfolio

Out[20]:
cost shares
symbol
AKBNK.IS 885.5 110
GARAN.IS 580.0 80
In [21]:
x = pd.Series({"GARAN.IS": get_price("GARAN.IS"), "AKBNK.IS": get_price("AKBNK.IS")})

In [22]:
portfolio["current_price"] = x

In [23]:
portfolio["shares"] * portfolio["current_price"]

Out[23]:
symbol
AKBNK.IS    884.4
GARAN.IS    636.0
dtype: float64
In [24]:
def get_prices(assets, time = None):
return {symbol: get_price(symbol, time) for symbol in assets}

pd.Series(get_prices(portfolio.index))

Out[24]:
AKBNK.IS    8.04
GARAN.IS    7.95
dtype: float64
In [25]:
portfolio["shares"] / 2

Out[25]:
symbol
AKBNK.IS    55.0
GARAN.IS    40.0
Name: shares, dtype: float64
In [26]:
def current_performance(portfolio, time=None):
portfolio["current_price"] = pd.Series(get_prices(portfolio.index, time))
portfolio["market_value"] = portfolio["shares"] * portfolio["current_price"]
portfolio["profit"] = portfolio["market_value"] - portfolio["cost"]

total_market_value = portfolio.market_value.sum()
portfolio["weight"] = portfolio["market_value"] / total_market_value

In [27]:
current_performance(portfolio)
portfolio

Out[27]:
cost shares current_price market_value profit weight
symbol
AKBNK.IS 885.5 110 8.04 884.4 -1.1 0.581689
GARAN.IS 580.0 80 7.95 636.0 56.0 0.418311
In [28]:
def historical_performance(transactions, prices):
"Returns historical market value of a portfolio."
starting_date = min(transactions, key=lambda x: x["time"])["time"]
ending_date = datetime.datetime.now()
symbols = set([t["symbol"] for t in transactions if t["status"]=="accepted"] )

symbol_price = (prices.loc[starting_date:ending_date][list(symbols)])

holdings_list = holdings(transactions)

return (holdings_list
.fillna(method='ffill')
.reindex(symbol_price.index.union(holdings_list.index))
.fillna(method='ffill')
.reindex(symbol_price.index)
.mul(symbol_price).sum(axis=1)
)

def holdings(transactions):
t = pd.DataFrame(transactions)
t["sign"] = t["action"].apply(lambda x: 1 if x=="buy" else -1)
t["signed_shares"] = t["sign"] * t["shares"]
t["time"] = pd.to_datetime(t["time"])

return (t.query("status == 'accepted'")
.pivot_table(values="signed_shares", columns="symbol", index="time")
.cumsum()
)

In [29]:
symbols = set([t["symbol"] for t in transactions if t["status"]=="accepted"] )
starting_date = min(transactions, key=lambda x: x["time"])["time"]
ending_date = datetime.datetime.now()
symbol_price = (prices.loc[starting_date:ending_date][list(symbols)])

In [30]:
def compare_with_benchmark(historical_value, benchmark_symbol="XU100.IS"):
algo = (historical_value[historical_value > 0].pct_change() + 1).cumprod()
algo.name = "Algorithm"
algo.plot(legend=True)
print "Algorithm performance:", (algo.ix[-1] - 1)*100

start_date = historical_value.index[0]

benchmark = (prices[benchmark_symbol].dropna().pct_change().loc[start_date:] + 1).cumprod()
benchmark.name = "Benchmark"
benchmark.plot(legend = True, figsize=[15,10])
print "Benchmark performance:", (benchmark.ix[-1] - 1)*100

In [31]:
historical_performance(transactions, prices).plot(figsize= [15,10])

Out[31]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fc0b3324410>

DividendAndSplit¶

TOC

In [32]:
def paid_dividends(transactions, dividends):

start_date = min(transactions, key=lambda x: x["time"])["time"]
end_date = datetime.datetime.now()

H= holdings(transactions)
H.index = pd.to_datetime(H.index)

H = (H.reindex(pd.date_range(start=start_date, end=end_date, freq='D'))
.fillna(method='ffill')
.fillna(0))

return (pd.melt(Dividends[Dividends.symbol.apply(lambda x: x in H.columns)]
.reset_index()
.rename(columns={'index':'time'})
.pivot_table(values="value", columns="symbol", index = 'time')
.reindex(H.index)
.mul(H)
.reset_index()
.rename(columns={'index':'time'})
, id_vars = 'time', var_name= 'symbol', value_name='paid_dividend'
)
).query("paid_dividend > 0")

In [33]:
paid_dividends(transactions, Dividends)

Out[33]:
time symbol paid_dividend

Rebalance¶

TOC

In [34]:
def rebalance(portfolio, target_weights, target_value = None, time = None):
"""New weights is a dictionary of {symbol: weights}.
Creates orders to make portfolio's weight 'new weights'.
Time indicates execution of rebalance operation.
"""
if time is None:
time = current_time()

if target_value is None:
target_value = portfolio.market_value.sum()

if len(portfolio)>0:
target_weights = {s:target_weights[s] if s in target_weights.keys() else 0
for s in set(portfolio.index | target_weights.keys())}

# check if the weights sum up to 1.
assert(sum(target_weights.values()) == 1)

rebalance_orders = []

target_market_value = {s:target_weights[s]*target_value for s in target_weights.keys()}

for symbol, weight in target_weights.iteritems():

if len(portfolio)>0 and symbol in portfolio.index:
delta_value = target_market_value[symbol] - portfolio["market_value"].loc[symbol]

if weight:
delta_lot = int(abs(delta_value / get_price(symbol, time)))
else:
delta_lot = portfolio["shares"].loc[symbol]

if delta_lot:
if delta_value > 0:
else:
action = 'sell'

order = {'symbol': symbol, 'shares': delta_lot, 'action': action, 'time': time}
rebalance_orders.append(order)
else:
delta_lot = int(target_market_value[symbol] / get_price(symbol, time))
order = {'symbol': symbol, 'shares': delta_lot, 'action': 'buy', 'time': time}
rebalance_orders.append(order)

return rebalance_orders

In [35]:
portfolio

Out[35]:
cost shares current_price market_value profit weight
symbol
AKBNK.IS 885.5 110 8.04 884.4 -1.1 0.581689
GARAN.IS 580.0 80 7.95 636.0 56.0 0.418311
In [36]:
portfolio["market_value"].loc['AKBNK.IS']

Out[36]:
884.39999999999986
In [37]:
orders_to_rebalance = rebalance(portfolio, {"AKBNK.IS":0.50, "GARAN.IS": 0.20, "ZOREN.IS": 0.30 })
pd.DataFrame(orders_to_rebalance)

Out[37]:
action shares symbol time
0 sell 41 GARAN.IS 2016-09-30
2 sell 15 AKBNK.IS 2016-09-30
In [38]:
execute_orders(orders_to_rebalance, transactions, positions, trades)

                          ***Transactions***
----------------------------------------------------------------------
action  commision  price  shares    status    symbol                 time
0     buy   0.075100   7.51     100  accepted  GARAN.IS  2016-05-15 10:00:00
1     buy   0.072500   7.25     100  accepted  GARAN.IS  2016-05-20 11:00:00
2     sel   0.087000   7.25     120  accepted  GARAN.IS  2016-05-22 09:50:00
3     buy   0.075000   7.50     100  accepted  AKBNK.IS  2016-05-20 16:30:00
4     buy   0.075000   7.50     100  accepted  AKBNK.IS  2016-05-21 10:57:23
5     buy   0.177100   8.05     220  accepted  AKBNK.IS  2016-05-24 10:00:00
6    sell   0.161000   8.05     200  accepted  AKBNK.IS  2016-05-24 12:00:00
7    sell   0.087450   7.95     110  accepted  AKBNK.IS  2016-05-27 00:00:00
8    sell        NaN    NaN      50  rejected  ZOREN.IS  2016-05-28 00:00:00
9    sell   0.032595   7.95      41  accepted  GARAN.IS           2016-09-30
10    buy   0.045474   1.59     286  accepted  ZOREN.IS           2016-09-30
11   sell   0.012060   8.04      15  accepted  AKBNK.IS           2016-09-30

***Positions***
----------------------------------------------------------------------
cost  initial_shares  price  shares    symbol                 time  type
0    0.00             100   7.51       0  GARAN.IS  2016-05-15 10:00:00  long
1  282.75             100   7.25      39  GARAN.IS  2016-05-20 11:00:00  long
2    0.00             100   7.50       0  AKBNK.IS  2016-05-20 16:30:00  long
3    0.00             100   7.50       0  AKBNK.IS  2016-05-21 10:57:23  long
4  764.75             220   8.05      95  AKBNK.IS  2016-05-24 10:00:00  long
5  454.74             286   1.59     286  ZOREN.IS           2016-09-30  long

----------------------------------------------------------------------
buy_price  profit  sell_price  shares    symbol                 time
0       7.51  -26.00        7.25     100  GARAN.IS  2016-05-22 09:50:00
1       7.25    0.00        7.25      20  GARAN.IS  2016-05-22 09:50:00
2       7.50   55.00        8.05     100  AKBNK.IS  2016-05-24 12:00:00
3       7.50   55.00        8.05     100  AKBNK.IS  2016-05-24 12:00:00
4       8.05  -11.00        7.95     110  AKBNK.IS  2016-05-27 00:00:00
5       7.25   28.70        7.95      41  GARAN.IS           2016-09-30
6       8.05   -0.15        8.04      15  AKBNK.IS           2016-09-30

In [39]:
portfolio = calculate_portfolio(positions)
portfolio

Out[39]:
cost shares
symbol
AKBNK.IS 764.75 95
GARAN.IS 282.75 39
ZOREN.IS 454.74 286
In [40]:
current_performance(portfolio)
portfolio

Out[40]:
cost shares current_price market_value profit weight
symbol
AKBNK.IS 764.75 95 8.04 763.80 -0.95 0.499676
GARAN.IS 282.75 39 7.95 310.05 27.30 0.202834
ZOREN.IS 454.74 286 1.59 454.74 0.00 0.297490
In [41]:
portfolio, transactions, positions, trades = [], [], [], []

orders_to_rebalance = rebalance([], {'AKBNK.IS': 0.50, 'GARAN.IS': 0.50}, 1000000)
pd.DataFrame(orders_to_rebalance)

Out[41]:
action shares symbol time
In [42]:
execute_orders(orders_to_rebalance, transactions, positions, trades)

                          ***Transactions***
----------------------------------------------------------------------
action  commision  price  shares    status    symbol        time
0    buy  49.999935   7.95   62893  accepted  GARAN.IS  2016-09-30
1    buy  49.999956   8.04   62189  accepted  AKBNK.IS  2016-09-30

***Positions***
----------------------------------------------------------------------
cost  initial_shares  price  shares    symbol        time  type
0  499999.35           62893   7.95   62893  GARAN.IS  2016-09-30  long
1  499999.56           62189   8.04   62189  AKBNK.IS  2016-09-30  long

----------------------------------------------------------------------
Empty DataFrame
Columns: []
Index: []

In [43]:
portfolio = calculate_portfolio(positions)
current_performance(portfolio)
portfolio

Out[43]:
cost shares current_price market_value profit weight
symbol
AKBNK.IS 499999.56 62189 8.04 499999.56 0.0 0.5
GARAN.IS 499999.35 62893 7.95 499999.35 0.0 0.5

Backtest¶

TOC

Algoritm Example: Beta¶

• Repeat each month the following procedure:
• Calculate beta values of each stocks against BIST 100 index. time window for beta calculation?
• Choose 10 stocks with the highest beta value.
• Rebalance the portfolio to be equal weight.
In [44]:
capital_base = 100000
start, end = np.datetime64('2016-01-20 00:00:00'), np.datetime64('2016-07-18 00:00:00')
running_points = [date for date in prices.index if start <= date <= end]


http://markets.ft.com/data/lexicon/term/beta

We use Beta 5Y from the Multex Ratios and Statistics table, which is provided to us by Reuters. The Market Guide Beta is the slope of the 60 month regression line of the percentage price change of the stock relative to the percentage price change of the S&P 500. Beta values are not calculated if less than 24 months of pricing is available.

In [45]:
def beta(price_data, start, end):
returns = (prices.loc[start:end]
.resample('3BMS', 'first')
.pct_change()
.dropna())

beta_values = {symbol: linregress(returns["XU100.IS"], returns[symbol])[0]
for symbol in price_data.columns if symbol != 'XU100.IS'}
return beta_values

In [46]:
portfolio, transactions, positions, trades = [], [], [], []

for t in running_points:
time = t.strftime("%Y-%m-%d")

if t in pd.date_range(start=running_points[0], periods=12, freq='BM'):
print t
print '-'*20
beta_values = beta(prices, prices.index[0], t)
for s in sorted(beta_values, key=beta_values.get, reverse=True):
print s, beta_values[s]

n = 5
new_weights = {s: 1./n for s in sorted(beta_values, key=beta_values.get, reverse=True)[:n]}
print new_weights

target_value = None if len(portfolio) else capital_base

if len(portfolio) > 0:
current_performance(portfolio, time)

rebalance_orders = rebalance(portfolio, new_weights, target_value, time)

print "Before Orders"
print "-"*20
print portfolio
print " "

print "Orders"
print "-"*20
print pd.DataFrame(rebalance_orders)
print " "
portfolio = calculate_portfolio(positions)
current_performance(portfolio, time)

print "After Orders"
print "-"*20
print portfolio
print " "

portfolio = calculate_portfolio(positions)

2016-01-29 00:00:00
--------------------
AFYON.IS 56.9642159504
GOODY.IS 6.87604665207
DOAS.IS 5.19504241764
AEFES.IS 3.51989365886
KOZAL.IS 3.3448762139
AKSA.IS 3.12012336438
EREGL.IS 2.84900427814
SISE.IS 2.51218079997
TCELL.IS 2.10369051414
FROTO.IS 2.09457851314
PETKM.IS 1.81512146095
TRKCM.IS 1.48578088376
THYAO.IS 1.18962314346
MGROS.IS 1.15606357034
TKFEN.IS 1.00811513171
GARAN.IS 1.00615148771
AKBNK.IS 0.886587616544
YKBNK.IS 0.867160616649
HALKB.IS 0.855486536853
ALARK.IS 0.820330070269
VAKBN.IS 0.750041809138
ZOREN.IS 0.646334486257
VAKFN.IS 0.251506076805
CIMSA.IS -0.00851550187079
AKENR.IS -0.796155439582
ULKER.IS -1.00029164062
KARSN.IS -1.51552933437
TMSN.IS -1.73699367046
BJKAS.IS -3.00339814457
{'DOAS.IS': 0.2, 'AFYON.IS': 0.2, 'AEFES.IS': 0.2, 'KOZAL.IS': 0.2, 'GOODY.IS': 0.2}
Before Orders
--------------------
[]

Orders
--------------------
action  shares    symbol        time

After Orders
--------------------
cost  shares  current_price  market_value  profit    weight
symbol
AEFES.IS  19999.40000    1108       18.05000   19999.40000     0.0  0.200036
AFYON.IS  19999.44000    3384        5.91000   19999.44000     0.0  0.200036
DOAS.IS   19991.44870    2059        9.70930   19991.44870     0.0  0.199956
GOODY.IS  19999.99295  417101        0.04795   19999.99295     0.0  0.200042
KOZAL.IS  19988.76000    1594       12.54000   19988.76000     0.0  0.199930

2016-02-29 00:00:00
--------------------
AFYON.IS 56.9642159504
GOODY.IS 6.87604665207
DOAS.IS 5.19504241764
AEFES.IS 3.51989365886
KOZAL.IS 3.3448762139
AKSA.IS 3.12012336438
EREGL.IS 2.84900427814
SISE.IS 2.51218079997
TCELL.IS 2.10369051414
FROTO.IS 2.09457851314
PETKM.IS 1.81512146095
TRKCM.IS 1.48578088376
THYAO.IS 1.18962314346
MGROS.IS 1.15606357034
TKFEN.IS 1.00811513171
GARAN.IS 1.00615148771
AKBNK.IS 0.886587616544
YKBNK.IS 0.867160616649
HALKB.IS 0.855486536853
ALARK.IS 0.820330070269
VAKBN.IS 0.750041809138
ZOREN.IS 0.646334486257
VAKFN.IS 0.251506076805
CIMSA.IS -0.00851550187079
AKENR.IS -0.796155439582
ULKER.IS -1.00029164062
KARSN.IS -1.51552933437
TMSN.IS -1.73699367046
BJKAS.IS -3.00339814457
{'DOAS.IS': 0.2, 'AFYON.IS': 0.2, 'AEFES.IS': 0.2, 'KOZAL.IS': 0.2, 'GOODY.IS': 0.2}
Before Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AEFES.IS  19999.40000    1108       16.98000   18813.84000 -1185.56000
AFYON.IS  19999.44000    3384        5.98000   20236.32000   236.88000
DOAS.IS   19991.44870    2059       10.08480   20764.60320   773.15450
GOODY.IS  19999.99295  417101        0.04646   19378.51246  -621.48049
KOZAL.IS  19988.76000    1594       16.24000   25886.56000  5897.80000

weight
symbol
AEFES.IS  0.179043
AFYON.IS  0.192580
DOAS.IS   0.197608
GOODY.IS  0.184417
KOZAL.IS  0.246351

Orders
--------------------
action  shares    symbol        time
3   sell     299  KOZAL.IS  2016-02-29

After Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AEFES.IS  22189.82000    1237       16.98000    21004.2600 -1185.56000
AFYON.IS  20776.84000    3514        5.98000    21013.7200   236.88000
DOAS.IS   20233.48390    2083       10.08480    21006.6384   773.15450
GOODY.IS  21637.42919  452345        0.04646    21015.9487  -621.48049
KOZAL.IS  16239.30000    1295       16.24000    21030.8000  4791.50000

weight
symbol
AEFES.IS  0.199905
AFYON.IS  0.199995
DOAS.IS   0.199927
GOODY.IS  0.200016
KOZAL.IS  0.200157

2016-03-31 00:00:00
--------------------
AFYON.IS 56.9642159504
GOODY.IS 6.87604665207
DOAS.IS 5.19504241764
AEFES.IS 3.51989365886
KOZAL.IS 3.3448762139
AKSA.IS 3.12012336438
EREGL.IS 2.84900427814
SISE.IS 2.51218079997
TCELL.IS 2.10369051414
FROTO.IS 2.09457851314
PETKM.IS 1.81512146095
TRKCM.IS 1.48578088376
THYAO.IS 1.18962314346
MGROS.IS 1.15606357034
TKFEN.IS 1.00811513171
GARAN.IS 1.00615148771
AKBNK.IS 0.886587616544
YKBNK.IS 0.867160616649
HALKB.IS 0.855486536853
ALARK.IS 0.820330070269
VAKBN.IS 0.750041809138
ZOREN.IS 0.646334486257
VAKFN.IS 0.251506076805
CIMSA.IS -0.00851550187079
AKENR.IS -0.796155439582
ULKER.IS -1.00029164062
KARSN.IS -1.51552933437
TMSN.IS -1.73699367046
BJKAS.IS -3.00339814457
{'DOAS.IS': 0.2, 'AFYON.IS': 0.2, 'AEFES.IS': 0.2, 'KOZAL.IS': 0.2, 'GOODY.IS': 0.2}
Before Orders
--------------------
cost  shares  current_price  market_value       profit  \
symbol
AEFES.IS  22189.82000    1237       21.16000   26174.92000   3985.10000
AFYON.IS  20776.84000    3514        6.37000   22384.18000   1607.34000
DOAS.IS   20233.48390    2083       11.24710   23427.70930   3194.22540
GOODY.IS  21637.42919  452345        0.08757   39611.85165  17974.42246
KOZAL.IS  16239.30000    1295       18.07000   23400.65000   7161.35000

weight
symbol
AEFES.IS  0.193889
AFYON.IS  0.165810
DOAS.IS   0.173539
GOODY.IS  0.293423
KOZAL.IS  0.173339

Orders
--------------------
action  shares    symbol        time
4   sell  144021  GOODY.IS  2016-03-31

After Orders
--------------------
cost  shares  current_price  market_value       profit  \
symbol
AEFES.IS  22993.90000    1275       21.16000   26979.00000   3985.10000
AFYON.IS  25388.72000    4238        6.37000   26996.06000   1607.34000
DOAS.IS   23798.81460    2400       11.24710   26993.04000   3194.22540
GOODY.IS  14731.62224  308324        0.08757   26999.93268  12268.31044
KOZAL.IS  19835.23000    1494       18.07000   26996.58000   7161.35000

weight
symbol
AEFES.IS  0.199897
AFYON.IS  0.200023
DOAS.IS   0.200001
GOODY.IS  0.200052
KOZAL.IS  0.200027

2016-04-29 00:00:00
--------------------
BJKAS.IS 5.33745899346
GOODY.IS 3.70296155031
AFYON.IS 2.73888471627
EREGL.IS 2.26335412215
KOZAL.IS 2.17678028137
TKFEN.IS 1.91104031464
YKBNK.IS 1.47010564428
DOAS.IS 1.28165996194
VAKBN.IS 1.27942651058
VAKFN.IS 1.25114330665
PETKM.IS 1.2243493208
FROTO.IS 1.18892366153
TCELL.IS 1.17502050664
AKBNK.IS 1.15415096839
TRKCM.IS 1.15112004053
AEFES.IS 1.0820661819
ALARK.IS 1.04582594283
GARAN.IS 0.924882254881
SISE.IS 0.819848136752
ULKER.IS 0.651242173138
THYAO.IS 0.577994374221
MGROS.IS 0.432742947264
AKENR.IS 0.411572932002
CIMSA.IS 0.409761734264
HALKB.IS 0.29317300613
ZOREN.IS 0.177975826959
AKSA.IS -0.164770083225
KARSN.IS -0.444213608009
TMSN.IS -1.12383635356
{'AFYON.IS': 0.2, 'BJKAS.IS': 0.2, 'EREGL.IS': 0.2, 'GOODY.IS': 0.2, 'KOZAL.IS': 0.2}
Before Orders
--------------------
cost  shares  current_price  market_value       profit  \
symbol
AEFES.IS  22993.90000    1275       21.72000   27693.00000   4699.10000
AFYON.IS  25388.72000    4238        6.15000   26063.70000    674.98000
DOAS.IS   23798.81460    2400       12.08000   28992.00000   5193.18540
GOODY.IS  14731.62224  308324        0.08822   27200.34328  12468.72104
KOZAL.IS  19835.23000    1494       18.30000   27340.20000   7504.97000

weight
symbol
AEFES.IS  0.201713
AFYON.IS  0.189845
DOAS.IS   0.211175
GOODY.IS  0.198124
KOZAL.IS  0.199143

Orders
--------------------
action  shares    symbol        time
2   sell    1275  AEFES.IS  2016-04-29
4   sell    2400   DOAS.IS  2016-04-29

After Orders
--------------------
cost  shares  current_price  market_value       profit  \
symbol
AEFES.IS      0.00000       0       21.72000       0.00000      0.00000
AFYON.IS  26778.62000    4464        6.15000   27453.60000    674.98000
BJKAS.IS  27452.70000    5310        5.17000   27452.70000      0.00000
DOAS.IS       0.00000       0       12.08000       0.00000      0.00000
EREGL.IS  27454.18131    6309        4.35159   27454.18131      0.00000
GOODY.IS  14989.04820  311242        0.08822   27457.76924  12468.72104
KOZAL.IS  19945.03000    1500       18.30000   27450.00000   7504.97000

weight
symbol
AEFES.IS  0.000000
AFYON.IS  0.200000
BJKAS.IS  0.199993
DOAS.IS   0.000000
EREGL.IS  0.200004
GOODY.IS  0.200030
KOZAL.IS  0.199973

2016-05-31 00:00:00
--------------------
BJKAS.IS 5.33745899346
GOODY.IS 3.70296155031
AFYON.IS 2.73888471627
EREGL.IS 2.26335412215
KOZAL.IS 2.17678028137
TKFEN.IS 1.91104031464
YKBNK.IS 1.47010564428
DOAS.IS 1.28165996194
VAKBN.IS 1.27942651058
VAKFN.IS 1.25114330665
PETKM.IS 1.2243493208
FROTO.IS 1.18892366153
TCELL.IS 1.17502050664
AKBNK.IS 1.15415096839
TRKCM.IS 1.15112004053
AEFES.IS 1.0820661819
ALARK.IS 1.04582594283
GARAN.IS 0.924882254881
SISE.IS 0.819848136752
ULKER.IS 0.651242173138
THYAO.IS 0.577994374221
MGROS.IS 0.432742947264
AKENR.IS 0.411572932002
CIMSA.IS 0.409761734264
HALKB.IS 0.29317300613
ZOREN.IS 0.177975826959
AKSA.IS -0.164770083225
KARSN.IS -0.444213608009
TMSN.IS -1.12383635356
{'AFYON.IS': 0.2, 'BJKAS.IS': 0.2, 'EREGL.IS': 0.2, 'GOODY.IS': 0.2, 'KOZAL.IS': 0.2}
Before Orders
--------------------
cost  shares  current_price  market_value        profit  \
symbol
AEFES.IS      0.00000       0       18.70000  0.000000e+00  0.000000e+00
AFYON.IS  26778.62000    4464        5.84000  2.606976e+04 -7.088600e+02
BJKAS.IS  27452.70000    5310        3.22000  1.709820e+04 -1.035450e+04
DOAS.IS       0.00000       0       10.92000  0.000000e+00  0.000000e+00
EREGL.IS  27454.18131    6309        4.12000  2.599308e+04 -1.461101e+03
GOODY.IS  14989.04820  311242        4.69645  1.461732e+06  1.446743e+06
KOZAL.IS  19945.03000    1500       13.74000  2.061000e+04  6.649700e+02

weight
symbol
AEFES.IS  0.000000
AFYON.IS  0.016803
BJKAS.IS  0.011020
DOAS.IS   0.000000
EREGL.IS  0.016753
GOODY.IS  0.942139
KOZAL.IS  0.013284

Orders
--------------------
action  shares    symbol        time
4   sell  245170  GOODY.IS  2016-05-31

After Orders
--------------------
cost  shares  current_price  market_value        profit  \
symbol
AEFES.IS       0.00000       0       18.70000        0.0000       0.00000
AFYON.IS  311005.58000   53133        5.84000   310296.7200    -708.86000
BJKAS.IS  320653.02000   96366        3.22000   310298.5200  -10354.50000
DOAS.IS        0.00000       0       10.92000        0.0000       0.00000
EREGL.IS  311758.90131   75315        4.12000   310297.8000   -1461.10131
GOODY.IS    3233.14670   66072        4.69645   310303.8444  307070.69770
KOZAL.IS  309625.45000   22583       13.74000   310290.4200     664.97000

weight
symbol
AEFES.IS  0.000000
AFYON.IS  0.200000
BJKAS.IS  0.200001
DOAS.IS   0.000000
EREGL.IS  0.200000
GOODY.IS  0.200004
KOZAL.IS  0.199995

2016-06-30 00:00:00
--------------------
BJKAS.IS 5.33745899346
GOODY.IS 3.70296155031
AFYON.IS 2.73888471627
EREGL.IS 2.26335412215
KOZAL.IS 2.17678028137
TKFEN.IS 1.91104031464
YKBNK.IS 1.47010564428
DOAS.IS 1.28165996194
VAKBN.IS 1.27942651058
VAKFN.IS 1.25114330665
PETKM.IS 1.2243493208
FROTO.IS 1.18892366153
TCELL.IS 1.17502050664
AKBNK.IS 1.15415096839
TRKCM.IS 1.15112004053
AEFES.IS 1.0820661819
ALARK.IS 1.04582594283
GARAN.IS 0.924882254881
SISE.IS 0.819848136752
ULKER.IS 0.651242173138
THYAO.IS 0.577994374221
MGROS.IS 0.432742947264
AKENR.IS 0.411572932002
CIMSA.IS 0.409761734264
HALKB.IS 0.29317300613
ZOREN.IS 0.177975826959
AKSA.IS -0.164770083225
KARSN.IS -0.444213608009
TMSN.IS -1.12383635356
{'AFYON.IS': 0.2, 'BJKAS.IS': 0.2, 'EREGL.IS': 0.2, 'GOODY.IS': 0.2, 'KOZAL.IS': 0.2}
Before Orders
--------------------
cost  shares  current_price  market_value        profit  \
symbol
AEFES.IS       0.00000       0          19.45          0.00       0.00000
AFYON.IS  311005.58000   53133           5.46     290106.18  -20899.40000
BJKAS.IS  320653.02000   96366           3.47     334390.02   13737.00000
DOAS.IS        0.00000       0          10.60          0.00       0.00000
EREGL.IS  311758.90131   75315           4.06     305778.90   -5980.00131
GOODY.IS    3233.14670   66072           3.32     219359.04  216125.89330
KOZAL.IS  309625.45000   22583          12.73     287481.59  -22143.86000

weight
symbol
AEFES.IS  0.000000
AFYON.IS  0.201867
BJKAS.IS  0.232681
DOAS.IS   0.000000
EREGL.IS  0.212773
GOODY.IS  0.152638
KOZAL.IS  0.200041

Orders
--------------------
action  shares    symbol        time
0   sell   13535  BJKAS.IS  2016-06-30
1   sell    4521  EREGL.IS  2016-06-30
2   sell       4  KOZAL.IS  2016-06-30
3   sell     491  AFYON.IS  2016-06-30

After Orders
--------------------
cost  shares  current_price  market_value        profit  \
symbol
AEFES.IS       0.00000       0          19.45          0.00       0.00000
AFYON.IS  308103.77000   52642           5.46     287425.32  -20678.45000
BJKAS.IS  266715.82000   82831           3.47     287423.57   20707.75000
DOAS.IS        0.00000       0          10.60          0.00       0.00000
EREGL.IS  292085.36292   70794           4.06     287423.64   -4661.72292
GOODY.IS   71296.46670   86573           3.32     287422.36  216125.89330
KOZAL.IS  309575.29000   22579          12.73     287430.67  -22144.62000

weight
symbol
AEFES.IS  0.000000
AFYON.IS  0.200000
BJKAS.IS  0.199999
DOAS.IS   0.000000
EREGL.IS  0.199999
GOODY.IS  0.199998
KOZAL.IS  0.200004


/home/can/.local/lib/python2.7/site-packages/ipykernel/__main__.py:3: FutureWarning: how in .resample() is deprecated
the new syntax is .resample(...).first()
app.launch_new_instance()

In [47]:
summary(transactions, positions, trades)

                          ***Transactions***
----------------------------------------------------------------------
action   commision     price  shares    status    symbol        time
0     buy    1.999145   9.70930    2059  accepted   DOAS.IS  2016-01-29
1     buy    1.999944   5.91000    3384  accepted  AFYON.IS  2016-01-29
2     buy    1.999940  18.05000    1108  accepted  AEFES.IS  2016-01-29
3     buy    1.998876  12.54000    1594  accepted  KOZAL.IS  2016-01-29
4     buy    1.999999   0.04795  417101  accepted  GOODY.IS  2016-01-29
5     buy    0.024204  10.08480      24  accepted   DOAS.IS  2016-02-29
6     buy    0.077740   5.98000     130  accepted  AFYON.IS  2016-02-29
7     buy    0.219042  16.98000     129  accepted  AEFES.IS  2016-02-29
8    sell    0.485576  16.24000     299  accepted  KOZAL.IS  2016-02-29
9     buy    0.163744   0.04646   35244  accepted  GOODY.IS  2016-02-29
10    buy    0.356533  11.24710     317  accepted   DOAS.IS  2016-03-31
11    buy    0.461188   6.37000     724  accepted  AFYON.IS  2016-03-31
12    buy    0.080408  21.16000      38  accepted  AEFES.IS  2016-03-31
13    buy    0.359593  18.07000     199  accepted  KOZAL.IS  2016-03-31
14   sell    1.261192   0.08757  144021  accepted  GOODY.IS  2016-03-31
15    buy    2.745270   5.17000    5310  accepted  BJKAS.IS  2016-04-29
16    buy    2.745418   4.35159    6309  accepted  EREGL.IS  2016-04-29
17   sell    2.769300  21.72000    1275  accepted  AEFES.IS  2016-04-29
18    buy    0.010980  18.30000       6  accepted  KOZAL.IS  2016-04-29
19   sell    2.899200  12.08000    2400  accepted   DOAS.IS  2016-04-29
20    buy    0.138990   6.15000     226  accepted  AFYON.IS  2016-04-29
21    buy    0.025743   0.08822    2918  accepted  GOODY.IS  2016-04-29
22    buy   29.320032   3.22000   91056  accepted  BJKAS.IS  2016-05-31
23    buy   28.430472   4.12000   69006  accepted  EREGL.IS  2016-05-31
24    buy   28.968042  13.74000   21083  accepted  KOZAL.IS  2016-05-31
25    buy   28.422696   5.84000   48669  accepted  AFYON.IS  2016-05-31
26   sell  115.142865   4.69645  245170  accepted  GOODY.IS  2016-05-31
27   sell    4.696645   3.47000   13535  accepted  BJKAS.IS  2016-06-30
28   sell    1.835526   4.06000    4521  accepted  EREGL.IS  2016-06-30
29   sell    0.005092  12.73000       4  accepted  KOZAL.IS  2016-06-30
30   sell    0.268086   5.46000     491  accepted  AFYON.IS  2016-06-30
31    buy    6.806332   3.32000   20501  accepted  GOODY.IS  2016-06-30

***Positions***
----------------------------------------------------------------------
cost  initial_shares     price  shares    symbol        time  type
0        0.00000            2059   9.70930       0   DOAS.IS  2016-01-29  long
1    17097.63000            3384   5.91000    2893  AFYON.IS  2016-01-29  long
2        0.00000            1108  18.05000       0  AEFES.IS  2016-01-29  long
3    16189.14000            1594  12.54000    1291  KOZAL.IS  2016-01-29  long
4     1338.28450          417101   0.04795   27910  GOODY.IS  2016-01-29  long
5        0.00000              24  10.08480       0   DOAS.IS  2016-02-29  long
6      777.40000             130   5.98000     130  AFYON.IS  2016-02-29  long
7        0.00000             129  16.98000       0  AEFES.IS  2016-02-29  long
8     1637.43624           35244   0.04646   35244  GOODY.IS  2016-02-29  long
9        0.00000             317  11.24710       0   DOAS.IS  2016-03-31  long
10    4611.88000             724   6.37000     724  AFYON.IS  2016-03-31  long
11       0.00000              38  21.16000       0  AEFES.IS  2016-03-31  long
12    3595.93000             199  18.07000     199  KOZAL.IS  2016-03-31  long
13       0.00000            5310   5.17000       0  BJKAS.IS  2016-04-29  long
14    7780.64292            6309   4.35159    1788  EREGL.IS  2016-04-29  long
15     109.80000               6  18.30000       6  KOZAL.IS  2016-04-29  long
16    1389.90000             226   6.15000     226  AFYON.IS  2016-04-29  long
17     257.42596            2918   0.08822    2918  GOODY.IS  2016-04-29  long
18  266715.82000           91056   3.22000   82831  BJKAS.IS  2016-05-31  long
19  284304.72000           69006   4.12000   69006  EREGL.IS  2016-05-31  long
20  289680.42000           21083  13.74000   21083  KOZAL.IS  2016-05-31  long
21  284226.96000           48669   5.84000   48669  AFYON.IS  2016-05-31  long
22   68063.32000           20501   3.32000   20501  GOODY.IS  2016-06-30  long

----------------------------------------------------------------------
buy_price        profit  sell_price  shares    symbol        time
0    12.54000  1.106300e+03    16.24000     299  KOZAL.IS  2016-02-29
1     0.04795  5.706112e+03     0.08757  144021  GOODY.IS  2016-03-31
2    18.05000  4.066360e+03    21.72000    1108  AEFES.IS  2016-04-29
3    16.98000  6.114600e+02    21.72000     129  AEFES.IS  2016-04-29
4    21.16000  2.128000e+01    21.72000      38  AEFES.IS  2016-04-29
5     9.70930  4.881271e+03    12.08000    2059   DOAS.IS  2016-04-29
6    10.08480  4.788480e+01    12.08000      24   DOAS.IS  2016-04-29
7    11.24710  2.640293e+02    12.08000     317   DOAS.IS  2016-04-29
8     0.04795  1.139673e+06     4.69645  245170  GOODY.IS  2016-05-31
9     5.17000 -9.027000e+03     3.47000    5310  BJKAS.IS  2016-06-30
10    3.22000  2.056250e+03     3.47000    8225  BJKAS.IS  2016-06-30
11    4.35159 -1.318278e+03     4.06000    4521  EREGL.IS  2016-06-30
12   12.54000  7.600000e-01    12.73000       4  KOZAL.IS  2016-06-30
13    5.91000 -2.209500e+02     5.46000     491  AFYON.IS  2016-06-30

In [48]:
current_performance(portfolio, time = '2016-08-04')
portfolio

Out[48]:
cost shares current_price market_value profit weight
symbol
AEFES.IS 0.00000 0 20.14 0.00 0.00000 0.000000
AFYON.IS 308103.77000 52642 5.48 288478.16 -19625.61000 0.190931
BJKAS.IS 266715.82000 82831 4.25 352031.75 85315.93000 0.232994
DOAS.IS 0.00000 0 10.29 0.00 0.00000 0.000000
EREGL.IS 292085.36292 70794 4.67 330607.98 38522.61708 0.218815
GOODY.IS 71296.46670 86573 3.58 309931.34 238634.87330 0.205130
KOZAL.IS 309575.29000 22579 10.18 229854.22 -79721.07000 0.152130
In [49]:
portfolio.market_value.sum()

Out[49]:
1510903.45
In [50]:
paid_dividends(transactions, Dividends)

Out[50]:
time symbol paid_dividend
816 2016-04-07 DOAS.IS 3.272736e+03
1113 2016-05-25 EREGL.IS 1.892700e+03
1362 2016-05-25 GOODY.IS 1.720580e+06
In [51]:
dividends_and_splits.query("symbol == 'GOODY.IS'")

Out[51]:
action value symbol
2016-06-01 SPLIT 0.045455 GOODY.IS
2016-05-25 DIVIDEND 5.528110 GOODY.IS
2015-05-20 DIVIDEND 0.794024 GOODY.IS
2015-05-12 DIVIDEND 0.794024 GOODY.IS
2014-05-06 DIVIDEND 5.243630 GOODY.IS
2013-05-16 DIVIDEND 0.833000 GOODY.IS
2012-05-31 DIVIDEND 1.035160 GOODY.IS
2011-05-26 DIVIDEND 0.230000 GOODY.IS
In [52]:
temp = historical_performance(transactions, prices)
compare_with_benchmark(temp)

Algorithm performance: 1565.96392855
Benchmark performance: 5.60699416203


Momentum Strategy¶

Initialization

1. Calculate absolute momentum (return) of funds and select n stocks with the highest moment.
2. Equal weight

Every month

1. If the moment of a stock in the portfolio is negative then replace it with the best option
2. Rebalance
In [53]:
# TODO: fill nan values
def momentum(price_data, start, end):
momentum_values = {symbol: (price_data[symbol].loc[end] - price_data[symbol].loc[start])
for symbol in price_data.columns if symbol != 'XU100.IS'}
return momentum_values

In [54]:
pd.date_range(start=running_points[0], periods=12, freq='BM')

Out[54]:
DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29',
'2016-05-31', '2016-06-30', '2016-07-29', '2016-08-31',
'2016-09-30', '2016-10-31', '2016-11-30', '2016-12-30'],
dtype='datetime64[ns]', freq='BM')
In [55]:
portfolio, transactions, positions, trades = [], [], [], []

for t in running_points:
time = t.strftime("%Y-%m-%d")

if t in pd.date_range(start=running_points[0], periods=12, freq='BM'):
print t
print '-'*20
momentum_values = momentum(prices, t - pd.DateOffset(months=5) - 1*BDay(), t - 1*BDay())
for s in sorted(momentum_values, key=momentum_values.get, reverse=True):
print s, momentum_values[s]

n = 5

if len(portfolio) == 0:
new_weights = {s: 1./n for s in sorted(momentum_values, key=momentum_values.get, reverse=True)[:n]}
print new_weights
target_value = capital_base
rebalance_orders = rebalance(portfolio, new_weights, target_value, time)
else:
potentials = {key:value for key, value in momentum_values.iteritems() if key not in portfolio.index }
new_weights = {}

for symbol in portfolio.index:
if portfolio["market_value"].loc[symbol]:
if momentum_values[symbol] < 0:
s = sorted(potentials, key=potentials.get, reverse=True)[0]
print symbol + "out" + s + "in"
new_weights[s] = 1./n
del potentials[s]
else:
new_weights[symbol] = 1./n

current_performance(portfolio, time)

print new_weights
rebalance_orders = rebalance(portfolio, new_weights, None, time)

print "Before Orders"
print "-"*20
print portfolio["market_value"].sum() if len(portfolio) else 0
print portfolio
print " "

print "Orders"
print "-"*20
print pd.DataFrame(rebalance_orders)
print " "

print sum([order["shares"]*get_price(order["symbol"], time) for order in rebalance_orders if order["action"]=="buy"])
print sum([order["shares"]*get_price(order["symbol"], time) for order in rebalance_orders if order["action"]=="sell"])

portfolio = calculate_portfolio(positions)
current_performance(portfolio, time)

print "After Orders"
print "-"*20
print portfolio
print portfolio["market_value"].sum()
print " "

portfolio = calculate_portfolio(positions)

2016-01-29 00:00:00
--------------------
TMSN.IS 4.5
FROTO.IS 2.4809
BJKAS.IS 1.02
PETKM.IS 0.83363
AFYON.IS 0.61
ALARK.IS 0.54994
ULKER.IS 0.39
ZOREN.IS 0.23881
AKBNK.IS 0.14716
SISE.IS 0.10687
YKBNK.IS 0.06
VAKFN.IS 0.0523
GARAN.IS 0.039
KARSN.IS 0.03
GOODY.IS 0.00778
AKSA.IS 0.0
AKENR.IS -0.01
TRKCM.IS -0.04577
VAKBN.IS -0.05946
TKFEN.IS -0.11
CIMSA.IS -0.6547
MGROS.IS -0.7
THYAO.IS -0.73
EREGL.IS -0.76409
HALKB.IS -0.79
TCELL.IS -1.23
DOAS.IS -1.7434
AEFES.IS -2.81
KOZAL.IS -12.3
{'AFYON.IS': 0.2, 'TMSN.IS': 0.2, 'BJKAS.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
0
[]

Orders
--------------------
action  shares    symbol        time

99982.3716
0
After Orders
--------------------
cost  shares  current_price  market_value  profit    weight
symbol
AFYON.IS  19999.4400    3384        5.91000    19999.4400     0.0  0.200030
BJKAS.IS  19999.9800    6734        2.97000    19999.9800     0.0  0.200035
FROTO.IS  19986.6816     636       31.42560    19986.6816     0.0  0.199902
PETKM.IS  19997.7500    6250        3.19964    19997.7500     0.0  0.200013
TMSN.IS   19998.5200    1901       10.52000    19998.5200     0.0  0.200020
99982.3716

2016-02-29 00:00:00
--------------------
TMSN.IS 3.55
BJKAS.IS 2.69
FROTO.IS 2.5783
DOAS.IS 0.9924
AKBNK.IS 0.80449
AFYON.IS 0.8
PETKM.IS 0.73861
CIMSA.IS 0.47284
SISE.IS 0.47201
GARAN.IS 0.443
ZOREN.IS 0.33625
YKBNK.IS 0.29
VAKBN.IS 0.2081
TCELL.IS 0.19
VAKFN.IS 0.1046
KARSN.IS 0.05
GOODY.IS 0.00748
AKENR.IS -0.04
AKSA.IS -0.04601
TKFEN.IS -0.05
TRKCM.IS -0.05492
ALARK.IS -0.07457
HALKB.IS -0.12
EREGL.IS -0.32613
ULKER.IS -0.34
THYAO.IS -0.8
MGROS.IS -1.32
AEFES.IS -4.3
KOZAL.IS -6.08
{'AFYON.IS': 0.2, 'BJKAS.IS': 0.2, 'TMSN.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
112051.4147
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS  19999.4400    3384        5.98000    20236.3200    236.8800
BJKAS.IS  19999.9800    6734        4.68000    31515.1200  11515.1400
FROTO.IS  19986.6816     636       33.95520    21595.5072   1608.8256
PETKM.IS  19997.7500    6250        3.21803    20112.6875    114.9375
TMSN.IS   19998.5200    1901        9.78000    18591.7800  -1406.7400

weight
symbol
AFYON.IS  0.180599
BJKAS.IS  0.281256
FROTO.IS  0.192729
PETKM.IS  0.179495
TMSN.IS   0.165922

Orders
--------------------
action  shares    symbol        time
1   sell    1945  BJKAS.IS  2016-02-29

9060.36499
9102.6
After Orders
--------------------
cost  shares  current_price  market_value     profit  \
symbol
AFYON.IS  22170.18000    3747        5.98000   22407.06000   236.8800
BJKAS.IS  14223.33000    4789        4.68000   22412.52000  8189.1900
FROTO.IS  20767.65120     659       33.95520   22376.47680  1608.8256
PETKM.IS  22292.20539    6963        3.21803   22407.14289   114.9375
TMSN.IS   23812.72000    2291        9.78000   22405.98000 -1406.7400

weight
symbol
AFYON.IS  0.200047
BJKAS.IS  0.200095
FROTO.IS  0.199774
PETKM.IS  0.200047
TMSN.IS   0.200037
112009.17969

2016-03-31 00:00:00
--------------------
FROTO.IS 2.8993
BJKAS.IS 2.89
TMSN.IS 1.89
KOZAL.IS 1.75
DOAS.IS 1.5914
ULKER.IS 1.52
TKFEN.IS 1.15
CIMSA.IS 1.04194
PETKM.IS 0.95009
AKBNK.IS 0.65168
YKBNK.IS 0.6
GARAN.IS 0.531
VAKBN.IS 0.50541
MGROS.IS 0.43
ZOREN.IS 0.33518
VAKFN.IS 0.3138
ALARK.IS 0.29827
SISE.IS 0.29389
AFYON.IS 0.2
EREGL.IS 0.13045
TRKCM.IS 0.10069
KARSN.IS 0.05
GOODY.IS 0.02904
AKENR.IS 0.02
TCELL.IS -0.03
AKSA.IS -0.22085
HALKB.IS -0.58
THYAO.IS -0.84
AEFES.IS -1.91
{'AFYON.IS': 0.2, 'BJKAS.IS': 0.2, 'TMSN.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
117341.42468
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS  22170.18000    3747        6.37000   23868.39000  1698.21000
BJKAS.IS  14223.33000    4789        5.05000   24184.45000  9961.12000
FROTO.IS  20767.65120     659       36.13460   23812.70140  3045.05020
PETKM.IS  22292.20539    6963        3.66856   25544.18328  3251.97789
TMSN.IS   23812.72000    2291        8.70000   19931.70000 -3881.02000

weight
symbol
AFYON.IS  0.203410
BJKAS.IS  0.206103
FROTO.IS  0.202935
PETKM.IS  0.217691
TMSN.IS   0.169861

Orders
--------------------
action  shares    symbol        time
0   sell      62  AFYON.IS  2016-03-31
1   sell     141  BJKAS.IS  2016-03-31
3   sell       9  FROTO.IS  2016-03-31
4   sell     565  PETKM.IS  2016-03-31

3532.2
3504.9378
After Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS  21803.76000    3685        6.37000   23473.45000  1669.69000
BJKAS.IS  13804.56000    4648        5.05000   23472.40000  9667.84000
FROTO.IS  20484.82080     650       36.13460   23487.49000  3002.66920
PETKM.IS  20484.40879    6398        3.66856   23471.44688  2987.03809
TMSN.IS   27344.92000    2697        8.70000   23463.90000 -3881.02000

weight
symbol
AFYON.IS  0.199998
BJKAS.IS  0.199989
FROTO.IS  0.200117
PETKM.IS  0.199980
TMSN.IS   0.199916
117368.68688

2016-04-29 00:00:00
--------------------
FROTO.IS 7.1323
KOZAL.IS 6.37
ULKER.IS 3.45
BJKAS.IS 2.94
AKBNK.IS 1.85052
TKFEN.IS 1.85
CIMSA.IS 1.7974
DOAS.IS 1.7132
MGROS.IS 1.49
GARAN.IS 1.387
PETKM.IS 1.15236
AEFES.IS 1.06
VAKBN.IS 0.93154
EREGL.IS 0.91318
YKBNK.IS 0.87
SISE.IS 0.81044
ALARK.IS 0.77365
TCELL.IS 0.68
TRKCM.IS 0.42106
VAKFN.IS 0.38851
AKENR.IS 0.34
ZOREN.IS 0.34
GOODY.IS 0.04098
HALKB.IS -0.02
KARSN.IS -0.11
AKSA.IS -0.28606
AFYON.IS -0.39
TMSN.IS -0.45
THYAO.IS -0.84
AFYON.ISoutKOZAL.ISin
TMSN.ISoutULKER.ISin
{'KOZAL.IS': 0.2, 'ULKER.IS': 0.2, 'BJKAS.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
117236.85822
cost  shares  current_price  market_value       profit  \
symbol
AFYON.IS  21803.76000    3685        6.15000   22662.75000    858.99000
BJKAS.IS  13804.56000    4648        5.17000   24030.16000  10225.60000
FROTO.IS  20484.82080     650       37.60000   24440.00000   3955.17920
PETKM.IS  20484.40879    6398        3.77889   24177.33822   3692.92943
TMSN.IS   27344.92000    2697        8.13000   21926.61000  -5418.31000

weight
symbol
AFYON.IS  0.193307
BJKAS.IS  0.204971
FROTO.IS  0.208467
PETKM.IS  0.206226
TMSN.IS   0.187028

Orders
--------------------
action  shares    symbol        time
0   sell     112  BJKAS.IS  2016-04-29
2   sell      26  FROTO.IS  2016-04-29
4   sell    3685  AFYON.IS  2016-04-29
5   sell    2697   TMSN.IS  2016-04-29
6   sell     193  PETKM.IS  2016-04-29

46880.86
46875.32577
After Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS      0.00000       0        6.15000       0.00000     0.00000
BJKAS.IS  13471.92000    4536        5.17000   23451.12000  9979.20000
FROTO.IS  19667.75520     624       37.60000   23462.40000  3794.64480
KOZAL.IS  23442.30000    1281       18.30000   23442.30000     0.00000
PETKM.IS  19866.87827    6205        3.77889   23448.01245  3581.13418
TMSN.IS       0.00000       0        8.13000       0.00000     0.00000
ULKER.IS  23438.56000    1052       22.28000   23438.56000     0.00000

weight
symbol
AFYON.IS  0.000000
BJKAS.IS  0.200023
FROTO.IS  0.200119
KOZAL.IS  0.199947
PETKM.IS  0.199996
TMSN.IS   0.000000
ULKER.IS  0.199915
117242.39245

2016-05-31 00:00:00
--------------------
FROTO.IS 4.6484
GOODY.IS 4.64283
ULKER.IS 3.28
TKFEN.IS 3.2
CIMSA.IS 2.03478
EREGL.IS 1.24341
DOAS.IS 1.2062
AKBNK.IS 1.20108
KOZAL.IS 1.16
PETKM.IS 1.10639
BJKAS.IS 1.04
YKBNK.IS 0.77
ALARK.IS 0.60587
VAKBN.IS 0.54504
TCELL.IS 0.53
GARAN.IS 0.446
TRKCM.IS 0.44164
SISE.IS 0.42748
VAKFN.IS 0.38104
AKENR.IS 0.14
ZOREN.IS -0.07
AEFES.IS -0.08
AFYON.IS -0.23
KARSN.IS -0.37
MGROS.IS -0.48
THYAO.IS -1.05
TMSN.IS -1.17
AKSA.IS -1.22878
HALKB.IS -1.47
{'KOZAL.IS': 0.2, 'BJKAS.IS': 0.2, 'ULKER.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
100730.78005
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS      0.00000       0        5.84000       0.00000     0.00000
BJKAS.IS  13471.92000    4536        3.22000   14605.92000  1134.00000
FROTO.IS  19667.75520     624       34.98000   21827.52000  2159.76480
KOZAL.IS  23442.30000    1281       13.74000   17600.94000 -5841.36000
PETKM.IS  19866.87827    6205        3.90761   24246.72005  4379.84178
TMSN.IS       0.00000       0        7.72000       0.00000     0.00000
ULKER.IS  23438.56000    1052       21.34000   22449.68000  -988.88000

weight
symbol
AFYON.IS  0.000000
BJKAS.IS  0.145000
FROTO.IS  0.216692
KOZAL.IS  0.174732
PETKM.IS  0.240708
TMSN.IS   0.000000
ULKER.IS  0.222868

Orders
--------------------
action  shares    symbol        time
2   sell      48  FROTO.IS  2016-05-31
3   sell     107  ULKER.IS  2016-05-31
4   sell    1049  PETKM.IS  2016-05-31

8080.3
8061.50289
After Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS      0.00000       0        5.84000       0.00000     0.00000
BJKAS.IS  19010.32000    6256        3.22000   20144.32000  1134.00000
FROTO.IS  18159.32640     576       34.98000   20148.48000  1989.15360
KOZAL.IS  25984.20000    1466       13.74000   20142.84000 -5841.36000
PETKM.IS  16510.45591    5156        3.90761   20147.63716  3637.18125
TMSN.IS       0.00000       0        7.72000       0.00000     0.00000
ULKER.IS  21054.60000     945       21.34000   20166.30000  -888.30000

weight
symbol
AFYON.IS  0.000000
BJKAS.IS  0.199944
FROTO.IS  0.199986
KOZAL.IS  0.199930
PETKM.IS  0.199977
TMSN.IS   0.000000
ULKER.IS  0.200163
100749.57716

2016-06-30 00:00:00
--------------------
TKFEN.IS 4.16
GOODY.IS 3.30205
CIMSA.IS 2.115
ULKER.IS 2.08
EREGL.IS 1.23068
AKBNK.IS 1.086
DOAS.IS 1.0207
VAKBN.IS 0.80396
PETKM.IS 0.62036
SISE.IS 0.5996
AEFES.IS 0.59
TRKCM.IS 0.58905
KOZAL.IS 0.45
BJKAS.IS 0.43
MGROS.IS 0.37
VAKFN.IS 0.33839
GARAN.IS 0.289
TCELL.IS 0.24
FROTO.IS 0.2344
YKBNK.IS 0.22
ZOREN.IS 0.15
AKENR.IS 0.04
ALARK.IS -0.06358
KARSN.IS -0.36
AFYON.IS -0.43
HALKB.IS -1.4
THYAO.IS -1.5
AKSA.IS -1.70033
TMSN.IS -3.14
{'KOZAL.IS': 0.2, 'BJKAS.IS': 0.2, 'ULKER.IS': 0.2, 'FROTO.IS': 0.2, 'PETKM.IS': 0.2}
Before Orders
--------------------
97640.14
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS      0.00000       0           5.46          0.00     0.00000
BJKAS.IS  19010.32000    6256           3.47      21708.32  2698.00000
FROTO.IS  18159.32640     576          30.60      17625.60  -533.72640
KOZAL.IS  25984.20000    1466          12.73      18662.18 -7322.02000
PETKM.IS  16510.45591    5156           3.84      19799.04  3288.58409
TMSN.IS       0.00000       0           7.40          0.00     0.00000
ULKER.IS  21054.60000     945          21.00      19845.00 -1209.60000

weight
symbol
AFYON.IS  0.000000
BJKAS.IS  0.222330
FROTO.IS  0.180516
KOZAL.IS  0.191132
PETKM.IS  0.202776
TMSN.IS   0.000000
ULKER.IS  0.203246

Orders
--------------------
action  shares    symbol        time
0   sell     628  BJKAS.IS  2016-06-30
3   sell      15  ULKER.IS  2016-06-30
4   sell      70  PETKM.IS  2016-06-30

2762.84
2762.96
After Orders
--------------------
cost  shares  current_price  market_value      profit  \
symbol
AFYON.IS      0.00000       0           5.46          0.00     0.00000
BJKAS.IS  17145.16000    5628           3.47      19529.16  2384.00000
FROTO.IS  20056.52640     638          30.60      19522.80  -533.72640
KOZAL.IS  26849.84000    1534          12.73      19527.82 -7322.02000
PETKM.IS  16286.48111    5086           3.84      19530.24  3243.75889
TMSN.IS       0.00000       0           7.40          0.00     0.00000
ULKER.IS  20720.40000     930          21.00      19530.00 -1190.40000

weight
symbol
AFYON.IS  0.000000
BJKAS.IS  0.200012
FROTO.IS  0.199947
KOZAL.IS  0.199998
PETKM.IS  0.200023
TMSN.IS   0.000000
ULKER.IS  0.200020
97640.02


In [56]:
summary(transactions, positions, trades)

                          ***Transactions***
----------------------------------------------------------------------
action  commision     price  shares    status    symbol        time
0     buy   1.999944   5.91000    3384  accepted  AFYON.IS  2016-01-29
1     buy   1.999852  10.52000    1901  accepted   TMSN.IS  2016-01-29
2     buy   1.999998   2.97000    6734  accepted  BJKAS.IS  2016-01-29
3     buy   1.998668  31.42560     636  accepted  FROTO.IS  2016-01-29
4     buy   1.999775   3.19964    6250  accepted  PETKM.IS  2016-01-29
5     buy   0.217074   5.98000     363  accepted  AFYON.IS  2016-02-29
6    sell   0.910260   4.68000    1945  accepted  BJKAS.IS  2016-02-29
7     buy   0.381420   9.78000     390  accepted   TMSN.IS  2016-02-29
8     buy   0.078097  33.95520      23  accepted  FROTO.IS  2016-02-29
9     buy   0.229446   3.21803     713  accepted  PETKM.IS  2016-02-29
10   sell   0.039494   6.37000      62  accepted  AFYON.IS  2016-03-31
11   sell   0.071205   5.05000     141  accepted  BJKAS.IS  2016-03-31
12    buy   0.353220   8.70000     406  accepted   TMSN.IS  2016-03-31
13   sell   0.032521  36.13460       9  accepted  FROTO.IS  2016-03-31
14   sell   0.207274   3.66856     565  accepted  PETKM.IS  2016-03-31
15   sell   0.057904   5.17000     112  accepted  BJKAS.IS  2016-04-29
16    buy   2.344230  18.30000    1281  accepted  KOZAL.IS  2016-04-29
17   sell   0.097760  37.60000      26  accepted  FROTO.IS  2016-04-29
18    buy   2.343856  22.28000    1052  accepted  ULKER.IS  2016-04-29
19   sell   2.266275   6.15000    3685  accepted  AFYON.IS  2016-04-29
20   sell   2.192661   8.13000    2697  accepted   TMSN.IS  2016-04-29
21   sell   0.072933   3.77889     193  accepted  PETKM.IS  2016-04-29
22    buy   0.553840   3.22000    1720  accepted  BJKAS.IS  2016-05-31
23    buy   0.254190  13.74000     185  accepted  KOZAL.IS  2016-05-31
24   sell   0.167904  34.98000      48  accepted  FROTO.IS  2016-05-31
25   sell   0.228338  21.34000     107  accepted  ULKER.IS  2016-05-31
26   sell   0.409908   3.90761    1049  accepted  PETKM.IS  2016-05-31
27   sell   0.217916   3.47000     628  accepted  BJKAS.IS  2016-06-30
28    buy   0.086564  12.73000      68  accepted  KOZAL.IS  2016-06-30
29    buy   0.189720  30.60000      62  accepted  FROTO.IS  2016-06-30
30   sell   0.031500  21.00000      15  accepted  ULKER.IS  2016-06-30
31   sell   0.026880   3.84000      70  accepted  PETKM.IS  2016-06-30

***Positions***
----------------------------------------------------------------------
cost  initial_shares     price  shares    symbol        time  type
0       0.00000            3384   5.91000       0  AFYON.IS  2016-01-29  long
1       0.00000            1901  10.52000       0   TMSN.IS  2016-01-29  long
2   11606.76000            6734   2.97000    3908  BJKAS.IS  2016-01-29  long
3   17378.35680             636  31.42560     553  FROTO.IS  2016-01-29  long
4   13992.02572            6250   3.19964    4373  PETKM.IS  2016-01-29  long
5       0.00000             363   5.98000       0  AFYON.IS  2016-02-29  long
6       0.00000             390   9.78000       0   TMSN.IS  2016-02-29  long
7     780.96960              23  33.95520      23  FROTO.IS  2016-02-29  long
8    2294.45539             713   3.21803     713  PETKM.IS  2016-02-29  long
9       0.00000             406   8.70000       0   TMSN.IS  2016-03-31  long
10  23442.30000            1281  18.30000    1281  KOZAL.IS  2016-04-29  long
11  20720.40000            1052  22.28000     930  ULKER.IS  2016-04-29  long
12   5538.40000            1720   3.22000    1720  BJKAS.IS  2016-05-31  long
13   2541.90000             185  13.74000     185  KOZAL.IS  2016-05-31  long
14    865.64000              68  12.73000      68  KOZAL.IS  2016-06-30  long
15   1897.20000              62  30.60000      62  FROTO.IS  2016-06-30  long

----------------------------------------------------------------------
buy_price      profit  sell_price  shares    symbol        time
0     2.97000  3325.95000     4.68000    1945  BJKAS.IS  2016-02-29
1     5.91000    28.52000     6.37000      62  AFYON.IS  2016-03-31
2     2.97000   293.28000     5.05000     141  BJKAS.IS  2016-03-31
3    31.42560    42.38100    36.13460       9  FROTO.IS  2016-03-31
4     3.19964   264.93980     3.66856     565  PETKM.IS  2016-03-31
5     2.97000   246.40000     5.17000     112  BJKAS.IS  2016-04-29
6    31.42560   160.53440    37.60000      26  FROTO.IS  2016-04-29
7     5.91000   797.28000     6.15000    3322  AFYON.IS  2016-04-29
8     5.98000    61.71000     6.15000     363  AFYON.IS  2016-04-29
9    10.52000 -4543.39000     8.13000    1901   TMSN.IS  2016-04-29
10    9.78000  -643.50000     8.13000     390   TMSN.IS  2016-04-29
11    8.70000  -231.42000     8.13000     406   TMSN.IS  2016-04-29
12    3.19964   111.79525     3.77889     193  PETKM.IS  2016-04-29
13   31.42560   170.61120    34.98000      48  FROTO.IS  2016-05-31
14   22.28000  -100.58000    21.34000     107  ULKER.IS  2016-05-31
15    3.19964   742.66053     3.90761    1049  PETKM.IS  2016-05-31
16    2.97000   314.00000     3.47000     628  BJKAS.IS  2016-06-30
17   22.28000   -19.20000    21.00000      15  ULKER.IS  2016-06-30
18    3.19964    44.82520     3.84000      70  PETKM.IS  2016-06-30

In [57]:
current_performance(portfolio, time = '2016-07-18')
portfolio

Out[57]:
cost shares current_price market_value profit weight
symbol
AFYON.IS 0.00000 0 5.14 0.00 0.00000 0.000000
BJKAS.IS 17145.16000 5628 3.90 21949.20 4804.04000 0.222960
FROTO.IS 20056.52640 638 32.32 20620.16 563.63360 0.209459
KOZAL.IS 26849.84000 1534 10.63 16306.42 -10543.42000 0.165641
PETKM.IS 16286.48111 5086 3.94 20038.84 3752.35889 0.203554
TMSN.IS 0.00000 0 7.10 0.00 0.00000 0.000000
ULKER.IS 20720.40000 930 21.00 19530.00 -1190.40000 0.198386
In [58]:
portfolio["market_value"].sum()

Out[58]:
98444.62
In [59]:
paid_dividends(transactions, Dividends)

Out[59]:
time symbol paid_dividend
564 2016-04-04 FROTO.IS 650.00
1146 2016-06-27 PETKM.IS 1624.14
In [60]:
temp = historical_performance(transactions, prices)
compare_with_benchmark(temp)

Algorithm performance: 13.1896335214
Benchmark performance: 5.60699416203


IndexCalculation¶

TOC

We can withdraw / deposit money into the portfolio or while rebalancing some amount of free cash can left. In this kind of situations it is hard to calculate the performance of a portfolio. To overcome this situation one way is to calculate an index value and to calculate performance over this index value instead of market value.

In [61]:
historical_performance(pd.DataFrame(transactions)[0:5].to_dict("records"), prices)["2016-02-25":"2016-03-02"]

Out[61]:
Date
2016-02-25    113231.4596
2016-02-26    111634.3921
2016-02-29    112051.4147
2016-03-01    113060.0381
2016-03-02    113371.5324
dtype: float64
In [62]:
historical_performance(transactions, prices)["2016-02-25":"2016-03-02"]

Out[62]:
Date
2016-02-25    113231.45960
2016-02-26    111634.39210
2016-02-29    112009.17969
2016-03-01    112774.81843
2016-03-02    112975.15510
dtype: float64
In [63]:
pd.pivot_table(pd.DataFrame(transactions), values="shares", index="time", columns="symbol")

Out[63]:
symbol AFYON.IS BJKAS.IS FROTO.IS KOZAL.IS PETKM.IS TMSN.IS ULKER.IS
time
2016-01-29 3384.0 6734.0 636.0 NaN 6250.0 1901.0 NaN
2016-02-29 363.0 1945.0 23.0 NaN 713.0 390.0 NaN
2016-03-31 62.0 141.0 9.0 NaN 565.0 406.0 NaN
2016-04-29 3685.0 112.0 26.0 1281.0 193.0 2697.0 1052.0
2016-05-31 NaN 1720.0 48.0 185.0 1049.0 NaN 107.0
2016-06-30 NaN 628.0 62.0 68.0 70.0 NaN 15.0

RiskCalculation¶

TOC

Value-at-Risk¶

The value-at-risk is a measure of how much money can be lost for a period of time. Of course there is a (very small) probability that we can lost all our money. We can talk about the distrubition of the money that we can lost. For the value-at-risk we choose a probability say 99% and say that we will not loose money more then $x$ with probability 99%.

There can be different methods to estimate the risk:

• Historical method:
• The Variance-Covariance Method:
• Simulation:

One way of chosing a methods is to test against historical data which is called backtesting.

In [64]:
from matplotlib.dates import AutoDateLocator
from matplotlib.ticker import MultipleLocator

In [65]:
# Historical method
returns = historical_performance(transactions, prices).pct_change().dropna()
returns.hist(bins=50, figsize=(15,10))
var_historic = returns.quantile(q = 0.01)
var_historic

Out[65]:
-0.072105940035707305
In [66]:
# The Variance-Covariance Method
mu = np.mean(returns)
sigma = np.std(returns)
var_parametric = st.norm.ppf(0.01) * sigma
var_parametric

Out[66]:
-0.079391854933226536
In [67]:
# Monte Carlo Simulation

samples = np.random.normal(mu, sigma, 100)
var_montecarlo = np.percentile(samples, 0.01)
var_montecarlo

Out[67]:
-0.09693688460895461
In [68]:
ax = returns.plot(kind='bar', title ="V comp",figsize=(15,10),legend=True, fontsize=12)
ax.set_xlabel("Hour",fontsize=12)
AutoDateLocator()
loc = MultipleLocator(base=10.0)
ax.xaxis.set_major_locator(loc)
ax.set_ylabel("V",fontsize=12)
plt.axhline(y=var_historic, color='r', linestyle='-')
plt.axhline(y=var_parametric, color='r', linestyle='-')
plt.axhline(y=var_montecarlo, color='r', linestyle='-')
plt.show()


Risk Profile¶

The risk profile is a way of categorizing portfolios according their risk. Risk profile of a portfolio depends on its yearly volatility. The yearly volatily is calculated by multiplying the standard deviation of weekly returns by square root of 52 (number of weeks in a year).

Cutoff points for yearly volatility is: [0, 0.5, 2, 5, 10, 15, 25]

In [69]:
historical_performance(transactions, prices).pct_change().resample("W-MON", label="left" ,closed="left").sum().plot()

Out[69]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fc0b029c5d0>
In [70]:
historical_performance(transactions, prices).pct_change().resample("W-MON", label="left" ,closed="left").sum().cumsum().plot()

Out[70]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fc0aae3dfd0>
In [71]:
def calculate_risk_value(historical_prices):
return np.std((historical_prices.pct_change() + 1).resample("W-MON", label="left" ,closed="left").prod() - 1) * sqrt(52)

risk_value = calculate_risk_value(historical_performance(transactions, prices)) * 100

In [72]:
from bisect import bisect
RiskLevels = [0, 0.5, 2, 5, 10, 15, 25]
bisect(RiskLevels, risk_value)

Out[72]:
7

Visualization¶

TOC

In [73]:
#sparkline
historical_prices = historical_performance(transactions, prices)
weekly_returns = ((historical_prices.pct_change() + 1).resample("W-MON", label="left" ,closed="left").prod() - 1)
plt.plot(weekly_returns)
plt.axis("off");
plt.savefig("trend.png")


ToDo¶

TOC

Overview¶
• Order lifecycle
• Transaction and position
• Strategies: Technical vs Fundemantal
• Trading algorithms from interactive brokers
Dividend and Split¶
• Implied transactions
Portfolio Calculation¶
• plot stock prices annotated by dividend and splits
• compute dividend and split automatically:
• get close prices (not adjusted)
• create split and dividend transactions?