-2

That is, I'm looking for a function true_row such that:

true_row([False, True, True, True, True, False, False])

returns False but

true_row([True, True, True, True, True, False, False])

returns True.

EDIT: In case it helps, I've attached the full code so far below:

position_open = False

def initialize(context):
    context.stock = sid(26578)
    context.open_hours = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
    context.is_bullish = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
    context.first_check_minute = 1
    context.second_check_minute = 57

def handle_data(context, data):

    event_hour = data[context.stock].datetime.hour
    event_minute = data[context.stock].datetime.minute
    hour_open_price = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    hour_close_price = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    global position_open

    # Hour 1 market direction checks

    if event_hour == context.open_hours[0] and event_minute == context.first_check_minute:
        hour_open_price[0] = data[context.stock].close_price

    if event_hour == context.open_hours[0] and event_minute == context.second_check_minute:
        hour_close_price[0] = data[context.stock].close_price

    if hour_open_price[0] < hour_close_price[0]:
        context.is_bullish[0] = True

    if hour_open_price[0] > hour_close_price[0]:
        context.is_bullish[0] = False

    # Hour 2 market direction checks

    if event_hour == context.open_hours[1] and event_minute == context.first_check_minute:
        hour_open_price[1] = data[context.stock].close_price

    if event_hour == context.open_hours[1] and event_minute == context.second_check_minute:
        hour_close_price[1] = data[context.stock].close_price

    if hour_open_price[1] < hour_close_price[1]:
        context.is_bullish[1] = True

    if hour_open_price[1] > hour_close_price[1]:
        context.is_bullish[1] = False

    # Same block repeated with different numbers x24 (edited out to reduce size)


    # Make Trades? - I want to edit this to detect if context.is_bullish has 5 trues in a row without needing to manually make more if statements like the one already below

    if event_hour in context.open_hours and context.is_bullish[0] == True and context.is_bullish[1] == True and context.is_bullish[2] == True and context.is_bullish[3] == True and context.is_bullish[4] == True and position_open == False:
        order(context.stock,+1000)
        log.info('Buy Order Placed')
        position_open = True

    if event_hour in context.open_hours and context.is_bullish[0] == False and position_open == True:
        order(context.stock,-1000)
        log.info('Buy Position Closed')
        position_open = False
  • there is not enough information here. the title, description, and code don't even seem to match. – Inbar Rose Jan 06 '13 at 17:01
  • Welcome to StackOverflow! Asking two questions within one is not a good idea. – David Robinson Jan 06 '13 at 17:05
  • Don't ask two questions at once. If you have more than one question that you cannot solve by searching, make separate questions. – Fredrick Brennan Jan 06 '13 at 17:05
  • @user1953134: That's OK, you can edit your question (I recommend removing the second one) – David Robinson Jan 06 '13 at 17:13
  • @user1953134: Another good idea is to include a reproducible example, something like "I want `[False, True, True, True, True, False, False]` to return `False` but `[True, True, True, True, True, False, False]` to return `True`". Not strictly necessary in this case but it would show you've thought a bit about the problem! – David Robinson Jan 06 '13 at 17:16
  • Would that be posssible? I'm a bit of a python noob... – user1953134 Jan 06 '13 at 17:23
  • @user1953134: I also helped edit the question a bit. – David Robinson Jan 06 '13 at 17:29
  • You might want to have a look at these previous questions about finding a sequence within a sequence (a more general case than what you're asking for): http://stackoverflow.com/questions/2250633/python-find-a-list-within-members-of-another-listin-order; http://stackoverflow.com/questions/425604/best-way-to-determine-if-a-sequence-is-in-another-sequence-in-python – Stuart Jan 06 '13 at 17:34
  • @user1953134: Anyway, there are two solutions to your problem below. (you should try one, and if it works, accept it by clicking the green checkmark) – David Robinson Jan 06 '13 at 17:35
  • Being rather new to python, they seem complicated :S (and my other languages haven't been used in a while either, having somehow ended up studying economics). If only there was a solution as simple as the first snippet here http://stackoverflow.com/questions/2250633/python-find-a-list-within-members-of-another-listin-order – user1953134 Jan 06 '13 at 17:42
  • @user1953134: You think the first solution is simple? It's recursive- it looks more complicated to me than either of our answers, especially A.R.S's. But you can always try them, and take them apart to understand – David Robinson Jan 06 '13 at 18:02
  • I suggest going to http://codereview.stackexchange.com/ to review your whole programme (although it's a lot quieter than stackoverflow) – Stuart Jan 06 '13 at 19:21

4 Answers4

2

Use itertools.groupby, which groups sets of identical elements in a row:

import itertools
any(len(list(g)) >= 5 and k == True for k, g in itertools.groupby(lst))
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • 1
    This is how I first thought to do it, but interestingly it seems to be much slower than the string approach (which is strange, since I thought it would be faster). – arshajii Jan 06 '13 at 17:26
  • @A.R.S.: Interesting, and maybe not that surprising- join and index operations are very fast. Replacing `len(list(g))` with `sum(1 for _ in g)` in my answer would speed it up. – David Robinson Jan 06 '13 at 17:29
1

If you had a list l, you could use

('True' * 5) in ''.join(map(str, l))

In other words your function would be

def true_row(row):
    return ('True' * 5) in ''.join(map(str, row))

>>> def true_row(row):
...     return ('True' * 5) in ''.join(map(str, row))
... 
>>> true_row([False, True, True, True, True, False, False])
False
>>> true_row([True, True, True, True, True, False, False])
True
arshajii
  • 127,459
  • 24
  • 238
  • 287
0

If I read your question correctly, you are only interested in the count of Boolean rather than consecutive True values. Also you are working on a List rather than any iterable. If that is the case, you can simply use count. I would suggest you convert the sequence to List to ensure, your result is consistent across any iterable

def true_row(row):
    return list(row).count(True) >= 5

As explained by OP, he needs 5 consecutive boolean affirmation, in which case, I would suggest a plain vanilla loop and count technique which has a short-circuit mechanism to quit searching whenever it encounter's 5 consecutive True's. And its 10 fold faster on a random sample of 1000 data I tested. I suspect you may have to iterate through thousands of stock data for a considerable duration, so this will come useful.

def true_row(row, length = 5):
    count = - length
    for e in row:
        if e:
            count += 1
        else:
            count = -length
        if not count:
            return True
    return False

Now the Speed Test

>>> seq = (choice([True, False]) for _ in xrange(1000))
>>> def David(seq):
    return any(len(list(g)) >= 5 and k == True for k, g in itertools.groupby(lst))

>>> def ARS(seq):
    return ('True' * 5) in ''.join(map(str, row))

>>> t_ab = timeit.Timer(stmt = "true_row(seq)", setup = "from __main__ import true_row, seq")
>>> t_david = timeit.Timer(stmt = "David(seq)", setup = "from __main__ import David, seq, itertools")
>>> t_ars = timeit.Timer(stmt = "ARS(seq)", setup = "from __main__ import ARS, seq")
>>> t_ab.timeit(number=1000000)
0.3180467774861455
>>> t_david.timeit(number=1000000)
10.293826538349393
>>> t_ars.timeit(number=1000000)
4.2967059784193395

Even for smaller sequence where it has to iterate over the entire sequence, this is faster

>>> seq = (choice([True, False]) for _ in xrange(10))
>>> true_row(seq)
False
>>> t_ab = timeit.Timer(stmt = "true_row(seq)", setup = "from __main__ import true_row, seq")
>>> t_david = timeit.Timer(stmt = "David(seq)", setup = "from __main__ import David, seq, itertools")
>>> t_ars = timeit.Timer(stmt = "ARS(seq)", setup = "from __main__ import ARS, seq")
>>> t_ab.timeit(number=1000000)
0.32354575678039055
>>> t_david.timeit(number=1000000)
10.270037445319304
>>> t_ars.timeit(number=1000000)
3.7353719451734833
Abhijit
  • 62,056
  • 18
  • 131
  • 204
  • He wants to determine if there are 5 *consecutive* trues. – arshajii Jan 06 '13 at 17:43
  • @A.R.S.: Hmmm in that case, I may be interpreting it incorrectly. I will leave my answer as of now, until user comes back with a clear written question explaining what he exactly wants. – Abhijit Jan 06 '13 at 17:49
  • Yes, A.R.S. is right. I'm using it to detect if a stock value has went up 5 hours in a row, as a determinant of whether the stock price is bullish and so whether my algorithm should place an order to buy the stock. – user1953134 Jan 06 '13 at 17:50
0

Here is an answer designed for simplicity

def five_true(L):
    for i in range(len(L) - 5):
        if L[i:i + 5] == [True] * 5:
            return True
    return False
Stuart
  • 9,597
  • 1
  • 21
  • 30