Wake up the strategy thread

Is there a way to wake up the strategy thread even in the absence of any tick on the instruments whose data series the strategy has added in its State.Configure.

I have told my strategy to close all positions at a certain time, basically around hour before the market closes…but sometimes there is not a single tick on the instrument at that point of time and so my OnBarUpdate never gets invoked and I never get a chance to check the time and close any open positions…

co-pilot tells me the only workaround is to add a secondary data series of a instrument like ES where one can be certain that there will be some trades taking place and hence invocation of the OnBarUpdate(or rather waking up of the strategy thread) is guaranteed.

But it is not really guaranteed, what if there is no tick generated on ES…so, I am wondering if there is some other more better guaranteed approach, does Ninjatrader has some inbuilt way of ensuring the strategy thread wakes up every x seconds no matter weather there is something happening in the market or not.
Can i define my own custom data series that sends a tick to the strategy every x seconds.

Thanks.

I might suggest a different approach..

Ask your ai to help you schedule a timer to fire at a specific time of day.

Be Safe in this Crazy World!
:smiling_face_with_sunglasses:

OnBarUpdate is the only way to execute code in the strategy thread and open close positions of managed orders, or even unmanaged orders I think…and OnBarUpdate is not something you can schedule, it is only invoked by a data series added to the strategy…

Do you know a way how OnBarUpdate can be invoked on the strategy thread, at a scheduled time, irrespective of weather there are any ticks coming for that instrument?

Take a look at the @BarTimer.cs built in indicator. It gives a good example of how to use the Threading.DispatchTimer to call a function in an indicator outside of the OnBarUpdate, OnOrderUpdate, and OnRender threads. It should be pretty easy to adapt this pattern to your use case.

This will not work because it will not be invoked in the strategy thread, am I missing something?

It seems writing an add-on is the only solution…

Pretty sure you can just call it from the worker thread. No need to use the bar update thread exclusively. I have have a base strategy template which I use for all my strategies and it calls Position.Close() from a different context. Never had any problems. I would think you could do the same with Account.Flatten(). Writing an add-on to close/cancel strategy orders would effectively be the same thing (operating in a different thread context).

I have seen very unpredictable behaviour when I have tried calling EnterLong EnterShort ExitLong ExitShort from a non strategy thread, I have managed to get a stable trader exclusively using managed orders API, keeping my code very simple, after I have strictly followed the rule of only invoking Enter/Exit in a strategy thread.
Add-on approach solves my issue actually so will just go with that.
I can then further develop that add-on into a dashboard to replace the Postions tab of control centre.
But I am afraid closing positions from the add on will drive my strategies out of sync, is there an API using which I can synchronise all my strategies. The only way of doing that so far I have found is from the right click menu of the strategies tab of the control centre.

Strategy going out of sync I can handle by subscribing to the event which will invoke the callback function OnPositionChanged so I guess I am sorted with the Add-on calling Account.Flatten()

I’ve programmed automated strategies that receive information from indicators via custom events, and it works perfectly. Using a Timer would be the same.
However, this is in Unmanaged mode. It’s possible that this does not work in Managed mode, but I haven’t tested it.

1 Like

yes managed mode is very restricted as mentioned in the documentation and as I learnt from my own experience

Doubtful.

I would suspect that you can submit orders from anywhere at any time.

Also, the timer idea is spot on.

I think what you may be missing is what to do when your timer does fire. Well, you call TriggerCustomEvent, which is basically going to setup everything and then call your specified method, effectively treating your method like a surrogate user-defined OnBarUpdate-like routine.

2 Likes

Managed Order documentation starts with the line - “Orders are primarily submitted from within the OnBarUpdate() method when a specific order method is called.” and then goes on to give examples, all of them only using OnBarUpdate.

Yes I was also very doubtful but then I found out the hard way since the documentation is not very explicit in saying dont do. it. It seems ninjatrader has assumed a person using managed order API obviously is not doing any multithreading.

Infact when I know in my OnExecuteUpdate/OnMarkerData/OnOrderUpdate that i need to close or open positions, i put that information in a queue which I then access next time when OnBarUpdate is invoked. And it is only after making this change that I finally have a trader that works perfectly as I expect it to…till then for a couple of months I was literally going mental…

I think your suggestion of using the TriggerCustomEvent works if my strategy defines the TriggerCutomEvent and registers as an event subscriber in OnStateChanged function because OnStateChanged function itself is running on the strategy thread.

Does this statement look correct? because I am using this pattern for sending trades to my trader strategy from other strategies that dont actually place orders, and it is working perfectly and it is a non blocking call.

Go to the link for TriggerCustomEvent above and study the example code they provide at the bottom – that should answer your question.

HINT: I pressed the copy button in upper right and pasted the example code into Notepad, then went to full screen and so I could easily read their embedded comments, which were quite verbose and very helpful.

1 Like

There is no Strategy thread.. They are called UI and Rendering threads.
Anytime working with objects, like orders, you’ll want to use UI thread.

https://ninjatrader.com/support/helpGuides/nt8/NT%20HelpGuide%20English.html?multi-threading.htm

private void DailyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    try
    {
        if (ChartControl != null && Instrument != null && selectedACC != null)
        {
			ChartControl.Dispatcher.InvokeAsync(new Action(() => 
			{
				Collection<Cbi.Instrument> instrumentsToCancel = new Collection<Instrument>();         
				instrumentsToCancel.Add(Instrument);     
				selectedACC.Flatten(instrumentsToCancel);
			}));
        }
    }
    catch { }
}

You also will not want to call Close[0] from any event, UI thread or not!
Bar OHLCV data is not garenteed accurate anywhere outside of OnBarUpdate!

Call a method from inside OnBarUpdate. Close[0] works fine in your method.
But from Timers or any Event calls, you’ll want to use BarsArray[0].Get???.

double lastPrice = BarsArray[0].GetClose(BarsArray[0].Count - 1);

Be Safe in this Crazy World!
:smiling_face_with_sunglasses:

2 Likes

Does this code work even in a headless strategy?

TriggerCustomEvent it seems like is pretty much like simulating a realtime tick, in terms of waking up the strategy thread (or UI thread as it is meant to be called), very handy, ideal for my usecase. Thanks.

No, that approach requires the strategy to be directly enabled on Chart.
ChartControl is NOT available when adding to ControlCenter Straties Tab!

TriggerCustomEvent() is probably your best approach in that situation.
bltdavid posted the newer help guide link above, here is older version.

https://ninjatrader.com//support/helpGuides/nt8/NT%20HelpGuide%20English.html?triggercustomevent.htm

Be Safe in this Crazy World
:smiling_face_with_sunglasses:

1 Like

Not sure I am reading / understanding this right but I use a time frame 345PM flatten all, granted this is used on NQ so it does not have to worry about tick data but market flatten is market flatten.

private readonly TimeSpan flattenTime = new TimeSpan(15, 45, 0);

Below inside ```
inside OnMarketData():


private DateTime lastFlattenDate = DateTime.MinValue;

if (Time[0].TimeOfDay >= flattenTime && lastFlattenDate.Date < Time[0].Date)
{
    if (Position.MarketPosition != MarketPosition.Flat)
    {
        Print("3:45 PM CST FLATTEN FAILSAFE");
        Flatten();
    }
    lastFlattenDate = Time[0].Date;
}
1 Like