-1

i want to run two for loops in which i calculate annualized returns of a hypothetical trading strategy which is based on moving average crossovers. It's pretty simple: go long as soon as the "faster" MA crosses the "slower". Otherwise move to cash.

My data looks like this:

enter image description here

My Code:

rets = {}
ann_rets = {}

#Nested Loop to calculate returns
for short in range(20, 200):
    for long in range(short + 1, 200):
        
        #Calculate cumulative return
        rets[short,long] = (aapl[short,long][-1] - aapl[short,long][1]) / aapl[short,long][1]
        
        #calculate annualized return
        ann_rets[short,long] = (( 1 + rets[short,long]) ** (12 / D))-1 

The error message i get is the following:

TypeError: list indices must be integers or slices, not tuple

EDIT: Using a dictionary works fine. The screenshot below shows where i'm stuck at the moment. I want to have three final columns: (SMA_1,SMA_2,Ann_rets) SMA_1: First Moving average e.g. 20 SMA_2: Second Moving average e.g. 50 Ann_rets: annualized return which is calculated in the loop above enter image description here

fhebe12
  • 69
  • 5

3 Answers3

1

You're trying access the index of a list with a tuple here: rets[short,long].

Try instead using a dictionary. So change

rets = []
ann_rets = []

to

rets = {}
ann_rets = {}
Kris
  • 564
  • 2
  • 6
  • Works - thank you! Do you know if it's possible to convert my dictionary to a dataframe with the columns (SMA_1, SMA_2, Annualized Return)? SMA_1 and SMA_2 are the numbers in the picture above and the annualized return is calculated within my loop. I know i can convert a dict using pd.DataFrame([ann_rets])...but i'd like to have the order above. – fhebe12 Jan 19 '21 at 12:58
  • See [this](https://stackoverflow.com/questions/33752819/pandas-dataframe-from-dict-not-preserving-order-using-ordereddict). Does that help? You can always change the order of the dataframe by just doing `df[list_of_columns_in_order]`. – Kris Jan 19 '21 at 13:03
1

A double index like rets[short, long] will work for NumPy arrays and Pandas dataframes (like, presumably, your aapl variable), but not for a regular Python list. Use rets[short][long] instead. (Which also means you would need to change the initialization of rests at the top of your code.)

To explain briefly the actual error message: a tuple is more or less defined by the separating comma, that is, Python sees short,long and turns that into a tuple (short, long), which is then used inside the list index. Which, of course, fails, and throws this error message.

9769953
  • 10,344
  • 3
  • 26
  • 37
1

I try to understand your questions. Hope this helps. I simplified your output ann_rets to illustrate reformatting to expected output format. Kr

rets = {}
ann_rets = {}

#Nested Loop to calculate returns
for short in range(20, 200):
    for long in range(short + 1, 200):
        
        #Calculate cumulative return
        rets[short,long] = (aapl[short,long][-1] - aapl[short,long][1]) / aapl[short,long][1]
        
        #calculate annualized return
        ann_rets[short,long] = (( 1 + rets[short,long]) ** (12 / D))-1 
        

# Reformat
Example data:
ann_rets = {(1,2): 0.1, (3,4):0.2, (5,6):0.3}
df1 = pd.DataFrame(ann_rets.values())
df2 = pd.DataFrame(list(ann_rets.keys()))
df = pd.concat([df2, df1], axis=1)
df.columns = ['SMA_1','SMA_2','Ann_rets']
print(df)

Which yields:

   SMA_1  SMA_2  Ann_rets
0      1      2       0.1
1      3      4       0.2
2      5      6       0.3
antoine
  • 662
  • 4
  • 10
  • Thanks for your suggestion. Would it also be possible to receive the structure of the dataframe i described above? – fhebe12 Jan 19 '21 at 13:27
  • Hi, do you means to have, e.g. `rets` and `ann_rets` in columns instead of in the index? or something else? – antoine Jan 19 '21 at 13:40
  • No, so basically three columns: SMA_1 , SMA_2 , ann_rets...the sole purpose of the rets function is to caluclate the ann_rets, so i don't need rets anymore. My goal is to plot a heatmap to see which crossovers will yield the best returns and therefore i need the values of the two moving averages as columns and the annualized return of each individual crossover as column – fhebe12 Jan 19 '21 at 13:44
  • Does my updated answer address your expected output? Kr. – antoine Jan 19 '21 at 14:05