Login Page - Create Account

Support Board


Date/Time: Fri, 18 Oct 2024 06:17:06 +0000



[User Discussion] - Custom Study Trade DOM

View Count: 289

[2024-07-20 13:16:09]
User357489 - Posts: 68
Hi SC

I'm looking to make a study for the trade Dom that highlights prices where the pulling/stacking column values on the bid and ask have values >=100, with the option for the user to input as many price levels as needed. Please see below my current attempt, with screenshots of the graphic output, however I'm at a loss as to why it's not actually functioning as intended, so seeking some help
#include "sierrachart.h"

SCDLLName("Custom DOM Study");

// Define the study function
SCSFExport scsf_CustomDOMStudy(SCStudyInterfaceRef sc)
{
// Initialization
if (sc.SetDefaults)
{
sc.GraphName = "Custom DOM Highlighting Study";
sc.StudyDescription = "Highlights prices in the DOM based on bid/ask volume conditions in pulling/stacking columns.";
sc.AutoLoop = 1; // Auto-loop enabled

// Define subgraphs for bid and ask highlights
sc.Subgraph[0].Name = "Bid Highlighted Prices";
sc.Subgraph[0].PrimaryColor = RGB(0, 255, 0); // Green for bid
sc.Subgraph[0].DrawStyle = DRAWSTYLE_TEXT; // Use DRAWSTYLE_TEXT to color text
sc.Subgraph[0].LineWidth = 2;

sc.Subgraph[1].Name = "Ask Highlighted Prices";
sc.Subgraph[1].PrimaryColor = RGB(255, 0, 0); // Red for ask
sc.Subgraph[1].DrawStyle = DRAWSTYLE_TEXT; // Use DRAWSTYLE_TEXT to color text
sc.Subgraph[1].LineWidth = 2;

// Input for volume threshold
sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(100); // Default threshold value

// Input for number of levels to consider
sc.Input[1].Name = "Number of Levels";
sc.Input[1].SetInt(5); // Default number of levels

return;
}

// Main calculation
int threshold = sc.Input[0].GetInt();
int numLevels = sc.Input[1].GetInt();

// Ensure we have market depth data
if (sc.UpdateStartIndex == 0)
{
// Initialize the subgraph to default values
for (int i = 0; i < sc.ArraySize; ++i)
{
sc.Subgraph[0][i] = 0.0;
sc.Subgraph[1][i] = 0.0;
}
}

s_MarketDepthEntry depthEntry;

// Loop through market depth data for ask and bid sides
for (int level = 0; level < numLevels; ++level)
{
// Ask side
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
int askVolume = depthEntry.Quantity;
float askPrice = depthEntry.Price;

// Check if ask volume is greater than or equal to threshold
if (askVolume >= threshold)
{
// Highlight ask price in the subgraph
for (int i = sc.UpdateStartIndex; i < sc.ArraySize; ++i)
{
if (sc.BaseData[SC_LAST][i] == askPrice)
{
sc.Subgraph[1][i] = askPrice; // Highlight ask price
}
}
}
}

// Bid side
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
int bidVolume = depthEntry.Quantity;
float bidPrice = depthEntry.Price;

// Check if bid volume is greater than or equal to threshold
if (bidVolume >= threshold)
{
// Highlight bid price in the subgraph
for (int i = sc.UpdateStartIndex; i < sc.ArraySize; ++i)
{
if (sc.BaseData[SC_LAST][i] == bidPrice)
{
sc.Subgraph[0][i] = bidPrice; // Highlight bid price
}
}
}
}
}
}

Appreciate anyone time and suggestions in advance.
imageimage.png / V - Attached On 2024-07-20 13:14:51 UTC - Size: 48.9 KB - 42 views
imageimage.png / V - Attached On 2024-07-20 13:15:05 UTC - Size: 33.54 KB - 37 views
[2024-07-20 14:46:56]
User431178 - Posts: 517
Hello,
Assuming you mean to draw within the DOM columns themselves, you cannot use subgraphs for that, you would need to use custom drawing (take a look at gdiexample.cpp in your sierrachart/acs_source folder).

When using DRAWSTYLE_TEXT, you actually have to set the text value to something, otherwise the is nothing to display. The value you set in the subgraph determines only the location (price) at which to display the text.

