Long only System trading need help in codeing

price above 200 moving average + RSI (2) above level 5 = Buy

RSi (2) below level 65 = close postion

39 responses

Hey Mani,

Thanks for your post. Can you clarify what you mean by "levels" and how you compute them?

Best,
Ryan

HI Good Day Ryan

default setting for RSI is mostly (14 days)
when you plot this on a chart. you can create indicator rise from level 0 -100 ,

How would one determine the levels mathematically from a time series?

http://www.fmlabs.com/reference/default.htm?url=RSI.htm

I think this link will help Sir!

I am more of technical then
Quant , in process of learning

Hey Mani,

The article seems to show how to compute RSI itself. By "levels," do you mean the values of RSI throughout the time series (this is not clear)? The web page you linked to lists "RMI," although this may be a typing error for RSI.

Best,
Ryan

Hi Mani,

Here is the algo you've requested with one modification. I've added price < MA(200) to exit conditions. Without this algo would sell immediately after buying for values of RSI(2) between 5 and 65. I thought it's not what you expected. Does it make sense for you?

93
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
# This algo buys when price > MA and RSI > RS_MIN
# and sells when price < MA and RSI < RS_MAX
#

# set RSI thresholds
RSI_MIN = 5
RSI_MAX = 65

# initialize RSI and MA
RSI = ta.RSI(timeperiod=2)
MA = ta.MA(timeperiod=200)

def initialize(context):
"""Initialize context object. It's passed to the handle_data function."""
context.security = sid(24)

# List of sell order ids
context.orders = []

def orders_filled(orders):
"""
Check if all orders have been filled.
:param orders: list of order ids
:returns: True if all orders have been filled, False otherwise
"""
for order_id in orders[:]:
orderobj = get_order(order_id)
if orderobj.filled != orderobj.amount:
return False
return True

def sellall(positions):
"""
Sell all active holdings.
:param positions: list of position objects
:returns: list of sell order ids
"""
orders = []
for position in positions.itervalues():
log.info("selling %d shares of %s" % (position.amount, position.sid.symbol))
orders.append(order(position.sid, -position.amount))
return orders

"""
:param security: sid
:param amount: amount of shares to buy
:returns: list of buy order ids
"""
log.info("buying %d shares of %s" % (amount, security.symbol))
return [order(security, amount)]

def handle_data(context, data):
"""
The main proccessing function.
Called whenever a market event occurs for any of algorithm's securities.

:param context: context object
:param data: Object contains all the market data for algorithm securities
keyed by security id. It represents a snapshot of algorithm's
universe as of when this method is called.
:returns: None
"""

# check if all orders have been filled
if not orders_filled(context.orders):
return

# assign local variables for readabilty
security = context.security
portfolio = context.portfolio

price = data[security].price
ma = MA(data)[security]
rsi = RSI(data)[security]

# plot price, MA and RSI
record(price=price, MA=ma, RSI=rsi)

# The algo itself
if not portfolio.positions and price > ma and rsi > RSI_MIN:
# buy if there are no open positions and entry conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
elif portfolio.positions and price < ma and rsi < RSI_MAX:
# sell all open positions if they exist and exit conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
context.orders = sellall(portfolio.positions)
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Thank you Ed Bartosh , I have got TA RSI calling in the programing '

MY main idea was to Exit trade when RSi MAX 65 is reached , irrespective off MA200.

Buy condition Is MA200 + RSI (2) minimum 5 , order size [100] magic number =1

sell condition is RSI (2) max 65, even the price is above MA200. sell order no =1 magic no 1

new order wait for RSI (2) minimum 5 and MA 200 Buy Condition

for Example GLD, GLL multiple SID like , SPY.SDS, TBT,TLT,SLV ,ZSL

WHEN TRADE CLOSED IN GLD MA200+RSI(2) MAX 65 PRICE BELOW 200MA.

HAVE BUY TRADE OPEN IN GLL , SIMILIAR SPY AND SDS AND SO ON....I

HOPE I AM CLEAR, HAPPY TO EXPLAIN AGAIN

Hi Mani,

Have I understood correctly that algo should exit the trade when RSI(2) >= 65? This is exactly the opposite of your initial explanations.

