Announcement

Collapse
No announcement yet.

Unique Chart ID / Read Drawn objects

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

  • Unique Chart ID / Read Drawn objects

    I'm working on using global variables to place an icon on the screen which will allow quick access to certain controls for my tools. In order to do this I need to find a way to uniquely identify a chart so that separate sets of tools on two identical charts can know that they are on separate charts. I tried playing with the ability to load some type of "marker" on the chart which could be placed by the first tool and then some value or even its existence could be read off by a separate .EFS however I couldn't find any way to achieve this as there is no way which I could find to read line tools or text objects placed on the chart.

    So, I propose this question: is it possible to create a unique ID for a chart which can be read by an .efs or multiple .EFSes actually so they can coordinate as to which ones are on which charts? It can be anything which can be easily attached to a chart and read back off by a new EFS loaded on that chart.

  • #2
    Spodumene,

    Yes, it can be done, but what you are asking is fairly difficult.

    First you can uniquely identify charts by obtaining symbol and interval information from each
    • var tmpa = getSymbol();
    • var tmpb = getInterval();

    Perhaps the chart interval would work for you to determine the command set for the buttons.

    Or you can load (set) information into global variables and read them (get) using these commands
    • setGlobalValue ();
    • getGlobalValue ();


    You could load information into a single global variable, read and modify its value to control the actions you want to take.

    There are several things to consider:

    1) If the global variable has not been set yet, it may come back as not defined or null.
    2) The charts do not always come up in the same order and I am pretty sure the efs's are run in a serial manner (i.e. one after the other).

    There is an efs that I published to the board a while back that allows you to pick different actions for a button set. Perhaps reviewing that will also give you some ideas. Here is a link to the trend line alert efs that has that feature.

    Comment


    • #3
      better explanation

      Hi Steve,
      Thanks for the quick reply. I guess I didn't explain myself well enough. I actually already have the code working fine. I'm loading a global variable whose name is based off the chart's symbol and interval. If the tool checks for the global var and it is not inited then it inits it and then any other tools will automatically see it and can sort themselves out. This lets the tools know the placement of buttons so they dont overlap and generally know which other tools are already loaded on the same chart. Everything works fine with multiple charts as long as they are all different symbols or intervals. I actually discovered that I can manually place text in the interval field after the number and two charts of "IBM,5" can be manually entered as "IBM,5 a" and "IBM,5 b" but they both load correct data. This lets the tools know they are on different charts.

      This is admittedly a bit of a kludge but it works for the moment.

      So, since this isnt very intuitive the issue is only when the user loads a second identical chart with the exact same symbol and interval all the tools added to that chart think they are on the first chart and can't tell that a new chart has been created. I'm looking for a way to put some kind of marker which can be globally read only by other tools on the same chart regardless of chart symbol or interval. Even if there is some way using .dlls to read the chart name i.e. "AdvCh1" vs "AdvCh2" etc. then I could use that as a unique ID. It's very tricky and I've racked my brain over it for a while.

      Thanks!
      Spodumene

      Comment


      • #4
        Spodumene,

        I would suggest creating the global values as an array, then measure the array length. For example, for an IBM chart with a 5 minute interval, create a global variable named IBM5 as an array variable, then if a new 5 minute chart is created, add another element to the array.

        The uniqueness will be determined upon efs load by the measurement of the array length. Upon efs closure, in the postmain function, you should decrement the length of the global array, or remove the global variable (depending on the length count) if that is the only instance.

        Comment


        • #5
          Hi Steve,

          I'll give this a try but I can forsee a potential problem. I have 10 tools (actually there are more, I'm working on the Arps Crown Jewels package but for the sake of example lets just say there are 10) all of which need a piece of screen real-estate on which to draw their control button. All tools use the exact same code to control the placement of said button. I have no charts loaded. I create a new chart of "IBM, 5".

          The way I have it written now the first tool is loaded on the chart and it checks for the existence of a global var called IBM5 (getSymbol() + getInterval() ). If it does not exist then one is created and the Tool's name is loaded as the first element of an array (slot 0) and the button is drawn in the lowest left corner of the screen.

          When another tool is loaded on that same chart it runs the same routine to draw the button but the global var is already there so it simply loads its name as the next available slot in the array (now slot 1) and the button is drawn on the screen just above the previous button. This could repeat 4 or 5 times (even up to 10 or more) and each tool gets its own "slot" and draws its button in a separate space on the screen all stacked up nice and neat.

          In the postmain there is a piece of code that clears out the array cell occupied by the tool. This means that if there are six tools on a chart and tool 1 is unloaded then the array slot 0 is cleared. Now when another tool is loaded it will see that slot 1 is empty and load itself there instead of stacking on top.

          However, If i create a new chart of IBM5 then load a tool on that new empty chart the problem occurs.

          The global var (whose name is based on getSymbol() and getInterval() ) already exists but we are actually on a new empty chart. The tool sees that the var exists and the first tool loaded on that new empty chart thinks it is on the other chart and there are already some tools loaded. Threfore it starts stacking up above where the other chart's tools stop and the apparent behavior is that the button gets drawn up in the middle of the screen for no reason. If there are enough tools on the first chart to stack up to the top and you create a new chart the tools keep stacking up past the top of the screen and things get all out of whack.

          So, how can I know when a new duplicate chart is created to give it a different var name but have any other tools loaded on that chart know it is the second IBM5 chart and use the second var instead of the first incorrect one?

          I know that eSignal itself must have some way of keeping track of its child windows using some type of handle hWnd or ID number. Could I propose a function perhaps called getChartID() or getChartHandle() which would simply return whatever id eSignal itself uses to refer to that particular chart window on which the tool is being loaded? Also, maybe there is a way to access this information using some standard windows .DLL but that seems unlikely. I suppose maybe I could find a way to read the handle of the active child window of eSignal... hmm... I'll have to look into that a bit more.

          An even more elegant solution would be to find a way for efs to query the chart and see the names of all the tools which are applied to that chart already, but that sounds like more work.

          Thanks,
          Jesse Jones
          Programmer
          Jan Arps' Traders' Toolbox

          Comment


          • #6
            Hi Jesse,

            Well, it seems as if you have used quite a few tricks to accomplish what you are after, and my last suggestion, it seems, has already been explored. At this time, I can think of no other ideas to accomplish what you want, other than those you have already suggested. Should you come upon a solution, please post it, as it would help us all. Also, it seems as if you have quite a bit of experience and knowledge regarding the platform. Any contributions to the forum you could make would be most appreciated.

            Comment


            • #7
              Hacked Solution!!!

              Hi,

              I'm pleased to say that I've come up with a pretty good solution. It needs a few more tweaks but it works for now and shows the general methods.

              The basic concept is to get the windows handle for the active child window of eSignal. We can do this using .dlls to call the FindWindowEx function from within user32.dll. However, we need to get the handle of eSignal itself which I do here using getActiveWindow which just gets the main active window for all of windows itself. This needs to be changed to just search for the process winsig.exe and find the handle that way.

              Please post any mods!

              PHP Code:
              /*----------------------------------------

              CHART ID TEST.EFS

              Coded by: 
              Jesse Jones 
              Jan Arps' Traders' Toolbox
              [url]http://www.janarps.com[/url]

              Date: 
              2005.05.22

              IF MODIFIED PLEASE RENAME OR AT LEAST ADD NOTES HERE:

              -----------------------------------------*/


              //init a DLL object

              //this is not the best way because it hard codes the system root which is just a bad thing to do. 
              //What if your dlls are in c:\winnt or d:\windows or ???
              //BAD BAD BAD... but simple
              var d=new DLL("c:\\windows\\system32\\user32.dll")


              //template for VB style function call
              //Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _
              //ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

              //example of addFunction syntax
              //d.addFunction("run", DLL.INT, DLL.STDCALL, "ShellExecuteA", DLL.INT, DLL.STRING, DLL.STRING, DLL.STRING, DLL.STRING, DLL.INT );    


              //add functions
              d.addFunction("FindWindowX"DLL.INTDLL.STDCALL"FindWindowExA"DLL.INT,DLL.INT,DLL.INTDLL.INT);
              d.addFunction("getActiveWindow"DLL.INTDLL.STDCALL"GetActiveWindow" );

              //never could get these to work
              d.addFunction("getClassName"DLL.INTDLL.STDCALL"GetClassNameA"DLL.INTDLL.STRINGDLL.INT);
              d.addFunction("sendMessageS"DLL.INTDLL.STDCALL"SendMessageA"DLL.INTDLL.INTDLL.INTDLL.STRING);

              /*
              Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, _
              ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

              Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
              ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
              */

              var chartID//create our chartID holder var out here so we can use it anywhere

              function preMain()
              {

              //first we get the handle for eSignal itself.. 
              //this is kindof sloppy because it assumes that eSignal is the active window.
              //it needs to use better way to get just the handle for eSignal or better yet 
              //just the instance of eSignal inside which our EFS is running 
              //(in case of multiple copies of EFS)

              hParent=d.call("getActiveWindow");
              debugPrintln("P=" hParent);

              //next we get the main child window which contains all the charts and 
              //visible windows such as formula output...etc
              hChild=d.call("FindWindowX"hParent,0,0,0);
              debugPrintln("C=" hChild);

              //now we get the handle for the topmost visible window... 
              //again this assumes that the chart we are on is the topmost visible chart 
              //which is rather sloppy but if this code is only used in premain it should be fine
              chartID=d.call("FindWindowX",hChild,0,0,0);


              debugPrintln("##" chartID);
              debugPrintln(" ");

              setStudyTitle(chartID+"");

              //uncomment below to list all handles for children and grandchildren. 
              //You could use EnumChildWindows to do a better job of this and get all windows
              //see [url]http://www.xtremevbtalk.com/archive/index.php/t-130418.html[/url] for more info

              /*
              for (
                  hChild=d.call("FindWindowX", hParent,0,0,0); //setup
                  hChild!=0;  //test
                  hChild=d.call("FindWindowX", hParent,hChild,0,0) //iterate\increment
                  )
                  //execute
                  {
                      for (
                      hChild2=d.call("FindWindowX", hChild,0,0,0); //setup
                      hChild2!=0;  //test
                      hChild2=d.call("FindWindowX", hChild,hChild2,0,0) //iterate\increment
                      )
                      {
                      className="                                                                ";//64 spaces
                      j=d.call("getClassName", hChild,className,63);
                      debugPrintln("       " + hChild2 + " - " + j);

                      }

                  
                  
                      className="                                                                ";
                      j=d.call("getClassName", hChild,className,63);
                      debugPrintln("   " + hChild + " - " + j);
                  
                  }
              */



              }

              function 
              main()
              {

              Comment


              • #8
                Hi Jesse,

                Very interesting solution, I had not thought of accessing built in windows functions as a dll, but what you posted makes sense. As you indicated, if the calls are made in the premain section, the window is pretty much guaranteed to be active. That also made sense until I thought about loading saved Pages or Layouts on eSignal startup. Then, the charts would not be active. What do you think?

                Comment


                • #9
                  Sorry for the late reply folks, I'm in NY this week, so haven't had a chance to read up on the forum postings lately.

                  Instead of doing the external DLL and window handle, couldn't you just use an incremented counter instead of the Symbol+Interval? This counter would act in the same way as a window handle.

                  Comment


                  • #10
                    Hi Dion,

                    I don't believe so because I believe there are also multiple efs's involved. My understanding is that if there are two charts of the same interval and name, with multiple efs's loaded in each (with each efs potentially having one or more buttons associated with available tools in the efs). To track the loaded tools in each chart, a global array named, using the interval and symbol with the array elements associated with the location of the tools, thus controlling their relative location on the screen of that individual chart . When adding tools to one of the charts, there is no way to distinguish which of the two charts it is being inserted into.

                    Jesse did come up with an interesting way to differentiate between the two charts. He hasn't responded yet, but it seems to me that when loaded up as saved layouts or page files, the methodology he outlined would not work reliably.

                    I believe the only bulletproof method of being able to track button controls between identical charts would be to somehow expose a unique identifyer for each chart as it is created such that it can be identified by the efs upon loading. Once the efs is loading, it could be used in the identification (name) of the global array, similar to the interval and symbol methods.

                    I hope all is well and you are enjoying yourself in New York!

                    TIA,

                    Comment


                    • #11
                      Hi Dion, thanks for joining in!

                      Steve:
                      Excellent summation of my problems for dion, you've explained it exactly. Also, simple testing shows that you are right about saved charts auto loading with eSignal. They do in fact come up with the same ID using this method since the first one loaded seems to remain at the foreground.

                      So, now I'm back to an older idea which is to find if there is any type of object that can be placed on a chart (linetool, text object, or any type of marker or tag) and read back only by other efs loaded on that chart. So far I haven't had any luck but perhaps someone else might have a suggestion.

                      Thanks!

                      Comment


                      • #12
                        I can add a function for you to retrieve a unique string ID. If this id is unique for each chart Window, will this suffice?

                        ie, 5 tools on the same chart window, 2 in the top pane, 3 in the bottom pane, all 5 get the same ID? or 2 get the same, and 3 in the bottom get the same?

                        Thanks.

                        Comment


                        • #13
                          New Function

                          Hi Dion,
                          A new function would be great. something like getChartHandle() or getChartID() i suppose.

                          In your example, I would think all 5 tools should return the same ID. The EFS will already know if its being loaded in the bottom pane because of setPriceStudy so that's easy enough to deal with. Also, unless you start grouping them each non price study .EFS gets its own little subgraph anyway so button overlapping isnt such an issue.

                          If it's easy, you could just return the windows handle for the chart window cause that's always guaranteed to be a unique number and then you can do all kinds of fun things with the API. but i guess your code might be too abstracted from that level of things so really any unique number would work, it could be a string even. I'm sure you have to have some kind of tracking system in place to keep track of and reference separate charts.

                          Thanks! Please let me know what you come up with. I'd love to test it and I'll be happy to answer any other questions.

                          Comment


                          • #14
                            Hi Dion,

                            Very nice solution. I defer to Jesse since he is the one that really needs the feature.

                            Thank You.

                            Comment


                            • #15
                              Jason has reminded me of getInvokerID(), which I believe may already do what you need it to do. From the code it appears to be on a per Chart Window basis. Could you try that out and let me know if this works for you?

                              Thanks.

                              Comment

                              Working...
                              X