I’d like to write a buy rule that would buy back a previously sold stock as soon as the price has increased 5% from its most recent low, and I can’t figure out how to do this. Can anyone help?
I’m trying to re-create a system I read about where you use trailing stops for both the sell and the buy orders.
You can approximate this behavior by using the undocumented buy rule factor ‘LastSellDays’ and converting the number of calendar days returned to the approximate number of trading days:
[font=courier new]SetVar(@LastSellBars, LastSellDays * (251 / 365))
SetVar(@Low, Eval(Between(@LastSellBars, 2, 2500), LowVal(Min(Max(@LastSellBars, 2), 2500), #Low), Eval(@LastSellBars < 2, Low(0), NA)))
Close(0) / @Low >= 1.05[/font]
Thanks - that LOOKS great. But of course if I put these as the only buy rules the sim won’t buy anything. Is there a way to allow for an initial buy of some stocks and then switch on these buy rules as a substitute?
This may work, but it’s hard to tell what’s happening exactly without a debugger;
SetVar(@Count,LoopSum("Eval(LastSellDaysLT(CTR)=False & LastSellDaysLT(CTR+1)=True,CTR,0)",100,1,1)) // returns zero if no sells within 100 bars
Eval(LastSellPrice=NA,True, (@Count!=0) & (Close(0)>LowVal(@Count+1,0)*1.05))
Something a bit less strict;
SetVar(@Count,LoopSum("Eval(LastSellDaysLT(CTR)=False & LastSellDaysLT(CTR+1)=True,CTR,0)",100,1,1)) // returns zero if no sells within 100 bars
Eval(LastSellPrice=NA,True, Eval(@Count!=0,(Close(0)>LowVal(@Count+1,0)*1.05),True))
Walter
EDIT: What the what? The above code ran under the new server and now fails with an error on LowVal (Error in LowVal() bars must be between 2 and 2500). Ha!
Your rule doesn’t seem to work every time. With daily rebalancing, it often has me buy much later than when the price goes up 5% from the previous low closing price. I looked at specific tickers, and I’m not sure what the buy rule is doing, but it’s not a simple 5% rise from the previous low close. I guess I’d have to understand the language here, and I’m failing to do so.
Might it be possible to use the programming language for the trailing stop, which works well, and just reverse it for the buy rule?
First of all, I missed a parameter in LowVal, so I was passing #Low as the offset parameter. Including that correction, I’ve put together a proof-of-concept that implements something similar to what you want to accomplish: port_summary.jsp?portid=1464076. The issue with implementing this is that the ranking system dominates when evaluating buy rules, so recently sold stocks cannot be preferred over other stocks when ranked, since LastSellDays is not accessible to a ranking system. Because of this issue, instead of always buying things never bought before, it applies the same 5% gain rule to the maximum lookback period. It’s still driven by ranking, and will always prefer higher ranked stocks meeting the criteria. To mitigate this issue, you may consider increasing the number of positions in your portfolio and decreasing the size of your universe (e.g. DJIA). We would have to add a feature to support your buyback behavior more exactly.
Just to explain this: someone posted a thread on another forum about his success using the following strategy: random stock picks; 10% trailing stop for sells based on close; 5% trailing stop for buys based on close; fixed amount each buy. I’m trying to see if I can replicate it here. I don’t believe that it works, but my results so far are flawed (and abysmal).
What I’ve done in terms of the other issue you mention is to use a small list of stocks to buy (under 50) in custom lists, an inlist buy rule, a fixed amount position size, and a ranking system with only one factor: random. When you look at the results, you don’t look at the percentage increase but the dollar increase and you compare that with a buy-and-hold approach.
I’ll also modify this buy rule to create a sell rule as a manual trailing stop since the default trailing stop uses an intraday high and I need a highval based on closing price.
I hope it helps :). Make sure to scale LastSellDays by (251 / 365) for better correctness. And if you want to find lowest low instead of lowest close, be sure to specify #Low for the series parameter of LowVal.