Apply stops in IB

As the ApplyStop(); function only works for backtesting functionalities I was wondering how I would use this feature for the IBcontroller WITHOUT doing a bracket order. I say this because on my back test I dont have the SetOption("ActivateStopsImmediately", True); meaning that if the stop/tp is indeed hit it close the position on the close of the current bar at the next bars open if you get what I am saying. I thought coding somthing that actually returns a array would work such as:

exit = C >= Ref(LastValue(Buy) + ATR(14), -1) OR C <= Ref(LastValue(Buy)-ATR(14), -1)<=C;
PlotShapes(exit * shapeUpArrow, colorYellow);

However that did not work and all it did was just plot a bunch of random yellow arrows on my screen lol. What I am trying to do is have it so I can a tp/sl array is returned whenenver the current bars high/low is >/< then the value when the last buy signal was plotted + ATR of when the buysignal occurred so I can write a code that looks something like this:

if( LastValue( exit ) )
{
  ibc = GetTradingInterface("IB");

  // check if we are connected OK
  if( ibc.IsConnected() )
  {
     // check if we do not have already open position on this stock
     if( ibc.GetPositionSize( "ESH1-GLOBEX-FUT" ) > 0 )
     {
        // transmit order
        ibc.PlaceOrder("ESH1-GLOBEX-FUT", "Sell", 1, "MKT", 0, 0, "GTC", True );
        ibc.Sleep( 4000 ); // sleep for 4000 milliseconds = 4 second (Time require for Ib to prove the buy )

     }
  }
}

ps I know its not best practice to have to have ibc.Sleep(); however because this algo is based off of closing values I feel its ok. If you believe other wise please explain your perspective

What I ended up doing was:

stop = ATR(14)*mult;

Equity(1, 0); //evalutes stops

inTrade = Flip(Buy, Sell); //turns on when we are in a trade

SetOption("everybarNullcheck", True);

stopline = IIf(intrade, ValueWhen(Buy, C - stop), Null);
tpline = IIf(intrade, Valuewhen(Buy, C + stop), Null);

Plot(stopline, "SL", colorRed, styleLine);
Plot(tpline, "SL", colorGreen, styleLine);

exit = C>= tpline OR C<=stopline;

Pretty sure it will work, testing it on live data right now ill come back and mark as solution if it does

The only correct way to implement ApplyStop(s) in IB auto trading is placing BRACKET ORDER.
Your code is incorrect for many reasons:

  • GetPositionSize values are DELAYED (they are updated by IB with 1+ second delay)
    so you are going to get duplicate orders
  • you are using ib.Sleep(4000) which is freezing everything (including IBController) for 4 seconds (absolute NO-NO)

Wow great point @Tomasz I did notice all my trades executed at a second delay. So what use static variables to store order state and make transitions from one state to another depending on order status? Can you point me to some docs on this? In general would you just not recommend doing stops by the per bar close method as I was talking about above? I feel like that in general would be the safer way incase trading/data connection is lost.

Placing bracket orders is documented here http://www.amibroker.com/at/

Oh no I know how to place bracket orders but I need to know how to use static variables to store order state and make transitions from one state to another depending on order status. So I can do market bracket orders without duplicate orders without the sleep function aswell. Also just my thought you've done a great job with the site but it would be of benefit if links opened in a new tab

There are TONS of examples here http://www.amibroker.org/userkb/

1 Like

@flip, this is the most straight forward tutorial/code snippet on state and managing IB trades that I know of: http://www.amibroker.org/userkb/2007/07/14/preventing-repeat-orders-and-whipsaws/

In my opinion it should be the main example code for the IB plugin, as it is the most complete+safest example I've seen yet.

1 Like

How come something like this doesn't return values for bracket orders as I believe I'm turning a array into a scalar and passing the scalar value bracket that order:

a = ATR(14);
var1 = (LastValue( C ) + LastValue( a ));
var2 = (LastValue( C ) - LastValue( a ));

Buy = 1;

if( ibc.IsConnected() AND ibc.GetPositionSize("ESH1-GLOBEX-FUT") == 0 AND LastValue(Buy)) // postion size check is for testing purposes only lol dont worry Tomasz
{

	parentID = ibc.PlaceOrder("ESH1-GLOBEX-FUT", "BUY", 1, "MKT", 0, 0, "GTC", False );
	ibc.PlaceOrder("ESH1-GLOBEX-FUT", "SELL", 1, "LMT", var1, 0, "GTC", False, 1, "GTC", parentID );
	ibc.PlaceOrder("ESH1-GLOBEX-FUT", "SELL", 1, "STP", var2, var2, "GTC", True, 1, "GTC", parentID );
	ibc.Sleep( 4000 ); //Dont worry for testing purposes only
}

Such as when I submit this order the stop and tp dont come up on IB
Thanks

I don't think you've got enough info here, you are missing the Attributes field after tick size (which in your case is wrong, it should be 2500). There should be some debug info in the trading console that pops up.
Here's exactly what I'm using for MES futures:

