Buys and Sells seem to change from one day to the next

I'm driving myself crazy trying to figure out why my outputs seem to be changing from on day to the next. I'm sure it's my fault, either code or a setting being wrong, but I've checked and changed everything that I can think of. I'll call myself a newbie compared to the posters that I've read on here, and I have read, and read, and read trying to find a solution. I promise!

I guess I should say that my goal is to use EOD data and trade at the open. As such, I've always used the Artificial Future Bar setting so that I can run the model either the night before, or early the morning of, and be prepared with my trading plan before the open.

I think I've got the timing set correctly. One thing that I found in the forum that I was REALLY hopeful would fix my issue was Ref(Ranking, -1) for my PositionScore, but it didn't seem to fix the issue. (If I'm trading Tuesday morning, then I want the ranking from Monday's close, seems to make sense to me.)

I've uploaded two pics of the Detailed log for the model, one from 8-17 and one from 8-18. You can see on the last line of each, "Open Positions" that the list for 8-17 that is on the 8-18 picture is different from the list for 8-17 that is on the 8-17 picture.

I think that the issue is related to PositionScore because the models (I have 5 that I'd like to trade) which use a shorter number of days in the PositionScore seem to have more changing trades than models which have a longer time frame for ranking them. That being said, I'm still aware of my newbie status, and I'll keep my mouth shut and take suggestions from the pros. (All 5 models exhibit the same issue that I'm posting about here.)

I've tried to include everything that would be needed to diagnose the problem. If I've left anything out I'll be happy to provide it ASAP, again, newbie compared to most of y'all.

Thank you in advance to anyone who had suggestions!

Anyway, on to the code -

Exectiming = 1; //  0 = Same Bar on Close, 1 = Next Bar on Open 
SetTradeDelays(Exectiming,Exectiming,Exectiming,Exectiming); 

posqty = 5;  //Optimize( "Max Positions", 1, 1, 30, 1);  //20
pctPer = 100/posqty;
fPort = 1;
SetOption("MaxOpenPositions",IIf(fPort ==1,posqty,1500));                
SetPositionSize(pctPer, spsPercentOfEquity  ); 
RoundLotSize = 1; 


V3 = 1;  //Optimize("V3", 1, 1, 5, 1);  //1

function HPI( MultFactor, PercentMove )
{
 M = ( H + L ) /2;
 My = Ref( M, -V3 );

 I = abs( OpenInt - Ref( OpenInt, -1 ) );
 G = Max( OpenInt, Ref( OpenInt, -1 ) );
 
 K = PercentMove * Volume * ( M - My ) * ( 1  + sign( M - My ) * 2 * I / G );
 
 return AMA( K, 1/MultFactor )/100000;  	

}

OI = C;

V1 = 3;  //Optimize("V1", 2, 2, 10, 1);  //3
V2 = 10;  //Optimize("V2", 5, 5, 15, 1);  //10

SMA3 = 6;  //Optimize("SMA3", 4, 4, 13, 1);  //6

MinPrice = 2;  //Optimize("MinPrice", 1, 1, 3, 1);  //2
MaxPrice = 150;  //Optimize("MaxPrice", 10, 10, 200, 10);  //150

Index1 = Foreign("^VIX", "C", True);
SMA = 5;  //Optimize("SMA", 2, 2, 8, 2);  //5
LMA = 85;  //Optimize("LMA", 80, 80, 130, 5);  //85
VIXLevel = 23;  //Optimize("VIXLevel", 21, 21, 24, 1);  //23

Buy = HPI(V1, V2) > MA(HPI(V1,V2), SMA3) AND C > MinPrice AND C < MaxPrice AND (MA(Index1, SMA) < MA(Index1, LMA) or Index1 < VIXLevel) AND (MA(C, 20) * MA(V, 20)) > 1000000;
Sell = HPI(V1, V2) < MA(HPI(V1,V2), SMA3);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


MinPrice2 = 9;  //Optimize("MinPrice", 5, 5, 11, 1);  //9
MaxPrice2 = 175;  //Optimize("MaxPrice", 55, 55, 100, 5);  //75

Index2 = Foreign("^VIX", "C", True);
SMA2 = 5;  //Optimize("SMA", 4, 4, 14, 2);  //4
LMA2 = 65;  //Optimize("LMA", 10, 10, 100, 5);  //28
VIXLevel2 = 20;  //Optimize("VIXLevel", 12, 12, 30, 2);  //10
 
V4 = 21;  //Optimize("V4", 12, 12, 24, 1);  //21
V5 = 6;  //Optimize("V5", 2, 2, 11, 1);  //6

