My auto trade execution code, Do you see any glaring issues?

I'm looking for input on my trade execution code for IBC. I've tested it, and used it without issue so far, but I would be very grateful if someone with more IBC experience could take a look and let me know if there are any glaring mistakes, or potential issues with my logic.

My code is a modified version of alternating trades from http://www.amibroker.org/userkb/2007/07/14/preventing-repeat-orders-and-whipsaws/

I've modified the code in the following ways:

  • Trades long only on MES/ES futures
  • Send a stop loss (child order) with my trade, while also accepting algorithmic sell orders.
  • Handling the child order when filled, and canceling it if an algorithmic sell order is placed.
  • Added a "kill switch" to turn auto trading off completely
  • Added a check to see that ibc is connected before executing ibc commands.
// AUTO TRADING IBC 
// This is built to place non repeating trades. Long only, handles signals and stops

autoTrade = ParamToggle("Auto Trading?","OFF|ON",0);
transmit = ParamToggle( "Transmit", "OFF|ON", 0 );
Reset = ParamTrigger( "Reset All", "RESET" );
BuyTrigger = ParamTrigger( "Place Buy order", "BUY" );
SellTrigger = ParamTrigger( "Place Sell order", "SELL" );

LastTrade = StaticVarGetText( "LastTrade" );
BuyOrderID = StaticVarGetText( "BuyOrderID" );
SellOrderID = StaticVarGetText( "SellOrderID" );
childID = StaticVarGetText("childID");


if( autoTrade )
{
    SetChartBkColor( colorGreen );
    ibc = GetTradingInterface( "IB" );

    if( ibc.IsConnected() )
    {
        BuyPending = ibc.IsOrderPending( BuyOrderID );
        SellPending = ibc.IsOrderPending( SellOrderID );
        ChildPending = ibc.IsOrderPending( childID );
        IBPosSize = ibc.GetPositionSize( Name() );
        BuyStatus = ibc.GetStatus( BuyORderID, True );
        SellStatus = ibc.GetStatus( SellORderID, True );
        ChildStatus = ibc.GetStatus( childID, True );

        if( ( BuyTrigger || LastValue( Buy ) ) )
        {
            if( LastTrade == "Sell" OR LastTrade == "" )
            {
                if( SellStatus == "Filled" OR SellStatus == "" )
                {
                    BuyOrderID = ibc.ModifyOrder( BuyOrderID, Name(), "BUY", 1, "LMT", LastValue( C ), 0, "GTC", False );
                    childID = ibc.ModifyOrder( childID, Name(), "SELL", 1, "STP", LastValue( C ) - LastValue( stops ) , LastValue( C ) - LastValue( stops ) , "GTC", transmit, 2500, "", BuyOrderID );
                    StaticVarSetText( "BuyOrderID", BuyOrderID );
                    StaticVarSetText( "childID", childID );
                    StaticVarSetText( "LastTrade", "Buy" );
                    SetChartBkColor( colorBrightGreen ) ;
                }
            }
        }
        else
            if( ( SellTrigger || LastValue( Sell ) ) )
            {
                if( LastTrade == "Buy")// OR LastTrade == "" ) // uncomment for short positions
                {
                    if( BuyStatus == "Filled" ) //OR BuyStatus == "" ) // uncomment for short positions
                    {
                        SellORderID = ibc.ModifyOrder( SellORderID , Name(), "Sell", 1, "MKT", 0, 0, "GTC", transmit );
                        ibc.CancelOrder( childID );
                        StaticVarSetText( "SellOrderID", SellOrderID );
                        StaticVarSetText( "LastTrade", "Sell" );
                        SetChartBkColor( colorRed ) ;
                    }
                }
            }
            else
                if( ChildStatus == "Filled")
                {
                    StaticVarSetText( "LastTrade", "" ); // clear last trade
                }
                else
                    if( Reset )
                    {
                        StaticVarSetText( "BuyOrderID", "" );

                        if( BuyPending ) ibc.CancelOrder( BuyOrderID );

                        StaticVarSetText( "SellOrderID", "" );

                        if( SellPending ) ibc.CancelOrder( SellOrderID );

                        StaticVarSetText( "childID", "" ); // clear child id

                        if( childPending ) ibc.CancelOrder( childID );

                        StaticVarSetText( "LastTrade", "" );
                        ibc.CloseAllOpenPositions();

                    }

        LastTWSMsg = ibc.getLastError( 0 );
        Title += "\n" +
                 "Last TWS Error Msg: " + LastTWSMsg + "\n" +
                 " BuyOrderID: " + BuyOrderID + " " + BuyStatus + "\n" +
                 " SellOrderID: " + SellOrderID + " " + SellStatus + "\n" +
                 " childID: " + childID + " " + ChildStatus + "\n" +
                 " Last Trade: " + LastTrade + "\n" +
                 " TWS Position Size: " + NumToStr( IBPosSize, 1.0, False );
    }
}
// END IBC

1 Like

Thanks to Pinecone for providing the framework, from which I began my attempt at writing an AT code.