childID = ibc.PlaceOrder(Name(), "SELL", 1, "STP", var2, var2, "GTC", transmit, 2500, "", parentID );

EDIT: actually it looks like you're using GTC in attribute. I don't think that's right. Just leave it blank "".

Most likely you pass wrong prices. TWS Expects price to be "tradeable". You either must round price to tradeable price or make IBController do the rounding but then you need to pass corret TickSize. Your TickSize is wrong (1) which represents 0.0001 movement
which is not the minimum fluctuation of futures ES contract.

1 Like

How do I round the value to the nearest tick value as doesn't the round(); function round to the next whole number? Or how do I do that in IB controller as I don't see that as a option in configure. Thank you for your time Tomasz.

You'll have to do it mathematically. For the nearest .25:
round(a*4)/4

1 Like

@Pinecone already told you in previous reply. Use correct TickSize in PlaceOrder call. Read the docs
IBController 1.3.8 READ ME For 0.01 movement TickSize parameter in PlaceOrder call should be 100. For 0.25 it should be 2500.

Reading docs IBController 1.3.8 READ ME is ESSENTIAL. You have to read SLOWLY and CAREFULLY. Every sentence counts. There is no chit-chat or "small talk" in the docs. There are only sentences filled with essence that must not be skipped.

PlaceOrder( string Ticker, string Action, number Quantity, string Type, number LimitPrice, number StopPrice, string TimeInForce, bool Transmit, [optional] number TickSize = 100, [optional] string Attributes = "", [optional] string ParentID = "", [optional] string OCAGroup, [optional] number OCAType, [optional] string FAParams, [optional] string Account)

TickSize - defines minimum price fluctuation allowed for given symbol expressed in pips (= 0.0001). For most US stocks it is 100 (represents 0.01 move), for most currencies: 1 (represents 0.0001 move), if minimum move is less than 0.0001 you can use fractional values for example 1/100 for 0.000001 move.

In these last 2 sentences there is a whole knowledge about correct price rounding.

2 Likes

Great thank you @Tomasz and @Pinecone I really do appreciate your time and I'm definitely starting to slowly get a better grasp on this language. On thing I am confused about though is in the back test my applystop(); is getting executed a different price then it should be for example it may get execute 1 point higher/lower then the actual ATR(); value and other time it will reflect a accurate price. I am not sure why this is as my bracket orders do get execute at the right price. Here is my code for the apply stops:

a = ATR(14);
stop = ApplyStop(stopTypeLoss,stopModePoint, LastValue( a, lastmode = True ), False, 0);
tp = ApplyStop(stopTypeProfit,stopModePoint, LastValue( a, lastmode = True ));

Then lastly here is my code for the brackets:

var1 = (LastValue( O, lastmode = True ) + LastValue( a, lastmode = True ));
var2 = (LastValue( O, lastmode = True ) - LastValue( a, lastmode = True ));
ibc = GetTradingInterface("IB");

if( ibc.IsConnected() AND ibc.GetPositionSize("ESH1-GLOBEX-FUT") == 0 AND LastValue(Buy)) // postion size check is for testing purposes only lol dont worry Tomasz
{

	parentID = ibc.PlaceOrder("ESH1-GLOBEX-FUT", "BUY", 1, "MKT", 0, 0, "GTC", False );
	ibc.PlaceOrder("ESH1-GLOBEX-FUT", "SELL", 1, "LMT", var1, 0, "GTC", False, 2500, "GTC", parentID );
	ibc.PlaceOrder("ESH1-GLOBEX-FUT", "SELL", 1, "STP", var2, var2, "GTC", True, 2500, "", parentID );
	ibc.Sleep( 4000 ); //Dont worry for testing purposes only
}

Not sure if you wanted the bracket code but thought I throw it in.
Any idea why this might be reflected different in the backtest?
Thanks.

For your stop you have it set to exit at trade price
For your target you don't have it set at all, so I assume it defaults to zero, which is the same as above.

You will want them set to ExitAtStop (1).

Also you still have "GTC" in a weird place with your IB LMT order.

I'm not trying to be mean, but you need to spend a little more time looking at the User's Guide, look through all the options you can set for each function. You can get to that screen from the AFL editor, Help>Help Contents.

Another helpful area to look at is the "SetOption" settings, these are backtester options. I have a group of them that I put on all my scripts so that my settings are always the same.

I do understand that there's a lot to this language, and if you are accustomed to other languages some things aren't 1:1, so questions are warranted! But when you are using the actual function you should at least read the docs on that function and go through things line by line while looking at your code.

Lastly I want to say, there is no race, take it slower. The market will always be there, and I believe there will always be opportunity for the diligent.

2 Likes

@Pinecone Thankyou for the thoughtful reply and advice. Sorry for the delayed response now that school started back up ive been swamped with school and work and only have time for this on weekends. The issue was that SellPrice= O; and this stop = ApplyStop(stopTypeLoss,stopModePoint, a, False, 0); instead of this stop = ApplyStop(stopTypeLoss,stopModePoint, a);

Totally understand, I've got a lot on my plate as well :smile:
Glad you found the bug!

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