Avoiding unwanted rapid fire order generation

Hello friends and seniors,

Recently, I came across a situation where hundreds of Buy/Sell pair of orders were generated during the same bar. This happened due to a condition wherein both BUY and SELL conditions became TRUE during that same bar.

This had lead to a situation, where orders for both Buy and Sell were generated per each tick. As this could lead to huge damages due to slippages and trade loss, I had to work out a solution.

After searching through internet and Amibroker forum, I could find suggested solutions like monitoring Order IDs and managing the situations accordingly. Also there were solutions given to use time delays.

However, i find it not completely suiting my situation.

One) Due to the trader platform limitations.

Two) In either case, the trades will be limited to 1 trade per the set time duration. As my trade system will be looking for an immediate opportunity, after a Buy/Sell pair has been executed, I need to workout a solution accordingly.

As I am both learning AFL and trading using it, in parallel, I need your expert guidance on the code below. It is found to be working fine during the Bar Replays, however, I am not sure if this is right way to deal with it.

Please guide me and help me improve the code. I have coded only the Buy part, please find it below.

Thanking you in advance,

//Buy Sell conditions to simulate rapid fire trade order generation.
//Code to filter such BUY conditions. Sell conditions are managed by Session State variables
Buy=Cross(MA(High,2),MA(High,7));
Sell=Cross(MA(High,5),MA(High,2));
		

//Setup for placing a BUTTON to clear Static variables during test.
LBClick = GetCursorMouseButtons() == 9;	 

MouseX  = Nz(GetCursorXPosition(1));		 
MouseY  = Nz(GetCursorYPosition(1));		 


procedure DrawBut (Text, x1, y1, x2, y2, colorFrom, colorTo)
{
	GfxSetOverlayMode(0);
	GfxSelectFont("Segoe UI", 9, 700);
	GfxSetBkMode(1);
	GfxGradientRect(x1, y1, x2, y2, colorFrom, colorTo);
	GfxDrawText(Text, x1, y1, x2, y2, 32|1|4|16);
}

procedure rapidFireClearAll()
{
	Buy=Sell=Short=Cover=0;

	StaticVarSet("_totalTradesInCurrentTimeSlot",0);
	StaticVarSet("_lastTradeTime",0);
	StaticVarSet("_tradeWithinTimeSlot",0);
	_TRACEF("\n All static variables reset to 0");
	_TRACEF("\n");
}

DrawBut ("Clear All", 20,70,120,100, colorGrey40, colorGrey40);
CursorInClearButton = MouseX >= 20 AND MouseX <= 120 AND MouseY >= 70 AND MouseY <= 100;
ClearButtonClick = CursorInClearButton AND LBClick;

if (ClearButtonClick) 
{ 
	DrawBut("Clear", 30, 30, 110, 60,  colorGrey40, colorGrey40);

	rapidFireClearAll(); //Clears all static variables
}
	

timeSlot_Length = 300; //Setting Slot within which rapid fire orders are to be limited.

tradesPer_TimeSlot = 2;	 //Setting maximum orders per set time slot above. 
                                        //This way, any number of can be permitted per slot.



