Back to Community
Q-Tip: How many days since a higher high (or lower low)?

Here is a quick snippet that can help you determine how long it has been since the price was higher (or lower) than today.

    # Get the last X days of prices for every stock in our universe.  
    closes = history(252, '1d', 'close_price').dropna(axis=1)  
    highs = history(252, '1d', 'high').dropna(axis=1)  
    lows = history(252, '1d', 'low').dropna(axis=1)

# How long since the stock was higher than today? (check 252 days)  
            for days in range(1,252):  
                # Check historical days, going back one day at a time  
                test_high = max(highs[stock][-(days+1):-1])  
                if test_high > highs[stock].iloc[-1]:  
                    # If the history day is higher than today, record # of days  
                    context.Highest_In = days  
                    break  
                elif days == 251:  # Today is the highest high in our history  
                    context.Highest_In = days

# How long since the stock was lower than today? (check 252 days)  
            for days in range(1,252):  
                # Check historical days, going back one day at a time  
                test_low = min(lows[stock][-(days+1):-1])  
                if test_low < lows[stock].iloc[-1]:  
                    # If the history day is lower than today, record # of days  
                    context.Lowest_In = days  
                    break  
                elif days == 251: # Today is the lowest low in our history  
                    context.Lowest_In = days 

# How long since the stock CLOSED higher than today? (check 252 days)  
            for days in range(1,252):  
                # Check historical days, going back one day at a time  
                test_high = max(closes[stock][-(days+1):-1])  
                if test_high > closes[stock].iloc[-1]:  
                    # If the history day is higher than today, record # of days  
                    context.Highest_Close_In = days  
                    break  
                elif days == 251: # Today is the highest close in our history  
                    context.Highest_Close_In = days

# How long since the stock CLOSED lower than today? (check 252 days)  
            for days in range(1,252):  
                # Check historical days, going back one day at a time  
                test_low = min(closes[stock][-(days+1):-1])  
                if test_low < closes[stock].iloc[-1]:  
                    # If the history day is lower than today, record # of days  
                    context.Lowest_Close_In = days  
                    break  
                elif days == 251: # Today is the lowest close in our history  
                    context.Lowest_Close_In = days  
9 responses

Hey Tristan great tool, I'm sure there is a nontrivial amount of people who would like a tool like this. I decided to try and make the code a little more concise. Here is a function that gets the number of days since the stock close was a higher than today, it takes in as a parameter a pandas Series and returns a timedelta object.

def days_since_close_was_higher(price_data):  
    highers = price_data[price_data > price_data[-1]]  
    today = price_data.index[-1]  
    last_higher = highers.index[-1]  
    return today - last_higher  

This function can be patterned for the other ones in your post as well.

Cheers!

J

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

James, Thanks for providing the same functionality in a concise function. Since your function returns a time-delta, I could append ".days" to get an integer of days, right?

# Gather history  
closes = history(252, '1d', 'close_price').dropna(axis=1)  
# Save the number of days since a higher close  
num_of_days = days_since_close_was_higher(closes).days  

In that case, your function would be better named "time_since_price_was_higher", because a user may want minutes, or hours, and because they may use "close" data series or "high" data series.

Here is the equivalent for time since price was lower:

def time_since_price_was_lower(price_data):  
    lowers = price_data[price_data < price_data[-1]]  
    today = price_data.index[-1]  
    last_lower = highers.index[-1]  
    return today - last_lower  

Is there any discussion about Quantopian providing a library of "helper" functions like these for us to use in our algos?

Tristan

Curating a library of 'helper' functions is a little difficult as people have widely varying needs, as you pointed out above, the function I gave you doesn't do the exact functionality and required you to tweak it and rename it. So it makes me doubt the value a library of helper functions would provide as users will just change them anyway. I think the current system of searching the forums, while far from perfect, is a good way to get inspiration and to continue the clone-and-tweak style that we currently see. Long term as more folks use the platform you'll see higher quality helper functions rise to the top. Finally another reason why a Quantopian curated function library may be ill advised as it may encourage people to blindly use these functions, and when something goes wrong they may not know how to fix the problem. Those are some of my thoughts on that idea. As always we carefully consider any ideas that have the potential to make the platform and the community better.

James C

James,

I understand what you are saying. Regarding "higher quality helper functions rise to the top", these forums are good, but not great for finding the best information. In fact, I think a lot of great information quietly rolls off the front page, never to be seen again, unless some gold digger finds it.

I would love for Q to provide a way for users to submit a function, and then have the community rate and review these functions. This will truly leverage your crowd-sourcing strengths; community members helping each other to create better algos by identifying the best code snippets.

An example of this type of system would be TradingView's public library of scripts.

I created a GitHub repo that can be used by this community to share functions like the ones above. This may not be the best place to host something like this, but it is better than nothing.

Quantopian-Community on GitHub

If anyone has ideas on how to improve sharing of code, let me know!

Tristan

Tristan - very cool! It's great to see a central source to share code tips and snippets. Looking forward to seeing others add their tips to the repo.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Hi,
How do you find two higher high,lower low for MACD?
The MACD result is using talib.
Thanks

@James - Something with your function is not working with Q2.

IndexError: index -1 is out of bounds for axis 0 with size 0  

It is failing on this line of code:

 last_higher = highers.index[-1]  

Any ideas what is happening differently in Q2 that broke this?

Cheers,

Tristan

I'm not so sure it is Q2 but that I made a mistake in the first iteration. Basically, and this from a cursory glance, I didn't have any code in that handles the edge case where there haven't been any higher days than today in the lookback windo. That seems to be the cause of the problem. Some revised code in provided below

def days_since_close_was_higher(price_data):  
    highers = price_data[price_data > price_data[-1]]  
    today = price_data.index[-1]  
    try:  
        last_higher = highers.index[-1]  
        return today - last_higher  
    except:  
        return np.nan