Not sure what the purpose of the inner loop here is, given that you are only looking to highlight the price levels.

if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
int askVolume = depthEntry.Quantity;
float askPrice = depthEntry.Price;

if (askVolume >= threshold)
{
// What is this loop for, it does not seem to fit with the logic of what you are trying to achieve?
for (int i = sc.UpdateStartIndex; i < sc.ArraySize; ++i)
{
// so you only want to highligt the last trade price, nowhere else?
if (sc.BaseData[SC_LAST][i] == askPrice)
{
sc.Subgraph[1][i] = askPrice;
}
}
}
}

Also, you have autoloop enabled, but are referencing sc.UpdateStartIndex within the inner loops, which may (not 100% sure) always be 0 when you have autoloop set. If so that will be very inefficient.
If your intention is to only draw in the DOM columns, then autoloop should be set to 0, as there is no need for the function to be called on every bar (as it would be with auto loop enabled).


Maybe you can provide an example of what you expect to see, or explain in more detail?
[2024-07-20 14:56:27]
User357489 - Posts: 68
Hi pal

Thanks for the reply, I'll do my best to elaborate! Please see attached my Trade DOM, column second and fifth columns along from the price, Bid/Ask pulling/stacking columns respectively.

I would like to see the prices where the volume value in the p/s columns are >= 100 (you'll see little "clusters" where the volume bars are in each p/s column.

As they flicker and change randomly and constantly, I wanted the study to highlight the price column, similar to have the name/value check boxes do in subgraph, so appreciate the assistance on not needed subgraphs!

Does this make more sense?
Private File
[2024-07-20 15:11:56]
User431178 - Posts: 517
No worries.
The attached trade DOm image is private, so not much help right now.
[2024-07-20 15:16:16]
User357489 - Posts: 68
Apologies! This work?
attachmentIMG-20240711-WA0006.jpeg - Attached On 2024-07-20 15:15:56 UTC - Size: 1.24 MB - 51 views
[2024-07-22 11:58:01]
User357489 - Posts: 68
Hi again,

after some more messing around and using the advice above; i have (almost) got what i wanted.
#include "sierrachart.h"

SCDLLName("Custom DOM Study")

/*==========================================================================*/
// Drawing function declaration
void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc);

/*==========================================================================*/
SCSFExport scsf_CustomDOMStudy(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
// Set the configuration and defaults
sc.GraphName = "Custom DOM Highlighting Study";
sc.GraphRegion = 0;

sc.AutoLoop = 0; // Auto-loop disabled

// Input for volume threshold
sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(100); // Default threshold value

// Input for number of levels to consider
sc.Input[1].Name = "Number of Levels";
sc.Input[1].SetInt(5); // Default number of levels

return;
}

// Ensure the drawing function is called
sc.p_GDIFunction = DrawToChart;
}


void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc)
{
int threshold = sc.Input[0].GetInt();
int numLevels = sc.Input[1].GetInt();
s_MarketDepthEntry depthEntry;

for (int level = 0; level < numLevels; ++level)
{
// Ask side
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
int askVolume = depthEntry.Quantity;
float askPrice = depthEntry.Price;

if (askVolume >= threshold)
{
// Set the drawing color to red for ask
n_ACSIL::s_GraphicsColor color;
color.SetRGB(255, 0, 0);

RECT rect;
int yPixelCoordinate = sc.RegionValueToYPixelCoordinate(askPrice, 0);
SetRect(&rect, sc.StudyRegionLeftCoordinate, yPixelCoordinate - 5, sc.StudyRegionRightCoordinate, yPixelCoordinate + 5);

HBRUSH brush = CreateSolidBrush(RGB(255, 200, 200)); // Light red for ask
FillRect(DeviceContext, &rect, brush);
DeleteObject(brush);
}
}

// Bid side
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
int bidVolume = depthEntry.Quantity;
float bidPrice = depthEntry.Price;

if (bidVolume >= threshold)
{
// Set the drawing color to green for bid
n_ACSIL::s_GraphicsColor color;
color.SetRGB(0, 255, 0);

RECT rect;
int yPixelCoordinate = sc.RegionValueToYPixelCoordinate(bidPrice, 0);
SetRect(&rect, sc.StudyRegionLeftCoordinate, yPixelCoordinate - 5, sc.StudyRegionRightCoordinate, yPixelCoordinate + 5);

HBRUSH brush = CreateSolidBrush(RGB(200, 255, 200)); // Light green for bid
FillRect(DeviceContext, &rect, brush);
DeleteObject(brush);
}
}
}
}
please see attached the outcome; instead of highlight the price column, it highlight the column to the left if it (which i can live with) and attached and crudely outlined is the result, i set the levels to 30 and the volume threshold to 100 to test, however it seems that the code is using data from the buy/ sell column as opposed to the bid/ ask pulling/ stacking columns specifically. My difficulty is substituting the depth columns for the pulling/stacking columns data. Hope this has made sense and thank you in advance.
imagedom.png / V - Attached On 2024-07-22 11:57:54 UTC - Size: 94.24 KB - 64 views
[2024-07-22 12:10:51]
User357489 - Posts: 68
EDIT: done it :)

