Python Forum
Stock Return calculation problem
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Stock Return calculation problem
#1
Hello,

I am trying to solve a portfolio management kind of exercise and I don't know what is wrong in my code. I am a beginner in Python but I know how to code in VBA so I've more this style to write my code.

I would like to have the return weighted of each stocks for each days added to a base 100 to have the percentage of evolution of my stocks and obviously py portfolio each days. For example:

100
100,04
101
102
101

at the end I'll have my annualized return in function of my portfolio, in this example: 101 = 1% in base 100 and 1000$ in 100 000$ portfolio.

Wish you a nice day,

L.

import numpy as np
import pandas as pd
import pandas_datareader as web
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn
import yfinance as yf

#Enter the stocks you want to use as variables

t1="BRK-B"
t2="AMZN"
t3="AAPL"
t4="NFLX"
t5="GOOG"

w1=.2
w2=.3
w3=.1
w4=.2
w5=.2

#select start date for correlation window as well as list of tickers

tickers_1 = [t1]
Stock_1 = web.get_data_yahoo(tickers_1,
start = "2013-01-01",
end = "2014-01-01")

tickers_2 = [t2]
Stock_2 = web.get_data_yahoo(tickers_2,
start = "2013-01-01",
end = "2014-01-01")

tickers_3 = [t3]
Stock_3 = web.get_data_yahoo(tickers_3,
start = "2013-01-01",
end = "2014-01-01") #Nadaq-SP500-Oil brut-Bitcoin

tickers_4 = [t4]
Stock_4 = web.get_data_yahoo(tickers_4,
start = "2013-01-01",
end = "2014-01-01")

tickers_5 = [t5]
Stock_5 = web.get_data_yahoo(tickers_5,
start = "2013-01-01",
end = "2014-01-01")

# w=[w1, w2, w3, w4, w5]


#Porfolio return weighted in function of the weight entered 

return_1 = Stock_1['Adj Close'].pct_change()[1:] * w1 
return_2 = Stock_2['Adj Close'].pct_change()[1:] * w2 
return_3 = Stock_3['Adj Close'].pct_change()[1:] * w3 
return_4 = Stock_4['Adj Close'].pct_change()[1:] * w4 
return_5 = Stock_5['Adj Close'].pct_change()[1:] * w5 

# print(return_1, return_2, return_3, return_4, return_5)

# cumulativelist = []
# length = len[cumulativelist]
countsum = 100
for i in range(252):

    countsum = countsum * (1 + return_1 + return_2 + return_3 + return_4 + return_5)
    i = i + 1

print(countsum)
Reply
#2
Hi, welcome to the forum.
I would like to help, but I find your explanation hard to understand. Your program looks quite nice at first sight.

(Sep-22-2022, 02:13 PM)LFin Wrote: I don't know what is wrong in my code
Well, I don't know either. You need to explain more about the problem. Does the program produce an error message? Then please show the complete error message. Does it not show the expexted result? Then show what you expected and what you get.
Reply
#3
You could significantly simplify your code. Get rid of the repetition, put tickers into list/tuple and iterate over them:

tickers = ("BRK-B", "AMZN", "AAPL", "NFLX", "GOOG")

for ticker in tickers:
    data = web.get_data_yahoo(ticker, start="2013-01-01", end="2014-01-01")
    # do something with data
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#4
(Sep-23-2022, 11:23 AM)perfringo Wrote: You could significantly simplify your code. Get rid of the repetition, put tickers into list/tuple and iterate over them:

tickers = ("BRK-B", "AMZN", "AAPL", "NFLX", "GOOG")

for ticker in tickers:
    data = web.get_data_yahoo(ticker, start="2013-01-01", end="2014-01-01")
    # do something with data