//Testing only BUY conditions that get generated during the same bar, wich leads to rapid Buy-Sell order pairs contunuously.
//Such situations arises as both Buy and Sell conditions become TRUE during the same bar in high volatale conditions.
if(LastValue(Buy) == 1)
{
	lastTradeTime = Nz(StaticVarGet("_lastTradeTime")); 
	nowTime = Now(4);

	tradeTimeDiff  = DateTimeDiff(nowTime,lastTradeTime);
 
	totalTradeCountThisSlot = Nz(StaticVarGet("_totalTradesInCurrentTimeSlot"));	
	if(totalTradeCountThisSlot == 0)
	{
		_TRACEF("\nFirst trade for the current slot  ");
	}
	else
	{
		_TRACEF("\n Last trade triggered at  " + lastTradeTime+"   Current Time  " + nowTime+"   Time Diff :  "+tradeTimeDiff);
	}
	
	//Refreshing slot	
	if(tradeTimeDiff >= timeSlot_Length AND lastTradeTime != 0)
	{
		_TRACEF("\n");
		_TRACEF("\n   New Time slot started  ");
		_TRACEF("\n");
		
		rapidFireClearAll();		
	}

		
	totalTradesInCurrentTimeSlot_Saved = Nz(StaticVarGet("_totalTradesInCurrentTimeSlot"));	 
	
	totalTradesInCurrentTimeSlot = totalTradesInCurrentTimeSlot_Saved + 1;
	
	_TRACEF("\n New Buy signal arrived. Total Buy signal/s in current time slot :    \n" + totalTradesInCurrentTimeSlot);
	
	_TRACEF("\n");
	
	StaticVarSet("_totalTradesInCurrentTimeSlot",totalTradesInCurrentTimeSlot); 
	
	//Averting rapid fire trade orders	
	totalTradeCountPerTimeSlot = Nz(StaticVarGet("_totalTradesInCurrentTimeSlot")); 
	
	if(totalTradeCountPerTimeSlot > tradesPer_TimeSlot)
	{
		tradesWithinTimeSlot_Saved = Nz(StaticVarGet("_tradeWithinTimeSlot")); 
		
		tradeAvertedCount = totalTradeCountPerTimeSlot - tradesWithinTimeSlot_Saved;
		
		_TRACEF("\n  Rapid fire trade averted   \n"+ tradeAvertedCount);
		_TRACEF("\n");
	}
	
	
	//Executing actual trades here.
	//placeOrder() or like functions appear here	
	else
	{
		tradesWithinTimeSlot_Saved = Nz(StaticVarGet("_tradeWithinTimeSlot")); 
		
		tradeWithinTimeSlot = tradesWithinTimeSlot_Saved + 1;
	
	
		_TRACEF("\n Trade Executed. # of trades :   \n"+tradeWithinTimeSlot);
		_TRACEF("\n");
		
		StaticVarSet("_tradeWithinTimeSlot",tradeWithinTimeSlot); 
		
		//Saving the time of first trade within the Time Slot set
		if(tradeWithinTimeSlot == 1)
		{
			StaticVarSet("_lastTradeTime",Now(4)); 
		}
	}	
	
}

Use the exrem function ("removes excessive signals"):

http://www.amibroker.com/guide/afl/exrem.html

Hello SteveH,

Thank you for the suggestion.

However, ExRem can filter out multiple successive same-type signals. Like it can filter out Multiple BUYs in a raw etc. Whereas, the problem that I am facing is of repeated order pairs of 'Buy-Sell', 'Short-Cover' - that get fired one after other, in rapid succession.

i did not read your code but it sounds like a problem that has been addressed before. To avoid multiple orders being sent in the same bar you could simple use:

if( LastValue( Ref( Buy, -1 ) ) )
{
    // a BUY occurred on last COMPLETED bar
}

you could also use static variables

then you use something like this:

// calculate Newbar
PrevTN = StaticVarGet( "TimeNumber" );
TN = LastValue( TimeNum() );
NewBar = TN != PrevTN;
StaticVarSet( "TimeNumber", TN );

// reset the value of the static variable at the start of a new bar
if( NewBar )
{
    StaticVarSet( "varBuy", 0 );
}

varBuy = Nz( StaticVarGet( "varBuy" ) );

if( LastValue( Buy ) AND varBuy == 0 )
{
    // do you buying

    // set the static variable
    StaticVarSet( "varBuy", 1 );
}
2 Likes

Hi empottasch,

Thank you very much for the guidance.

The code suggested by you is greatly useful to avoid multiple trade entries per bar. Now, if you switch over to a different time frame, it will be acting accordingly and there still will be only one trade per bar.

Consider a condition where there may be a second or third chance to enter into a trade within that same bar, Say Hourly or 15 Min etc. During intra-day, this chance should not be missed out too.

But the problem is, if we permit this, then there will be continuous rapid order generation for the Buy/Sell trades as the conditions in both case becomes TRUE during the same bar. Here, both LastValue(Buy) and LastValue(Sell) will be 1 and with ExRem, alternate trades happen for each tick.

This could lead to a disastrous situation of system placing hundreds or thousands of orders if not manually interrupted.

I could not find a solution for this with my searches, hence posted.

Thanks and regards.

how do you decide when to buy? For instance when you are showing a 15 minute chart how do you decide that you have to make more than 1 buy inside that bar? Do you use another lower timeframe chart to make that decision, or do you have some other criteria?

Hi empottasch,

I am not sure if I got your question correctly.

If you are asking about the criteria for number of trades to be permitted within a set time slot and the decision on the length of the time slot thus set, then that is purely on the strategy, risk tolerance and how volatile the script we are dealing with.

I have tried to code in such a way that, both these factors can be set as per the traders above mentioned considerations. In fact, the timeSlot_Length variable if set to timeSlot_Length = interval() and
tradesPer_TimeSlot set to 1, it should work as one trade per each Bar.

