Login Page - Create Account

Support Board


Date/Time: Mon, 25 Nov 2024 22:18:21 +0000



[Programming Help] - Access data using GDIFunction DrawToChart()

View Count: 686

[2024-01-18 22:07:28]
User895355 - Posts: 55
I'm not sure how to do this, been through the example. I've got it working in a basic sense on my chart, however, I have a
std::map<float, char>
that I populate, how do I pass that data to DrawToChart()? Any help would be greatly appreciated. Thank you.
[2024-01-18 22:42:31]
User719512 - Posts: 264
Store it in a PersistentPointer Persistent Variable Functions

Your GDI function gets a "sc" reference, so you can access it.
[2024-01-19 12:16:55]
User895355 - Posts: 55
I'm having an issue understanding how to use the
PersistentPointers
. Can you help me out here?

for (auto it = tpo.begin(); it != tpo.end(); it++)
{
auto val1 = it->first;
auto val2 = it->second;
sc.SetPersistentPointer(sc.Index, &val1);
sc.p_GDIFunction = DrawToChart;
}

Then in DrawToChart()...
void *val1 = sc.GetPersistentPointer(sc.Index);

Date Time Of Last Edit: 2024-01-19 12:30:43
[2024-01-19 13:27:04]
User431178 - Posts: 541
Maybe the info linked below is helpful?
ACSIL Programming Concepts: Allocating Memory for Classes

Once you've read it, see if you still have questions.


sc.p_GDIFunction = DrawToChart;

This only needs to be set once, you are setting a function pointer (to a function that is called once the study calcs are done), repeatedly setting it in you loop serves no purpose.
[2024-01-19 17:06:51]
User895355 - Posts: 55
That was *very* helpful. Thank you. I was able to run the example and see how it can apply. However, when I try to implement it in my code, Sierra crashes. Is there any way I can post or send you the script so you can help me to understand what I'm doing wrong?
[2024-01-19 17:35:58]
User431178 - Posts: 541
Is there any way I can post or send you the script so you can help me to understand what I'm doing wrong?

Post it here or send via direct message if you prefer.
Date Time Of Last Edit: 2024-01-19 17:36:51
[2024-01-19 18:22:49]
User719512 - Posts: 264
Have you looked at the GDIExample.cpp in C:\SierraChart\ACS_Source? You could start with something that works, and go from there. Also see the numerous other samples there for how to work with various Sierra APIs.
[2024-01-19 20:16:52]
User895355 - Posts: 55
Yes, been through that file. I have what I want working as far as the layout, a rectangle along the right side of the chart. I got the data working with the example you showed me using a double Array. I was able to display the dummy data. However, *I think* I need to use a map and I believe the allocation of memory is what is busting my script.
This is the meat of my script after sc.SetDefaults:

// Section 2 - Do data processing here
std::map<float, char> *tpoMap = (std::map<float, char> *)sc.GetPersistentPointer(1);
if (sc.LastCallToFunction)
{
if (tpoMap != NULL)
{
sc.FreeMemory(tpoMap);
sc.SetPersistentPointer(1, NULL);
}
return;
}
if (tpoMap == NULL)
{
// allocate memory
tpoMap = (std::map<float, char> *)sc.AllocateMemory(1024 * sizeof(std::map<float, char>));

if (tpoMap != NULL)
{
it = tpoMap->find(sc.Close[sc.Index]);
if (it != tpoMap->end())
{
tpoMap->erase(it);
msg.Format("Index exists...%.2f", sc.Close[sc.Index]);
sc.AddMessageToLog(msg, 1);
return;
}
else
{
tpoMap->insert({sc.Close[sc.Index], 'A'});
sc.SetPersistentPointer(1, tpoMap);
}
}
}
sc.p_GDIFunction = DrawToChart;

Then in DrawToChart() I try and pull in the data like so:

