Support Board
Date/Time: Sun, 24 Nov 2024 00:56:56 +0000
[User Discussion] - Custom Study Trade DOM
View Count: 363
[2024-07-20 13:16:09] |
User357489 - Posts: 72 |
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. |
[2024-07-20 14:46:56] |
User431178 - Posts: 541 |
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: 72 |
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: 541 |
No worries. The attached trade DOm image is private, so not much help right now. |
[2024-07-20 15:16:16] |
User357489 - Posts: 72 |
Apologies! This work?
|
IMG-20240711-WA0006.jpeg - Attached On 2024-07-20 15:15:56 UTC - Size: 1.24 MB - 63 views |
[2024-07-22 11:58:01] |
User357489 - Posts: 72 |
Hi again, after some more messing around and using the advice above; i have (almost) got what i wanted. #include "sierrachart.h" 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.
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); } } } } |
[2024-07-22 12:10:51] |
User357489 - Posts: 72 |
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: 541 |
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: 72 |
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 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!
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); } } |
To post a message in this thread, you need to log in with your Sierra Chart account: