Back to Community
Backtest Question: How do I define an initial variable outside the backtest loop?

I am trying to define a variable only once when running the algorithm. Since the backtest acts as a for loop for every minute, I am having a problem being able to do that. Essentially, I am trying to create a complex stop-loss logic:
1) Sell only if shares are bought
2) Sell 50% when the price falls by this much
3) Sell the rest of the 50% when the price falls by this much

This code example explains what I am trying to do.

# initialize variable  
var = "Buy"

for x in range(0, 6): #a for loop example to mimic the backtest every minute loop  
    print "Starting Operation Num %d" % (x)  
    if var == "Buy":  
        print "Buy 100%"  
        var = "Sell"  
    elif var == "Sell":  
        print "Sell 50%"  
        var = "Sell 50%"  
        if var == "Sell 50%":  
            print "Sell 100%"  
            var = "Buy"  

If there's another method of doing this (complex or nested stop-loss logic), feel free to mention it.

9 responses

One can define 'global' variables as a member of 'context' (eg context.my_variable'). This is the preferred method according to Q (see https://www.quantopian.com/tutorials/getting-started#lesson5 ). Something like this


def initialize(context):  
    """  
    Called once at the start of the algorithm.  
    """  
    # Initialize any global variables as a new member of context  
    context.my_global_variable = "buy"


def handle_data(context, data):  
    """  
    Called every minute  
    """  
    if context.my_global_variable == "buy":  
        log.info("Buy 100%")  
        context.my_global_variable = "Sell"  
    elif context.my_global_variable == "Sell":  
        log.info("Sell 50%")  
        context.my_global_variable = "Sell 50%"  
    elif context.my_global_variable == "Sell 50%":  
        log.info("Sell 100%")  
        context.my_global_variable = "buy" 


See attached algorithm. Look at the logs for the output. Good luck

Clone Algorithm
0
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: 5a80c8877ada5f4237c8cb78
There was a runtime error.

Dan,
Thanks, a lot!
The logic worked between buy and sell commands and now I am only selling currently bought positions.
That said, I have a function implemented for selling all positions by the end-of-day (25 mins before the market closes) and now it's not working after adding the nested sell logic.
Under initialize, I have this scheduled:

    schedule_function(func=close_all,  
                      date_rule=date_rules.every_day(),  
                      time_rule=time_rules.market_close(minutes=25)  
                     )  

then I created a function close_all:

def close_all(context, data):  
    for stock in context.portfolio.positions:  
        order_target_percent(stock, 0.0)  
    log.info("END OF DAY!!!")  

It's only working when I have a simple buy/sell logic. See screenshots below:
Before: (able to sell at 3:36)
https://www.dropbox.com/s/ak57nub072aggws/yes_end_of_day_sell.png?dl=0
After:
https://www.dropbox.com/s/wmvsxgsxc53hu4x/no_end_of_day_sell.png?dl=0

Maybe attach a backtest. It would be easier to troubleshoot. It looks like your logic has already closed all the positions by 9:53. The end of day logic is probably being called its that there is nothing to close.

Dan's deduction sounds correct. Are you seeing the "END OF DAY!!!" log appear? If so, the function is being called but not actually closing anything since the positions are already closed out at that point.

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.

Thanks, Jamie and Dan for your response.
I am seeing "END OF DAY!!!" in the log. I added it to test if the function is being called.
You've stated: "the function is being called but not actually closing anything since the positions are already closed out at that point."
That's what I thought at first, but why is it not selling at the end of the day the newly bought shares (at 9:43)?
I have attached my backtest for reference. It looks like there's a buy (9:41) - sell (9:42) - Buy (9:43) pattern. shouldn't the function close the shares that were bought at 9:43?

Clone Algorithm
2
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: 5a81d07b107d124221485e6b
There was a runtime error.

Looking at the trades on 2018-1-24...

9:41 buy 530 / total shares 530  
9:42 sell 1059 / total shares -529 (short 529 shares)  
9:43 buy 529 / total 0 shares  

After 9:43 there are no shares held. What was bought at 9:43 covered the shares that were shorted the minute before so the net is 0.

Does that make sense?

This definitely explains what's happing. However, I am not sure I understand why it's shorting the stock. Sorry if it's a stupid question, but is that by default? is it because I am calling order_target_percent(context.stock1, 0)?
How do I prevent shorting and make sure I place a sell for currently owned position only?

This shows the order to short at minute 11, the same minute long was reported bought.

2018-01-24 06:40 _trac:252 INFO   10   Buy 530 FB _ at 188.57                                  cf16  
2018-01-24 06:41 handle_data:188 INFO Sell 50%  
2018-01-24 06:41 _trac:252 INFO   11      Bot 530 FB (530) at 188.86                           cf16  
2018-01-24 06:41 _trac:252 INFO   11   Sell -1059 FB (530) at 188.86                           3d8b  
2018-01-24 06:42 handle_data:197 INFO Sell the rest of 50%  
2018-01-24 06:42 _trac:252 INFO   12      Sold -1059 FB (-529) at 189.07  (+5)                 3d8b  
2018-01-24 06:42 _trac:252 INFO   12   Buy 529 FB (-529) at 189.07                             3bf4  
2018-01-24 06:43 _trac:252 INFO   13      Bot 529 FB _ at 188.98                               3bf4  

So, does that mean selling then buying shorted stocks does not affect the performance ratio in the backtest at all?