std::map<float, char> *tpoMap = (std::map<float, char> *)sc.GetPersistentPointer(1);
std::map<float, char>::iterator it;

With a loop like so:

for (auto it = tpoMap->begin(); it != tpoMap->end(); it++)
{
val.Format("Val: %.2f %c", it->first, it->second);
sc.AddMessageToLog(val, 1);

sc.Graphics.DrawTextAt(val + "<", sc.StudyRegionRightCoordinate - 200, (sc.StudyRegionTopCoordinate + 5) * 20);
}

I'm sure this is not correct, but I'm not sure how to correct it.
Date Time Of Last Edit: 2024-01-19 20:17:30
[2024-01-19 20:55:20]
User719512 - Posts: 264
Try using new/delete. You don't need to use the sc heap apis.


if (sc.LastCallToFunction)
{
if (tpoMap != NULL)
{
delete tpoMap;
sc.SetPersistentPointer(1, NULL);
tpoMap = NULL; // not needed, but good pattern!
}

return;
}

...
if (tpoMap == NULL)
{
// allocate memory
tpoMap = new std::map<float, char>;
if (topMap != NULL)
sc.SetPersistentPointer(1, tpoMap);
else
return;
}
...
// at this point, we know tpoMap is a valid pointer
...



your code also seems to have a logic error. If you just allocated/new the map, it will not have anything to find. that logic should probably be its own block outside allocation.
Date Time Of Last Edit: 2024-01-19 21:05:12
[2024-01-21 03:08:44]
User895355 - Posts: 55
Ok, I'm getting there, you'll see the price displayed in the
DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc)
window/rectangle on the right with letters next to them(The beginnings of a static TPO chart) in the attached image. Two things:

1. Can I make the window scrollable, or can I make that rectangle a scrollable list or something?

2. Frequently crashes Sierra. I have this:

if (sc.LastCallToFunction || sc.IsFullRecalculation)
{
if (tpoMap != NULL)
{
sc.FreeMemory(tpoMap);
delete tpoMap;
sc.SetPersistentPointer(sc.Input[0].GetInt(), NULL);
tpoMap = NULL;
}
return;
}
Since I'm also using an "iterator" ->
std::map<float, std::vector<char>>::iterator it;
do I need to delete and free up that memory too?

https://www.sierrachart.com/image.php?Image=1705805956782.png
Date Time Of Last Edit: 2024-01-21 03:26:09
imagetpoDisplay.png / V - Attached On 2024-01-21 02:57:08 UTC - Size: 41.2 KB - 50 views
[2024-01-21 11:08:54]
User431178 - Posts: 541
2. Frequently crashes Sierra. I have this:

Re-read this - ACSIL Programming Concepts: Allocating Memory for Classes - the section titled Allocating Memory for Classes

Or simply change your code to reflect that shown by User719512


Since I'm also using an "iterator" ->
do I need to delete and free up that memory too?

No.
The iterator is a type based on the characteristics of your container, and you are not allocating memory for it on the heap.


If you want help fixing this, you will need to share more of the code, it is impossible to know with certainty where you are going wrong otherwise.
Date Time Of Last Edit: 2024-01-21 16:23:15
[2024-01-21 14:27:42]
User895355 - Posts: 55
Here is the main processing code. Since I'm running it on "Chart Replay", the crash happens when I stop the chart replay, the chart never recovers and crashes.


// Section 2 - Do data processing here
SCString msg;
int currentDate = sc.BaseDateTimeIn[sc.Index].GetDate();
int currentTime = sc.BaseDateTimeIn[sc.Index].GetTime();
SCDateTime currentBar = COMBINE_DATE_TIME(currentDate, currentTime);
SCDateTime newYorkStart = COMBINE_DATE_TIME(currentDate, HMS_TIME(9, 30, 0));
SCDateTime newYorkEnd = COMBINE_DATE_TIME(currentDate, HMS_TIME(16, 30, 0));
char rotationLetter = GetRotationLetter(sc);

