Login Page - Create Account

Support Board


Date/Time: Tue, 26 Nov 2024 15:39:49 +0000



[Programming Help] - GDI w/2551 and study updates (manual vs auto looping implications)

View Count: 821

[2023-11-11 00:58:11]
User133994 - Posts: 80
Support,

Great update to the GDI interface! Excellent.

I've succeeded in getting the GDI example to work inside some of my custom studies, however, I am interested in knowing some 'best practices' concerning updating variables.

Basically, I'm using GDIExample.cpp and it works for static information. However, market data is always changing along with many other variables. What is the best practice, for example, for showing the current sc.Index which changes with every bar?

I've succeeded in using autoloop=1, but it is obviously not the most efficient use of GDI--as the GDI text is constantly being repainted. The most efficient use would to only paint the text 1x upon a variable update, but I'm not quite finding a way to do this. That explicitly means GDI paints only 1x per bar, as the sc.Index is only updated 1x per bar. Perhaps that is part of the challenge of using GDI vs builtin drawing capability.

If anyone has a working sample of how to display the current sc.Index as text (just for a simple example) as the chart is painting using GDI, I would appreciate seeing how that would work. I know manual looping is more efficient in many ways, but don't know if there are other considerations for GDI and interaction with SC that would prohibit using a certain approach.

Yes, I already can do this using autoloop = 1, but that is inefficient as I described above. I'm looking for the 'best practice' for this use case, if you can help with that.

Thanks!

Ok, here is my sample code that shows the 're-painting' when using autoloop=1 :

//%{{% for SC post full GDI example
// Drawing function declaration
void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc);


/*==========================================================================*/
SCSFExport scsf_DrawToChartExample(SCStudyInterfaceRef sc)
{
  if (sc.SetDefaults)
  {
    // Set the configuration and defaults

    sc.GraphName = "Draw To Chart Example";
    sc.GraphRegion = 0;

    sc.AutoLoop = 1;
    return;
  }


  // This is where we specify the drawing function. This function will be called
  // when the study graph is drawn on the chart. We are placing this after
  // if (sc.SetDefaults). So in case the study DLL is unloaded and reloaded,
  // this will continue to be set to the correct address.
  sc.p_GDIFunction = DrawToChart;


}
/*==========================================================================*/

void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc )
{
//%{{% demo showing repaints

auto& someNum = sc.GetPersistentInt(26); // this reveals repaints
if (sc.IsFullRecalculation && sc.Index == 0){
//%{{% initial value
someNum = 1; // starting y position
return;
//%}}%
}

  sc.Graphics.SetTextAlign(TA_NOUPDATECP);

  n_ACSIL::s_GraphicsFont GraphicsFont;

  GraphicsFont.m_Height = 16;
  GraphicsFont.m_Weight = FW_BOLD;
  sc.Graphics.SetTextFont(GraphicsFont);

  n_ACSIL::s_GraphicsColor GraphicsColor;
  GraphicsColor.SetRGB(64, 128, 0);

  sc.Graphics.SetBackgroundColor(GraphicsColor);

SCString text;
text.Format("Hello %d", someNum++);

  sc.Graphics.DrawTextAt(text, 350, 200);


  return;
//%}}%
}
//%}}%

So you add this custom study to a non-updating chart (i.e. on Saturday when the market is off) and the numbers keep counting...even though no bars are painting, etc. I know it is part of the autoloop--which is why I'm asking for help; I don't know how to prevent GDI from repainting even though there are no updates occurring on an autoloop--while still allowing for updates to repaint (only when required, not every second or every tick, etc.). Said another way, the goal is to only paint the current sc.Index (on a weekend chart) 1x, and then on Sunday nite when the market opens, that should be the next 're-paint' because a new bar caused the index to increment. Hope this makes sense.

Yes, I know if I use sc.Index instead of someNum variable (in the above autoloop example) then the painted number won't change until Sunday, but it WILL repaint the same sc.Index over and over and over--the same number (even though our eyes wouldn't be able to detect it); I want to eliminate all that redundant painting...wasting precious CPU/memory cycles.

thanks again
[2023-11-11 01:50:13]
User133994 - Posts: 80
Ok, so I'm being told this:
When using GDI for drawing in Sierra Chart, if you draw on the chart within a study's function, those GDI drawings are not persistent by default. They are only present until the chart is updated again, such as with a new tick of data.

If the study function does not explicitly redraw the GDI objects on every update (which includes updates within the same bar), the drawings will disappear until the next time the study function executes and performs the drawing operation again. This is why you might see the GDI drawing disappear on a new update and reappear when the study function runs for the first event on a new bar.

To maintain GDI drawings on the chart, you would typically need to ensure that the drawing code is executed on every update, not just on the first calculation of a new bar. This is often managed by checking if the chart needs redrawing and then performing the GDI drawing operations accordingly.

credit: openAI

Can anyone confirm this statement? That would explain the *REQUIRED* redrawing on every tick (at least if you have autoloop = 1).