for anyone that wants to see what i was doing, here you are! :) enjoy do with it what you will
#include "sierrachart.h"

SCDLLName("Custom DOM Study")

/*==========================================================================*/
// Drawing function declaration
void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc);

/*==========================================================================*/
SCSFExport scsf_CustomDOMStudy(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
// Set the configuration and defaults
sc.GraphName = "Custom DOM Highlighting Study";
sc.GraphRegion = 0;

sc.AutoLoop = 0; // Auto-loop disabled

// Input for volume threshold
sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(100); // Default threshold value

// Input for number of levels to consider
sc.Input[1].Name = "Number of Levels";
sc.Input[1].SetInt(5); // Default number of levels

return;
}

// Ensure the drawing function is called
sc.p_GDIFunction = DrawToChart;
}

/*==========================================================================*/
// This is the actual drawing function. This function is specified by the
// "sc.p_GDIFunction" member in the main study function above. This drawing
// function is called when Sierra Chart draws the study on the chart.

void DrawToChart(HWND WindowHandle, HDC DeviceContext, SCStudyInterfaceRef sc)
{
int threshold = sc.Input[0].GetInt();
int numLevels = sc.Input[1].GetInt();
s_MarketDepthEntry depthEntry;

for (int level = 0; level < numLevels; ++level)
{
// Ask side pulling/stacking
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingAsk = sc.GetAskMarketDepthStackPullValueAtPrice(depthEntry.Price);

if (pullingStackingAsk >= threshold)
{
// Set the drawing color to red for ask
n_ACSIL::s_GraphicsColor color;
color.SetRGB(255, 0, 0);

RECT rect;
int yPixelCoordinate = sc.RegionValueToYPixelCoordinate(depthEntry.Price, 0);
SetRect(&rect, sc.StudyRegionLeftCoordinate, yPixelCoordinate - 5, sc.StudyRegionRightCoordinate, yPixelCoordinate + 5);

HBRUSH brush = CreateSolidBrush(RGB(255, 200, 200)); // Light red for ask
FillRect(DeviceContext, &rect, brush);
DeleteObject(brush);
}
}

// Bid side pulling/stacking
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingBid = sc.GetBidMarketDepthStackPullValueAtPrice(depthEntry.Price);

if (pullingStackingBid >= threshold)
{
// Set the drawing color to green for bid
n_ACSIL::s_GraphicsColor color;
color.SetRGB(0, 255, 0);

RECT rect;
int yPixelCoordinate = sc.RegionValueToYPixelCoordinate(depthEntry.Price, 0);
SetRect(&rect, sc.StudyRegionLeftCoordinate, yPixelCoordinate - 5, sc.StudyRegionRightCoordinate, yPixelCoordinate + 5);

HBRUSH brush = CreateSolidBrush(RGB(200, 255, 200)); // Light green for bid
FillRect(DeviceContext, &rect, brush);
DeleteObject(brush);
}
}
}
}

[2024-07-22 13:20:34]
User431178 - Posts: 517
Ok, good, you got it working.

If you want to place the drawings in one or other of the DOM columns, check out these functions:

sc.GetDOMColumnLeftCoordinate()
sc.GetDOMColumnRightCoordinate()

