Dictionaries and the Robo-Advisor¶
One helpful trick with dictionaries is to use them to store data with names.
Consider the robo-advisor tool below.
def get_age():
need_age = True
while need_age:
age = input('What is your age? Enter it as a numberic argument (e.g. "50", not "fifty")\n')
try:
age = int(age) # this will break (raise an exception) if age is not numeric
need_age = False
except Exception as e:
print('Please try entering your age again')
return age
def get_risk_preference():
need_preference = True
while need_preference:
response = input("On a scale of 1-5, how much do you dislike risk? 1=not bothered by risk, 5=extremely worried about risk.\n")
try:
response = int(response) # this will break if response is not 1-5
need_preference = False
except Exception as e:
print('Please try entering your preference again')
return response
def get_allocation():
age = get_age()
# apply rule of 100
equity_weight = 100-int(age)
# get user's risk preference
preference = get_risk_preference()
# shift the allocation according to the user's preference
if preference == 1:
equity_weight += 10
elif preference == 2:
equity_weight += 5
elif preference == 4:
equity_weight -= 5
elif preference == 5:
equity_weight -= 10
# correct weights to stick within 0-100
equity_weight = min(equity_weight, 100)
equity_weight = max(equity_weight, 0)
debt_weight = 100-equity_weight
print('I would recommend', equity_weight, 'percent stocks and ', debt_weight, 'percent bonds')
return [equity_weight, debt_weight]
get_allocation()
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-2-19454c49e5b0> in <module>
----> 1 get_allocation()
<ipython-input-1-bbc80d1b0c91> in get_allocation()
23 def get_allocation():
24
---> 25 age = get_age()
26
27 # apply rule of 100
<ipython-input-1-bbc80d1b0c91> in get_age()
2 need_age = True
3 while need_age:
----> 4 age = input('What is your age? Enter it as a numberic argument (e.g. "50", not "fifty")\n')
5 try:
6 age = int(age) # this will break (raise an exception) if age is not numeric
/mnt/software/anaconda3/lib/python3.8/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
855 """
856 if not self._allow_stdin:
--> 857 raise StdinNotImplementedError(
858 "raw_input was called, but this frontend does not support input requests."
859 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
The block of code where where shift the equity_weight variable is a bit tedious to look at.
A more convenient way to store that information is via a dictionary like so:
def get_allocation():
age = get_age()
# apply rule of 100
equity_weight = 100-int(age)
# get user's risk preference
preference = get_risk_preference()
# shift the allocation according to the user's preference
shift = {1: 10, 2: 5, 3: 0, 4: -5, 5: -10}
equity_weight += shift[preference]
# correct weights to stick within 0-100
equity_weight = min(equity_weight, 100)
equity_weight = max(equity_weight, 0)
debt_weight = 100-equity_weight
print('I would recommend', equity_weight, 'percent stocks and ', debt_weight, 'percent bonds')
return [equity_weight, debt_weight]
get_allocation()
What is your age? Enter it as a numberic argument (e.g. "50", not "fifty")
31
On a scale of 1-5, how much do you dislike risk? 1=not bothered by risk, 5=extremely worried about risk.
5
I would recommend 59 percent stocks and 41 percent bonds
[59, 41]
So, why does this work? Well, recall that we asked the user to state their risk preference. This risk preference was given as an integer between 1 and 5. So, we can think of the integers 1-5 as “names” for preferences. That is, a person who is a 1 is very risk-tolerant/risk-loving. A person who is a 5 is very risk-averse.
Each of these five types of people has a “shift” to the rule of thumb equity weight. For instance, a very risk-averse person receives a shift of -10 to their recommended equity weight.
The dictionary:
shift = {
1: 10,
2: 5,
3: 0,
4: -5,
5: -10
}
print(shift)
{1: 10, 2: 5, 3: 0, 4: -5, 5: -10}
records the person type as the key and the corresponding shift-value as the value in the dictionary.
Any person can then be referenced by their risk preference and their corresponding shift value is returned.
shift[5]
-10
shift[3]
0
Dictionaries are frequently used in this manner. That is, a programmer specifies a dictionary with a set of key-value pairs, and then later uses the dictionary by providing a key to receive the corresponding value.
Let’s consider another example of a dictionary in action.
sectors = {
'Materials': 'ASIX',
'Communications': 'T',
'Cyclical': 'FLWS',
'Energy': 'BATL',
'Financial': 'TROW',
'Healthcare': 'ABBV',
'Industries': 'MMM',
'Technology': 'BOX',
'Utilities': 'CPK'
}
This dictionary uses sector names as keys and stock tickers as values.
Suppose the robo-advisor asks a user what sector they are interested in learning more about. For now, we don’t have enough tools in our toolkit to provide the user with a detailed response (though we will shortly!). Instead, let’s give the robot a bit of personality.
def fave_sector():
need_fave = True
while need_fave:
fave = input('''What is your favorite sector?\n
\t Materials\n
\t Communications\n
\t Energy\n
\t Financial\n
\t Healthcare\n
\t Industrials\n
\t Technology\n
\t Utilities\n''')
if fave in sectors.keys():
need_fave = False
print("That's cool,", sectors[fave],"is my favorite stock")
fave_sector()
What is your favorite sector?
Materials
Communications
Energy
Financial
Healthcare
Industries
Technology
Utilities
Industries
That's cool, MMM is my favorite stock