Event methods not triggering on events

Okay, so I’ve progressed to the point of having my Indicator create orders when the appropriate entry triggers appear.

Before I get too far into my rather complicated trade management system, however, I need to know why the event triggers don’t seem to be triggering on the actual events. It would appear that they are only running when OnBarUpdate does, if even then.

Wednesday - NQ
Wednesday - NQ
A - Order = Filled, Position =
D - Order = Filled, Position =
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Execution updated.
Order: Entry Quantity: 1 Price: 30142.25
Open position = instrument=‘NQ 06-26’ account=‘Playback101’ avgPrice=30142.25 quantity=1 marketPosition=Long statementDate=‘2099-12-01’
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Execution updated.
Order: Entry Quantity: 1 Price: 30142.5

In this excerpt from my Output1 tab, you see the “Wednesday - NQ” report, which is generated by an Indicator that does nothing but toggle a boolean that is visible to the main Indicator to determine, based on time-of-day, whether I am in a valid trading window or not.

The A and D order output comes from the main Indicator, and those print lines are in OnBarUpdate.

Finally, you see the “Order updated.” report, which comes from OnOrderUpdate.

Later, you see the execution update information, which comes from OnExecutionUpdate.

This issues are these:

I was already in a position at the time of the first two output lines. The A and D lines use a variable, the value of which is supposed to be there after the "Position = ", that is populated by OnPositionUpdate. As you can see, that variable is still null, even though I am already in a position.

Eventually, the “Open position” report, from OnPositionUpdate does show up, but again, it’s only after I’ve already been in a position for at least 40 seconds (two bars on my 20-sec. chart).

And the OrderUpdate and ExecutionUpdate also take the same 40 seconds to fire, despite the fact that both of those events must have happened for me to get into the position in the first place.

So, when do these event triggers actually fire? I would have thought it would be as soon as the actual event takes place. But here, I am having to wait a long time for these event triggers to act, and it is preventing me from executing logic based on what the state of things is the instant I enter a position.

Any help would be appreciated. Thank you!

Nevermind. I figured it out.

It had to do with where in my Indicator code I was doing the subscriptions. It turned out that my subscriptions were inside a conditional that tested whether an order had already been placed, and was sequentially before the code that generates orders. So, the subscriptions wouldn’t execute until the next candle printed after the order had already gone through, thus the delay.

All fixed! Thank you!

They should fire when the order / execution / position event happens, not only on OnBarUpdate.

Your log points to a different issue: you are relying on OnPositionUpdate to initialize a variable for a position that already existed. OnPositionUpdate does not necessarily fire just because you are already in a position. It fires when a new position update is received. NinjaTrader says OnPositionUpdate() is typically called after OnExecutionUpdate(), and the strategy position is driven by executions.

So this part is expected

A - Order = Filled, Position =
D - Order = Filled, Position =

Your variable is blank because no new position update has populated it yet.

Also important: your A and D prints are inside OnBarUpdate, so those lines will only print when OnBarUpdate runs. That does not prove the account events are delayed. It only proves your print check is delayed.

Blunt diagnosis:

  1. Your position variable is null because you did not initialize it from Account.Positions.

  2. OnPositionUpdate is not a “tell me my current position now” method.

  3. For instant entry-fill logic, use ExecutionUpdate.

  4. For an Indicator placing account orders, subscribe to Account.OrderUpdate, Account.ExecutionUpdate, and Account.PositionUpdate; do not rely on Strategy-only assumptions.

  5. On Playback, NinjaTrader can fire order events before the order method even returns an Order object.

examples

private Account myAccount;
private MarketPosition currentMarketPosition = MarketPosition.Flat;
private int currentQty = 0;
private double currentAvgPrice = 0;