Hope I had made it clear.

my point is that I understand you can get multiple buy signals within 1 timeframe. But these buy signals should be the same buy signal over and over. You use the static variable as shown above to make sure that this signal only executes once.

You can not go and have multiple different buy signals within 1 timeframe. If this is the case you should switch to a lower timeframe. You should make sure that only 1 buy signal and 1 sell signal can occur during 1 bar. If you have a system that makes multiple trades within 1 bar then I am not suited to give you an answer since I never traded such a system.

1 Like

Hi empottasch,

Thank you for your valuable time.

The Buy/Short signal could be of same condition or different one within the same timeframe/Bar. This happens when i follow price action and/or strategy based on oscillators like ATR/RSI etc. This is the same reason why I do not want to lower time frames, as it become very volatile.

Say, for example, if I want to enter a Buy trade when the High of the bar crosses a certain level and exit that trade when low crosses below a certain level. This could happen multiple times within the same bar. I want to limit it or else it may lead to a loop.

ok, i think I can't help with that i leave it to someone else.

Hi empottasch,

Thank you very much for your help and guidance.

Regards.

Eventually, if you are planning on entering your orders in the real world through Amibroker using the IBController interface to Interactive Brokers, you setup something like this:

Keep track of your market position with a static variable:

static _market_position;

positionFlat = 0;
positionLong = 1;
positionShort = 2;

Your order management code is going to know what to do and not do based on whether _market_position is equal to the flat, long or short state. You're building an order state machine on top of the IBController interface so you're not going to have these problems of out-of-control buy and sell orders (b/c your order state machine won't allow it). I can help you solve trading problems using IBController, but if you're still in the what-if stage of development with Amibroker backtesting, there are others here far more expert than me.

2 Likes

Thank you Steve, for your detailed reply.

In fact, this is exactly what I was trying to achieve in the code that I had posted initially. However, I was not sure if that is the right way.

Basically, I am executing my trades through a different broker platform and API other than IB. That is why I had to device a system by which the filtering of out-of-control trade generation has to be done at the code level itself.

The advantage I think this method will have is, that I can be in any time-frame and yet control my trade count per time slot/Bar duration/Day. Also the duration between two consecutive similar trades can be set.

However, as suggested by you, I will turn towards IB Controller based development. Your help will be very much needed.

Thanks and regards.

Hi

I was trying this out. It works great by switching down to lower time-frame.

However, in my code that I employ for live day-trading, I compute the entry/exit rules with 30 Min bars and apply it on 1 Min chart to place orders. Why I take this route is because of the undependable nature of trend and direction calculated using 1 Min candles. This looks more stable in 30 Min Time-Frame.

My AFL makes the entry/exit decisions on the Next-Candle-Open . This way, if there is a trading signal at the very beginning of the 30 Min candle, the trade will happen only after another 30 Min. By that time the prices would have already reached to a level, it is no more tradeable.

This is the reason why I thought of using 1 Min bar chart to make entry/exit. The problem with this is that, there could be one trade per each 1 Min bar as long as the entry condition is true, unless it is handled.

Thus, I thought of creating three filters. Max-Number-of-trades permitted per Bar/ a pre-set Time Slot/ Day. I hope this way, the issue can be resolved. The code given above is to deal with this. I would like to know if the concept is right and what could be a better method.

did you try using the 1min chart and then calculating your signals in the 30min timeframe using the timeframeset, timeframerestore functions? Then you can just stay in the 1min chart while your signals are calculated in the 30min timeframe. You also need the timeframeexpand function and you probably need to get rid of excess signals. There is a basic example in the manual, see timeframeset

Thank you Edward for the reply.

I had employed a methodology exactly as you had mentioned.

The trouble is that, when I go to 1 Min chart for live trading, and if I use Bar based filtering to avoid repeated trade, there are situations wherein the entry condition is TRUE across multiple 1 Min candles and each of them fire an entry trade for every 1 Min bars during this period.

I am trying to avoid these excess signals, staying in 1 Min chart with 30 Min calculated values.

Everything was already said many times, you just need to read extensive documentation on automatic trading with practical examples and formulas available here http://www.amibroker.org/userkb/
Just read the whole thing, especially sections:
Real-Time AFL Applications
Developing a RT Trading Dashboard
Preventing Repeat Orders and Whipsaws

1 Like

Thank you Tomasz,

Somehow I missed the documentation earlier --> Real-Time AFL Applications.

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.