Considering the "Non-Manual" signals, it is always an issue of what to do with the "Phantom" signals (those pesky rascals that show themselves, then quickly disappear).

The "quick" choice would be to simple ignore them (by using a lookback for generation). However, I find that Phantom signals are more beneficial (months of data).....if one can keep track of them (and manage them properly).

Do any forum-folks care to discuss this issue?

Hi @Possum, It was not my intent to provide execution code for others, but to get a code review from others. It was never reviewed. Be sure to visit the link in the first post because that's what my code was based on, modified for my own specific use-case.

A message to you and others:
If you choose to use this unreviewed code, use it at your own risk. Test your systems thoroughly on paper.

As for your question, I had a thread on the topic here

These "phantom signals" you talk about are discrepancies between the streaming and backfill data. There is a solution in that thread, hopefully someday we will be able to use the solution. Until then I've given up on low timeframe bars.

I am very risk-averse. If I can't backtest with tons of data, I will not trade it.

Hi Pinecone,

I only used your post as a framework! It got me started. I was (and am) grateful for you having posted your work!

Working in "backtest" mode is indeed somewhat changed when dealing with "realtime" datafeed.
This is more of a mental thing (you are likely to understand what I mean by the statement).

An example: if I get a "Phantom signal" in 15-minute bars, it is giving me a "record" of what has occurred in a higher frequency (say 5-minute bars). I don't develop code for trading in higher frequencies than 1-minute bars ---- as the swings don't generate enough profit (per my methodology).

Funny how higher-frequency and lower-timeframe are the same suggestion.

Clarification: my posting of " "backtest" mode ", is NOT related to the AmiBroker backtest.

I'm simply talking about the mental approach, when working with charts/data that is not live!

Of course, I could use the term "RePaint" instead of "Phantom".

If your signals on closed bars are re-painting, you probably have a future leak in your backtests...

I'm simply attempting to converse about signals that appear intra-bar.....then disappear before bar-close. While I am aware of "future leaks", I have not included such in my desired conversation( it being a somewhat different topic of conversation).

I am most grateful that you have taken your time to interact with me on this forum!

Thank you Pinecone!

Ah ok, "Repainting" is a term generally used when talking about signals changing after bar close, not during an open bar, hence my confusion.

Multi-timeframe system will be your friend in this case. You will be able to better gather stats on those intra-bar signals. This also exponentially increases your work :wink:

As for bad streaming data, I personally found any of my systems lower than 5 minutes suffered. The higher timeframes are less affected by imperfections. Perhaps some smoothing of the signals could help.

All that being said, I've moved to daily bars so that I know for certain my prices are settled.

Sure, Mulit-Timeframe generation solves the "Phantom" issue.....however, I was attempting to suggest that using these Phantom signals, in a single time-frame, could allow me to "gain" insight into the higher frequency input (as you suggest, it would otherwise be exponentially more work).

The most glaring issue, in managing Phantom signals (they are initially EntryFlags) is how they must properly have their own "Exit". IOW, if you are using an algo for entry, a Phantom becomes "Naked".

I like you Pinecone! I'm just kinda hanging out here out the house, working on me some code.

I thought I'd attempt to fire-up a conversation on this site.....and low-and-behold you have joined into the conversation. I am appreiciative.

You know, conversations on this site are uncommon. I've always wondered why that is the case.

I presume it to be that the site is for answering problematic issues with the software....or a user's code (of course, they will be required to share the code....I fully understand the reasoning).

I simply don't get why Amibroker users don't want to chat. To chat about the stuff that we are so passionate about, seems to be an easy thing to embrace. Yet, that has not been my experience here.

I had a very profitable system at 15-seconds, but the data issues ate the edge. We need more C programmers here so that we can get plugins made without having to bug/ wait on/ convince Tomasz.

I could probably figure out how to create the plugin for "settled" 5-second bars if I had the original IB data plugin code, but I am not skilled enough to write this from scratch. Unfortunately that code is not open source (this would be a nice change in policy, too!)

As for auto trade code that you have shown it is pretty straightforward. There are some caveats, especially for those who did not understand original intent of this post (code review) and copy-paste this code blindly.

  • it works for single symbol and single active trade (either long or short) only
  • it works for single instance (single chart) because it does not use unique key for static variables
  • it does not do anything when IBc is not connected (does not sound alarm or anything)
  • CloseAllOpenPositions call as written in the docs may fail in some circumstances (for example when markets are closed but the code above assumes it "always works" and resets static variables)
3 Likes

Thank you for the code review @Tomasz.

@Possum I've thought about the same thing, and have come to a few conclusions:

  • Most algo traders are fairly secretive if they have an edge.
  • A lot of non-AFL specific questions I see are pretty basic. This isn't saying all users are basic, but it may make those with knowledge shy away from interacting on this platform.

At the end of the day, AMI broker is hands down the best platform out there if you spend the time to learn the language (which is arguably the easiest in the biz!). The only sticky point is the lack of connectivity and the need for knowing C if you want to trade anywhere other than IB.

1 Like