Python Forum
[Tkinter] User interface for stock portfolio optimisation
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] User interface for stock portfolio optimisation
#1
Thanks by advance for your help. I know it is a complex request. I did my best to do it on my own, but I am stuck… I am using Python 3 on Anaconda, Jupyter.

-----
Hi, I am a noob on Python and more generally in programming, but I am doing my best to learn thanks to online tutorials.
I would like to code a small downloadable program allowing anyone to obtain the optimal stock weights to include in a portfolio in order to maximise expected return. Even if you know nothing about finance, you can still help me because my computations are already working. I just need a “Tkinter expert” ?

Based on a code I found online and some personal adjustments, the code is operational and gives me the outcomes (text and graphs) that I want already. However, I would like to make the code "responsive" to inputs entered in a user interface. For this, I know I have to use Tkinter. I have made several attemps, but I cannot succeed to connect my python code and the user interface thanks to Tkinter. I just miss that "link" to make everything go smoothly.

Could you please help me?
I would like to add a picture of the final result I am looking for but I don't know how to dit on this forum. So here is a quick description.

-----

I would like to have a downloadable program with an icon, which opens a window when we click on it. Just like any program.
Once the window opens it would be organised as follow:

Top section: Logo + Welcome + Instructions
Next to it, two buttons one "Export the document as PDF" and another "Clear inputs"

Inputs section: 3 labels with 3 entry boxes and one button "Go"
Label 1: How many stocks are there in your portfolio?
Entry box 1: horizontal slider widget ranging from 3 to 30
Label 2: Enter the related stock tickers (yahoo finance)
Entry box 2: text box - important to type stocks as follow 'AAPL', 'GOOGL', 'FB' ......
Label 3: Precise time interval for historic performance and volatility
Entry box 3: radio button - 1 year or 3 years or 5 years from today (last closing price when the user opens the program)
A button "Go" to run the program


Outputs section: 2 graphs and 2 texts
Graph 1: Efficient frontier
Text 1: Max Sharpe Ratio Portfolio and Min Variance Portfolio descriptions
Graph 2: Pie chart with related weights
Graph 2: Stocks' historical return and volatility

-----

Here is the code (with no Tkinter attempt)
I will post my unworking Tkinter attempt afterwards.

import numpy as np
import pandas as pd 
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
import seaborn as sns
import quandl
import scipy.optimize as sco
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
plt.style.use('fivethirtyeight')
np.random.seed(777)


#I think this is a CRITICAL part from which many inputs should be collected from the user interface’s entry boxes, but I do not know how to connect them (eg: replace 'AAPL', 'AMZN', 'FB', 'GOOGL' by what is written in entry box 2).
tickers = ['AAPL', 'AMZN', 'FB', 'GOOGL']
stocks = pd.DataFrame()
for t in tickers:
    stocks[t] = wb.DataReader(t, data_source='yahoo', start='2019-3-31', end='2020-3-31')['Adj Close']


def pfolio_ann_perf(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns * weights ) * 250
    std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(250)
    return std, returns

#Here as well, I need to make sure that the value of rf-rate changes according to what the user wrote in entry box 4, but don’t know how.
returns = stocks.pct_change()
mean_returns = returns.mean()
cov_matrix = returns.cov()
num_pfolio = 25000
rf_rate = 0.01


def neg_sharpe_ratio(weights, mean_returns, cov_matrix, rf_rate):
    p_var, p_ret = pfolio_ann_perf(weights, mean_returns, cov_matrix)
    return -(p_ret - rf_rate) / p_var

def max_sharpe_ratio(mean_returns, cov_matrix, rf_rate):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix, rf_rate)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))
    result = sco.minimize(neg_sharpe_ratio, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)
    return result


def pfolio_volatility(weights, mean_returns, cov_matrix):
    return pfolio_ann_perf(weights, mean_returns, cov_matrix)[0]

def min_variance(mean_returns, cov_matrix):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))

    result = sco.minimize(pfolio_volatility, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)

    return result