protected override void OnStateChange()
{
if (State == State.DataLoaded)
{
myAccount = Account.All.FirstOrDefault(a => a.Name == “Playback101”);

    if (myAccount != null)
    {
        myAccount.OrderUpdate += OnAccountOrderUpdate;
        myAccount.ExecutionUpdate += OnAccountExecutionUpdate;
        myAccount.PositionUpdate += OnAccountPositionUpdate;

        // IMPORTANT: initialize existing position immediately
        foreach (Position p in myAccount.Positions)
        {
            if (p.Instrument.FullName == Instrument.FullName)
            {
                currentMarketPosition = p.MarketPosition;
                currentQty = p.Quantity;
                currentAvgPrice = p.AveragePrice;
                Print("INITIAL POSITION = " + currentMarketPosition + " Qty=" + currentQty + " Avg=" + currentAvgPrice);
                break;
            }
        }
    }
}
else if (State == State.Terminated)
{
    if (myAccount != null)
    {
        myAccount.OrderUpdate -= OnAccountOrderUpdate;
        myAccount.ExecutionUpdate -= OnAccountExecutionUpdate;
        myAccount.PositionUpdate -= OnAccountPositionUpdate;
    }
}

}

Then update it from the event

private void OnAccountPositionUpdate(object sender, PositionEventArgs e)
{
if (e.Position.Instrument.FullName != Instrument.FullName)
return;

currentMarketPosition = e.Position.MarketPosition;
currentQty = e.Position.Quantity;
currentAvgPrice = e.Position.AveragePrice;

Print("POSITION UPDATE = " + currentMarketPosition + " Qty=" + currentQty + " Avg=" + currentAvgPrice);

}

For trade management, use execution, not position, as your main trigger. NinjaTrader specifically says if you want fill-driven logic, use OnExecutionUpdate() instead of OnOrderUpdate(); OnExecutionUpdate() fires after order update and represents the fill.

private void OnAccountExecutionUpdate(object sender, ExecutionEventArgs e)
{
if (e.Execution == null || e.Execution.Order == null)
return;

if (e.Execution.Instrument.FullName != Instrument.FullName)
return;

if (e.Execution.Order.Name == “Entry”)
{
Print(“ENTRY FILLED NOW. Price=” + e.Execution.Price + " Qty=" + e.Execution.Quantity);

// submit stop / target / management logic here
}
}

You must have forgot the example I showed you to paste code on this forum. :joy:

I had cut-and-pasted code from an old Indicator that I wrote, which was itself using code borrowed from somewhere else, that only populates myAccount at order-generation-time using asynchronous ChartTrader Controls. That is why I had a conditional to check for an order. Since all of the necessary variables were generated at the same time, if there was an order, than myAccount would have to no longer be null.

As of now, I have moved that myAccount population command outside of the order conditional, putting it in with some other code that tracks if the active account in Chart Trader gets changed.

That part actually works quite nicely. If I change the account in Chart Trader, it unsubscribes, updates the myAccount variable, and then resubscribes. It’s pretty slick, if I do say so, myself. :blush:

The modern version of Output1 reads as follows:

Wednesday - NQ
Wednesday - NQ
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 30136.5 Quantity: 4 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Execution updated.
Order: Entry Quantity: 1 Price: 30139
Open position = instrument=‘NQ 06-26’ account=‘Playback101’ avgPrice=30139 quantity=1 marketPosition=Long statementDate=‘2099-12-01’
Order updated.
Stop price: 0 Quantity: 2 Limit price: 0
Execution updated.
Order: Entry Quantity: 1 Price: 30139.25
Order updated.
Stop price: 30136.5 Quantity: 4 Limit price: 0
Order updated.
Stop price: 30136.5 Quantity: 4 Limit price: 0
Wednesday - NQ

As you can see, the two orders (Entry and SAR) get updated immediately.

Then, the Entry order, which is a market order, gets updated.

And then, the Position gets updated. That might only be because it filled the two entry contracts at different prices, forcing the output to happen on the execution of the second entry, but it doesn’t matter. It still seems to be working exactly the way it’s supposed to. :grinning_face:

Thanks for replying!

1 Like