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.