Hi, first of all, thank you for your help. I totally understand and I did it, exactly what you wrote in the first time but as I am going to use different weights (w1, w2...) for each assets and The computation of my last formula (Base * (1 + return1*w1 + return2*w2...) I think I need to separate them...

What is wrong is that the code I wrote is showing NaN for each return value and is not showing any good results as I explained in my post. It should return:
100
102
103
102
105
107
104
...
112
114

Something like that with each daily returns of each stocks * their weights in the portfolio and for Base the total of yesterday so each day, the return take account of the previous one kind of compound returned if I may say.

I have:
Output:
Symbols AAPL AMZN BRK-B GOOG NFLX Date 2013-01-03 NaN NaN NaN NaN NaN 2013-01-04 NaN NaN NaN NaN NaN 2013-01-07 NaN NaN NaN NaN NaN 2013-01-08 NaN NaN NaN NaN NaN 2013-01-09 NaN NaN NaN NaN NaN ... ... ... ... ... ... 2014-12-24 NaN NaN NaN NaN NaN 2014-12-26 NaN NaN NaN NaN NaN 2014-12-29 NaN NaN NaN NaN NaN 2014-12-30 NaN NaN NaN NaN NaN 2014-12-31 NaN NaN NaN NaN NaN [503 rows x 5 columns]
Thanks for your help, I still not found the solution for the moment.
Reply
#5
(Sep-23-2022, 06:46 PM)LFin Wrote: I totally understand and I did it, exactly what you wrote in the first time but as I am going to use different weights (w1, w2...) for each assets and The computation of my last formula (Base * (1 + return1*w1 + return2*w2...) I think I need to separate them...

Maybe you should try it again. I can't see any advantages of having separate variables/names compared to list/tuple/dictionary approach. You can access both by name and in container they become iterable in case you need to access them dynamically:

>>> weights = (0.2, 0.3, 0.4)
>>> weights[0]
0.2
>>> for weight in weights: 
...     print(weight)
...
0.2
0.3
0.4
>>> weights = {1: 0.2, 2: 0.3, 4: 0.4}
>>> weights[2]
0.3
You should also think about future self. If you return to your code in two days/weeks/months do you remember what tickers_3 / return_3 were? Was it AMZN or APPL?
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#6
If you want the percent change for each day I would do this:
import pandas_datareader as web
import pandas as pd

#Enter the stocks you want to use as variables
 
portfolio = {
    "BRK-B":0.2,
    "AMZN":0.3,
    "AAPL":0.1,
    "NFLX":0.2,
    "GOOG":0.2,
}
 
#select start date for correlation window as well as list of tickers
def percent_change(portfolio, start, end):
    pct_change = {}
    for ticker in portfolio:
        stock = web.get_data_yahoo(ticker, start=start, end=end)
        pct_change[ticker] = stock['Adj Close'].pct_change()[1:]
    return pd.DataFrame(pct_change)

pct_change = percent_change(portfolio, "2013-01-01", "2013-01-10")

weighted_change = pct_change * portfolio.values()
weighted_change['Total'] = weighted_change.sum(axis = 1)

countsum = []
cs = 100
for total in weighted_change["Total"]:
    cs *= (1 + total)
    countsum.append(cs)
weighted_change["Countsum"] = countsum

print(weighted_change)
Output:
BRK-B AMZN AAPL NFLX GOOG Total Countsum Date 2013-01-03 0.000901 0.001364 -0.001262 0.009955 0.000116 0.011075 101.107477 2013-01-04 0.000491 0.000778 -0.002785 -0.001263 0.003952 0.001173 101.226027 2013-01-07 -0.000852 0.010778 -0.000588 0.006710 -0.000873 0.015174 102.762025 2013-01-08 0.000770 -0.002324 0.000269 -0.004113 -0.000395 -0.005792 102.166791 2013-01-09 -0.001045 -0.000034 -0.001563 -0.002573 0.001315 -0.003900 101.768360 2013-01-10 0.002850 -0.001138 0.001240 0.004358 0.000910 0.008221 102.605005
Reply
#7
(Sep-24-2022, 08:14 AM)perfringo Wrote:
(Sep-23-2022, 06:46 PM)LFin Wrote: I totally understand and I did it, exactly what you wrote in the first time but as I am going to use different weights (w1, w2...) for each assets and The computation of my last formula (Base * (1 + return1*w1 + return2*w2...) I think I need to separate them...

Maybe you should try it again. I can't see any advantages of having separate variables/names compared to list/tuple/dictionary approach. You can access both by name and in container they become iterable in case you need to access them dynamically:

>>> weights = (0.2, 0.3, 0.4)
>>> weights[0]
0.2
>>> for weight in weights: 
...     print(weight)
...
0.2
0.3
0.4
>>> weights = {1: 0.2, 2: 0.3, 4: 0.4}
>>> weights[2]
0.3
You should also think about future self. If you return to your code in two days/weeks/months do you remember what tickers_3 / return_3 were? Was it AMZN or APPL?

Hello, thank you very much for this answer, as I am new in python I did not know that I could access variables independently, very useful !
Reply
#8
(Sep-24-2022, 11:11 AM)deanhystad Wrote: If you want the percent change for each day I would do this:
import pandas_datareader as web
import pandas as pd

#Enter the stocks you want to use as variables
 
portfolio = {
    "BRK-B":0.2,
    "AMZN":0.3,
    "AAPL":0.1,
    "NFLX":0.2,
    "GOOG":0.2,
}
 
#select start date for correlation window as well as list of tickers
def percent_change(portfolio, start, end):
    pct_change = {}
    for ticker in portfolio:
        stock = web.get_data_yahoo(ticker, start=start, end=end)
        pct_change[ticker] = stock['Adj Close'].pct_change()[1:]
    return pd.DataFrame(pct_change)

pct_change = percent_change(portfolio, "2013-01-01", "2013-01-10")

weighted_change = pct_change * portfolio.values()
weighted_change['Total'] = weighted_change.sum(axis = 1)

countsum = []
cs = 100
for total in weighted_change["Total"]:
    cs *= (1 + total)
    countsum.append(cs)
weighted_change["Countsum"] = countsum

print(weighted_change)
Output:
BRK-B AMZN AAPL NFLX GOOG Total Countsum Date 2013-01-03 0.000901 0.001364 -0.001262 0.009955 0.000116 0.011075 101.107477 2013-01-04 0.000491 0.000778 -0.002785 -0.001263 0.003952 0.001173 101.226027 2013-01-07 -0.000852 0.010778 -0.000588 0.006710 -0.000873 0.015174 102.762025 2013-01-08 0.000770 -0.002324 0.000269 -0.004113 -0.000395 -0.005792 102.166791 2013-01-09 -0.001045 -0.000034 -0.001563 -0.002573 0.001315 -0.003900 101.768360 2013-01-10 0.002850 -0.001138 0.001240 0.004358 0.000910 0.008221 102.605005

Hi, so if I understand well the code, it is good because it take each time the adjusted countsum and multiply it by the total weighted return (Asset 1 return * weight 1 + asset 2 return * weight 2...)

If you can confirm I am right, it is perfect and it will allow me to adapt my code and understand better the functionalities as I am new to python. Thanks for that !
Reply
#9
Verify it yourself.
pct_change = percent_change(portfolio, "2013-01-01", "2013-01-10")
print(pct_change)  # Or just print a slice pct_change[:10]
weighted_change = pct_change * portfolio.values()
print(weighted_change)
I don't trust anyone to do anything correctly. I test and verify. You should do the same with your code.
Reply
#10
(Sep-26-2022, 03:24 PM)deanhystad Wrote: Verify it yourself.
pct_change = percent_change(portfolio, "2013-01-01", "2013-01-10")
print(pct_change)  # Or just print a slice pct_change[:10]
weighted_change = pct_change * portfolio.values()
print(weighted_change)
I don't trust anyone to do anything correctly. I test and verify. You should do the same with your code.

Of course, that's why I think there is a problem somewhere but I did not have time to work on it this morning. Indeed, it is impossible that the return of the portfolio in the year 2013 - 2014 was 80% (Base 100 at the beginning and then 180 at the end of the year)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Dataframe mean calculation problem: do we have to loop? sparkt 1 2,177 Aug-28-2020, 02:41 PM
Last Post: sparkt
  Any suggestions to improve BuySell stock problem efficiency? mrapple2020 0 1,375 May-13-2020, 06:19 PM
Last Post: mrapple2020
  Problem with simple 3D Vektor calculation Pythocodras 0 1,714 Dec-11-2019, 07:18 PM
Last Post: Pythocodras
  Matrix Calculation Problem arshad 4 2,645 Nov-04-2019, 03:48 PM
Last Post: baquerik
  Pass variable script return twice output problem Faruk 8 4,390 Dec-26-2018, 11:57 AM
Last Post: Faruk
  problem with function return value ujjwalrathod007 9 23,345 Sep-23-2016, 03:02 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

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