Send orders to IB on next bar (Intraday)

Moderator comment: @pel - you need to follow forum rules. The code in your post was not formatted. This time I edited the message to be correctly formatted.

Trying to send alerts to Interactive Broker (IB) on bar signal is triggered. Below is an example of alerts I can send to IB, but I just need to send after the bar paint when the trigger is fired. How can that be accomplished.

if( LastValue(Buy) AND openposition==0 AND transmit==1)
{
  price=LastValue(C);
  numbuyshares= Max(round(purchaseamount/price),1);
  orderid=ibc.PlaceOrder( Name(), "BUY", 1, "MKT", 0, 0, "Day", Transmit );
  openposition=1;
}
if(  LastValue(Sell) AND openposition==1 AND transmit==1 )
{
  ibc.PlaceOrder( Name(), "SELL", 1, "MKT", 0, 0, "Day", Transmit );
  openposition=0;
}

Hi.
Just use ref() function for this job.

buy = MyContition;

// We have a Buy signal on previous finished bar
buy = ref( buy,-1);



//  And the rest of your code below is sniped
  if( LastValue(Buy) AND openposition==0 AND transmit==1)
  {
// Just remember that usually the Buy price is on the next bar Open 
buyprice = open;  
// .... 
// .....
}
  


1 Like

Thanks, I'll give this a try in EOD optimization, and then ultimately during paper intraday trading.

Recall, there was a response to use:

SetTradeDelays(1,1,1,1);

to buy/sell/short/cover on the next bar. For your recommendation to use the Open price, you won't know what the Open price is for the next bar?

Ops . Sorry I did see that you have you have open a duplicate thread, and another user answer already your question.
Maybe you didn’t have the time yet to read the documentation of SetTradeDelays().
https://www.amibroker.com/guide/afl/settradedelays.html

Since you will read the above link, you are going to realise that @snoopy.pa30 and me we are speaking for the exact same think. :wink:

You said: " but I just need to send after the bar paint when the trigger is fired"

And of Couse you know the open price of the next bar. Think about that….
When the new bar is just arrives , a new bar appears in your chart. Is this new bar has an Open price?

Please also note that this SetTradeDelays function will override the settings from the "Settings" menu.

BuyPrice = Open;
SetTradeDelays( 1,0,0,0 ); //The other 3 values which are set to 0 can be anything depending on your requirement.

Edit:
You must use ONE solution and NOT both of them.
The ref(buy,-1) or SetTradeDelays()

okay, thanks a lot for the reply.

