Then make intercommunication with strategy and make chart F5
Announcement
Collapse
Looking for a User App or Add-On built by the NinjaTrader community?
Visit NinjaTrader EcoSystem and our free User App Share!
Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less
Partner 728x90
Collapse
NinjaTrader
Add indicator through Add-On
Collapse
X
-
Add strategy to chart, it can make AddChartIndicator (but during DataLoaded)
Then make intercommunication with strategy and make chart F5
-
-
Hi everyone!
Let me also add my vote for this feature. And I'd like to share my experience as I faced exactly the same problem - adding indicator to any open (or new) chart control via AddOn.
I spent some time debugging the code and ended up with some understanding of the implemented workflows:
1) ChartControl is created using a template containing some indicators
2) ChartControl is created and indicator is added manually (via `Indicators` window)
3) ChartControl instrument is changed
Case 3 is the simplest one and is just for reference - everything is handled by NT, once you have an indicator added to any ChartControl instance, everything should work smooth and no extra handlers required. If you debug your code, you'll probably notice methods like
Code:ApplyNinjaScripts() RefreshIndicators()
Cases 1 and 2 are more complicated.
Case 1 workflow relies on some serialized XML data (I didn't look into it to be honest). But the main idea is that when an indicator is created there is no chart control and instrument, so this case workflow is: "Create Chart" -> "deserialize XML" -> "Create empty indicator by name" -> "Add indicator to ChartControl.Indicators list" -> "Select instrument" -> "Initialize indicator". Actually it's difficult to understand what happens during "Select instrument" stage as we cannot dive into protected code with debugger. But it seems that instrument is selected and data is fetched first, then indicator is initialized. Please pay your attention to the fact that indicator is already added to ChartControl.Indicators list before instrument is selected.
Case 2 - when you open `Indicators` window all the indicators instances are created. `SetDefault` state is triggered by an indicator constructor. When you add any indicator to `Configured` list, it's cloned. When you press `Ok` - it's cloned again. But at that stage chart control and instrument (and other parameters) are available. So when an indicator is added to `Configured` list, it has references to instrument, bars etc. (and you may see it in the configuration window). When you press "Ok" button - the cloned version will have all the required parameters.
Why do I explain two cases? Actually, Case 1 demonstrates that if you inject your custom indicator on window creation, it will work fine. Just a brief example (Add-On):
Code:protected override void OnWindowCreated(Window window) { var chartWindow = window as Chart; if(chartWindow == null) return; var chartControl = chartWindow.ActiveChartControl; chartControl.Indicators.Add(new MyCustomIndicator()); }
The problem is with already created chart controls and indicators added via the Indicators window. Some magic is hidden somewhere in `OnIndicatorsHotKey` and related commands, when you click "OK" button - indicator is cloned and initialized. That means that the snippet above won't work for already opened windows (e.g. when Add-On is hot loaded/reloaded with some chart controls already initialized). In call stack you may notice that the indicator initialization magic is somewhere in:
Code:OnIndicatorsHotKey() ApplyIndicatorChanges()
Code:protected override void OnWindowCreated(Window window) { var chartWindow = window as Chart; if(chartWindow == null) return; var chartControl = chartWindow.ActiveChartControl; chartControl.Indicators.Add(new MyCustomIndicator()); var refreshAllBarsMethod = chartControl.GetType().GetMethod("RefreshAllBars", BindingFlags.NonPublic | BindingFlags.Instance); refreshAllBarsMethod.Invoke(chartControl, new object[] { }); }
UPD: I tested the solution a bit more and found one more drawback: unfortunately, you cannot invoke "RefreshAllBars" every time "OnWindowCreated" is triggered as it may be triggered either by the corresponding event handler (when window is created indeed) or by some other routines when add-on is hot reloaded (in such case indicator would be duplicated). To overcome this problem, I'd recommend to check if ChartControl is fully initialized adding one more if-clause around method invocation:
Code:if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method { var refreshAllBarsMethod = chartControl.GetType().GetMethod("RefreshAllBars", BindingFlags.NonPublic | BindingFlags.Instance); refreshAllBarsMethod.Invoke(chartControl, new object[] { }); }
Code:var indicator = chartControl.Indicators.OfType<MyCustomIndicatorType>().FirstOrDefault(); if (indicator != null) { // If indicator is added, change its status to Finalized (which will trigger Finalized -> Terminated transition under the hood) indicator.SetState(State.Finalized); chartControl.Indicators.Remove(indicator); }
As mentioned in the snippet, you should set only "Finalized" status and "Terminated" status would be triggered under the hood.
Unfortunately, all this things are not documented and found empirically, so be careful and use it at your own risk. I tested different scenarios, seems to work correctly. If you want to add Indicator not on window creation but e.g. on button click, the principle remains the same, you should add indicator to "ChartControl.Indicators" list and trigger "RefreshAllBars" method. Not the best solution as bars are reloaded, but still we are limited in documentation.
Probably you should play around "ApplyNinjaScripts" and "RefreshIndicators" mentioned above. I tried to set all the parameters to a created indicator instance manually (e.g. "Instrument", "BarPeriod" etc.) with no any luck, the answer is probably somewhere in "OnIndicatorsHotKey" which handles indicator initialization when added via the Indicators window and related "ApplyIndicatorChanges" method. Both are not documented and protected so no way to debug it. Looking for a better solutionLast edited by EvSpirit; 04-06-2023, 07:01 AM.
Comment
-
It seems a slightly better solution found. Instead of triggering "RefreshAllBars" we may use "RefreshIndicators" mentioned above. I tried one before, but it failed and I could not see the reason. Now I see what's missing - indicator "Input" parameter. Actually that's what happening in the IndicatorSelector window - when you add any indicator to "Configured" list, it's initialized with "Input series" parameter. When you click "OK" - indicator is cloned, but it already has input series defined. I also found out that one more parameter "ChartBars" is required before triggering "RefreshIndicators" method. So the updated code looks like:
Code:protected override void OnWindowCreated(Window window) { var chartWindow = window as Chart; if(chartWindow == null) return; var chartControl = chartWindow.ActiveChartControl; var indicator = new MyCustomIndicator(); chartControl.Indicators.Add(indicator); if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method { // before invoking "RefreshIndicators" required parameters must be set indicator.ChartBars = chartControl.PrimaryBars; indicator.SetInput(new PriceSeries(chartControl.PrimaryBars.Bars, PriceType.Close)); var refreshIndicatorsMethod = chartControl.GetType().GetMethod("RefreshIndicators", BindingFlags.NonPublic | BindingFlags.Instance); refreshIndicatorsMethod.Invoke(chartControl, new object[] { true, true }); } }
When you invoke "RefreshIndicators" - it triggers all the indicator statuses updates under the hood, so still no need to explicitly update indicator status.
This solution seems to be better as it does not reload bar history, so it's quite close to the initial NT implementation (when you add indicator via IndicatorSelector window). Going to use and test if for a while, let's see how it works
- Likes 1
Comment
-
After testing the solution above I've noticed one more problem - drawing methods do not work properly. But if indicator is added manually via Indicators dialog - everything works fine. After comparing the states of indicators added using different approaches I noticed some more missing parameters. In case you need drawing support, you should also add "IsOwnedByChart" property. Some more properties are missing, they do not affect drawing support, however, I think it's better to keep them defined. So the patched code is:
Code:protected override void OnWindowCreated(Window window) { var chartWindow = window as Chart; if(chartWindow == null) return; var chartControl = chartWindow.ActiveChartControl; var indicator = new MyCustomIndicator { IsOwnedByChart = true, // this one is required for drawing // values below are not required for drawing, however they are defined when an indicator is added via Indicators dialog Owner = chartWindow, NumberOfPanels = 1, Panel = -1 } chartControl.Indicators.Add(indicator); if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method { // before invoking "RefreshIndicators" required parameters must be set indicator.ChartBars = chartControl.PrimaryBars; indicator.SetInput(new PriceSeries(chartControl.PrimaryBars.Bars, PriceType.Close)); var refreshIndicatorsMethod = chartControl.GetType().GetMethod("RefreshIndicators", BindingFlags.NonPublic | BindingFlags.Instance); refreshIndicatorsMethod.Invoke(chartControl, new object[] { true, true }); } }
- Likes 3
Comment
-
Latest Posts
Collapse
Topics | Statistics | Last Post | ||
---|---|---|---|---|
Started by bortz, 11-06-2023, 08:04 AM
|
47 responses
1,607 views
0 likes
|
Last Post
by aligator
Today, 07:22 PM
|
||
Started by jaybedreamin, Today, 05:56 PM
|
0 responses
9 views
0 likes
|
Last Post
by jaybedreamin
Today, 05:56 PM
|
||
Started by DJ888, 04-16-2024, 06:09 PM
|
6 responses
19 views
0 likes
|
Last Post
by DJ888
Today, 05:12 PM
|
||
Started by Jon17, Today, 04:33 PM
|
0 responses
6 views
0 likes
|
Last Post
by Jon17
Today, 04:33 PM
|
||
Started by Javierw.ok, Today, 04:12 PM
|
0 responses
15 views
0 likes
|
Last Post
by Javierw.ok
Today, 04:12 PM
|
Comment