price above 200 moving average + RSI (2) above level 5 = Buy

RSi (2) below level 65 = close postion

that is my first postings ED Bartosh

thxs lot for your input sir

Yep, this is exactly what I saw and what confuses me.
You want position to be open when price > MA 200 and RS(2) > 5 and closed when RS(2) < 65. However, as I already mentioned, this would cause immediate closing position if RSI stays between 5 and 65. Are you sure you want that?

In your today post you mentioned that closing condition is "RSI (2) max 65" and "exit trade when RSi MAX 65 is reached". Looks like you mentioned 3 different exit conditions:
- RSi (2) below level 65
- RSI (2) max 65
- RSi MAX 65 is reached

We need to pick up only one, I'm afraid :)

Just to make it more clear I've changed closing conditions to RSI(2) < 65 and picked up SPY as a security.
Here are some recent log entries to illustrate how algo behaves:
1. 8th of April: enter conditions are met (price 185.110000 > MA200 175.841400 and RSI(2) 27.777778 > 5
2014-04-08 handle_data:86DEBUGRSI=27.777778, price=185.110000, MA=175.841400
2. So, create a buy order:
3. 9th of April: our buy order has been filled
4. 10th of April: closing conditions are met(RSI(2) 33.612040 < 65
2014-04-10 handle_data:90DEBUGRSI=33.612040, price=183.150000, MA=176.114650
5. 10th of April: so, create a sell order for our open position:
2014-04-10 sellall:42INFO selling 5593 shares of SPY

So, my question remains the same: Are you sure you want position to be closed right after opening when RSI(2) remains between 5 and 65?

i think if we stick to closing all positions when price cross below MA 200 . sounds good !

when you back test on daily data results or promising ,but when run back test on minute data it is different all together?

Yes, results on different timeframes can be different. This is normal.

Hi guys,

It is exciting to see this type of collaborative work in the forums! In case you missed this post last night, I wanted to point out that we've just released a collaboration feature that you can use to simultaneously edit and debug an algorithm with any other Quantopian member(s). In order to invite a collaborator in to an existing algorithm you're working on simply click on the new "Collaborate" button in the upper right corner of the IDE window.

You'll be prompted to invite a collaborator (for now you need to have their email address) and have the option of notifying them via email.

There is even a built-in real-time chat window so you can communicate while collaborating within the same workspace - the chat is on a new tab in the same window where you can display logs and runtime errors:

I'd love to get feedback on this feature so please keep us posted if you get a chance to check it out.

Best regards, Jess

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.

Hi Jess,

The feature looks good. It's perfect for private collaboration. However, I like this forum better to share ideas and algos with everyone who is interested. Some people might want to join our work here, but they'll not have a chance to do that if we collaborate privately.

Hi Ed,

Yup - I totally agree and that was my only hesitation with this suggestion. I don't want to push any public collaboration to be private since there is indeed great value there. I just figured I'd share this since there can come a point during a collaboration where details can be more easily ironed out with real-time collaboration versus forum threads and I wanted to make sure this was on your radar!

Cheers,
Jess

Ok Guys thanks you for all the inputs...!!!!
I like this forum better to share ideas and algos with everyone who is interested, but I am keen to learn programming python and get back were in my learning curve may be best off 3 months to 6 months ,but May 19 / 2014 . is the time I am interested in taking advantage off ,going live with algos with IB.

I have been trading for a while with different front end ,like MT4, ninjatrader,,thinkorswim,, I can generate many systems with few drag and drop no other programming skill involed...?
what is there for me ?
hence I am all for open source and open forum model, but some time I feel I can express better with few chart and picture to explain, any one is interested in collaboration in the forum , or privately
you can contact me
thanking you
mani kannan

lol at Ed's algo backtest. I think people should be prohibited from using Apple to showcase their algo.

Here's the same thing, but using SPY instead of APPL

17
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
# This algo buys when price > MA and RSI > RS_MIN
# and sells when price < MA and RSI < RS_MAX
#

# set RSI thresholds
RSI_MIN = 5
RSI_MAX = 65

# initialize RSI and MA
RSI = ta.RSI(timeperiod=2)
MA = ta.MA(timeperiod=200)

def initialize(context):
"""Initialize context object. It's passed to the handle_data function."""
context.security = sid(8554)

# List of sell order ids
context.orders = []

def orders_filled(orders):
"""
Check if all orders have been filled.
:param orders: list of order ids
:returns: True if all orders have been filled, False otherwise
"""
for order_id in orders[:]:
orderobj = get_order(order_id)
if orderobj.filled != orderobj.amount:
return False
return True

def sellall(positions):
"""
Sell all active holdings.
:param positions: list of position objects
:returns: list of sell order ids
"""
orders = []
for position in positions.itervalues():
if position.amount > 0:
log.info("selling %d shares of %s" % (position.amount, position.sid.symbol))
orders.append(order(position.sid, -position.amount))
return orders

"""
:param security: sid
:param amount: amount of shares to buy
:returns: list of buy order ids
"""
log.info("buying %d shares of %s" % (amount, security.symbol))
return [order(security, amount)]

def handle_data(context, data):
"""
The main proccessing function.
Called whenever a market event occurs for any of algorithm's securities.

:param context: context object
:param data: Object contains all the market data for algorithm securities
keyed by security id. It represents a snapshot of algorithm's
universe as of when this method is called.
:returns: None
"""

# check if all orders have been filled
if not orders_filled(context.orders):
return

# assign local variables for readabilty
security = context.security
portfolio = context.portfolio

price = data[security].price
ma = MA(data)[security]
rsi = RSI(data)[security]

# plot price, MA and RSI
record(price=price, MA=ma, RSI=rsi)

# The algo itself
if not portfolio.positions and price > ma and rsi > RSI_MIN:
# buy if there are no open positions and entry conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
elif portfolio.positions and price < ma and rsi < RSI_MAX:
# sell all open positions if they exist and exit conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
context.orders = sellall(portfolio.positions)
There was a runtime error.

Hi Jason,

I picked AAPL on purpose to clearly show how algo underperforms last two years.

BTW, adding something negatively correlated to SPY would make this algo worth looking at. If anybody interested I think I can do that.

Regards,
Ed

yes Ed if spy close below MA200 all positions is closed !

then buy ETF SDS which is inverse of spy.

keep switching between SPY and SDS with MA200 as exit conditions.

I will be interested in it

Hi Mani,

I need a bit more details. Should I use the same entry and exit criterias for SDS or they're different? Please, give as many details as possible.

Regards,
Ed

Hi Ed when I look MA 200 will determine the directions of the trade ,

Long when price is closed above MA200

close all positions when price is close below MA200.

but RSI(2) min 5 is the signel to get in long trade =+1

and RSI (2) max 65 is the signel to close the long trade = -1 backtest in min data in one year 2013-2014.

Regards
mani kannan

Hi Mani,

It's hard to understand your terminology sometimes. I'm having hard time getting what does it mean +1/-1, min 5, max 65 and so on.

Here is what I understood so far:
Type of strategy: long only pair trading. Only one of two securities can be traded at the same time
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65

Regards,
Ed

Type of strategy: long only pair trading. Only one of two securities can be traded at the same time
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65

your right ED, sorry about my expression ,this is what some software help in generating signels ignore about it !!

Regards
mani kannan

Hi Mani,

I've changed the algo a bit as I think that simple RSI strategy (buy when RSI < 5(oversold) and sell when RSI>65(overbought)) is what you wanted
Anyway, I used these conditions:
enter conditions: price > MA200 and RSI(2) < 5
exit conditions: price < MA200 or RSI(2) > 65

The results are not that impressive even without taking commissions and slippage into account.
You can play with the code and ask questions. I's possible that I implemented not what you wanted.

Regards,
Ed

93
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
"""
Type of strategy: Long only pair trading.
Only one of two securities can be traded at the same time
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65
"""

# set RSI thresholds
RSI_MIN = 5
RSI_MAX = 65

# initialize RSI and MA
RSI = ta.RSI(timeperiod=2)
MA = ta.MA(timeperiod=200)

def initialize(context):
"""Initialize context object. It's passed to the handle_data function."""
context.secs = [sid(8554), sid(32382)]

def handle_data(context, data):
"""
The main proccessing function.
Called whenever a market event occurs for any of algorithm's securities.

:param context: context object
:param data: Object contains all the market data for algorithm securities
keyed by security id. It represents a snapshot of algorithm's
universe as of when this method is called.
:returns: None
"""

# check if all orders have been filled
if get_open_orders():
return

record(price1=data[context.secs[0]].price,
price2=data[context.secs[1]].price)

portfolio = context.portfolio
rsidata = RSI(data)

for security in context.secs:
# set local variables for security price, ma and rsi
price = data[security].price
rsi = rsidata[security]

position = portfolio.positions.get(security)

# The algo itself
if not portfolio.positions and price > ma and rsi < RSI_MIN:
# buy if there are no open positions and entry conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
amount = int(portfolio.cash/price)
log.info("buying %d shares of %s" % (amount, security.symbol))
order(security, amount)
return
elif position and (price < ma or rsi > RSI_MAX):
# sell open position if exit conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
log.info("selling %d shares of %s" % (position.amount, security.symbol))
order(security, -position.amount)
return
There was a runtime error.

based on Ed last version, I found follow issue, the RSI value seems not work normally, it should not high volatility in same day.

2013-01-02handle_data:59DEBUGRSI=3.547335, price=52.262000, MA=52.185360
2013-01-02handle_data:66DEBUGRSI=81.306333, price=52.270000, MA=52.189720
2013-01-02handle_data:67INFOselling 19134 shares of SDS
2013-01-02handle_data:59DEBUGRSI=3.260405, price=52.280000, MA=52.257376
2013-01-02handle_data:66DEBUGRSI=82.919438, price=52.350000, MA=52.260226
2013-01-02handle_data:67INFOselling 19138 shares of SDS
2013-01-02handle_data:59DEBUGRSI=4.868233, price=145.050000, MA=144.913513
2013-01-02handle_data:66DEBUGRSI=68.166267, price=145.019000, MA=144.914658
2013-01-02handle_data:67INFOselling 6902 shares of SPY
2013-01-03handle_data:59DEBUGRSI=4.115801, price=145.865000, MA=145.395185
2013-01-03handle_data:66DEBUGRSI=83.877706, price=145.919000, MA=145.405430
2013-01-03handle_data:67INFOselling 6859 shares of SPY
2013-01-03handle_data:59DEBUGRSI=3.071142, price=146.164500, MA=145.718233

RSI is 3.54, 3.26, 4.86, 4.11 and 3.07 for SDS and 81.30, 82.91, 68.16 and 83.87 for SPY in your example. They're calculated for the minute time frame. Why do you think they're wrong?

Hi Ed and Mani and others.

I am a new comer to Quantopian. Found the exchange you had about the RSI/MA combination very interesting. Not sure whether you have given up or gone elsewhere after April.

It was only towards the end that I saw the references to using this algo for minute trading. earlier I would have thought, my bias, that Mani might have been looking for a daily approach. Like her I am not only new to the site, but even newer to Python. I am interested how the algo worked on a daily only basis, My expectation is that RSI triggered trades are more reliable if it is done on a daily basis, but I may well be wrong. I use RSI mostly for my option trading, and there I use it on the daily chart only.

The paired trading that you were getting to at the end is quite extreme I think, and as Ed wrote the results are not all that impressive. I wonder whether you could check what the result would be, if you do paired trading with SPY and TLT. If both meet the buy condition, than the relative performance over the preceding 91 days should identify the choice for the ETF to use ( an alternative would be to go 70/30 between the best relative performance and second relative performance, but that seems for now unnecessary complication. The fail save third condition would be that if neither of SPY r TLT meet the buy conditions that the portfolio is fully invested in SHY.

Have you already tried something like that?

Hi Bernard,

Here is a back test on daily time frame using SPY and TLT.

93
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
"""
Type of strategy: Long only pair trading.
Only one of two securities can be traded at the same time
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65
"""

# set RSI thresholds
RSI_MIN = 5
RSI_MAX = 65

# initialize RSI and MA
RSI = ta.RSI(timeperiod=2)
MA = ta.MA(timeperiod=200)

def initialize(context):
"""Initialize context object. It's passed to the handle_data function."""
context.secs = [symbol('SPY'), symbol('TLT')]
#sid(8554), sid(32382)]

def handle_data(context, data):
"""
The main proccessing function.
Called whenever a market event occurs for any of algorithm's securities.

:param context: context object
:param data: Object contains all the market data for algorithm securities
keyed by security id. It represents a snapshot of algorithm's
universe as of when this method is called.
:returns: None
"""

# check if all orders have been filled
if get_open_orders():
return

record(price1=data[context.secs[0]].price,
price2=data[context.secs[1]].price)

portfolio = context.portfolio
rsidata = RSI(data)

for security in context.secs:
# set local variables for security price, ma and rsi
price = data[security].price
rsi = rsidata[security]

position = portfolio.positions.get(security)

# The algo itself
if not portfolio.positions and price > ma and rsi < RSI_MIN:
# buy if there are no open positions and entry conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
amount = int(portfolio.cash/price)
log.info("buying %d shares of %s" % (amount, security.symbol))
order(security, amount)
return
elif position and (price < ma or rsi > RSI_MAX):
# sell open position if exit conditions are met
log.debug("RSI=%f, price=%f, MA=%f" % (rsi, price, ma))
log.info("selling %d shares of %s" % (position.amount, security.symbol))
order(security, -position.amount)
return
There was a runtime error.

Wow Ed that is a great quick turnaround and a surprising result. More surprising for the difference with other sources than for the actual outcome. Not sure whether you spend any time at such places as Seeking Alpha, but if you do check out ( who has published on the topic with very different results. ref Lewis A Glenn (lewglenn on SA) or Gary Antonacci who recently published a book about Dual Momentum, also published available through the Internet; Dual Momentum Risk Premia Harvesting )

Looking at the chart, what surprises me is how far the benchmark outpaces the algorithm for extended periods of time i.e 2003 through 2007and 2009 through2014. The Algorithm, supposedly goes with the winner of TLT or SPY, rebalancing monthly, so why would SPY be able to outperform the ALGO? Let me try to look into this ALGO and perhaps suggest a few changes to more closely verify the referenced works of Antonacci and Glenn.

THANKS again for the very quick response.

Bernard

Ed , after closer reading/ reflection, could you change the code to stay on pair trading, but not on a minute but daily basis, with the enter criteria being that the security to be bought / retained ( with the other being sold or not maintained in the portfolio) is the security which shows the best Relative Performance. Relative Performance being defined as the percent change over the preceding 91 days including distributions and taking into account say $10 commission per trade? The next iteration would be to NOT do this daily (assuming commissions may eat any positive gross trading results ( lets assume a$100,000 starting amount)) but at a slower frequency, say every 7, 15, 33, 45 trading days.

Not sure how much work this requires, but I am MOST interested in the results if and when you have time to these thoughts in code to apply to Quantopian 's data base.

Cheers

Bernard

Hi Bernard,

I'm not sure I understand how what you've asked is related to this algorithm.

Here is what I programmed:

Type of strategy: Long only pair trading.
Only one of two securities can be traded at the same time
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65

You're asking about daily time frame, another enter criteria and no exit criteria if I understood you correctly.

Regards,
Ed

Ed,

You are right. I was initially attracted by the title chosen by Mani. I thought that Mani's idea was not all that different from something I was thinking about. I was wrong, what I have in mind is quite different and is not an easy modification of the code you put together here initially. I will have to learn Python myself or find someone who can put my idea in code, but indeed it is not a simple modification of Mani's idea. Maybe I have to start a new thread on my idea. Before I do that, I will check first whether there is already something written about ETF pair trading or generally ETF Tactical Asset Allocation. If so, starting a new thread would unnecessarily clutter up this site with virtual duplications.

You earlier made the observation that the enter condition RSI(2)> 5 and exit condition RSI(2) < 65 would not work. I thought hat was a correct and logical observation, but your last response above still has that enter and exit condition. Aren't most circumstances which meet the enter condition not also meeting the exit condition as written above?

Hi Bernard,

Sorry, I copied enter and exit conditions from the header. I mentioned that I changed them to this:
enter conditions: price > MA200 and RSI(2) < 5
exit conditions: price < MA200 or RSI(2) > 65

Regarding your algo. I'd suggest you take my code and modify enter and exit conditions. Me or other programmers can help you with that. I looked again at what you want and it looks like it should not be hard to modify my code to do it.

Regards,
Ed

Thanks Ed,

I will spend more time on developing something that works, but at this point I am painfully aware of my lack of Python knowledge / skills.

Is there a way to print the code displayed on the Quantopian side or copy it into a Word document for offline consideration? I will likely have to go through the code I find on this site and go through it line by line , making notes as to what it is and what I need to do to adjust it to get to what I am looking for. I found some other threads relative to Mebane Faber ( refer Mebane Faber Relative Strength Strategy with MA Rule ) and his approaches to Tactical Asset Allocation, which come pretty close to what I am trying to model, but are not quite "it" yet.

Sure, you can copy code to clipboard using Ctl-A(select all) and then Ctrl-C(copy to clipboard) and then paste it to any editor of your choice with Ctl-V.

I can help you with your algo if you want. However, it make sense to learn some Python to be able to understand and modify the code if needed. Unless you want only this program and will never modify it.

Ed

Thanks Ed,

I am not sure yet whether I will eventually get really into using Python a lot, most likely not ( age considerations etc. LOL). My expectation is that I only will use this site and its features to test a number of Tactical Allocation Strategies for ETFs. If indeed my usage will be that limited, learning Python may be too much of a long roundabout way. My preference is to first test out the basic idea of trading a portfolio of up to 10 ETFs ( e.g. VTI, VEA, VWO, VNQ, RWX, BIV, LQD,TLT,TIP, PBE) with the portfolio never invested in more than say 3 or 4 ( variable in code) of the top ranked ETFs, and not invested at all if their Relative Strength is negative / lower than the Relative Strength of SHY. The Lookback / Formation period for the Relative Strength calculation is to be a variable as well, possibly a weighted average of two Lookback periods, and the frequency of rebalancing is to be a variable, since daily is likely to chew up a lot of commission ( another variable). I started with some Internet based Python education, but it likely will be a while before I can effectively code all of the above.

IF you would have time to help me with that, that would be great, but it may take more of your spare time than you would want to allocate to something like this.

Bernard

Hi Bernard,

The strategy you've described reminds me of this implementation https://www.quantopian.com/posts/global-market-rotation-strategy-buggy-implementation of Frank Grossmann's strategy http://seekingalpha.com/article/1622832-a-global-market-rotation-strategy-with-an-annual-performance-of-41-4-since-2003
Ranking criteria is different and Frank's strategy uses only one ETF and rebalances monthly, but the idea is the same if I understood it correctly. At least it looks much closer to yours than pair trading strategy from this thread.

Regards,
Ed

For fun I threw this together trading the DollarVolumeUniverse, I'm pretty sure I got the rules right.

16
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
"""
Type of strategy: Long only RSI and moving average
Capital allocation for the trade: 100%
Timeframe: minute
Enter conditions: price > MA200 and RSI(2) > 5
Exit conditions: MA200 > price and RSI(2) < 65
"""
import talib
import numpy as np

# set RSI thresholds
RSI_MIN = 5
RSI_MAX = 65

# initialize RSI and MA

def initialize(context):
"""Initialize context object. It's passed to the handle_data function."""
set_universe(universe.DollarVolumeUniverse(floor_percentile=99,
ceiling_percentile=100))

context.ma_window = 200
context.rsi_window = 2

time_rule=time_rules.market_open())

def handle_data(context, data):
pass

market_value = 0
position_count = 0
for stock in data:
amount = context.portfolio.positions[stock].amount
price = data[stock].price
market_value += abs(amount) * price
if amount != 0:
position_count += 1

leverage = market_value / context.portfolio.portfolio_value

record(position_count=position_count,
leverage=leverage)

prices = history(500, '1d', 'price').iloc[-context.ma_window:]
mavg = prices.mean()
rsi = prices.apply(talib.RSI, timeperiod=context.rsi_window).iloc[-1]

for stock in data:
if get_open_orders(stock) or np.isnan(rsi[stock]):
continue
if prices[stock][-1] > mavg[stock] and rsi[stock] > RSI_MIN and leverage < 1.8:
if context.portfolio.positions[stock].amount == 0:
order_target_percent(stock, 0.03)