Just finished developing a strategy in Wealth Lab (pretty much C#) which works in AB. The Forum moderator (Eugene) was very big on not sending alerts for trades using the same bar, since it's unrealistic and results in a type of leading indicator.

Using the intraday code below for Interactive Brokers (IB), is there a way to send Buy and Sell triggers to IB at the next, e.g., 1-min bar?


OptimizerSetEngine("cpso");

VarPfx = Name();
openposition = StaticVarGet(VarPfx + "openposition");
numtrades = StaticVarGet(VarPfx + "numtrades");
numwins = StaticVarGet(VarPfx + "numwins");
numlosses = StaticVarGet(VarPfx + "numlosses");
entrydtg = StaticVarGetText(VarPfx + "entrydtg");
entryprice = StaticVarGet(VarPfx + "entryprice");
exitdtg = StaticVarGetText(VarPfx + "exitdtg");
exitprice = StaticVarGet(VarPfx + "exitprice");
totsharesowned=StaticVarGet(VarPfx + "totsharesowned");
netprofitthisasset = StaticVarGet(VarPfx + "netprofitthisasset");
netprofitsession = StaticVarGet("netprofitsession");
availfunds=StaticVarGet("availfunds");
currvalue=StaticVarGet("currvalue");

if (IsEmpty(openposition))
    {
    openposition=0;
    entryprice=0;
    exitprice=0;
    numtrades = 0;
    numwins = 0;
    numlosses = 0;
    netprofitthisasset = 0;
    netprofitsession = 0;
    totsharesowned=0;
    StaticVarSet(VarPfx + "openposition",0);
    StaticVarSet(VarPfx + "numtrades",0);
    StaticVarSet(VarPfx + "numwins",0);
    StaticVarSet(VarPfx + "numlosses",0);
    StaticVarSet(VarPfx + "entryprice",0);
    StaticVarSet(VarPfx + "exitprice",0);
    StaticVarSet(VarPfx + "netprofitthisasset",0);
    StaticVarSet("netprofitsession",0);
    StaticVarSet(VarPfx + "totsharesowned",0);
    }

purchaseamount=Param("Purchase amount",500,100,1000,50);
RequestTimedRefresh( 1 ); 
Transmit = ParamToggle("Transmit to IB","OFF|ON",0); 
if (Transmit){
StartIBClockTime = Now(4); 
ibc = GetTradingInterface("IB"); 
}

Buy = ExRem(Buy,Sell); //Removing Excessive Buy Signals At each bars
Sell = ExRem(Sell,Buy); //Removing Excessive Sell Signals at each bars

IIf( (Buy),PlotShapes(shapeUpTriangle*Buy,colorGreen),0);
IIf( (Sell),PlotShapes(shapeDownTriangle*Sell,colorRed),0);

if( LastValue(Buy) AND openposition==0 AND transmit==1)
{
  price=LastValue(C);
  numbuyshares= Max(round(purchaseamount/price),1);
  orderid=ibc.PlaceOrder( Name(), "BUY", 1, "MKT", 0, 0, "Day", Transmit );
  totsharesowned=totsharesowned+numbuyshares;
  StaticVarSet(VarPfx + "totsharesowned", totsharesowned);
  openposition=1;
  StaticVarSet(VarPfx + "openposition", 1);
  numtrades=numtrades+1;
  StaticVarSet(VarPfx + "numtrades",numtrades);
  entryprice = LastValue(C);
  StaticVarSet(VarPfx + "entryprice",entryprice);
}
if(  LastValue(Sell) AND openposition==1 AND transmit==1 )
{
  ibc.PlaceOrder( Name(), "SELL", 1, "MKT", 0, 0, "Day", Transmit );
  StaticVarSet(VarPfx + "totsharesowned", 0);
  openposition=0;
  StaticVarSet(VarPfx + "openposition", 0);
  exitprice=LastValue(C);  
  StaticVarSet(VarPfx + "exitprice",exitprice);
  if (exitprice > entryprice)
   {
   numwins+=1;
   StaticVarSet(VarPfx + "numwins",numwins);
   }
  if (exitprice < entryprice)
   {
   numlosses+=1;
   StaticVarSet(VarPfx + "numlosses",numlosses);
  }
  netprofitthisasset=netprofitthisasset+(exitprice-entryprice);
  StaticVarSet(VarPfx + "netprofitthisasset",netprofitthisasset);
  netprofitsession=netprofitsession+(exitprice-entryprice);
  StaticVarSet("netprofitsession",netprofitsession);
}
if (transmit==1){
     totsharesowned=ibc.GetPositionSize( VarPfx );
     StaticVarSet(VarPfx + "totsharesowned", totsharesowned);
     currvaluestr= ibc.GetAccountValue("[USD]TotalCashBalance");
     currvalue=StrToNum(currvaluestr);
     realizedpnlstr= ibc.GetAccountValue("[USD]RealizedPnL");
     realizedpnl=StrToNum(realizedpnlstr);
     unrealizedpnlstr= ibc.GetAccountValue("[USD]UnRealizedPnL");
     unrealizedpnl=StrToNum(unrealizedpnlstr);
     StaticVarSet("realizedpnl",realizedpnl);
     StaticVarSet("unrealizedpnl",unrealizedpnl);
     StaticVarSet("currvalue",currvalue);
     if(unrealizedpnl !=0 && realizedpnl !=0){
         netprofitsession=unrealizedpnl-realizedpnl;
     }
     StaticVarSet("netprofitsession",netprofitsession);
     availfundsstr= ibc.GetAccountValue("[USD]AvailableFunds");
     availfunds=StrToNum(availfundsstr);
     StaticVarSet("availfunds",availfunds);
}


profitboard = ParamToggle("Profit Board","Show|Hide",1);
if (profitboard == 1 )
{
GfxSelectFont( "Tahoma", 8, 100 );
GfxSetBkMode( 1 );
GfxSetTextColor( colorWhite);
 
if ( netprofitthisasset> 0)
{
GfxSelectSolidBrush( colorGreen ); // this is the box background color
}
else
{
GfxSelectSolidBrush( colorRed ); // this is the box background color
}
pxHeight = Status( "pxchartheight" ) ;
xx = Status( "pxchartwidth");
Left = 1100;
width = 310;
x = 5;
x2 = 290;
 
y = pxHeight;
 
GfxSelectPen( colorGreen, 1); // broader color
GfxRoundRect( x, y - 98, x2, y , 7, 7 ) ;
GfxTextOut( ( "Profit Board"),13,y-100);
GfxTextOut( ("Shares owned:" + totsharesowned ), 13, y-90) ; // The text format location
GfxTextOut( ("#Wins:" + numwins ), 13, y-80) ; // The text format location
GfxTextOut( ("#Losses:" + numlosses ), 13, y-70) ; // The text format location
GfxTextOut( ("CurrentValue:" + currvalue ), 13, y-60) ; // The text format location
GfxTextOut( ("Net profit this session:" + netprofitsession ), 13, y-50) ; // The text format location
GfxTextOut( ("Available funds:" + availfunds ), 13, y-40) ; // The text format location
GfxTextOut( ("openposition:" + openposition ), 13, y-30) ; // The text format location
}

@pel, I did only a cursory glance at your code, but think you might want to look at

SetTradeDelays(1,1,1,1);

Thanks, will optimize with that and see if results are more pessimistic (more real-world).

Isn't the SetTradeDelays for backtesting, or will it actually send trades on the next bar during live trading (intraday)?

I used SetTradeDelays(1,1,1,1) during optimization, and following backtesting, the alerts showing on the price chart (all-in-one) are different (obviously) from the alerts shown on the strategy indicator, which sits in the pane below. Is there a link to how to resolve the difference?

@pel, if you read the manual on SetTradeDelays() you will see that it works directly in the backtester. To use it for "live" trading, you would have to follow the way it is internally applied, as described in the manual - using the Ref() function.

So, as @panos indicated in the duplicate thread, they really are the same thing. :grinning:

Yes, thanks. I'll drop use of SetTradeDelays and manually code the use of Ref(,-1) to send alerts on the next bar. The position entry price for Buy and Short positions will then be Open[i] for the ith bar in the loop(?)

Why bother with the loop?

If you are on a bar and get a signal (from the previous bar) just take the Open for the current bar as your price.

I know it takes a while to wrap you head around the array processing style of AFL, but it is really worth it to use the array and avoid the loops. It is blindingly FAST!

I am not sure about your level as an AFL/AB user. Your recent joining, and short read time would hint that you are new to it. Your posted code would indicate that you know what you are doing. Your duplicate post and questions lean more to being a newbie. So please do not take offense as I am just guessing at your level of knowledge.

I suggest to new users to think about AFL like trying to program in Excel. You have a ROW for each item like Open, High, Low, Close, and Below that, all of your variables. You have a COLUMN for each Time Period.

When you want to calculate something, you need to think about using a New Row. Each Cell (row/column) can ONLY reference Cells Above and to the Left of the current Cell.

If you already understand all of that, then you should seriously think about if you need a loop.

Now there are a few cases where you do need a loop, but most of the time a loop is not needed.

Thanks, using a loop because I need to memorize entry price of trades in order to exit headfakes (position going wrong way) via current price being above(below) a type of MA plus(minus) some optimized value. Just need a double for those optimized values and not an array. Can use the Flip function to determine if a bar currently has an open position, but can use a single boolean for that. Thus far I saved from using two arrays.

Regarding your array description, I mentally transpose in order to follow the customary asset x time data matrix definition in QF papers. I also use time in rows for most other analyses.

I don't believe double, int, or byte types exist in AB, since everything is essentially an array. Like if the bar count is 1000 and you invoke standarddev = 6, then you just filed an array with 1000 values of 6.

Your response to me indicates more of a sequential programmer thinking. (That was my start in AB/AFL as well.) I originally had difficulty in wrapping my head around the array processing method, and continued to think in terms of "new bar processing". Now I am about 50/50 but with some thinking and playing get almost exclusively what I need in array processing.

As I don't know your methodology, and have not ventured into the Back Tester, these suggestions may not be useful, but here goes:
To "Memorize" entry Price, you could set a persistent variable, or have it as an array variable that you set only when you make an entry. It can then be that value until you exit (with your code controlling when and how to set it).
The Datat ypes (double, int, byte) are handled internally by AmiBroker and @Tomasz would have to instruct.
The array is just the structure that contains the data type necessary.

And your example about standarddev is correct. So.... AB manages memory for you and makes it easy for you to reference. Do you really care if you use up 1000 bytes, or 2000 bytes or 8000 bytes to hold the standarddev value? You can also have that value change bar by bar as you move along, and still have a "simple" call to standarddev and it will reference the bar value. Again, another concept that I struggled with initially, but use for controlling colours on plots.

Try to move away from thinking like a low level C programmer, and let AB handle the data types and memory allocations for you. Then you might get away from the loop idea, which I don't know if your situation calls for it or not. Just trying to open up your thinking.

Good Luck.

1 Like

I explain that not everything in AFL is array in separate topic here:

Type handling in AFL

As to "memorizing" bar by bar values - you need to start thinking array-wise as explained in http://www.amibroker.com/guide/h_understandafl.html

There is ValueWhen() function that does exactly that

memorized_input_value_when_condition_happens = ValueWhen( condition, input );

More info: http://forum.amibroker.com/search?q=valuewhen
and http://www.amibroker.com/kb/2014/09/29/debugging-techniques-part-1-exploration/

@snoopy.pa30 yes I understand, my answer was actually to @pel post.

Thanks @Tomasz.

I knew you were doing all the work in the background to control memory usage. I just didn't want to claim that I knew what it was.

Thanks - this is very helpful. Didn't know about the ValueWhen function. However, it's not a LastValueWhen, since you need to know how many bars back to look when the last alert was triggered. My code already has this solved by using lastentryprice = O[i], if the Buy (Short) evaluates to True. Recall, .NET has an indexing function called LastValueOf(), which privides the array's index when the Of() value evaluates to True. For the last Open value of the most recent Buy, it would look something like: lastentryprice = Open(Buy.LastValueof(1)). But this is academic, I already simply fetch the last entry price inside alert logical which evaluates to True.