Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Combining a PnL indicator with an account-auto-detection indicator

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

    Combining a PnL indicator with an account-auto-detection indicator

    Hi everyone,

    I'm still pretty new as far as NinjaScript/C# goes, and I'm not a programmer. I've gone from 0 to an okay working knowledge in a short time, but still, my experience and skill is limited... Being new, sometimes, while implementing a new concept, I run into roadblocks I don't know how to resolve, don't want to/can't spend more time on yet, and shelf (to later ask the forum for help figuring it out). So, I've built up a few things by now I will need help understanding. But I finally set up a forum account because I ran into one such roadblock that I think (if resolved) will help my efficiency too drastically to shelf.

    Time to start clearing those shelves (I hope)!

    I'll start by saying that, for this post, my goal is basically to combine the code of two indicators I've found.

    I found the "Position Display Indicator" posted by NinjaTrader_Jim on the NT ecosystem (I'll call this the Display script):
    This indicator provides a customizable text box which displays a position’s UnRealized PnL, Realized PnL of a selected account, and the overall cash value of the account.


    Works exactly as intended, and it's a great starting point to piggyback off of (with some mods, I think I can get the kind of display I want out of it, or at least close enough for now). However, the way it's scripted, it requires that I go into the user dialog to select the account I want it drawing its info from. Huge inconvenience when needing to switch between a variety of accounts (such as sim accounts to test/practice varying concepts concurrently). For now, I don't want more charts/chart tabs to juggle. I prefer to just change accounts as needed in the chart trader drop-down, keeping a cleaner interface with a lower impact on computer resources.

    So, I searched for how to auto-detect the account name that's already attached to a given chart window, and I found the following link with a "PrintChartTraderSelectedAccount" indicator zip file posted by NinjaTrader_AlanP (See "SelectedAccount Script Link" below -- I'll call this one the Account script).

    Again, works great. It detects the account name in the chart trader, then prints that name. Simple. Any time I switch accounts in that chart window, the printout text changes to match. (It spammed the prints, but I figured out a workaround to fix that. Now it only prints once per change.)

    Where I'm struggling is with how to combine the two indicators. I've tried a few things, but I'm just too green still to know what I'm missing. I hoped I could incorporate the language from the Account script into the Display script and then tweak the account reference language (such as in the State.DataLoaded section, among others) in the Display script, but no dice.

    I'm figuring I'll need to do at least 3 things (maybe more?):
    1. Put part of the Account script in the State.DataLoaded section (to get the account reference set initially, since that's where the Display script starts its account identifiers)... I've modified the original Account script to test this out independently (along with the spam-limiting code), and rearranging the script into the DataLoaded section does work in the stand-alone Account indicator...

    2. Because the "xAlselector" variable is designated as a string in the Account script, I'm assuming I need a different variable specifically designated as an "Account" for the Display script to accept it in place of the user dialog menu (maybe along the lines of "accountContainer = xAlselector.SelectedAccount"?)

    3. Because "State.DataLoaded" only loads once (when the chart is first opened/refreshed), I'm also figuring I'll have to put pieces of the Account script in other places (such as OnRender in the Display script, and/or add an OnBarUpdate section to it, etc) to actively "update" the account reference variables whenever the account is changed on the chart. Otherwise, the script will just cling to the account that was active when the chart was reloaded without ever updating.

    I'm hoping the blending of the two scripts would be simple enough for someone (more knowledgeable than myself, lol) to just walk me through it step by step (tell me exactly what needs to change and where in the Display script, so that it can accommodate the concept from the Account script). But the things I tried to do weren't good enough, so I'm sure I was missing some key things.


    Thanks very much for any help you all can give me!

    I've learned a ton from countless pages across the NT Help Guide and this forum, along with sample scripts (help guide) or ecosystem scripts I could study and dissect to understand how things interact and sometimes splice together what I need. Thanks to EVERYONE who generously contributes to all those sources, helping people like me go from absolute, literal programming newb to building enough knowledge to quickly start DIYing custom indicators/strategies that have made my life easier. Love it.
    This SelectedAccount indicator automatically detects what account is actively selected in the Chart Trader on a given chart, and retrieves that information.

    #2
    Hello TakeFlight,

    Thank you for your post.

    Can you explain what specifically you need assistance with? What part of the code are you struggling with specifically?

    Are you unable to detect the account from the Chart Trader? If so, please see the example code linked in another forum post:

    Comment


      #3
      Hello NinjaTrader_Gaby​,

      First, thank you for the link you provided. That thread is not one I had come across yet while trying to find a solution, so I had not seen the modified version of the PositionDisplayIndicator you had created and posted there. I see the differences between how I was unsuccessfully trying to modify the DataLoaded section versus how you scripted it. Your version does identify and use the account that was initially selected in Chart Trader when a given chart was first loaded, and that is a good step toward what I needed, yes. I couldn't even get that part working correctly, so thank you.

      However, my ultimate goal is to get the indicator to update its display any time I switch accounts in the chart window, not only when the chart first loads. In that regard, I'm still having an issue.

      I duplicated the AccountSelector block of code from the DataLoaded section to the OnRender section* and got the script to partially update when I switch accounts: The "Account Balance" and "Realized PnL" both appear to work fine, displaying data for the correct account when I switch. But the "UnRealized PnL" is still not working correctly.

      Here's what's happening:

      Let's say I have three sim accounts for running tests, with two of them in positions. If I force-refresh the chart while selected on the account that is not in a position, the "UnRealized PnL" will show 0, as it should. If I then click into one of the two accounts that are in positions, the indicator appears to accurately show that account's "UnRealized PnL." But then, if I switch back to the account without an active position, the "UnRealized PnL" continues to reflect whichever account with trades I last had loaded. It should show 0 (given that I'm selecting an account that doesn't have positions open), but it doesn't. And it doesn't just return a static number from the account with a position open, it continues to update the value as though I'm still switched onto that account. That said, if I switch between only the two accounts with positions, the "UnRealized PnL" does reflect the selected account (and, as I say, it then retains that one's "UnRealized PnL" when I switch to the one without positions).

      I've tried rearranging the code numerous ways without success. For reference, here are the two sections I've changed in one of those many iterations:

      Code:
      private void OnPositionUpdate(object sender, PositionEventArgs e)
      {
      { // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      if (account == accountSelector.SelectedAccount) // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      { // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      if (e.Position.Instrument == Instrument && e.MarketPosition == MarketPosition.Flat)
      position = null;
      else if (e.Position.Instrument == Instrument && e.MarketPosition != MarketPosition.Flat)
      position = e.Position;
      } // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      else if (account != accountSelector.SelectedAccount) // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      position = null; // ADDED THESE LINES IN ATTEMPT TO GET "UNREALIZED PNL" TO ATTACH ONLY TO ACTIVELY SELECTED ACCOUNT
      }
      }​

      Code:
      protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
      {
      base.OnRender(chartControl, chartScale);
      
      [HASHTAG="t3322"]region[/HASHTAG] THIS REGION ADDED TO MAKE THE ACCOUNTSELECTOR UPDATE UPON SWITCHING ACCOUNTS IN CHART TRADER, WHILE ATTEMPTING TO GET "UNREALIZED PNL" TO ATTACH TO THE CORRECT (SELECTED) ACCOUNT
      if (ChartControl != null)
      {
      ChartControl.Dispatcher.InvokeAsync((Action)(() =>
      {
      accountSelector = Window.GetWindow(ChartControl.Parent).FindFirst("C hartTraderControlAccountSelector") as NinjaTrader.Gui.Tools.AccountSelector;
      if (account != accountSelector.SelectedAccount)
      {
      account = accountSelector.SelectedAccount;
      }
      }));
      }
      
      if (account != null && account == accountSelector.SelectedAccount)
      {
      account.AccountItemUpdate += OnAccountItemUpdate;
      account.PositionUpdate += OnPositionUpdate;
      
      foreach (Position pos in account.Positions)
      if (pos.Instrument == Instrument)
      position = pos;
      
      realizedPnL = account.Get(AccountItem.RealizedProfitLoss, Currency.UsDollar);
      cashValue = account.Get(AccountItem.CashValue, Currency.UsDollar);
      
      {
      if (position != null)
      unRealizedPnL = position.GetUnrealizedProfitLoss(PerformanceUnit, Close.GetValueAt(CurrentBar));
      else if (position == null)
      unRealizedPnL = 0;
      }
      }
      #endregion​

      Any ideas how to make it accurately show 0 when switching from accounts that have positions to an account that is not in a position?


      * Is there a less redundant/more elegant way to get the script to continue to update the AccountSelector after the DataLoaded section than to copy the entire block of AccountSelector code? So far, that's the only way I can get it to (partially) work. I'm wondering, for example, if there's a way to turn the AccountSelector code into a "class" or something, and whether that would solve both the code redundancy and the "UnRealized PnL" not wanting to update. But I haven't learned anything yet about making classes, and I don't know if that would even help. Any suggestions?


      Thanks very much!

      Comment


        #4
        Hi all,

        I still don't know how to get the "unrealized" PnL to show correctly (explanation of what it's doing wrong in my last message... although I removed some of the code from what I last posted -- the test code I had added -- because the extra code was causing additional errors, basically breaking the script until I removed that code). I gave up trying to fix the "unrealized" PnL display for a few weeks, but decided to try again today. Still no luck.

        Here's a copy of my modifications (the above link from Gaby detected the selected account in Chart Trader when the chart is first loaded, while my modifications will now also detect when the account selection is changed in real time without having to force a refresh):
        PositionDisplayIndicatorTestV2.zip

        Anyone with a fix that could get the "unrealized" PnL to stop holding onto the data of the wrong account when switching the chart trader from accounts that are in positions to accounts that are not in positions? If not for that problem, the PnL script otherwise seems to work pretty well with the account auto-selector added.​

        If anyone can tell me what I'm missing to make the unrealized PnL work right, that would be great. Thank you.
        Last edited by TakeFlight; 09-04-2024, 06:50 PM.

        Comment


          #5
          Anyone with any ideas why the "unrealized" P&L isn't switching accounts like it should (as explained in my 7/22/24 post), and what I can change to fix it? It doesn't give errors. It just doesn't display right under those certain circumstances. I've tried a few things, but I haven't resolved it. I assume I'm missing something. Or maybe there's a glitch in the system regarding unrealized P&L.

          Thanks.

          Comment


            #6
            Hello TakeFlight,

            Are you using the accountSelector.SelectionChanged event to detect when the account has changed?

            Comment


              #7
              Hello Gaby,

              As you might have seen in the sample script I included in my 9/4/24 post, I have the account selector update itself in two locations:

              1. Data.Loaded
              • This section finds the account upon initial chart loading, as it was written in your sample script/link from your first reply here.
              • However, this location only updates the associated account when the chart is initially loaded (as would be expected).
              • Relying on this section alone means a forced refresh is required to change the displayed values to the newly selected account.
              • Force-refreshing the chart is a bad solution when running strategies on that chart, as it completely disrupts the strategies, among other reasons it's not desirable.
              2. OnRender
              • My adding the chart controls to this section allowed the script to find the selected account any time the account is changed and update itself accordingly, rather than just once at chart loading.
              • Semi-static values (realized P&L, overall cash in account) update correctly when switching between accounts on the fly, whether in or not in position in any given account.
              • Dynamic values (unrealized P&L) do not update correctly when switching between accounts that have positions to accounts with "null" (no) positions.
              • So, as I tried to describe in my earlier posts, it seems that the account updates itself fine, but the position doesn't like to update itself to the newly selected account when that account has no position open (null) and the last-selected account did have a position.
              • For those reasons, while I didn't specifically incorporate the code "accountSelector.SelectionChanged" into my previously posted sample script, I do not believe that's the problem, since the account is updating as it should but the position values (specifically when null) are the problem.
              However, despite all of that, I viewed the link you provided and I tested the sample script (DetectAccountSelectionChange) the user in that thread offered, just in case there was something about it that resolved my issue. Unfortunately, it not only didn't resolve my problem (unrealized still wasn't updating like it should, even in that script), it actually made matters worse initially (nothing was updating dynamically at first, until I made more extensive changes).

              For simplicity, I'll refer to the scripts hereafter as:
              1. "PDv2" (PositionDisplayIndicatorTestV2 script) and
              2. "DASC" (DetectAccountSelectionChange script)

              If I change nothing about DASC, it appears to work exactly as it's meant to: Every time a different account is selected, the script displays fixed text on the chart and outputs a message, both identifying the name of the newly selected account. But, after incorporating the necessary components from PDv2 into DASC to convert DASC into a display of P&L, the P&L display did not update dynamically until I modified the OnBarUpdate chart controls in several ways. In any event, the "unrealized" P&L still did not work correctly even before I updated OBU:
              1. Leaving the chart controls as-written in DASC, displayed values updated only once, when the account selection is changed, but the display did not continue updating as a person's P&L changes.
              2. As an extension of point 1, even though the "unrealized" P&L updated only once per account selection, it still did not update to the newly selected account (it persisted in retaining the last-known static unrealized P&L of the last account selected with an open position, rather than updating itself to 0 to reflect the account now selected that has no open position).
              3. In keeping with the DASC format, in an effort to change as little as possible, I nullified the chart control code in OnRender (as written in PDv2) and added the P&L code to the chart control code in OnBarUpdate instead (as written in DASC).
              4. I couldn't add the P&L-updater variables to OnBarUpdate outside of chart control section in DASC, because the script threw errors saying that a different part of the script owned chart control (chart controls in DASC also get modified in the State.Realtime and private void "initAccountSelectionEventHandler" sections -- one of those must be interfering).
              5. Instead, I had to add the P&L code inside the chart control in OBU of DASC to resolve the chart control error, but this still left the P&L updating only when account selection was changed, due to how the chart control section was written in DASC.
              6. Incidentally, even adding the P&L code inside of chart control in OBU in DASC (without changing anything else about the manner in which the script assigns or utilizes chart controls) still did not resolve the noted problem with "unrealized" profit.
              7. In order to get DASC to update dynamically, I had to modify the chart control section in OBU (I made a new copy of that segment of code, rather than modifying the original).
              8. Even once I had OBU revised so that the P&L display would start updating dynamically, now with the P&L code inside the chart controls of OBU so they should be always taking their cues from the most recently selected account, DASC's P&L display still has precisely the same problem PDv2 has.
              9. I should note, as an extension of point 8, that I did already try effectively the same thing weeks ago: In PDv2, I temporarily added an OnBarUpdate section and then tried putting the chart control codes in there instead of OnRender, but, just like in DASC, moving the code to OBU failed to resolve the "unrealized" P&L problem (and it added an annoying lagtime between when a person switches accounts and when the display of the new account would show, since it had to wait for, ya know, bar updates -- which often come slowly outside of NYSE market hours -- thus why I ultimately deleted the OBU section and reverted to the OnRender chart control method).
              As you might be noticing, I've tried a lot of troubleshooting, and no solution has been forthcoming. That's why I'm posting the question. I may be missing something key to making "unrealized" P&L play friendly, but the fact that the account side of PDv2 has worked all along and the testing I've now done with DASC didn't improve my results, it's clear that the problem has nothing to do with needing to incorporate a "SelectionChanged" event into PDv2 (it's not failing to recognize the account, just the lack of position in a given account).

              To summarize, the issue I'm having is this:
              1. The realized value and account-cash value both display correctly in PDv2 when changing accounts (even between accounts with positions versus those without positions open).
              2. The unrealized value does not display correctly if switching from accounts that have open positions to accounts that have no open positions (null positions).
              3. The script simply doesn't seem to pick up on the fact that the newly selected account has a null position (which should revert the display to "0"), so it acts like the last-selected account with open positions is still the currently selected account (and continues to dynamically update the display, making it look like the account is in a position when, in fact, it has no position).
              4. There are no errors thrown, and no amount of trying to narrow the parameters of how "unrealized" gets its info has worked for me, yet (for example, adding it directly inside the chart control framework does nothing to fix this, as previously noted in this post).
              In short, the script should recognize that a newly selected account is not in a position (null) and update the display to "0" -- but it's more like it rejects the lack of position and defaults to the last active position from a previously selected account.

              Although I've already attached a copy of PDv2 in one of my earlier posts, it seems the NT forum broke/lost that file link (it worked right after I posted it back then, but isn't working today), so I'll post it again here:
              PositionDisplayIndicatorTestV2.zip

              I'm also attaching my now-modified copy of DASC here (the script from your link, with the P&L code now incorporated into it as regions named "P&L display" and an additional revision I noted in OBU), just for reference, so that whoever can help me iron this out can see that the problem still persists even with a "SelectionChanged" event added:
              DetectAccountSelectionChangeV2_displayPnL.zip


              It's seeming to me like the problem in PDv2 is some sort of processing error built into NinjaTrader/NinjaScript, especially now that another variation of this kind of script (DASC) simply reproduces the same problem (even when no changes are made to the chart control codes except to add in the P&L variable containers -- which leaves the P&L display static but nonetheless inaccurate for "unrealized"). I'm hoping someone from NT staff can load the PDv2 script (attached) and test it (in the manner I've described herein) to check for NT errors.

              If it's not an NT error, I'm hoping there is someone who can tell me what I need to add to make "unrealized" display correctly, because I'm at a total loss for a solution.

              Comment


                #8
                Hello,

                I am not able to replicate this behavior in a simple test script. The unrealized pnl values do update when switching the account in the attached simple test script, even when switching from an account with open positions to an account with no open positions.

                Note that ForceRefresh() is used in this script - ForceRefresh() does not disrupt strategy calculations, it simply forces the chart visuals to re-render.

                However, the ForceRefresh() call can be commented out and the script will still work as expected. You will only need for the next OnBarUpdate() call for the chart visuals to re-render in order for the Draw.TextFixed() call to update.



                Here is a video of me testing out the script: https://app.screencast.com/qH5zAiNRpB0pD
                Attached Files

                Comment

                Latest Posts

                Collapse

                Topics Statistics Last Post
                Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                0 responses
                576 views
                0 likes
                Last Post Geovanny Suaza  
                Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                0 responses
                334 views
                1 like
                Last Post Geovanny Suaza  
                Started by Mindset, 02-09-2026, 11:44 AM
                0 responses
                101 views
                0 likes
                Last Post Mindset
                by Mindset
                 
                Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                0 responses
                553 views
                1 like
                Last Post Geovanny Suaza  
                Started by RFrosty, 01-28-2026, 06:49 PM
                0 responses
                551 views
                1 like
                Last Post RFrosty
                by RFrosty
                 
                Working...
                X