Efficient Frontier


Reading time: about 30 minutes
In [1]:
get_ipython().ast_node_interactivity = 'all'
import os
import matplotlib.pyplot as plt
import numpy as np
np.set_printoptions(suppress=True)
import matplotlib
import math
from PIL import Image
import pandas as pd
import random
import tqdm
from collections import defaultdict
from scipy.optimize import *
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from queue import SimpleQueue

import warnings
warnings.filterwarnings('ignore')
In [2]:
targets = (
    #'MATRIKS.AKSA',
    #'MATRIKS.AKSEN',
    #'MATRIKS.AKBNK',
    'MATRIKS.ADEL',
    #'MATRIKS.CCOLA',
    #'MATRIKS.ALKIM',
    #'MATRIKS.ANHYT',
    #'MATRIKS.ALARK',
    #'MATRIKS.KAREL',
    #'MATRIKS.ISMEN',
    #'MATRIKS.ARCLK',
    #'MATRIKS.EREGL',
    #'MATRIKS.SISE',
    #'MATRIKS.PETKM',
    #'MATRIKS.SASA',
    #'MATRIKS.VESTL',
    'MATRIKS.VESBE',
    #'MATRIKS.XAUTRY',
    #'MATRIKS.XAGTRY',
    #'MATRIKS.USDTRY',
    #'MATRIKS.EURTRY',
    #'MATRIKS.GBPTRY',
    #'MATRIKS.BIMAS',
    #'MATRIKS.TAVHL',
    'MATRIKS.MTRKS',
    #'MATRIKS.MGROS',
    'MATRIKS.SOKM',
    'MATRIKS.TCELL',
    'MATRIKS.GARAN',
    'MATRIKS.ENJSA',
    'MATRIKS.ASELS',
    'MATRIKS.SAHOL',
    'MATRIKS.TTKOM',
    'MATRIKS.ENKAI',
    'MATRIKS.AEFES',
    'MATRIKS.GSDHO',
    'MATRIKS.AKSEN',
    'MATRIKS.TKFEN',
    'MATRIKS.ALARK',
    'MATRIKS.CIMSA',
    'MATRIKS.ECILC',
    'MATRIKS.SISE',
    'MATRIKS.TTRAK',
    # test
    #'MATRIKS.DOHOL',
    #'MATRIKS.THYAO',
    #'MATRIKS.KCHOL',
    #'MATRIKS.EKGYO',
    # end test
    #'TEFAS.FYD',
    #'TEFAS.TCD',
    #'TEFAS.TCB',
    #'MATRIKS.SAHOL',
    #'MATRIKS.MAVI',
    #'MATRIKS.BUCIM',
    #'MATRIKS.GLDGR',
    #'MATRIKS.GWIND',
    #'MATRIKS.PGSUS',
)
In [3]:
# Fetch data
import miniclickhouse

ch = miniclickhouse.connect(database="algotrade")

qry = """
select * from daily_price_pivot
where `date` > today() - 365
and `MATRIKS.CCOLA` is not null
order by date asc
"""

symbol_data = defaultdict(lambda: [])

for row in ch.execute(qry):
    for target in targets:
        symbol_data[target].append(row[target])
In [4]:
def start_from_zero(vals):
    return [x - vals[0] for x in vals]
In [5]:
def returns(values):
    values = list(values)
    prev = values[0]

    for val in values[1:]:
        yield (val - prev) / prev
        prev = val
In [6]:
def accumulate(values):
    t = 0
    yield t
    for val in values:
        t += val
        yield t
In [7]:
_ = plt.figure(dpi=200)

for target in targets:
    _ = plt.plot(list(accumulate(returns(symbol_data[target]))), label=target)

_ = plt.legend()
Out:
<Figure size 1280x960 with 1 Axes>
In [8]:
def normalize(x):
    x = np.array(x)
    x = x + np.abs(np.min(x))
    return x / np.sum(x)
In [9]:
def portfolio_to_prices(portfolio):
    assert len(portfolio) == len(targets)
    prices = []
    for row in zip(*[symbol_data[target] for target in targets]):
        p = 0
        for v, w in zip(portfolio, row):
            p += v * w
        prices.append(p)
    return prices
In [10]:
_ = plt.figure(dpi=200)
_ = plt.plot(list(accumulate(returns(portfolio_to_prices([1 / len(targets)] * len(targets))))))
Out:
<Figure size 1280x960 with 1 Axes>
In [11]:
def random_weights(N):
    w = np.random.uniform(0, 1, N)
    return normalize(w)

def random_portfolio():
    return random_weights(len(targets))

_ = plt.figure(dpi=200)
for _ in range(512):
    _ = plt.plot(list(accumulate(returns(portfolio_to_prices(random_portfolio())))), linewidth=0.2)
Out: