Interactive brokers problem, it sends MULTIPLE orders at the same time

Hi, I LOVE AMIBROKER, well to be honest at the beggining I hated it, I was used to program in MQL5 ( coding logic was easier for me ), so I didn't even touched AB for a couple of years, until a few months ago I decided to give it a try, fell in love with it, I knew I could trade in IB with AB but seemed a bit scary ( complicated ) a few days ago I opened a real account with IB and slowly started to think about AB, so I managed to connect AB with IB with the plugin, then I was able to place my first order using amibroker, today I learned how to place stop loss and take profit ( I'm really excited about the posibilities ) now I have one problem when my entry condition is True, it sends multiple PlaceOrders requests making it dangerous, I tried to find a way to only place 1 trade at a time ( in each symbol ) but still everything I try doesn't work, I even tried this
preventing-repeat-orders-and-whipsaws
suggested by Tom in some other post, but I'm gonna be honest, I don't even know how to implement it in my code, its all chinese to me, so please anybody save me :frowning: is there a way to only allow one trade at a time? )

I'm afraid to share my code coz I know theres gotta have 10000000000 mistakes ( I'm just learning ) any advice its welcome.

 _SECTION_BEGIN("Price");
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " +WriteVal( V, 1.0 ) +" {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 )) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

_SECTION_END();



_SECTION_BEGIN("activar_Robot");
strategy1 = Param("strategy1",0,0,1,1,0);
Send_Orders = Param("Send_Orders",0,0,1,1,0);
Simbolo_full_name  = ParamStr("SYMBOL-EXCHANGE-TYPE-CURRENCY","XPON-NASDAQ-STK-USD");
_SECTION_END();

SetPositionSize(1,spsShares);

if(strategy1)
{

	Up_level = Max(HHV(Ref(C,-1),5),HHV(Ref(O,-1),5));
	Down_level = Min(LLV(Ref(C,-1),5),LLV(Ref(O,-1),5));

	Buy_signal = IIf(Ref(Volume,-1) > HHV(Ref(Volume,-2),5),L,Null) AND Ref(C > Up_level,-1);

	take_profit_level = IIf(Buy_signal,O + Ref(Up_level - Down_level,-1),Null);
	stop_loss_level = IIf(Buy_signal,Ref(Down_level,-1),Null);




	Buy = IIf(take_profit_level > 0 ,True,False) ;
	Sell = 0;
	ApplyStop(stopTypeLoss,stopModePoint,Open - stop_loss_level,1,False,0,0,-1,0);
	ApplyStop(stopTypeProfit,stopModePoint,take_profit_level - Open,1,False,0,0,-1,0);


	ShareSize = 1; //round(200 / LastValue(Close));

	if(Send_Orders)
	{
		if( LastValue( Buy ) )
		{
		 ibc = GetTradingInterface("IB");

		  // check if we are connected OK
		  if( ibc.IsConnected() )
		  {
				// Transmit order
				parentID = ibc.PlaceOrder(Name(), "Buy", ShareSize, "MKT", 0, 0, "Day", False);
				ibc.PlaceOrder(Name(), "SELL", ShareSize, "LMT", LastValue(take_profit_level), 0, "Day", False, 1, "", parentID);
				ibc.PlaceOrder(Name(), "SELL", ShareSize, "STP", 0, LastValue(stop_loss_level), "Day", False, 1, "", parentID);
		  }
		}
	}

	Plot(Up_level,"Up_level",colorgold,styleLine,Null,Null,0,1,2);
	Plot(Down_level,"Down_level",colorBlue,styleLine,Null,Null,0,1,2);
	PlotShapes(IIf(Buy_signal > 0,1,0),colorGreen,0,L,-12,0);
	PlotShapes(IIf(Buy_signal > 0,21,0),colorGreen,0,take_profit_level,0,0);
	PlotShapes(IIf(Buy_signal > 0,21,0),colorRed,0,stop_loss_level,0,0);
	Plot(take_profit_level,"take_profit_level",colorWhite,styleNoDraw,Null,Null,0,0,1);
	Plot(stop_loss_level,"stop_loss_level",colorWhite,styleNoDraw,Null,Null,0,0,1);
}

You are getting multiple orders because you are calling PlaceOrder multiple times.
Each time your formula executes (which can be couple of times per second).

What you should do is to PREVENT calling PlaceOrder if you already called it before.
You should do that using static variables as explained in the AmiBroker Users' Knowledge Base » Preventing Repeat Orders and Whipsaws

In principle it looks like this (NOTE that this just shows IDEA, not ready for copy-pasting):

// this code would Place order only once
if( LastValue( Buy ) )
{
    status = Nz( StaticVarGet("OrderPlacedAlready") );
 
    if( status == False )
    {
        ib.PlaceOrder(...);
        StaticVarSet("OrderPlacedAlready", True ); // store status in static variable
    }
}

If it is "Chinese" to you, it might mean that you are not yet ready for automated trading.

actually I know I'm not ready for automated trading that is a FACT, but I like learning in the process. I know there is alot to learn,

lets see I think I understand your code and yes, it should place a trade only once and thats it, but I need something that will place 1 trade per buy signal, so I think I have to find a way to assign the value of False to the staticvar whenever there is no signal. Do you think this would work?

if(Send_Orders)
{
	IsTradeOpen = Nz( StaticVarGet("OrderPlacedAlready") );
	if( LastValue( Buy ) )
	{
	 ibc = GetTradingInterface("IB");

	  // check if we are connected OK
	  if( ibc.IsConnected() )
	  {	
		if( IsTradeOpen == False )
		{
			// Transmit order
			parentID = ibc.PlaceOrder(Name(), "Buy", ShareSize, "MKT", 0, 0, "Day", False);
			ibc.PlaceOrder(Name(), "SELL", ShareSize, "LMT", LastValue(take_profit_level), 0, "Day", False, 1, "", parentID);
			ibc.PlaceOrder(Name(), "SELL", ShareSize, "STP", 0, LastValue(stop_loss_level), "Day", False, 1, "", parentID);
			StaticVarSet("OrderPlacedAlready", True ); // store status in static variable
		}
	  }
	}
	else {StaticVarSet("OrderPlacedAlready", False ); }// store status in static variable}
}

That would only prevent duplicate for as long as LastValue(Buy) doesn't change.
In practice, you would only reset that static variable after position is exited.

Typically you would need to implement state machine, saving last OrderIDs and checking order status and going thru

flat :arrow_right: entry order sent :arrow_right: position opened :arrow_right: exit order sent :arrow_right: postition closed :arrow_right: flat

cycle.

oh I see, makes sense, I kinda have an idea, but I have a couple of questions about it

first: the orderID is the variable where we executed the PlaceOrder function correct? in my case parentID.

so I would save the orderID and then what?, I would have to loop through all opened positions to see if my OrderID matches with the OrderID of any opened position at the moment. if there is no match between my OrderID and the OrderID from the opened positions in the loop means that I don't have an open position in the symbol I'm trading.

is that how its done?

OrderID is value RETURNED by PlaceOrder function. It uniquely identifies the order in IB system.

As to what to do exactly, it is covered in AmiBroker Users' Knowledge Base » Preventing Repeat Orders and Whipsaws

Thank you SOOOOOO much Tomasz it took me a few days but I finally made it work. now I just need to learn how to check for order status so instead of checking if there is no buy signal to free the orderID I need to learn how to check the order status to see if the order was closed. baby steps :slight_smile:

if(Send_Orders)
{


	// Retrieve the trading interface
	ibc = GetTradingInterface("IB");

	BuyOrderID = StaticVarGetText("BuyOrderID"); 
	
		if(LastValue(Buy) AND (BuyOrderID == "" OR BuyOrderID == Name()))
		{
			BuyOrderID = ibc.PlaceOrder( Name(), "Buy", ShareSize, "MKT", 0, 0, "Day", True); 
			if(BuyOrderID != "")
			{
			StaticVarSetText("BuyOrderID",BuyOrderID);
			}
		}
		
		if(LastValue(Buy) == False OR FREE_ORDERID ) // FREE_ORDERID is a Paramtrigger to force it.
		{
			StaticVarSetText("BuyOrderID",Name());
		}
}