I did attempt to confirm this by only drawing on the first tick of each bar...and yes, the GDI drawings disappeared after the 1st tick...(of course I'm using autoloop = 1). If autoloop = 0, I'm sure the drawing wouldn't disappear, but then I have to ask, how do I get a GDI 'update' (from a study) to paint with autoloop = 0 (only 1x and persist for an entire bar's worth of tick updates)? Thanks in advance.
Date Time Of Last Edit: 2023-11-11 01:51:13
[2023-11-11 09:06:23]
User431178 - Posts: 543
I would ignore the answer you got from openAI, though it is correct, it is not relevant.
You are defining a function (DrawToChart) that the program calls when a gui update is required, not "drawing from within a study's function" which is what is described by openAI.
The program determines when a repaint is needed (e.g. new data received, user interaction with gui etc), all you are doing is pointing it to the relevant function to call when doing so.

how do I get a GDI 'update' (from a study) to paint with autoloop = 0 (only 1x and persist for an entire bar's worth of tick updates)
You can't, each time the chart window updates it is redrawn. Autoloop is not relevant either.

So you add this custom study to a non-updating chart (i.e. on Saturday when the market is off) and the numbers keep counting...even though no bars are painting, etc.
Are you sure? My experience is different.
[2023-11-11 17:18:07]
User133994 - Posts: 80
Thanks for your response. Yes, it appear as though the upwards counting is simply counting the 'redraw' events that SC is initiating...isn't related to autoloop =1 or not.

I've confirmed this, by making these changes:
sc.AutoLoop = 0;
and
void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc )
{
//%{{% demo showing repaints

auto& someNum = sc.GetPersistentInt(26); // this reveals repaints
if (sc.UpdateStartIndex == 0 ){
//%{{% intialize someNum
someNum = 1; // starting y position
return;
//%}}%
}

  sc.Graphics.SetTextAlign(TA_NOUPDATECP);

  n_ACSIL::s_GraphicsFont GraphicsFont;

  GraphicsFont.m_Height = 16;
  GraphicsFont.m_Weight = FW_BOLD;
  sc.Graphics.SetTextFont(GraphicsFont);

  n_ACSIL::s_GraphicsColor GraphicsColor;
  GraphicsColor.SetRGB(64, 128, 0);

  sc.Graphics.SetBackgroundColor(GraphicsColor);

SCString text;
text.Format("Hello manual update %d", someNum++);

  sc.Graphics.DrawTextAt(text, 350, 200);


  return;
//%}}%
}

So, this version also repaints with numbers incrementing even though I'm not doing a replay and the market isn't open. I must have simply found the SC (or windows) internal redrawing activity.

In fact, when I add a condition that returns immediately unless it is the 1st tick of the new bar and do a replay, the GDI text draws for only that moment for the 1st tick of the new bar, and then disappears for the other 100+ ticks. So, repainting is required to be visible to the user *on every tick* whether it is autoloop=1 or autoloop=0.

Thus, manual looping is optimal, since repainting is needed to view the actual GDI drawing. Using autoloop adds all the repeated function call overhead (on every bar). At least that is what I think is happening.

My experience is different.
-- might be related to your charts' update interval. I'm not sure why you aren't seeing an incrementing numbers.
Date Time Of Last Edit: 2023-11-11 17:18:31
[2023-11-11 17:25:19]
User133994 - Posts: 80
Found one answer to how to display study updates in a GDI drawing:
use sc.GetPersistentIntFromChartStudy() inside the DrawToChart function. Or, I suppose even using an SCInputRef studyToDisplay = sc.Input[1] can work as I've done many times in non-GDI ACSIL studies.

Now, I'm really interested if anyone has any GDI libraries that already know how to use the basics of lines/text/circles/shapes to create bar charts, pie charts, or other fancy reporting UI objects. It would be great to plug and play into SC.

Thanks all.
[2023-11-11 18:24:40]
User133994 - Posts: 80
Ok, just confirmed. The incrementing number's speed *IS* the visual for the chart's update interval.

I've changed it from 500ms to 100ms and the numbers counted quicker, i.e. instead of painting 2 number per second, it started counting faster, painting 10 numbers per second.

I guess I unintentionally found a way to visualize your chart's update interval in realtime! In case you need a tool to give you visual feedback on the update interval...
[2023-11-11 23:27:38]
User719512 - Posts: 264
You can also force repainting by moving the chart as it has to redraw the screen.
Your approach of using persistent data from the main study is the best way I have found, and why the GDI function gets the SC param, since it has no state otherwise.
You can optimize by looking at visible bars as well for bar-specific info versus static drawings on the screen that don't scroll with the bars.
An approach I use is a single GetPersistentPointer, and then the struct I point it to can change without a ton of updates to the scsf_ code. new it during IsFullRecalculation, and delete during LastCallToFunction.
It's a great pattern even if not using GDI. Way easier to manage built-in types, lists<>, etc. in my opinion.

Example:
PersistentData* p_PersistentData = (PersistentData*)sc.GetPersistentPointer(42);

[2023-11-13 02:01:58]
User133994 - Posts: 80
Excellent, thank you for the idea. I am familiar with using persistent pointers with other ACSIL and it does work wonderfully. Appreciate your thoughts.

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account