SMA4 = 22;  //Optimize("SMA4", 16, 16, 46, 2);  //22

Short = HPI(V4, V5) < 0 AND HPI(V4, V5) < MA(HPI(V4, V5), SMA4) AND C > MinPrice2 AND C < MaxPrice2 AND (MA(Index2, SMA2) > MA(Index2, LMA2) and Index2 > VIXLevel2) AND (MA(C, 20) * MA(V, 20)) > 5000000;
Cover = HPI(V4, V5) > 0 OR HPI(V4, V5) > MA(HPI(V4, V5), SMA4);

amount = 6.4;  //Optimize("Profit", 6, 6, 7, .1);  //6.4
ApplyStop( stopTypeProfit, stopModePercent, amount, True );

Days = 9;  //Optimize("Days", 7, 7, 9, 1);  //9
ApplyStop( stopTypeNbar, stopModePercent, Days, True );


StockReturn1 = 5;  //Optimize("StockRT1", 2, 2, 20, 1);  //5
StockReturn2 = 2;  //Optimize("StockRT2", 1, 1, 5, 1);  //2


Ranking = 1000 + (1000 + ROC(C, StockReturn1)) - (1000 + ROC(C, StockReturn2));

PositionScore = Ref(Ranking,-1);

8-17 HPI

8-18 HPI

General Settings

Portfolio Settings

Not sure exactly what the problem is, but I have one observation that might help.

On the screen shot that shows Aug 14 and 17, I see that on Aug 17 there is still an open PACB position at the end of the day.

On the screen shot that shows Aug 17 and 18, I see that on Aug 17 there is no open PACB position at the end of the day because there was a PACB exit on Aug 17. This exit makes room for a new entry.

So, why did the exit change?

It's not entirely clear if Aug 17 on the first SS and Aug 18 on the second SS are "real" dates or if those are artificial future bars. However, I don't think it should really matter if you're using trade delays of 1 bar for all entries and exits.

Ok, so I should point out that on the screen shot with 14th and 17th that the 17th is an artificial bar, and on the screen shot with the 17th and 18th, the 18th is an artificial bar.

But, yes, the problem is that on the 17th I should've stayed in PACB and bought ACRS, but then on the morning of the 18th it's acting like I sold PACB on the 17th, and ACRS is nowhere to be found, plus IPI should've been bought on the 17th (according to the file output on the 18th).

Thanks for bringing to my attention that I didn't specify that the last date on each screenshot was an artificial bar. That's certainly relevant info that I didn't originally include.

That points to the problem more likely being connected to your exits than your entries.

Looking at your code again, I believe the problem may be caused by your stops. When you run on the 14th and the 17th is an AFB, then no stops is triggered for PACB. However, when you run on the 17th and have real data for the 17th, then a stop is triggered for PACB, thus causing some changes in the number of slots you have available.

You could try setting the "exitatstop" parameter of ApplyStop() to 2 instead of true (1) so that trades exit on the next bar at the regular trade price. This may not ultimately be the behavior you want, but it would be a good way to check whether this fixes your consistency issues. If you want your stops to exit intraday (as you have them now), then really you want the stops to be evaluated after all the entries for the day have taken place.

I've only had the chance to test one day so far, but, I used to have about 5 changed trades between the five models, and with the change you suggested there was only 1 change. Thank you!

I'm really starting to figure out just how much I don't know, because I didn't realize that I could have the stops evaluated after the entries had taken place. Is that hard to change? I definitely need to keep those stops intraday, changes the whole model without that.

If you use a low-level CBT, you can call bo.HandleStops() whenever you want to relative to processing entries and exits. Without a CBT I'm not sure if there's a way to force the order of processing to be Exits, then Entries, then Stops.

Yeah, I think a custom back tester is a bit of a reach for my skills right now. I've been searching and reading here based on your first reply. Reread a bunch of stuff on how the stops work, which led me to ApplyStopNow info. https://www.amibroker.com/guide/afl/applystop.html

Specifically, this section -

ApplyStopsImmediately

Playing around with the parameters after reading that led me to conclude that the model, as was originally programmed, was exiting at the profit target stops during the day and then that cash was available for a new buy right then, while I thought that the new cash wouldn't be available until the next open.

I'm not 100% sure that this explains 100% of the changed trades, but it seems to be a likely explanation after reading that and playing around with it.

  1. Thank you for your help!
  2. Do you agree with that assessment?
  3. I think my next step is trying to figure out how to ignore the profit stop IF it's going back into the same stock. (The system does that pretty often and I need to see if the results are still pretty good if that's the only change I make). Would you be able to point me in a direction on that task? Would that also be handled in a CBT?

