Class based directional indicator

2019-08-27 11:33发布

I'm creating a class based directional indicator that given a number of days (n_days) and a list of numbers, it gives the (number of numbers out of the most recent n_days on which the number was higher than the previous number minus the n_days out of the previous n_days on which the number went down). So if the number in the list increases I want it to return +1, if it decreases I want it to return -1, otherwise it should be 0 so the first number should always be 0 since you can't compare it to anything. Then based on n_days I basically want to take the sum of the of the recent n_days, so for example in a list of [1,2,2,1,2,1] the change should be [0,+1,0,-1,1,-1] and if I want the sum of the change in the 2 recent numbers for each day so it should be [0,+1,-1,0,+1,0] because on the first day there is only 0, on the second day you take the sum of the most recent two days 0+(+1)=1, the third day (+1)+0=+1, the fourth day 0+(-1)=-1 and so forth. Here is my code that's not working:

class Directionalindicator():
    def __init__(self, n_days, list_of_prices):
        self.n_days = n_days
        self.list_of_prices = list_of_prices

    def calculate(self):
        change = []
        for i in range(len(self.list_of_prices)):
            if self.list_of_prices[i-1] < self.list_of_prices[i]:
                change.append(1)
            elif self.list_of_prices[i-1] > self.list_of_prices[i]:
                change.append(-1)
            else:
                change.append(0)
        directional = []
        for i in range(len(change)):
            directional.append(sum(change[i+1-self.n_days:i+1]))
        return directional

testing it with:

y = Directionalindicator(2,[1,2,2,1,2,1])

y.calculate()

should return:

[0,+1,+1,-1,0,0]

and it does.

But testing it with:

y = Directionalindicator(3, [1,2,3,4,5,6,7,8,9,10])

y.calculate()

should return

[0, 0, 2, 3, 3, 3, 3, 3, 3, 3]

but it returns

[0, 0, 1, 3, 3, 3, 3, 3, 3, 3]

I printed change to see what it was doing and the first value is a -1 instead of a 0. Also, the code in one of the answers works using zip, but I don't understand why mine doesn't work for that list from 1-10.

1条回答
啃猪蹄的小仙女
2楼-- · 2019-08-27 12:29

Your comparison

i > i-1

will always be True. You are comparing each price to itself minus one, which will always be smaller. Instead, you should be comparing pairs of prices. zip is useful for this:

change = [0] # first price always zero change
for a, b in zip(self.list_of_prices, self.list_of_prices[1:]):
    if a < b: # price went up
        change.append(1)
    elif a > b: # price went down
        change.append(-1)
    else: # price stayed the same
        change.append(0)

When you plug this into your code and use your example

Directionalindicator(2, [1, 2, 2, 1, 2, 1])

you get:

change == [0, 1, 0, -1, 1, -1]
directional == [0, 1, 1, -1, 0, 0]

This seems to be correct according to your initial statement of the rules, but for some reason doesn't match your "expected output" [0, 1, -1, 0, 1, 0] from the end of your question.


The reason your edit doesn't work is that you are using an index i on the list. When i == 0, i-1 == -1. When used as an index list_of_prices[-1], this gives you the last element in the list. Therefore change contains [-1, 1, 1, 1, 1, 1, 1, 1, 1, 1], as it compares 1 with 10, not [0, 1, 1, 1, 1, 1, 1, 1, 1, 1] as you expected.

查看更多
登录 后发表回答