Announcement
Collapse
No announcement yet.
Partner 728x90
Collapse
NinjaTrader
Custom Performance Metric
Collapse
X
-
Hello TAJTrades,
The SampleCumProfit included with NinjaTrader provides sample code.
On lines 38 through 42 of the sample, the metric value is assigned in OnAddTrade().
For Currency, the sample code is assigning the trade.ProfitCurrency on line 38. This is the value showing in the summary results.
In your code you posted in post #1, you have:
Values[(int)Cbi.PerformanceUnit.Currency] += trade.ProfitCurrency;
This is where you are setting the performance value to the net profit and it's in OnAddTrade(). Set this to 5 if you want it to have a value of 5. (Use '=' instead of '+=' to make the value 5 exactly and not accumulate 5 for each trade.
Your initial inquiry appeared to be asking about the merged results from total row and not the metric value for individual iterations. This is what would be calculated in OnMergePerformanceMetric().
Below is a link to an additional example custom metric script and performance metric script.
-
Not finding any joy here. Did a search on "onAddTrade" and did not find any working examples. Also tried adding in some code in "OnAddTrade" and nothing.
Maybe I am not making myself clear. All I am trying to do is create a Custom PerformanceMetric that acts just like the PerformanceMetric "R squared / Ulcer Index / Sortino ratio / Sharp ratio" above it when Backtesting, Optimizing or in Trade Performance.
The Metric I want to create is RoMaD (Return over Maximum Drawdown). The math is simply:
TradesPerformance.NetProfit / TradesPerformance.Currency.Drawdown.
Everything I have tried somehow defaults back to displaying Total net profit.
This image is for BackTest.
This is for Optimization on a single Instrument
Do you know of any sample code that will do this? Can we work together to create some Sample Code for other users?
Thanks
Leave a comment:
-
Hello TAJTrades,
So instead of the merge results, you want to change the value in individual backtest results, correct?
Set the Values[] collection to 5 in OnAddTrade().
Leave a comment:
-
I can duplicate what you have shown in the image. The issue with OnMergePerformanceMetric makes sense.
However, I am trying to get the $5.00 to calculate for each instrument in your example. When I do a Backtest on 1 Instrument the value shown is the same Total Net Profit.
Can this be done?
Is there something like this that does not require the "Merge" part: protected override void OnPerformanceMetric(PerformanceMetricBase target)
I have searched high and low for some sample code and have come up empty.
Thanks.
Leave a comment:
-
-
Hello TAJTrades,
Thank you for your patience. I am looking into this on my end.
Leave a comment:
-
Chelsea,
I rebooted the computer and restarted NT8 8.1.4.1 (latest download)
MyCustomPerformanceMetric is showing the same value as SampleCumProfit and top line Total net profit.
I tried with Backtest and Optimization. Same results.
Any other suggestions?
Thanks for your help.
Leave a comment:
-
After making the assignment may I confirm you have compiled the script without errors? Compiles. No Errors
If you restart NinjaTrader and run a new backtest, does the merged values show 5? Will reboot computer and try.
Leave a comment:
-
Hello TAJTrades,
After making the assignment may I confirm you have compiled the script without errors?
If you restart NinjaTrader and run a new backtest, does the merged values show 5?
Leave a comment:
-
Custom Performance Metric
This Performance Metric is almost identical the "SampleCumProfit".
Would you please educate me on why this Performance Metric is displaying the Total Net Profit value and not 5.00 that is hard coded in protected override void OnMergePerformanceMetric.
This is the image of the Analyzer:PHP Code://This namespace holds Performance metrics in this folder and is required. Do not change it. namespace NinjaTrader.NinjaScript.PerformanceMetrics { public class MyCustomPerformanceMetric : PerformanceMetric { private Cbi.Currency denomination = (Cbi.Currency) (-1); protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Enter the description for your new custom Performance Metric here."; Name = "MyCustomPerformanceMetric"; } else if (State == State.Configure) { Values = new double[5]; // There needed to be one value per Cbi.PerformanceUnit, which is why the values are managed in an array of length "ValueArrayLength" } else if (State == State.Active) { Array.Clear(Values, 0, Values.Length); // Needed to be reset before every backtest iteration. } } protected override void OnAddTrade(Trade trade) { if (denomination == (Cbi.Currency) (-1)) denomination = trade.Exit.Account.Denomination; Values[(int)Cbi.PerformanceUnit.Currency] += trade.ProfitCurrency; Values[(int)Cbi.PerformanceUnit.Percent] = (1.0 + Values[(int)Cbi.PerformanceUnit.Percent]) * (1.0 + trade.ProfitPercent) - 1; Values[(int)Cbi.PerformanceUnit.Pips] += trade.ProfitPips; Values[(int)Cbi.PerformanceUnit.Points] += trade.ProfitPoints; Values[(int)Cbi.PerformanceUnit.Ticks] += trade.ProfitTicks; } // This is called as the values of a trade metric are saved, which occurs e.g. in the strategy analyzer on optimizer runs protected override void OnCopyTo(PerformanceMetricBase target) { // You need to cast, in order to access the right type MyCustomPerformanceMetric targetMetrics = (target as MyCustomPerformanceMetric); if (targetMetrics != null) Array.Copy(Values, targetMetrics.Values, Values.Length); } protected override void OnMergePerformanceMetric(PerformanceMetricBase target) { // You need to cast, in order to access the right type MyCustomPerformanceMetric targetMetrics = (target as MyCustomPerformanceMetric); // This is just a simple weighted average sample if (targetMetrics != null && TradesPerformance.TradesCount + targetMetrics.TradesPerformance.TradesCount > 0) for (int i = 0; i < Values.Length; i++) { targetMetrics.Values[i] = 5.00; // Will eventually be: // TradesPerformance.NetProfit / TradesPerformance.Currency.Drawdown } } // The display attribute determines the name of the performance value on the grid (the actual property name below is irrelevant for that matter) [Display(Name = "MyCustomPerformanceMetric", Description = "Enter the description for your new custom Performance Metric here.", Order = 0)] public double[] Values { get; private set; } #region Miscellaneous // The format method allows you to customize the rendering of the performance value on the summary grid. public override string Format(object value, Cbi.PerformanceUnit unit, string propertyName) { double[] tmp = value as double[]; if (tmp != null && tmp.Length == 5) switch (unit) { case Cbi.PerformanceUnit.Currency : return Core.Globals.FormatCurrency(tmp[0], denomination); case Cbi.PerformanceUnit.Percent : return tmp[1].ToString("P"); case Cbi.PerformanceUnit.Pips : return Math.Round(tmp[2]).ToString(Core.Globals.GeneralOptions.CurrentCulture); case Cbi.PerformanceUnit.Points : return Math.Round(tmp[3]).ToString(Core.Globals.GeneralOptions.CurrentCulture); case Cbi.PerformanceUnit.Ticks : return Math.Round(tmp[4]).ToString(Core.Globals.GeneralOptions.CurrentCulture); } return value.ToString(); // should not happen } #endregion } }​
Thanks.Tags: None
Latest Posts
Collapse
| Topics | Statistics | Last Post | ||
|---|---|---|---|---|
|
Started by cmoran13, Yesterday, 01:02 PM
|
0 responses
33 views
0 likes
|
Last Post
by cmoran13
Yesterday, 01:02 PM
|
||
|
Started by PaulMohn, 04-10-2026, 11:11 AM
|
0 responses
23 views
0 likes
|
Last Post
by PaulMohn
04-10-2026, 11:11 AM
|
||
|
Started by CarlTrading, 03-31-2026, 09:41 PM
|
1 response
162 views
1 like
|
Last Post
|
||
|
Started by CarlTrading, 04-01-2026, 02:41 AM
|
0 responses
96 views
1 like
|
Last Post
by CarlTrading
04-01-2026, 02:41 AM
|
||
|
Started by CaptainJack, 03-31-2026, 11:44 PM
|
0 responses
151 views
2 likes
|
Last Post
by CaptainJack
03-31-2026, 11:44 PM
|

Leave a comment: