Back to Community
Creating a rolling window of theil-sen estimator values?

Hello,

I would like to create a rolling window of theil-sen estimator median slope values for use in entry triggers but I am still not too familiar with python / coding in general so I've run into some difficulties.

Is there a way to create a rolling window of tse (medslope) values that can be accessed in a similar fashion to talib.EMA values?
Ideally, I would like to be able to access tse (medslope) values the same way I do with ema values:

If tse[-1] > tse[-2]:
#do something like setting weight to 0.95

Attached is some code I've written to show where I am at so far:
I only know how to generate and access the current bar's TSE medslope value using the scipy theilslopes function.

I appreciate any and all help.

Clone Algorithm
4
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 596fc19cc33d0d53ed6fb083
There was a runtime error.
5 responses

Something like tse_prv here would be my first guess.

The rest would be a few tips and some of my style-OCD's, not to pick on anyone in particular, that's some fine code. For example I can't see straight until I've removed all instances of 'my_', it reminds me of this moment in history brought to you by Disney. (mine mine mine mine in Finding Nemo). Yes folks, I know it is yours. When I see pronouns in code, "my", "our", "we", etc, since I don't know who or what groups those are referring to, it doesn't compute so I often just move on. Remainder of this rant withheld. This was such a good question I couldn't resist taking a look.

from scipy import stats  
import numpy as np  
import talib

def initialize(context):  
    context.spylong = sid(38533)     #sid(38532)  
    context.maximum_profit = 0.001  
    context.maximum_loss   = 0.001

    total_minutes = (6 * 60) + 15  
    for i in range(1, total_minutes):  
        if i % 5 == 0:  
            schedule_function(trade, date_rules.every_day(), time_rules.market_open(minutes=i))

    schedule_function(abandon_ship, date_rules.every_day(), time_rules.market_close(minutes=10))

def assign_weights(context, data):  
    weight = 0

    closes_1m   = data.history(context.spylong, 'close', 390, '1m').ffill().bfill()  
    fast_ema_1m = talib.EMA(closes_1m, timeperiod = 8)

    tse_input = closes_1m[-10:]  
    tse       = stats.mstats.theilslopes(tse_input,       np.arange(len(tse_input)     ))[0]  
    tse_prv   = stats.mstats.theilslopes(tse_input[0:-1], np.arange(len(tse_input) - 1 ))[0]

    # What I would like to be able to do:  
    # if the current tse value > the tse value for the previous bar:  
        #weight = 0.95

    if tse > tse_prv:  
        weight = 0.95  
    elif 0 and fast_ema_1m[-1] > fast_ema_1m[-2]:    # 0 and    has this turned off  
        weight = 0.5

    return weight

def target_stop_exit(context, data):  
    verdict = ''  
    s   = context.spylong  
    pos = context.portfolio.positions

    if pos[s].amount > 0:  
        amount = pos[s].amount  
        current_value = amount * data.current(s, 'price')  
        paid_value    = pos[s].amount * pos[s].cost_basis  
        if   current_value >= paid_value * (1 + context.maximum_profit):  
            verdict = 'target'  
        elif current_value <= paid_value * (1 - context.maximum_loss):  
            verdict = 'stop'  
    return verdict

def trade(context, data):  
    weight = assign_weights(context, data)  
    pos    = context.portfolio.positions  
    oo_spylong = get_open_orders(context.spylong)

    if not pos[context.spylong].amount and not oo_spylong:  
        if weight > 0:  
            print 'Opening position, weight {}'.format(weight)  
            order_target_percent(context.spylong, weight)

    elif pos and not oo_spylong:  
        if   target_stop_exit(context, data) == 'target':  
            #cancel_oos(context, data)  
            order_target(context.spylong, 0)  
            print 'exit, target {}'.format(data.current(context.spylong, 'price'))  
        elif target_stop_exit(context, data) == 'stop':  
            #cancel_oos(context, data)  
            order_target(context.spylong, 0)  
            print 'exit,           stop at {}'.format(data.current(context.spylong, 'price'))

def abandon_ship(context, data):  
    if get_open_orders(context.spylong):  
        print 'Abandon Ship'  
        cancel_oos(context, data)  
        order_target(context.spylong, 0)

def cancel_oos(context, data):  
    oo = get_open_orders()  
    for s in oo:  
        for o in oo[s]: cancel_order(o.id)  

Bump/Update:

I understand that I could 'manually' create such a rolling window which would involve a 'warm-up' period dependent on how many bars I want to lookback and a length-managed list where I would store these values and use listname.pop(-len(listname)) / listname.append(x) to keep it from growing massive and slowing down the algorithm.

Hopefully this is more optional than mandatory.

For just the last 10 in a list being appended, I've been doing this a lot. Maybe there's a better way, not sure. Sure glad you mentioned that. I made a correction above, changed to closes_1m[-10:] and the result looks better.

listname.append(x)  
listname = listname[-10:]    # just the last 10  

Oh my apologies,

I did not see your post when I made my bump/update. Going to go ahead and fiddle around with what you were generous enough to give me.
Will be back here to discuss results

Thanks for all the help, Blue!

I've looked through your code and most of it is pretty self explanatory.
I see that for generating tse_prv, you run the theilsen regression excluding the current bar thereby getting the medslope for 9 bars instead of 10.
A functional shortcut but a shortcut I'd rather not take nonetheless; no worries though, I've already made the necessary changes to fit it to my preference.

While your approach does not actually create a rolling window, it has opened my eyes to a very viable method of simply utilizing the rolling window of closes easily set up by data.history and generating previous bar regression values a la carte via running the regression function on slices of data.history output.

Your help is certain to go a long way for me; thank you for taking the time to answer my call for help :)