Thanks again

Your assessment seems correct. You should be able to verify using the Detailed Log output as you've already been doing.

Not sure what you mean by "ignore the profit stop IF it's going back into the same stock". If you change your logic so that stops occur after entries and exits, then there can't possibly be another entry for the same stock on that day, correct? And if you don't want to re-enter the same stock on the next day, you can use the reentryDelay parameter of ApplyStop.

Thanks for your reply,

Well, I didn't realize just how much performance depended on this behavior of exiting intraday and then immediately getting back into the same stock or another one. I want the turnover that the combination of the stops and ranking system generates, but I thought I had a system designed to trade at the open, when I'd mistakenly designed something that's more like a half intraday / half EOD system.

So, I want it to pick stock B as soon as stock A's position score isn't the highest any longer, but as long as stock A is still killin it, I want it to ignore stock A's intraday stop. Then I can set the parameters to leave the cash until the next morning, but it'll only do that if it's a change to stock B.

Basically, I'm trying to see if the system can stay as one that I can enter trades each morning and forget it, or if I'm going to have to go down the road of an actual intraday system.

Does that make sense, or am I missing something?

I don't think there's any way to tell ApplyStop to conditionally enforce the stop price. Even though you don't think it makes sense from a live trading standpoint, I would see what happens if you exit A on the stop price and then allow A to re-enter the next morning at the Open if A still happens to be close enough to the top of your ranking.

No matter what you do with A and B from your example, your performance is likely going to take a hit when you fix the problem that you had before, which was essentially entering positions at the open using capital than wouldn't actually be available until later in the day when the stop occurs. In other words, your current results are unrealistic, so you can't really use them as a benchmark.

Yeah, uh, unfortunately, I've already looked at the performance when using the settings to enter only the following morning, is wasn't nearly as good, like you said.

But that brings up another question which I'll have to look into. When stock A does exit intraday, is the buy price for the replacement, B, the open price, or the price it was at the time that the intraday exit for A occured?

Up until your last reply, I'd been working under the premise that stock B was entered at the time that stock A was exited, and not that B was bought at the open even though A was exited at some random time during the day.

I'll have to run a day or two of detailed logs to see if the entry prices for changed trades match opening prices, or random intraday prices.

Thanks again for all your helpful replies!

What duration bars are you backtesting against? If you're using daily bars as shown in one of your screen shots, then there would be no way for AmiBroker to know that A exited at 10:15am and therefore B should enter at its 10:15am price. So if you specify the BuyPrice is Open, then B is entering at the Open price of the day, and that event would have occurred before A's intraday exit. Like I said... not a valid real-world scenario.

Yep, obviously you're right, that was a real brain lapse moment on my part. AB knows that price to report for the profit target exit because it's just a calculated number and it knows the high for the day after I download that days data.

That gets me back to trying to use an If or IIF statement on the exit of A if it's just going to go back into A. I think that may save enough of the performance to still make the models worth trading on an EOD basis.

It's either that or go all in on intraday, and, right now, that seems like the difference between backyard camping and climbing Everest. Of course, everyone who's climbed Everest started with backyard camping, so maybe that's just the journey I have to take!

Thanks again,

Here's a quick analysis you could do to see if it's worth messing around with conditional profit targets:

  1. Run a back test that processes exits, then entries, then stops (as we've previously discussed

  2. Pull the trade list into Excel, sort by symbol and then by date

  3. Whenever there's an entry for A, check the previous row to see if it was a stop (profit target) exit for A on the previous day. If so, then see if the new entry price was lower than the prior exit (which means you actually increased your profit) or higher than the prior exit (you missed out on some of the profits). Record the total dollars (or %) gained or lost due to exit followed immediately by reentry.

  4. Sum up all of the results from #3 to find the net effect on your P/L.

Good luck!

Thought through it last night and realized that even if I could make the profit target conditional that it wouldn't matter - there wouldn't be any info for the model to re-rank the issues and see if "A" is still in the lead or if "B" had overtaken it.

Initial test on removing the extra gain from rebuying at the open price on days that the profit target got hit, (on only one of the five models) left me with half of the total profit compared to the original backtest. Getting cut in half certainly isn't fun, but the numbers would absolutely still be worth trading. That being said, probably worth coming up with an exit strategy besides the profit target now that I realize how many problems it introduces.

Again, thank you for all of your help. I feel like I've learned more from this one exercise than the last few years combined.

1 Like