sc.GetDOMColumnLeftCoordinate()
[2024-07-22 13:35:02]
User357489 - Posts: 68
Thanks again!

I also wanted to calculate the active range, if you like, ie the lowest ask price thats highlighted minus highest bid price highlighted- as well as a calc that gives a sort of tethered % of bid vs ask orders,
// Calculate the bid and ask stacked sums
double bidStackedSum = sc.GetBidMarketDepthStackPullSum();
double askStackedSum = sc.GetAskMarketDepthStackPullSum();

if (bidStackedSum + askStackedSum > 0) // Ensure there is no division by zero
{
double bidPercentage = (bidStackedSum / (bidStackedSum + askStackedSum)) * 100;
double askPercentage = (askStackedSum / (bidStackedSum + askStackedSum)) * 100;

// Display the percentage information

// Display B% anchored to the highest bid price
SCString bidPercentageText;
bidPercentageText.Format("B%%: %.2f%%", bidPercentage);

s_UseTool bidPercentageTool;
bidPercentageTool.Clear();
bidPercentageTool.ChartNumber = sc.ChartNumber;
bidPercentageTool.DrawingType = DRAWING_TEXT;
bidPercentageTool.AddAsUserDrawnDrawing = 1;
bidPercentageTool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
bidPercentageTool.BeginValue = highestBidPrice; // Position the text at the highest bid price
bidPercentageTool.Color = RGB(255, 255, 255); // White text
bidPercentageTool.Text = bidPercentageText;
bidPercentageTool.FontSize = 12;
bidPercentageTool.LineNumber = 1; // Unique identifier for updating
bidPercentageTool.AddMethod = UTAM_ADD_OR_ADJUST;

sc.UseTool(bidPercentageTool);

// Display S% anchored to the lowest ask price
SCString askPercentageText;
askPercentageText.Format("S%%: %.2f%%", askPercentage);

s_UseTool askPercentageTool;
askPercentageTool.Clear();
askPercentageTool.ChartNumber = sc.ChartNumber;
askPercentageTool.DrawingType = DRAWING_TEXT;
askPercentageTool.AddAsUserDrawnDrawing = 1;
askPercentageTool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
askPercentageTool.BeginValue = lowestAskPrice; // Position the text at the lowest ask price
askPercentageTool.Color = RGB(255, 255, 255); // White text
askPercentageTool.Text = askPercentageText;
askPercentageTool.FontSize = 12;
askPercentageTool.LineNumber = 2; // Unique identifier for updating
askPercentageTool.AddMethod = UTAM_ADD_OR_ADJUST;

sc.UseTool(askPercentageTool);
}

// Calculate and display the range
if (lowestAskPrice != FLT_MAX && highestBidPrice != -FLT_MAX)
{
double rangeTicks = (lowestAskPrice - highestBidPrice) / 0.25;
double rangePoints = rangeTicks / 4.0;

// Display the range information
SCString rangeText;
rangeText.Format("Active Range: %.0f ticks (%.2f points)", rangeTicks, rangePoints);

s_UseTool rangeTool;
rangeTool.Clear();
rangeTool.ChartNumber = sc.ChartNumber;
rangeTool.DrawingType = DRAWING_TEXT;
rangeTool.AddAsUserDrawnDrawing = 1;
rangeTool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
rangeTool.BeginValue = highestBidPrice; // Position the text near the highest bid price
rangeTool.Color = RGB(255, 255, 255); // White text
rangeTool.Text = rangeText;
rangeTool.FontSize = 12;
rangeTool.LineNumber = 3; // Unique identifier for updating
rangeTool.AddMethod = UTAM_ADD_OR_ADJUST;

sc.UseTool(rangeTool);
}
}
being a cpp novice, having several difficulties in noticing something 'obvious' in terms of errors. This addition to the bottom of the previous code that now works, gives a really crummy output, and it "duplicates" the text and overlays it making it look like a snakes wedding. so i wondered, is it possible to display text information such as the above examples, in a seperate chart window, like a little "attachment" to the dom, similar to how T&S is? Apologies if anyone is having difficulties decoding my idea, novice developer, so just learning 'on the job', helpers/tips welcomed!

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

Login

Login Page - Create Account