Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Simple "Moving Average Ratio" Strategy

Hello guys,

I have some experience with mql4 but none with other programming codes. Since I'd like to test a very simple strategy maybe someone among you is so generous and will help me. I'd like to code the following strategy:

  1. Calculate a RATIO between price and its simple moving average (20): RATIO = LAST/ SMA(20)
  2. SELL when ratio is above a given value. CLOSE position when ratio is below 1 or when unrealized loss is 2% of capital.
  3. BUY when ratio is below a given value. CLOSE position when ratio is above 1 or when unrealized loss is 2% above capital.

Thank you in advance.

Matteo

23 responses

If I understand correctly you are trying to detect overbought/oversold conditions to trade, and closing when the average reflects the current value (suggesting the price has reached it's true price)?

I've created a long-only version of your above logic (if I've understood you correctly), as a place to start.

It seems at first glance to meet that age old problem stated by Keynes... "The market can stay irrational far longer than you can remain solvent".

Either that or it's my coding (I'm tired and out of practice :P).

Dear Adam,

thank you very much for your help. I forgot to mention that my analysis is based on daily data and on major stock indexes such as SPY and DIA. Here you find another backtest set with my parameters. From a study I'm conducting at the moment I'm finding that these major stock indexes tend to revert to the mean when some extremes are reached. I perfectly know that using most oscillators you end up with losing strategies; however, this RATIO I thought of seems to work.

I managed to code two versions, one for the shorts and one for the shorts. Below are the backtest of the short version.

and the backtest of the long version.

I'd like to do some test on multiple stocks. I read the sample code provided for multiple securities algorithms but I always get an error message. Could anyone suggest a feasible solution for converting this single stock code to a multiple stocks one? Thank you in advance.

Matteo,

One way to incorporate multiple stocks into your algorithm is to declare the code below in your initialize method

context.stocks = [#your multiple sids here]  

and in your handle_data method, you would iterate through each of these stocks like so

for stocks in context.stocks:  
# Your main methods below  

One other thing to note is that your buy_order and close_buy_order methods must also be changed to take in the current stock as a parameter as in

def buy_order(context, stock):  

I've attached a backtest to show what kind of changes you'd need to have.

Hope this helps!

-Seong

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.

Thank you very much Seong.

I'm testing the new code you provided. However, I'm trying to discover why the results for two stocks backtests differ dramatically from the results of single backtests combined...

I'm investigating the transaction details and it looks that the algorithm now trades like a pair trading strategy, and so buying one security and selling the other one at the same time.

Hi Matteo,

Is there an ideal behavior instead of what's happening now?

(I hope I'm getting your question) Yes of course there's an ideal behavior. The idea is quite simple: this algorithm monitors the divergence of price from a moving average and enters in favor of trend, when extreme counter-trend deviations are detected. It trades very infrequently but when it does it is accurate. The divergence is measured with the variable called "ratio". The major trend is detected simply by comparing two moving averages. At the moment I'm fine with the algorithm and next steps would be:
1. including multiple securities
2. combining the long version and the short version under one single algorithm.

Matteo,

I've found what's causing the strategy to trade like a pair trading strategy. It was in the logic of the boolean, context.position_closed, which was being switched on and off every time a security was bought instead of being turned on and off for each individual security. E.g. If you bought SPY, it would turn False for the entire algorithm, instead of just for the SPY. Thankfully, there's a fix to this by using a Python dictionary and I've attached a solution here:

-Seong

Thank you very much Seong. I'm currently testing different ETFs for this strategy. The final step will be combining the long version and the short version under one single algorithm. I'll post some backtest soon. Thank you again. :)

No Problem! Looking forward to seeing your results!

Below you find a back test for one aggressive Long version. Underlyings are SPY and DIA.

I'm trying to figure out if the algorithm works fine with multiple securities. I can't understand how, if I backtest the algorithm at first only on the SPY, then only on the DIA, and then on the SPY and DIA together I get the following results (from 2010 to 2013 with daily data):
1. only SPY: 14.5% return
2. only DIA: 17.8% return
3. SPY and DIA: 17.1% return

Shouldn't I expect to get roughly 14.5% + 17.8% return?

Matteo,

Looking over the algorithm again, I have some questions that may help us get to the root of the problem.

  • I believe the logic of current_position_value <> context.position_cost is an issue. Do you think context.position_cost should be individual for each security like we did for context.position_closed?

SEONG, I think I solved that problem separating, in the code, the variables for the buy and sell orders. Here's a backtest on SPY, DIA, IWR. The next step I find a bit tricky is to allocate to each ticker a portion of capital. For example I tried setting the buy and sell size as: size=(10000*0.1)/price , the problem is that it opens orders in the correct way, but when it closes an order, the price of the stock has changed and though the closing size results slightly different than the opening size, and this creates some "positions residuals" that disturb the strategy. Any help or suggestion in this sense or for the strategy in general is welcome! :)

Matteo,

Great to hear!! The algo is looking very impressive now.

Do you think you provide a short example on what "position residuals" you are referring to?

For now, I'd like to suggest a target weight to use for each security (e.g. everytime the SPY triggers the conditions, it will hold 30% of the portfolio?) but am getting the feeling that you'd get the same problem as before.

Yes. The problem is that when you define the entry size using a formula like "portfolio/price", and then set the exit size just as "- entry size" you end up having different entry and exit size: this leads to imperfect closing of position and so to the "residuals". For example you enter with a size of 10000/10= 1000 shares, but on closing day the price has risen to 15 and your closing size becomes 10000/15= 667 shares.

For exit size you could possibly do

context.portfolio.positions[sid].amount * data[sid].price  

And this would give you the current number of shares held * the current price of the security, giving you a complete exit

Yes. Thank you Seong. I solved that problem. Backtests look interesting. What do you think? Do you have any suggestion on the strategy?

Glad to hear.

As for suggestions, I say try testing the strategy using leverage constraints and commissions and see how your results look there.
To see ideas on leverage constraint, check this thread