def efficient_return(mean_returns, cov_matrix, target):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)

    def pfolio_return(weights):
        return pfolio_ann_perf(weights, mean_returns, cov_matrix)[1]

    constraints = ({'type': 'eq', 'fun': lambda x: pfolio_return(x) - target},
                   {'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0,1) for asset in range(num_assets))
    result = sco.minimize(pfolio_volatility, num_assets*[1./num_assets,], args=args, method='SLSQP', bounds=bounds, constraints=constraints)
    return result


def efficient_frontier(mean_returns, cov_matrix, returns_range):
    efficients = []
    for ret in returns_range:
        efficients.append(efficient_return(mean_returns, cov_matrix, ret))
    return efficients


def display_ef_with_selected(mean_returns, cov_matrix, rf_rate):
    max_sharpe = max_sharpe_ratio(mean_returns, cov_matrix, rf_rate)
    sdp, rp = pfolio_ann_perf(max_sharpe['x'], mean_returns, cov_matrix)
    max_sharpe_allocation = pd.DataFrame(max_sharpe.x,index=stocks.columns,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T
    max_sharpe_allocation

    min_vol = min_variance(mean_returns, cov_matrix)
    sdp_min, rp_min = pfolio_ann_perf(min_vol['x'], mean_returns, cov_matrix)
    min_vol_allocation = pd.DataFrame(min_vol.x,index=stocks.columns,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T
    
    an_vol = np.std(returns) * np.sqrt(252)
    an_rt = mean_returns * 252
    
    print ("-"*80)
    print ("Maximum Sharpe Ratio Portfolio Allocation\n")
    print ("Annualised Return:", round(rp,2))
    print ("Annualised Volatility:", round(sdp,2))
    print ("\n")
    print (max_sharpe_allocation)
    print ("-"*80)
    print ("Minimum Volatility Portfolio Allocation\n")
    print ("Annualised Return:", round(rp_min,2))
    print ("Annualised Volatility:", round(sdp_min,2))
    print ("\n")
    print (min_vol_allocation)
    print ("-"*80)
    print ("Individual Stock Returns and Volatility\n")
    for i, txt in enumerate(stocks.columns):
        print (txt,":","annualised return",round(an_rt[i],2),", annualised volatility:",round(an_vol[i],2))
    print ("-"*80)
    
    fig, ax = plt.subplots(figsize=(10, 7))
    ax.scatter(an_vol,an_rt,marker='o',s=200)

    for i, txt in enumerate(stocks.columns):
        ax.annotate(txt, (an_vol[i],an_rt[i]), xytext=(10,0), textcoords='offset points')
    ax.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    ax.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')

    target = np.linspace(rp_min, 0.34, 50)
    efficient_pfolio = efficient_frontier(mean_returns, cov_matrix, target)
    ax.plot([p['fun'] for p in efficient_pfolio], target, linestyle=':', color='black', label='Efficient frontier')
    ax.set_title('Portfolio Optimization with Individual Stocks')
    ax.set_xlabel('Annualised Volatility')
    ax.set_ylabel('Annualised Returns')
    ax.legend(labelspacing=0.8)

display_ef_with_selected(mean_returns, cov_matrix, rf_rate)
-----

This is my failed attempt at tkinter. Since it was not working for entry boxes, I did not try to do more.

from tkinter import *
from PIL import ImageTk, Image


root = Tk()
root.title('MT Finance')
root.iconbitmap(r'D:/Coding/Portfolio_Optimisation/Logo.ico')


mylabel1 = Label(root, text='Please type stock tickers (eg: "AAPL")')
mylabel1.grid(row=2, column=0)
e1 = Entry(root, width=35, borderwidth=5)
e1.grid(row=3, column=0, columnspan=3, padx=10, pady=10)

mylabel2 = Label(root, text='Please type start date (eg: 1-1-2019)')
mylabel2.grid(row=4, column=0)
e2 = Entry(root, width=35, borderwidth=5)
e2.grid(row=5, column=0, columnspan=3, padx=10, pady=10)

mylabel3 = Label(root, text='Please type end date (eg: 1-1-2020)')
mylabel3.grid(row=6, column=0)
e3 = Entry(root, width=35, borderwidth=5)
e3.grid(row=7, column=0, columnspan=3, padx=10, pady=10)


#def mystocks():
    #selected_stocks = Label(root, text=e1.get())
    #selected_stocks.grid(row=9, column=0)
    #e1.delete(0, END)
    
# Display the button triggering the function

#mybutton = Button(root, text='Write stocks', padx=10, pady=10, command=mystocks, fg='red')
#mybutton.grid(row=8, column=0)



tickers = [e1.get()]
start_date = [e2.get()]
end_date = [e3.get()]

stocks = pd.DataFrame()
for t in tickers:
    stocks[t] = wb.DataReader(t, data_source='yahoo', start_date, end_date)['Adj Close']

def price_graph():
    (stocks / stocks.iloc[0] * 100).plot(figsize=(15, 6))
    plt.legend(loc='upper left', fontsize=10)
    plt.ylabel('price in $')
    plt.show()

price_graph_button = Button(root, text='Price Graph', padx=10, pady=10, command=price_graph, fg='red')
price_graph_button.grid(row=8, column=0)

root.mainloop()
-----

As, said before, all my computations and graphs are displaying correctly in Python. However, I need your help to make the connection between my code and a simple user interface via Tkinter. I watched several tutorials but I am stuck.
First of all, I would like to have a basic, ugly version working from inputs to outputs. Afterwards, and if you are still kind enough to help me, we can have a look at the “export”, “clear” buttons and the layout :D

If this is not clear please tell me and I will be happy to give more information!

PS: I had to retype all this TWICE because the forum does not allow to edit a message 10 minutes after starting to type. This was, VERY, annoying.
Reply
#2
your thread is similar to this one data from internet and post in gui tkinter
maybe it can help with your start,
Reply
#3
Thank you for your help @joe_momma. I had a look at the other post, but unfortunately, as I have told you, I am a real beginner and this is hard for me to understand and adapt to my particular case. Could you provide some more guidance on how I should do this concretely please? Maybe you know some videos online to make this particular thing or maybe you could give me some hints yourself?

Do you think I should repost it in the "Homework" section to look for help maybe?

Thank you.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] User interface for stock portfolio optimisation Fourchelangue 0 1,997 Apr-02-2020, 10:10 PM
Last Post: Fourchelangue
  [PyQt] Invoking user interface design 12203276 1 3,449 May-22-2017, 06:46 PM
Last Post: Larz60+
  [PyQt] User Interface to Python Raures 11 10,603 Jan-24-2017, 05:01 AM
Last Post: California

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020