Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Trading multiple instruments

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Trading multiple instruments

    Here is my code for making trades:

    protectedvoid CheckTrade() {
    for (int tPair = 0; tPair < 3; tPair++) {
    switch (desiredPosition) {
    case -1:
    if (Positions[tPair].MarketPosition != MarketPosition.Short) {
    entrySignal[tPair] = tradePair[tPair] +
    " " + signal;
    EnterShort(tPair,
    1,entrySignal[tPair]);
    }
    break;
    case0:
    if (Positions[tPair].MarketPosition == MarketPosition.Long) {
    ExitLong(tPair,
    1,signal,entrySignal[tPair]);
    }
    if (Positions[tPair].MarketPosition == MarketPosition.Short) {
    ExitShort(tPair,
    1,signal,entrySignal[tPair]);
    }
    break;
    case1:
    if (Positions[tPair].MarketPosition != MarketPosition.Long) {
    entrySignal[tPair] = tradePair[tPair] +
    " " + signal;
    EnterLong(tPair,
    1,entrySignal[tPair]);
    }
    break;
    }
    }
    }

    As you can see, it should execute simultaneous identical trades (or none) depending on "desiredPosition" and the current market position on 3 instruments (indexed by tPair). Strategy Analyzer shows trades for only one instrument (tPair = 0).

    Also, BTW, the exit signal names do not show in the "Trades" grid (although the entry signal names do).

    Can you help?

    #2
    What is entrySignal[]? I suggest you first use this to debug your orders: http://www.ninjatrader-support.com/v...ead.php?t=3627

    You will want to first confirm that your orders are actually being made on your various instruments. Also ensure you have data for all the instruments.
    Josh P.NinjaTrader Customer Service

    Comment


      #3
      Originally posted by Josh View Post
      What is entrySignal[]
      string []

      (i.e. an array of strings)

      tradePair[] is an array of strings too (instrument symbols for currency pairs).
      Last edited by mikeyork; 07-30-2008, 11:50 PM.

      Comment


        #4
        Understood. Any luck with the TraceOrders?
        Josh P.NinjaTrader Customer Service

        Comment


          #5
          Here is a sample from the trace:

          5/16/2008 12:47:48 PM Ignored PlaceOrder() method at 5/16/2008 12:47:48 PM: Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='$EURUSD CloseDn' FromEntrySignal='' Reason='Exceeded entry signals limit based on EntryHandling and EntriesPerDirection properties'
          5/16/2008 1:00:14 PM Entered internal PlaceOrder() method at 5/16/2008 1:00:14 PM: Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='$USDCHF CloseDn' FromEntrySignal=''
          5/16/2008 1:00:14 PM Ignored PlaceOrder() method at 5/16/2008 1:00:14 PM: Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='$USDCHF CloseDn' FromEntrySignal='' Reason='Exceeded entry signals limit based on EntryHandling and EntriesPerDirection properties'
          5/16/2008 12:47:48 PM Entered internal PlaceOrder() method at 5/16/2008 12:47:48 PM: Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='$EURUSD CloseDn' FromEntrySignal=''
          5/16/2008 12:47:48 PM Ignored PlaceOrder() method at 5/16/2008 12:47:48 PM: Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='$EURUSD CloseDn' FromEntrySignal='' Reason='Exceeded entry signals limit based on EntryHandling and EntriesPerDirection properties'

          Note that
          1. Nothing appears before 5/16, even though several orders were made and some (but GBPUSD only) executed. I am guessing that because the trace is huge, the earlier entries have been deleted (due to a fixed size buffer?).
          2. The FromEntrySignal field has spurious text.
          3. The times do not correspond to anything remotely reasonable (assuming the SignalName field is correct and in terms of my intended logic). However the actual executed trades appearing in the Strategy Analyzer grid DO correspond to what I would expect.

          It is as though the unexecuted trades for the other pairs are hanging around and generating nonsense in the trace.

          Ps. The trace is huge -- even though only 11 trades were actually executed.
          Last edited by mikeyork; 07-31-2008, 02:27 PM.

          Comment


            #6
            You will need to limit your backtesting down to a period containing your earlier trades then to see what is happening there. The signal name text will print whatever text you give it. Please run additional Print()s to see what is actually contained in your string arrays.

            I suggest you strip down your strategy into its core design and work slowly upwards to see where it is messing up. If you want multiple open positions you will probably need to increase your EntriesPerDirection or EntryHandling to unique entries.
            Josh P.NinjaTrader Customer Service

            Comment


              #7
              Ok, the problem with only getting one pair traded was due to the "Entries per direction" parameter being 1. (I had naively assumed this would apply to each instrument.)

              I am now getting all three pairs traded with each signal. However, even though they are all coded to execute in the same loop (on the same indicator tick), they get different execution times, typically minutes apart.

              Only the very first three trades on the very first signal look nearly simultaneous. After that they seem to become more and more independent in timing.

              When I look at the order grid, I see that some orders are cancelled. This seems to occur when I reverse position (e.g. "EnterShort" when already long) which is recorded in the trades grid as two separate trades (e.g. close long and then go short). What seems to happen is that the second part of the trade is sometimes cancelled and then renewed some time later (often several minutes).

              Please explain what is going on here.

              The output window still fills with masses of incomprehensible garbage generated purely by TraceOrders (I have no Print statements in my code).

              Later:

              More info.

              1. I fixed the order cancellation by using the IOrder object to look for fills and not to execute an order unless it was null.
              2. Even for the very first set of 3 trades, the Time field in the order grid varies with each pair and in all cases is minutes ahead of the recorded Entry Time in the trades grid. This presumably means that I have unfilled orders hanging around for minutes so the orders (before I checked the IOrder object) would have been repeatedly submitted many times before one was filled -- which would presumably account for the Traceorders garbage. Since I am only backtesting using the Strategy Analyzer, I don't understand why orders should not be filled immediately.
              Last edited by mikeyork; 08-18-2008, 03:58 PM.

              Comment


                #8
                Well you will need to tease out the TraceOrders to find the reason why your orders are cancelled. Without knowledge of why they are cancelling or we cannot proceed to address the issue. I suggest you backtest on a very small data set that is able to contain your scenario so you have less trace logs to push through.

                As for possible cancellation reasons I suspect (just a hunch) it may be due to the failure of resubmissions on the next bar which causes the order to be cancelled. Please try using liveUntilCancelled = true.
                Josh P.NinjaTrader Customer Service

                Comment


                  #9
                  Originally posted by Josh View Post
                  As for possible cancellation reasons I suspect (just a hunch) it may be due to the failure of resubmissions on the next bar which causes the order to be cancelled. Please try using liveUntilCancelled = true.
                  As I added later to my last post, I have resolved the cancellation problem by using IOrder. I also notice that there is no "liveUntilCancelled" data member of a Strategy object, although LiveUntilCancelled is a member of IOrder. I don't see any means to set this when submitting the order, since I only get the IOrder object by return. Are you suggesting that I set it true at this point? Or in OnOrderUpdate?

                  I notice that the documentation states, in reference to LiveUntilCancelled, that "In a historical backtest, orders will always reach a "Working" state". Since I am doing a historical backtest, doesn't this imply that the order has passed the stage where it might be cancelled?

                  Also can you address the issue of how I get the Time field in the Orders grid showing three different times for the components of the first trade and minutes ahead of the entry times (simultaneous for the first trade only) in the Trades grid? (Even when OnBarUpdate is called every tick.)

                  Comment


                    #10
                    No. Order cancellation occurs if you don't resubmit your order at the beginning of every new bar. Since you are using multiple instruments I can see this happening immediately as you switch over to the next bars object. Say you submit orders during the instrument A's bar object. The same orders for all 3 instruments are not resubmitted when instrument B's bar object is updated causing a cancellation. It gets hairy real quick.

                    What you want to do is now use liveUntilCancelled = true. These are completely compatible with using IOrders, but it is not applicable for use on market orders. I did not notice you used market orders earlier.

                    I am confused as to what problem you are facing now if you said your orders are not cancelled. If you submit an order it will fill at whatever timestamp it fills at. Please be aware the time stamps will not be the same across all your timestamps given the nature of multi-instrument strategies. Say you submitted the orders on instrument A at 11:00. Instrument A updates before instrument B and C so the time you are still at on B and C is actually 10:59 or even later depending on the time period you are running on.

                    If you feel this is not the source of the discrepancy you will need to use time prints to see when your orders are filling. I suggest you print within the OnExecution() or OnOrderUpdate() methods. Print your IOrder objects out and trace them manually instead of TraceOrders.
                    Josh P.NinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by Josh View Post
                      No. Order cancellation occurs if you don't resubmit your order at the beginning of every new bar. Since you are using multiple instruments I can see this happening immediately as you switch over to the next bars object. Say you submit orders during the instrument A's bar object. The same orders for all 3 instruments are not resubmitted when instrument B's bar object is updated causing a cancellation. It gets hairy real quick.
                      Both instruments being traded and instruments used for the indicator (not the same) are updating on each tick. The orders are submitted for the traded instruments on tick updates of the indicator bars. All three traded instruments have their orders submitted on the same indicator tick.

                      What you want to do is now use liveUntilCancelled = true. These are completely compatible with using IOrders, but it is not applicable for use on market orders. I did not notice you used market orders earlier.
                      As I said before, the compiler does not recognize "liveUntilCancelled" and I cannot find this in the documentation.

                      I am confused as to what problem you are facing now if you said your orders are not cancelled. If you submit an order it will fill at whatever timestamp it fills at. Please be aware the time stamps will not be the same across all your timestamps given the nature of multi-instrument strategies. Say you submitted the orders on instrument A at 11:00. Instrument A updates before instrument B and C so the time you are still at on B and C is actually 10:59 or even later depending on the time period you are running on.
                      Are you saying that I cannot submit an order for A B and/or C on an update of D? I do not see this in the documentation. Besides, I am running on ticks, so I don't see how I can get differences of minutes.

                      If you feel this is not the source of the discrepancy you will need to use time prints to see when your orders are filling. I suggest you print within the OnExecution() or OnOrderUpdate() methods. Print your IOrder objects out and trace them manually instead of TraceOrders.
                      I'll try this tomorrow.

                      Comment


                        #12
                        liveUntilCancelled is not for market orders which is why you can't find it in the EnterLong() or EnterShort() documentation. This was my mistake earlier and hopefully it is cleared out now.

                        You submit your orders on a tick. That tick is correlated with one instrument. It does not correspond with all instruments. Only one tick from one instrument is processed at a time, but you can submit orders to other instruments regardless of which instrument tick you are processing at the moment. This is what you are doing and you should not have problems. In line with my earlier misunderstanding is that market orders do not get cancelled on the next bar either so you don't need to worry about this part.

                        So to clarify, you can submit orders to any bars object (instrument) from any other bars object. Market orders should not have any of the complication issues. What you want to do is monitor OnOrderUpdate() or OnExecution(). Market orders will fill at the earliest time possible. See how the order states of your orders progresses and timestamp them for back referencing.
                        Josh P.NinjaTrader Customer Service

                        Comment


                          #13
                          Here is my OnOrderUpdate code:

                          protectedoverridevoid OnOrderUpdate(IOrder order)
                          {
                          bool done = false;
                          for (int tPair = 0; tPair < numTradePairs; tPair++) {
                          if (entryOrder[tPair] != null && entryOrder[tPair].Token == order.Token) {
                          // is entry order for tPair
                          done = true;
                          Print("O: " + order.Time.ToString() + " -- " + order.ToString());
                          if (order.OrderState == OrderState.Filled
                          || order.OrderState == OrderState.Cancelled
                          || order.OrderState == OrderState.Rejected) {
                          entryOrder[tPair] = null;
                          }
                          }
                          if (exitOrder[tPair] != null && exitOrder[tPair].Token == order.Token) {
                          // is exit order for tPair
                          done = true;
                          Print("O: " + order.Time.ToString() + " -- " + order.ToString());
                          if (order.OrderState == OrderState.Filled
                          || order.OrderState == OrderState.Cancelled
                          || order.OrderState == OrderState.Rejected) {
                          exitOrder[tPair] = null;
                          }
                          }
                          }
                          if (!done) {
                          Print("O?: " + order.Time.ToString() + " -- " + order.ToString());
                          }
                          }

                          Here are the first few output lines generated by the Print statements:

                          O: 9/8/2008 8:59:00 AM -- Order='NT-00000/Back101' Name='IntraDn' State=PendingSubmit Instrument='$GBPUSD' Action=SellShort Limit price=0 Stop price=0 Quantity=3 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=0 Fill price=0 Token='b67e523a91df429ca271f368f8d49ec5' Gtd='12/1/2099 12:00:00 AM'
                          O: 9/8/2008 8:59:00 AM -- Order='NT-00000/Back101' Name='IntraDn' State=Accepted Instrument='$GBPUSD' Action=SellShort Limit price=0 Stop price=0 Quantity=3 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=0 Fill price=0 Token='b67e523a91df429ca271f368f8d49ec5' Gtd='12/1/2099 12:00:00 AM'
                          O: 9/8/2008 8:59:00 AM -- Order='NT-00000/Back101' Name='IntraDn' State=Working Instrument='$GBPUSD' Action=SellShort Limit price=0 Stop price=0 Quantity=3 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=0 Fill price=0 Token='b67e523a91df429ca271f368f8d49ec5' Gtd='12/1/2099 12:00:00 AM'

                          So far so good for the order for the first instrument. We go from "Pending" to "Accepted" to "Working". Then the order for the second instrument has essentially the same three entries with the same time-stamp. Good so far!

                          But then, for the third instrument, I get the same three entries but with a different time-stamp:

                          O: 9/8/2008 8:59:17 AM -- etc. which is 17 seconds later. Why, since all three orders were submitted on the same event?

                          Then follow three entries for the fills -- one for each instrument. But this time, the later order is printed first -- ahead of the ones which were supposedly filled before it! As shown here:

                          O: 9/8/2008 8:59:17 AM -- Order='NT-00002/Back101' Name='IntraDn' State=Filled Instrument='$USDCHF' Action=SellShort Limit price=0 Stop price=0 Quantity=10 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=10 Fill price=1.1312 Token='0060e9f3a27f48108f4712fa54b202aa' Gtd='12/1/2099 12:00:00 AM'
                          O: 9/8/2008 8:59:00 AM -- Order='NT-00001/Back101' Name='IntraDn' State=Filled Instrument='$EURUSD' Action=SellShort Limit price=0 Stop price=0 Quantity=4 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=4 Fill price=1.4128 Token='ec6f18a9a65547af9534a1a0e959a405' Gtd='12/1/2099 12:00:00 AM'
                          O: 9/8/2008 8:59:00 AM -- Order='NT-00000/Back101' Name='IntraDn' State=Filled Instrument='$GBPUSD' Action=SellShort Limit price=0 Stop price=0 Quantity=3 Strategy='AndysBasicStrategy' Type=Market Tif=Gtc Oco='' Filled=3 Fill price=1.7542 Token='b67e523a91df429ca271f368f8d49ec5' Gtd='12/1/2099 12:00:00 AM'

                          Now amazingly enough, if we go back to the "Trades" grid for the Strategy Analyzer to see how these trades are recorded, we find they all have the same entry time: 9:03:31 -- more than three minutes later than shown in the output window!

                          Now let's go back to the output window. We find similar entries for further trades but with similar time issues and again in reverse order of time-stamp.

                          O: 9/9/2008 2:02:00 AM -- Order='NT-00003/ GBPUSD
                          O: 9/9/2008 2:01:25 AM -- Order='NT-00004/ EURUSD
                          O: 9/9/2008 2:00:45 AM -- Order='NT-00005/ USDCHF

                          These are the exit trades for the 3 entries above.

                          But now we see something even more mysterious, the exact same three exit orders again -- with the exact same time-stamps -- but with new numbers 0006,0007,0008. These are followed by 3 cancellations, each followed by a fill of the earlier entry:

                          O: 9/9/2008 2:00:45 AM -- Order='NT-00008..State=PendingCancel
                          O: 9/9/2008 2:00:45 AM -- Order='NT-00008..State=Cancelled
                          O?: 9/9/2008 2:00:45 AM -- Order='NT-00005..State=Filled
                          O: 9/9/2008 2:01:25 AM -- Order='NT-00007..State=PendingCancel
                          etc.
                          O: 9/9/2008 2:02:00 AM -- Order='NT-00006..State=PendingCancel
                          etc.

                          But note the '?' after 'O" for the fill. This means that the original IOrder object lost its token (see my code above) -- also the only way, in my code, that the order would be re-submitted, since an order requires a null IOrder object for that instrument.

                          The execution times again differ from those in the trades grid:
                          2:05:51 AM for USDCHF
                          2:05:51 AM for EURUSD
                          2:06:00 AM for GBPUSD
                          which also differ, even though they were submitted on the same event.

                          This continues in a similar vein for other trades.

                          Comment


                            #14
                            1. Just because you submit your orders at the same time does not mean they will "work" at the same time. There can be any number of reasons as to why your 3rd instrument isn't trading yet. You need TraceOrders = true to see if the order is ignored or what not.

                            2. Orders states DO NOT have any set order in which they will come in at. It can be order1, order2, order3 sequentially or it can be order1 order3 order2. Changes in order states can happen with order1->order2->order2->order1->order3. Any thing can happen. This is the nature of being multi-threaded. Timestamping is meaningless when working under this context

                            3. Order tokens can never be "lost" unless somewhere in your code you set that IOrder to null. This is what is happening.

                            You cannot program expecting a certain sequence of events to happen. Things will come at you as they become available.
                            Josh P.NinjaTrader Customer Service

                            Comment


                              #15
                              Originally posted by NinjaTrader_Josh View Post
                              1. Just because you submit your orders at the same time does not mean they will "work" at the same time. There can be any number of reasons as to why your 3rd instrument isn't trading yet. You need TraceOrders = true to see if the order is ignored or what not.
                              TraceOrders produced so much stuff before, I decided it was better to do my own tracing. But I will set it true again and see if I can trace what is going on with the first set of orders. BTW, how about giving me some of those reasons as to why an instrument isn't trading? I'm backtesting. Why aren't market orders executed instantly?

                              2. Orders states DO NOT have any set order in which they will come in at. It can be order1, order2, order3 sequentially or it can be order1 order3 order2. Changes in order states can happen with order1->order2->order2->order1->order3. Any thing can happen. This is the nature of being multi-threaded. Timestamping is meaningless when working under this context
                              So are you saying that the time-stamp on an order has nothing to do with the time of the tick on which it is submitted? What's the point of having a time field in an IOrder object in that case?

                              3. Order tokens can never be "lost" unless somewhere in your code you set that IOrder to null. This is what is happening.
                              Only because a spurious and unnecessary duplicate order (which I did not submit, yet which I now see must have had the same token as the one I did submit which was already at "Working" status!!) was cancelled. Either that or OnOrderUpdate() does not get called at the moment the order is updated -- which would be very strange even for a multi-threaded application.

                              You cannot program expecting a certain sequence of events to happen. Things will come at you as they become available.
                              Sure, but why such huge time differences (as much as minutes) on simultaneous orders submitted on the same tick? I understand that events in multi-threaded applications do not happen in a pre-determined sequence, but when certain states (such as the sequence of states for an order) have a necessary logical order, then you'd better make sure (using event synchronization and locks) that the execution of events respects that order.
                              Last edited by mikeyork; 09-10-2008, 05:34 PM.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                              0 responses
                              587 views
                              0 likes
                              Last Post Geovanny Suaza  
                              Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                              0 responses
                              341 views
                              1 like
                              Last Post Geovanny Suaza  
                              Started by Mindset, 02-09-2026, 11:44 AM
                              0 responses
                              103 views
                              0 likes
                              Last Post Mindset
                              by Mindset
                               
                              Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                              0 responses
                              555 views
                              1 like
                              Last Post Geovanny Suaza  
                              Started by RFrosty, 01-28-2026, 06:49 PM
                              0 responses
                              552 views
                              1 like
                              Last Post RFrosty
                              by RFrosty
                               
                              Working...
                              X