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!
See more
See less

Partner 728x90

Collapse

Inconsistency in Unrealized PnL Updates Relative to Market Price Changes

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

    Inconsistency in Unrealized PnL Updates Relative to Market Price Changes

    Hi everyone,

    I'm currently developing an add-on that uses the AccountItemUpdate event to manage trading restrictions based on unrealized PnL changes. I've subscribed to the AccountItemUpdate event as follows:

    Code:
    account.AccountItemUpdate += (sender, e) => eventHandlers.OnAccountItemUpdate(sender, e);
    In the event handler, I am monitoring unrealized PnL to apply trading restrictions based on certain conditions (e.g., exceeding a loss threshold). However, I've noticed an issue where the unrealized PnL updates provided through this event do not always seem to align closely with the actual market price movements observed on the chart. There appears to be a delay or inconsistency in how quickly these PnL updates reflect the current market conditions.

    Here’s what I am observing:
    • When a significant price movement occurs, the corresponding update to unrealized PnL seems delayed or does not occur as frequently as I would expect based on the price volatility at the time.
    • This delay affects the responsiveness of my trading restrictions, potentially impacting the effectiveness of the strategy, especially in fast-moving markets.

    I'm curious if anyone else has encountered similar issues or if there are known limitations or settings within NinjaTrader that might affect the frequency and timing of these updates. Any insights into how unrealized PnL calculations are triggered and whether there are ways to optimize or better synchronize this with real-time market data would be greatly appreciated.

    Thank you in advance for your help and suggestions!

    #2
    Hello Aviram Y,

    The information coming from the account can have a small delay as it takes a small amount of time for the account value to change on the brokerage servers and then for this information to be sent to the subscribing client, that message is then processed and the account values are updated in NinjaTrader.

    You could choose to calculate the unrealized pnl based on the entry price and the current price all locally which would be a bit faster than waiting on update messages from the brokerage.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Understood. To calculate the unrealized PnL locally and more promptly, would this approach necessitate subscribing to price data feeds for each individual instrument involved in open positions? Would I then compute the unrealized PnL by comparing the entry price with the current market price?

      For position updates, such as increasing the size of an open position, would I need to continuously adjust the calculation based on the new average fill price for these updated positions against the current market price?

      Does implementing this local calculation also require converting price movements into currency values for each specific instrument, particularly considering different tick sizes and value per tick across various instruments?

      Comment


        #4
        Hello Aviram Y,

        Yes, that would be correct. You would need data feeds streaming data for each instrument to make these calculations as the price changes for each instrument.
        Yes, you would be comparing the number of ticks from the entry price multiplied by the point value.
        Yes, you would need to adjust the average position price as new entries are made.
        Yes, you would need to add up the calculated pnl of each instrument (number of ticks by point value).
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Thanks for the quick reply, your services are much appreciated! i will update if i need anything else.

          Best, Aviram Y.

          Comment


            #6
            Hi NinjaTrader_ChelseaB

            I’m following up on my earlier discussions regarding challenges with unrealized PnL updates and their synchronization with market movements. I've encountered a persistent issue with subscribing to real-time market data using BarsRequest, which is critical for implementing local PnL calculations as previously discussed.

            I have used the following documentation for the logic: https://ninjatrader.com/support/help...arsrequest.htm

            The Issue: Despite various attempts to fetch and subscribe to market data using BarsRequest for instruments, I consistently receive an error indicating that "The given key was not present in the dictionary," accompanied by an "ErrorCode: Panic". This occurs even after validating the instrument’s availability and trying multiple retrieval methods:
            1. Direct use of the passed Instrument object.
            2. Fetching the instrument using Instrument.GetInstrument(instrument.FullName).
            3. Fetching the instrument using Instrument.GetInstrument(instrument.MasterInstrume nt.Name).

            Each method fails to prevent the error during the subscription request. Here's a condensed version of the code used to manage subscriptions:

            First the OnPositionUpdate event handler used to call the method:
            Code:
                    public void OnPositionUpdate(object sender, PositionEventArgs e, Account account)
                    {
                        Print($"MarketPosition: {e.MarketPosition}, Operation: {e.Operation}, Quantity: {e.Quantity}, Instrument: {e.Position.Instrument.FullName}");
                    
                        if (e.MarketPosition != MarketPosition.Flat && e.Operation == Operation.Add)
                        {
                            // Subscribe to market data when a new position is added or an existing position is modified but not closed
                            EnsureMarketDataSubscription(e.Position.Instrument);
                            
                        }
                        else if (e.MarketPosition == MarketPosition.Flat)
                        {
                            // consider unsubscribing from market data if applicable
                            
                            ConsiderMarketDataUnsubscription(e.Position.Instrument);
                            
                        }
                    }​
            Then the code handling the subscription:
            Code:
            private void EnsureMarketDataSubscription(Instrument passedInstrument)
            {
                var activeBarsRequests = new Dictionary<string, BarsRequest>(); // Simulated active requests dictionary for context
            
                Instrument validInstrument = Instrument.GetInstrument(passedInstrument.FullName);
                if (validInstrument == null)
                {
                    Print("Instrument retrieval failed. Unable to subscribe to market data.");
                    return;
                }
            
                if (!activeBarsRequests.ContainsKey(validInstrument.FullName))
                {
                    var barsRequest = new BarsRequest(validInstrument, DateTime.Now.AddMinutes(-30), DateTime.Now)
                    {
                        BarsPeriod = new BarsPeriod { BarsPeriodType = BarsPeriodType.Tick, Value = 1 },
                        TradingHours = TradingHours.UseInstrumentSettingsInstance
                    };
            
                    barsRequest.Update += OnBarUpdate;
                    barsRequest.Request((bars, errorCode, errorMessage) =>
                    {
                        if (errorCode != ErrorCode.NoError)
                        {
                            Print($"Error requesting bars for {validInstrument.FullName}: {errorMessage}, ErrorCode: {errorCode}");
                        }
                        else
                        {
                            Print($"Successfully subscribed to market data for {validInstrument.FullName}");
                            activeBarsRequests[validInstrument.FullName] = barsRequest;
                        }
                    });
                }
                else
                {
                    Print($"Already subscribed to {validInstrument.FullName}");
                }
            }
            
            private void OnBarUpdate(object sender, BarsUpdateEventArgs e)
            {
                // Handling bar updates
            }
            ​
            Questions:
            • Are there known issues with BarsRequest that could lead to such errors, particularly with certain instruments or configurations?
            • Could the "ErrorCode: Panic" provide specific insights into what might be going wrong?
            • Are there alternative approaches within NinjaTrader to ensure more reliable real-time data subscriptions that I might consider?
            What am i missing?

            Thank you in advance for any help or insights you can offer!

            Best regards, Aviram Y.

            Comment


              #7
              Originally posted by Aviram Y View Post
              Hi NinjaTrader_ChelseaB

              I’m following up on my earlier discussions regarding challenges with unrealized PnL updates and their synchronization with market movements. I've encountered a persistent issue with subscribing to real-time market data using BarsRequest, which is critical for implementing local PnL calculations as previously discussed.

              I have used the following documentation for the logic: https://ninjatrader.com/support/help...arsrequest.htm

              The Issue: Despite various attempts to fetch and subscribe to market data using BarsRequest for instruments, I consistently receive an error indicating that "The given key was not present in the dictionary," accompanied by an "ErrorCode: Panic". This occurs even after validating the instrument’s availability and trying multiple retrieval methods:
              1. Direct use of the passed Instrument object.
              2. Fetching the instrument using Instrument.GetInstrument(instrument.FullName).
              3. Fetching the instrument using Instrument.GetInstrument(instrument.MasterInstrume nt.Name).

              Each method fails to prevent the error during the subscription request. Here's a condensed version of the code used to manage subscriptions:

              First the OnPositionUpdate event handler used to call the method:
              Code:
              public void OnPositionUpdate(object sender, PositionEventArgs e, Account account)
              {
              Print($"MarketPosition: {e.MarketPosition}, Operation: {e.Operation}, Quantity: {e.Quantity}, Instrument: {e.Position.Instrument.FullName}");
              
              if (e.MarketPosition != MarketPosition.Flat && e.Operation == Operation.Add)
              {
              // Subscribe to market data when a new position is added or an existing position is modified but not closed
              EnsureMarketDataSubscription(e.Position.Instrument);
              
              }
              else if (e.MarketPosition == MarketPosition.Flat)
              {
              // consider unsubscribing from market data if applicable
              
              ConsiderMarketDataUnsubscription(e.Position.Instrument);
              
              }
              }​
              Then the code handling the subscription:
              Code:
              private void EnsureMarketDataSubscription(Instrument passedInstrument)
              {
              var activeBarsRequests = new Dictionary<string, BarsRequest>(); // Simulated active requests dictionary for context
              
              Instrument validInstrument = Instrument.GetInstrument(passedInstrument.FullName);
              if (validInstrument == null)
              {
              Print("Instrument retrieval failed. Unable to subscribe to market data.");
              return;
              }
              
              if (!activeBarsRequests.ContainsKey(validInstrument.FullName))
              {
              var barsRequest = new BarsRequest(validInstrument, DateTime.Now.AddMinutes(-30), DateTime.Now)
              {
              BarsPeriod = new BarsPeriod { BarsPeriodType = BarsPeriodType.Tick, Value = 1 },
              TradingHours = TradingHours.UseInstrumentSettingsInstance
              };
              
              barsRequest.Update += OnBarUpdate;
              barsRequest.Request((bars, errorCode, errorMessage) =>
              {
              if (errorCode != ErrorCode.NoError)
              {
              Print($"Error requesting bars for {validInstrument.FullName}: {errorMessage}, ErrorCode: {errorCode}");
              }
              else
              {
              Print($"Successfully subscribed to market data for {validInstrument.FullName}");
              activeBarsRequests[validInstrument.FullName] = barsRequest;
              }
              });
              }
              else
              {
              Print($"Already subscribed to {validInstrument.FullName}");
              }
              }
              
              private void OnBarUpdate(object sender, BarsUpdateEventArgs e)
              {
              // Handling bar updates
              }
              ​
              Questions:
              • Are there known issues with BarsRequest that could lead to such errors, particularly with certain instruments or configurations?
              • Could the "ErrorCode: Panic" provide specific insights into what might be going wrong?
              • Are there alternative approaches within NinjaTrader to ensure more reliable real-time data subscriptions that I might consider?
              What am i missing?

              Thank you in advance for any help or insights you can offer!

              Best regards, Aviram Y.
              The issue was the trading hours, i now use the passed instrument like so and it works great:
              barsRequest.TradingHours = instrument.MasterInstrument.TradingHours;

              Comment


                #8
                Hello Aviram Y,

                Below is a link to an example of a BarsRequest you may find helpful.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  This is what i used exactly haha, thanks!

                  Comment

                  Latest Posts

                  Collapse

                  Topics Statistics Last Post
                  Started by EvaisDery, Today, 05:44 AM
                  0 responses
                  5 views
                  0 likes
                  Last Post EvaisDery  
                  Started by JerryWar, 11-19-2016, 08:14 AM
                  3 responses
                  2,070 views
                  0 likes
                  Last Post tradertom2012  
                  Started by capt34, Today, 03:46 AM
                  0 responses
                  8 views
                  0 likes
                  Last Post capt34
                  by capt34
                   
                  Started by wuannetraam, Today, 12:22 AM
                  1 response
                  11 views
                  0 likes
                  Last Post wuannetraam  
                  Started by TGOG1, Yesterday, 03:02 PM
                  2 responses
                  26 views
                  0 likes
                  Last Post TGOG1
                  by TGOG1
                   
                  Working...
                  X