Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Need guidance on simplifying variables within code

Hi all, new to Quantopian & Python.

I've attached some code where I have three scheduled functions for SPY, IWM & TLT. I begin each function by defining variables for moving averages, price, ratios etc based on the securities tested. If I try moving the variables to the initialize(context), it doesn't work, so I am forced to repeat the same lines for each subsequent function. I'd like to define them once for all scheduled iterations instead of repeating. I'm sure it must be a simple principle that I'm not aware of to make this work. Any thoughts?

Much appreciated!

4 responses

I'll start off with a big disclaimer... coding is very subjective. There are always many ways to accomplish the same tasks. One person's idea of 'simple' or 'the best' way to implement some logic will invariably be different than another person's.

That said, here is how I would simplify the code. First, as was noted, there is a chunk of code duplicated across several functions. It's generally good practice to pull duplicated code out into a single separate function and simply call it multiple times, or ideally execute it only once. In this case since the logic is doing price fetching (very slow) it makes sense to try to execute it only once. So I'd create a new function called something like 'get_data' to first go out and get all the data we will need, for all our decisions, at one time. Store any results as 'globals' in the context object. A common practice on the Quantopian platform is to store 'global' variables as custom attributes of 'context' (ie the algo object). This way all functions can easily share data.

Second, it appears the intent of the algo is to determine which one of three ETFs to hold at any given time. One never holds more than one ETF. With that observation, I wouldn't start with three functions each of which determines if to hold a specific ETF. Why? It takes a bit of cross checking between those functions to ensure one and only one ETF is opened. Conventional guidance for coding is functions should be independent of one another. I shouldn't need to know what is going on inside another function. So, I would create a single function called something like 'determine_target_portfolio' which uses the data fetched in 'get_data' to determine which ETF to hold.

Finally, another conventional guidance of coding is for each function to do a single task. To this end, I'd then create a third function to do all the ordering. Don't intermix the selection process with the ordering process. On a higher level, this is typically the way more complex trading algorithms break things up. There is a section which determines the desired (or target) stocks one wants to hold. Then there is a separate section which does the execution and tries to get to that target.

A final note. Going forward it might be good to generalize the code to use any three ETFs. This wouldn't change the logic at all but rather just the naming (ie don't hardcode the ETFs into the variable names). It becomes confusing if one wanted to try this algo using QQQ rather than SPY. The next level of generalization would be to change the code to work with a variable number of securities. That's a different animal but may be a good challenge?

Anyway, as I started off with, there's no 'best' way to do things, but this is how I would have coded this.

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 Dan, very detailed and exactly what I was looking for.

One clarifying question: you referenced in your source code that spy_price, iwm_price & tlt_price aren't needed because they can be derived from history_***. How would I revise the get_data function to remove the redundancy? I.e. somehow reference history_spy in place of spy_price?

When fetching prices with data.history(context.spy , 'price', 50, '1d') the current price is actually the last value of the series. So these two are equivalent

    # get price data  
    history_spy = data.history(context.spy , 'price', 50, '1d')  
    history_iwm = data.history(context.iwm , 'price', 50, '1d')  
    history_tlt = data.history(context.tlt , 'price', 50, '1d')

    # get current price with data fetch  
    spy_price = data.current(context.spy , 'price')  
    iwm_price = data.current(context.iwm , 'price')  
    tlt_price = data.current(context.tlt , 'price')

    # get current price from data.history  
    spy_price = history_spy[-1]  
    iwm_price = history_iwm[-1]  
    tlt_price = history_tlt[-1]

There isn't a lot of difference and probably boils down to personal preference. Actually, the first method may be a little more obvious in case someone didn't know the [-1] fact. Note, yesterday's close price is at [-2] if one wanted to check yesterdays price.

That makes sense. Thank you very much!