if (currentBar < newYorkStart || currentBar > newYorkEnd)
return;
std::map<float, std::vector<char>, std::greater<float>> *tpoMap = (std::map<float, std::vector<char>, std::greater<float>> *)sc.GetPersistentPointer(sc.Input[0].GetInt());
std::map<float, std::vector<char>>::iterator it;

if (sc.LastCallToFunction || sc.IsFullRecalculation)
{
if (tpoMap != NULL)
{
/* sc.FreeMemory(tpoMap); */
delete tpoMap;
sc.SetPersistentPointer(sc.Input[0].GetInt(), NULL);
tpoMap = NULL;
}
return;
}
if (tpoMap == NULL)
{
tpoMap = new std::map<float, std::vector<char>, std::greater<float>>;
if (tpoMap != NULL)
sc.SetPersistentPointer(sc.Input[0].GetInt(), tpoMap);
else
return;
}

if (tpoMap != NULL)
{
it = tpoMap->find(sc.Close[sc.Index]);
if (it != tpoMap->end())
{
for (it = tpoMap->begin(); it != tpoMap->end(); it++)
{
std::vector<char> &charVector = it->second;

bool letterExists = false;
for (char c : charVector)
{
if (c == rotationLetter)
{
letterExists = true;
break;
}
}
if (!letterExists)
{
it->second.push_back(rotationLetter);
}
}
}
else
{
tpoMap->insert({sc.Close[sc.Index], std::vector<char>{rotationLetter}});
sc.SetPersistentPointer(sc.Input[0].GetInt(), tpoMap);
}
}

sc.p_GDIFunction = DrawToChart;
}

Date Time Of Last Edit: 2024-01-21 14:33:14
[2024-01-21 16:22:22]
User431178 - Posts: 541

if (currentBar < newYorkStart || currentBar > newYorkEnd)
return;

The above code should be below the LastCallToFunction block, and probably below the block where you allocate the new map.
Why?
What happens if you remove the study outside of NY hours? You would never clean up the memory that you allocated.
What happens when you recalculate the chart? You may well delete the map and not reallocate it, but the DrawToChart function is still being called, maybe with an invalid pointer being used.

You could set the below when you recalculate the chart.
sc.p_GDIFunction = nullptr
That would prevent the DrawToChart function being called until you do actually reallocate the map.

And what about the code that you use for drawing? Do you check that the persistent pointer is valid?
Date Time Of Last Edit: 2024-01-21 16:22:58
[2024-01-21 16:56:44]
User895355 - Posts: 55
Wow, thanks for your help! I've made those changes and it's not crashing now at all. Please see the changes I've made:

--- brevity
if (sc.LastCallToFunction || sc.IsFullRecalculation)
{
if (tpoMap != NULL)
{
/* sc.FreeMemory(tpoMap); */
delete tpoMap;
sc.SetPersistentPointer(sc.Input[0].GetInt(), NULL);
tpoMap = NULL;
sc.p_GDIFunction = nullptr;
}
return;
}
// I put this here
if (currentBar < newYorkStart || currentBar > newYorkEnd)
return;
if (tpoMap == NULL)
{
tpoMap = new std::map<float, std::vector<char>, std::greater<float>>;
if (tpoMap != NULL)
sc.SetPersistentPointer(sc.Input[0].GetInt(), tpoMap);
else
return;
}
----- brevity

...and here is my DrawToChart() code:

void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc)
{

if (sc.GetPersistentPointer(sc.Input[0].GetInt()) == NULL)
return;
std::map<float, std::vector<char>, std::greater<float>> *tpoMap = (std::map<float, std::vector<char>, std::greater<float>> *)sc.GetPersistentPointer(sc.Input[0].GetInt());
std::map<float, std::vector<char>>::iterator it;

SCString val;

// yellow brush
n_ACSIL::s_GraphicsBrush GraphicsBrush;
GraphicsBrush.m_BrushType = n_ACSIL::s_GraphicsBrush::BRUSH_TYPE_SOLID;
GraphicsBrush.m_BrushColor.SetRGB(25, 25, 25);
sc.Graphics.SetBrush(GraphicsBrush);

// pen
n_ACSIL::s_GraphicsPen GraphicsPenForRectangle;
GraphicsPenForRectangle.m_PenColor.SetColorValue(COLOR_BLUE);
GraphicsPenForRectangle.m_PenStyle = n_ACSIL::s_GraphicsPen::e_PenStyle::PEN_STYLE_SOLID;
GraphicsPenForRectangle.m_Width = 1;
sc.Graphics.SetPen(GraphicsPenForRectangle);

// draw rectangle at top right of chart
sc.Graphics.DrawRectangle(sc.StudyRegionRightCoordinate - 200, sc.StudyRegionTopCoordinate + 5, sc.StudyRegionRightCoordinate, sc.StudyRegionBottomCoordinate);

// hollow rectangle
sc.Graphics.ResetBrush();

// marker
sc.Graphics.SetTextAlign(TA_NOUPDATECP);
n_ACSIL::s_GraphicsFont GraphicsFont;
GraphicsFont.m_Height = 6;
GraphicsFont.m_Weight = FW_NORMAL;
sc.Graphics.SetTextFont(GraphicsFont);
n_ACSIL::s_GraphicsColor GraphicsColor;
n_ACSIL::s_GraphicsColor BgColor;
GraphicsColor.SetRGB(255, 255, 255);
BgColor.SetRGB(25, 25, 25);
sc.Graphics.SetTextColor(GraphicsColor);
sc.Graphics.SetBackgroundColor(BgColor);

/* sc.Graphics.DrawTextAt(val + "<", sc.StudyRegionRightCoordinate - 200, (sc.RegionValueToYPixelCoordinate(sc.Close[sc.Index], sc.GraphRegion) - 10)); */
SCString debug;

int count = 8;

/* for (const auto &pair : *tpoMap) */
for (it = tpoMap->begin(); it != tpoMap->end(); it++)
{
const std::vector<char> &charVector = it->second;

std::string chars;
for (char c : charVector)
{
chars += c;
}
SCString pointer = "<";
if (sc.Close[sc.Index] == it->first)
val.Format("%.2f %s %s", it->first, chars.c_str(), pointer.GetChars());
else
val.Format("%.2f %s", it->first, chars.c_str());

sc.Graphics.DrawTextAt(val, sc.StudyRegionRightCoordinate - 200, (sc.StudyRegionTopCoordinate + 5) + count);
count += 8;
}

/* n_ACSIL::s_GraphicsPen MarkerPen;
MarkerPen.m_PenColor.SetColorValue(COLOR_WHITE);
MarkerPen.m_PenStyle = n_ACSIL::s_GraphicsPen::e_PenStyle::PEN_STYLE_SOLID;
MarkerPen.m_Width = 2;
sc.Graphics.SetPen(MarkerPen);
sc.Graphics.MoveTo(sc.StudyRegionRightCoordinate - 150, sc.RegionValueToYPixelCoordinate(sc.Close[sc.Index], sc.GraphRegion));
sc.Graphics.LineTo(sc.StudyRegionRightCoordinate - 200, sc.RegionValueToYPixelCoordinate(sc.Close[sc.Index], sc.GraphRegion)); */

return;
}

[2024-01-21 17:09:56]
User431178 - Posts: 541
Ok, good.

Not important, but if you like brevity, you might also like the auto and using keywords in c++.
[2024-01-24 06:53:01]
User895355 - Posts: 55
The problem I'm facing now is the tpo values are real-time. When I reload the chart the previous(historical) data is missing. What's the best way to grab that historical data first before the real-time kicks in again?

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

Login

Login Page - Create Account