Login Page - Create Account

Support Board


Date/Time: Sat, 23 Nov 2024 18:21:31 +0000



[Programming Help] - ACSIL Custom Autotrading System assistance

View Count: 1815

[2024-08-06 09:42:00]
User357489 - Posts: 72
Hi SC Engineering

Im a novice and hit a brick wall.

I have a working version of my autotrader, and i had a "bright idea" of tweaking it (outlined in the attached explanation text file)

I have the following iteration of my tweaks, and it provides several horrific looking errors and a failed build.

I feel it may be something "obvious" but for more experienced eyes, so would appreciate the help.

#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 1;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

double bidMboOrderSum = 0;
double askMboOrderSum = 0;

// Check top 5 bid levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry bidDepthEntry(0); // Initialize with dummy value

if (sc.GetBidMarketDepthEntryAtLevel(level, bidDepthEntry))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceIndex = 0;

if (sc.VolumeAtPriceForBars->GetPriceIndexForPrice(sc.ArraySize - 1, bidDepthEntry.Price, priceIndex))
{
sc.VolumeAtPriceForBars->GetVAPElementAtIndex(sc.ArraySize - 1, priceIndex, &volumeAtPrice, false);

if (volumeAtPrice && bidDepthEntry.StackPullValue >= volumeThreshold && (volumeAtPrice->AskVolume - volumeAtPrice->BidVolume) > 0)
{
buyConditionMet = true;
}
}
}
}

// Check top 5 ask levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry askDepthEntry(0); // Initialize with dummy value

if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceIndex = 0;

if (sc.VolumeAtPriceForBars->GetPriceIndexForPrice(sc.ArraySize - 1, askDepthEntry.Price, priceIndex))
{
sc.VolumeAtPriceForBars->GetVAPElementAtIndex(sc.ArraySize - 1, priceIndex, &volumeAtPrice, false);

if (volumeAtPrice && askDepthEntry.StackPullValue >= volumeThreshold && (volumeAtPrice->AskVolume - volumeAtPrice->BidVolume) < 0)
{
sellConditionMet = true;
}
}
}
}

// Final conditions: Only enter a trade if MBO conditions are also met
if (buyConditionMet && bidMboOrderSum > askMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && askMboOrderSum > bidMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Exit conditions and trailing stop management
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}

// Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

}

return;
}

Please also find attached the text file of my working iteration.
attachmentExplanations.txt - Attached On 2024-08-06 09:38:28 UTC - Size: 4.3 KB - 643 views
attachmentSweepGenieMrB.txt - Attached On 2024-08-06 09:41:39 UTC - Size: 6.66 KB - 635 views
[2024-08-06 09:45:57]
User357489 - Posts: 72
Without bombarding the board with all the errors; they are pertaining to getting the market depth data and vbp data;

error: cannot bind non-const lvalue reference of type 's_MarketDepthEntry&' to an rvalue of type 's_MarketDepthEntry'
121 | if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))
| ^~~~~
In file included from scstructures.h:104,
[2024-08-06 10:18:39]
User431178 - Posts: 541
s_MarketDepthEntry bidDepthEntry(0); // Initialize with dummy value

Remove the (0)
s_MarketDepthEntry only has a default constructor (which takes no parameters).
When it is constructed both member variables are zero initialized anyway.

sc.VolumeAtPriceForBars->GetPriceIndexForPrice(sc.ArraySize - 1, askDepthEntry.Price, priceIndex))

This is a non-existant function, is it a ChatGPT hallucination?

Try lookng at
sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists
or
sc.VolumeAtPriceForBars->GetVAPElementAtPrice

When you use the vap container, the prices are in ticks, so you need to use sc.PriceValueToTicks to convert the price first.


volumeAtPrice->AskVolume - volumeAtPrice->BidVolume) < 0
This won't work as these values are unsigned integers.

Rather than subtracting and comparing to zero, why not compare the variables directly.

Replace
(volumeAtPrice->AskVolume - volumeAtPrice->BidVolume) < 0
with
(volumeAtPrice->BidVolume > volumeAtPrice->AskVolume)


Replace
(volumeAtPrice->AskVolume - volumeAtPrice->BidVolume) > 0
with
(volumeAtPrice->AskVolume > volumeAtPrice->BidVolume)


If your code still does not compile, post all the remaining error messages.
[2024-08-06 10:36:39]
User357489 - Posts: 72
Hi there, appreciate the help!

Yes admittedly, i thought ChatGPT (4o) would understand my desired modifications enough but not the cdase, which is fine, we're both learning!

here's the errors: apologies for being slow, its a lot to take in hence AI assistance thus far

-- Starting remote build of Custom Studies Source files: sweepgeniedeltacheck.cpp. 64-bit -- 11:34:23

Allow time for the server to compile the files and build the DLL.

Server: https://build.sierrachart.com
The remote build is complete.
The build failed.
sweepgeniedeltacheck.cpp: In function 'void scsf_SweepGenie(SCStudyInterfaceRef)':
sweepgeniedeltacheck.cpp:101:46: error: cannot bind non-const lvalue reference of type 's_MarketDepthEntry&' to an rvalue of type 's_MarketDepthEntry'
101 | if (sc.GetBidMarketDepthEntryAtLevel(level, bidDepthEntry))
| ^~~~~
In file included from scstructures.h:104,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
scconstants.h:1986:2: note: after user-defined conversion: 's_MarketDepthEntry::s_MarketDepthEntry(int)'
1986 | s_MarketDepthEntry(int DummyValue = 0)
| ^~~~~~~~~~~~~~~~~~
sweepgeniedeltacheck.cpp:106:118: error: no matching function for call to 'c_VAPContainer::GetVAPElementForPriceIfExists(int, int&, const s_VolumeAtPriceV2**)'
106 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
| ^
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
VAPContainer.h:630:13: note: candidate: 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
630 | inline bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VAPContainer.h:630:13: note: candidate expects 4 arguments, 3 provided
sweepgeniedeltacheck.cpp:108:35: error: 'struct s_MarketDepthEntry' has no member named 'PullingStacking'
108 | if (bidDepthEntry.PullingStacking > volumeThreshold && volumeAtPrice->AskVolume > volumeAtPrice->BidVolume)
| ^~~~~~~~~~~~~~~
sweepgeniedeltacheck.cpp:121:46: error: cannot bind non-const lvalue reference of type 's_MarketDepthEntry&' to an rvalue of type 's_MarketDepthEntry'
121 | if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))
| ^~~~~
In file included from scstructures.h:104,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
scconstants.h:1986:2: note: after user-defined conversion: 's_MarketDepthEntry::s_MarketDepthEntry(int)'
1986 | s_MarketDepthEntry(int DummyValue = 0)
| ^~~~~~~~~~~~~~~~~~
sweepgeniedeltacheck.cpp:126:118: error: no matching function for call to 'c_VAPContainer::GetVAPElementForPriceIfExists(int, int&, const s_VolumeAtPriceV2**)'
126 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
| ^
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
VAPContainer.h:630:13: note: candidate: 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
630 | inline bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VAPContainer.h:630:13: note: candidate expects 4 arguments, 3 provided
sweepgeniedeltacheck.cpp:128:35: error: 'struct s_MarketDepthEntry' has no member named 'PullingStacking'
128 | if (askDepthEntry.PullingStacking > volumeThreshold && volumeAtPrice->BidVolume > volumeAtPrice->AskVolume)
| ^~~~~~~~~~~~~~~


-- End of Build -- 11:34:27

I have looked through the documentation, but i'm having difficulty applying it without guidance
[2024-08-06 10:37:50]
User357489 - Posts: 72
FYI, these errors have been the main issue, among several attempts, so have been going back and forth to no avail at present
[2024-08-06 11:20:04]
User431178 - Posts: 541
If you have edited the code already, please post it.

Replace this
s_MarketDepthEntry bidDepthEntry(0); // Initialize with dummy value
and this
s_MarketDepthEntry askDepthEntry(0); // Initialize with dummy value

with
s_MarketDepthEntry bidDepthEntry;
and
s_MarketDepthEntry askDepthEntry;

That should fix the first errors.


To get pull stack values, you need to call separate functions.


sc.GetBidMarketDepthStackPullValueAtPrice
sc.GetAskMarketDepthStackPullValueAtPrice

sc.GetBidMarketDepthStackPullValueAtPrice()


Once those errors are fixed, post the code and we fix the VAP errors.
Date Time Of Last Edit: 2024-08-06 11:20:42
[2024-08-06 11:27:15]
User357489 - Posts: 72
implementing the above:
#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

// Set attached order types
order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 1;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

double bidMboOrderSum = 0;
double askMboOrderSum = 0;

// Check top 5 bid levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry bidDepthEntry; // Default initialization

if (sc.GetBidMarketDepthEntryAtLevel(level, bidDepthEntry))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceInTicks = sc.PriceValueToTicks(bidDepthEntry.Price);

if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
{
double bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(bidDepthEntry.Price);
if (bidPullingStacking >= volumeThreshold && volumeAtPrice->AskVolume > volumeAtPrice->BidVolume)
{
buyConditionMet = true;
}
}
}
}

// Check top 5 ask levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry askDepthEntry; // Default initialization

if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceInTicks = sc.PriceValueToTicks(askDepthEntry.Price);

if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
{
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
if (askPullingStacking >= volumeThreshold && volumeAtPrice->BidVolume > volumeAtPrice->AskVolume)
{
sellConditionMet = true;
}
}
}
}

// Final conditions: Only enter a trade if MBO conditions are also met
if (buyConditionMet && bidMboOrderSum > askMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && askMboOrderSum > bidMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Exit conditions and trailing stop management
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}

// Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

} // End of trade management logic

return;
}

This returned:

-- Starting remote build of Custom Studies Source files: sweepgeniedeltacheck.cpp. 64-bit -- 12:26:42

Allow time for the server to compile the files and build the DLL.

Server: https://build2.sierrachart.com
The remote build is complete.
The build failed.
sweepgeniedeltacheck.cpp: In function 'void scsf_SweepGenie(SCStudyInterfaceRef)':
sweepgeniedeltacheck.cpp:101:46: error: cannot bind non-const lvalue reference of type 's_MarketDepthEntry&' to an rvalue of type 's_MarketDepthEntry'
101 | if (sc.GetBidMarketDepthEntryAtLevel(level, bidDepthEntry))
| ^~~~~
In file included from scstructures.h:104,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
scconstants.h:1986:2: note: after user-defined conversion: 's_MarketDepthEntry::s_MarketDepthEntry(int)'
1986 | s_MarketDepthEntry(int DummyValue = 0)
| ^~~~~~~~~~~~~~~~~~
sweepgeniedeltacheck.cpp:106:118: error: no matching function for call to 'c_VAPContainer::GetVAPElementForPriceIfExists(int, int&, const s_VolumeAtPriceV2**)'
106 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
| ^
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
VAPContainer.h:630:13: note: candidate: 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
630 | inline bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VAPContainer.h:630:13: note: candidate expects 4 arguments, 3 provided
sweepgeniedeltacheck.cpp:122:46: error: cannot bind non-const lvalue reference of type 's_MarketDepthEntry&' to an rvalue of type 's_MarketDepthEntry'
122 | if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))
| ^~~~~
In file included from scstructures.h:104,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
scconstants.h:1986:2: note: after user-defined conversion: 's_MarketDepthEntry::s_MarketDepthEntry(int)'
1986 | s_MarketDepthEntry(int DummyValue = 0)
| ^~~~~~~~~~~~~~~~~~
sweepgeniedeltacheck.cpp:127:118: error: no matching function for call to 'c_VAPContainer::GetVAPElementForPriceIfExists(int, int&, const s_VolumeAtPriceV2**)'
127 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice))
| ^
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniedeltacheck.cpp:1:
VAPContainer.h:630:13: note: candidate: 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
630 | inline bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VAPContainer.h:630:13: note: candidate expects 4 arguments, 3 provided


-- End of Build -- 12:26:46
[2024-08-06 13:29:22]
User431178 - Posts: 541
if (sc.GetBidMarketDepthEntryAtLevel(level, bidDepthEntry))
if (sc.GetAskMarketDepthEntryAtLevel(level, askDepthEntry))

Sorry, missed this before, the parameters are the wrong way around in those lines above, should be depth struct followed by level index.

sc.GetAskMarketDepthEntryAtLevel
Date Time Of Last Edit: 2024-08-06 13:29:47
[2024-08-06 13:38:11]
User357489 - Posts: 72
ok so this:
#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

// Set attached order types
order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 1;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

double bidMboOrderSum = 0;
double askMboOrderSum = 0;

// Check top 5 bid levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry bidDepthEntry; // Default initialization

if (sc.GetBidMarketDepthEntryAtLevel(bidDepthEntry, level))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceInTicks = sc.PriceValueToTicks(bidDepthEntry.Price);
unsigned int unusedVar; // An unused variable to meet the function signature

if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice, unusedVar))
{
double bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(bidDepthEntry.Price);
if (bidPullingStacking >= volumeThreshold && volumeAtPrice->AskVolume > volumeAtPrice->BidVolume)
{
buyConditionMet = true;
}
}
}
}

// Check top 5 ask levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry askDepthEntry; // Default initialization

if (sc.GetAskMarketDepthEntryAtLevel(askDepthEntry, level))
{
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;
int priceInTicks = sc.PriceValueToTicks(askDepthEntry.Price);
unsigned int unusedVar; // An unused variable to meet the function signature

if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice, unusedVar))
{
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
if (askPullingStacking >= volumeThreshold && volumeAtPrice->BidVolume > volumeAtPrice->AskVolume)
{
sellConditionMet = true;
}
}
}
}

// Final conditions: Only enter a trade if MBO conditions are also met
if (buyConditionMet && bidMboOrderSum > askMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && askMboOrderSum > bidMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Exit conditions and trailing stop management
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}

// Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

} // End of trade management logic

return;
}
, now only seems to return issues with VAP, so i think Market depth may have been solved (THANKYOU SO FAR! lifesaver)

-- Starting remote build of Custom Studies Source files: sweepgeniehelp1.cpp. 64-bit -- 14:37:12

Allow time for the server to compile the files and build the DLL.

Server: https://build2.sierrachart.com
The remote build is complete.
The build failed.
sweepgeniehelp1.cpp: In function 'void scsf_SweepGenie(SCStudyInterfaceRef)':
sweepgeniehelp1.cpp:107:104: error: invalid conversion from 'const s_VolumeAtPriceV2**' to 's_VolumeAtPriceV2**' [-fpermissive]
107 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice, unusedVar))
| ^~~~~~~~~~~~~~
| |
| const s_VolumeAtPriceV2**
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniehelp1.cpp:1:
VAPContainer.h:633:21: note: initializing argument 3 of 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
633 | , t_VolumeAtPrice** p_VAP
| ~~~~~~~~~~~~~~~~~~^~~~~
sweepgeniehelp1.cpp:129:104: error: invalid conversion from 'const s_VolumeAtPriceV2**' to 's_VolumeAtPriceV2**' [-fpermissive]
129 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice, unusedVar))
| ^~~~~~~~~~~~~~
| |
| const s_VolumeAtPriceV2**
In file included from scstructures.h:108,
from sierrachart.h:22,
from sweepgeniehelp1.cpp:1:
VAPContainer.h:633:21: note: initializing argument 3 of 'bool c_VAPContainerBase<t_VolumeAtPrice>::GetVAPElementForPriceIfExists(unsigned int, int, t_VolumeAtPrice**, unsigned int&) [with t_VolumeAtPrice = s_VolumeAtPriceV2]'
633 | , t_VolumeAtPrice** p_VAP
| ~~~~~~~~~~~~~~~~~~^~~~~


-- End of Build -- 14:37:16
[2024-08-06 13:51:35]
User357489 - Posts: 72
PS the reason i wanted to use vap>0/<0:

please see attached screenshot (far left col), changing the VBP study to Ask vol- bid Vol to display, the premise being the system will only enter longs/shorts at prices where delta >0/<0, does this make sense,
imageimage.png / V - Attached On 2024-08-06 13:51:18 UTC - Size: 35.81 KB - 41 views
[2024-08-06 14:45:54]
User431178 - Posts: 541

please see attached screenshot (far left col), changing the VBP study to Ask vol- bid Vol to display, the premise being the system will only enter longs/shorts at prices where delta >0/<0, does this make sense,

So do you want to know whether the current bar has +/- delta at price or the volume profile?



sweepgeniehelp1.cpp: In function 'void scsf_SweepGenie(SCStudyInterfaceRef)':
sweepgeniehelp1.cpp:107:104: error: invalid conversion from 'const s_VolumeAtPriceV2**' to 's_VolumeAtPriceV2**' [-fpermissive]
107 | if (sc.VolumeAtPriceForBars->GetVAPElementForPriceIfExists(sc.ArraySize - 1, priceInTicks, &volumeAtPrice, unusedVar))

This means that you need to drop the const prefix from here
const s_VolumeAtPriceV2* volumeAtPrice = nullptr;

Another option would be to use GetVAPElementAtPrice which returns a const reference to the VAP object (which is empty if not found).


const auto& vap = sc.VolumeAtPriceForBars->GetVAPElementAtPrice(sc.ArraySize - 1, priceInTicks);

if (!vap.IsEmpty())
{
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
if (askPullingStacking >= volumeThreshold && volumeAtPrice->BidVolume > volumeAtPrice->AskVolume)
{
sellConditionMet = true;
}
}

The member functions for vapcontainer are mentioned here - ACSIL Interface Members - Variables and Arrays: sc.VolumeAtPriceForBars Member Function Descriptions


You would also want to add the below to your setdefaults section.

sc.scMaintainVolumeAtPriceData = 1;

ACSIL Interface Members - Variables and Arrays: sc.MaintainVolumeAtPriceData
[2024-08-06 14:49:19]
User357489 - Posts: 72
"So do you want to know whether the current bar has +/- delta at price or the volume profile?"
the volume profile at price- i wanted the condition that "if the price level delta from vol profile >0 AND bid pulling stacking (over 5 bid levels)>=threshold, if so then buy.

to differentiate bogus entries entering long when the price level has a displayed delta volume of -1000 for sake of argument.
[2024-08-06 14:55:25]
User357489 - Posts: 72
#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

// Set attached order types
order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 0;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

sc.MaintainVolumeAtPriceData = 1; // Ensure VolumeAtPrice data is maintained

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

double bidMboOrderSum = 0;
double askMboOrderSum = 0;

// Check top 5 bid levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry bidDepthEntry;

if (sc.GetBidMarketDepthEntryAtLevel(bidDepthEntry, level))
{
int priceInTicks = sc.PriceValueToTicks(bidDepthEntry.Price);
const auto& volumeAtPrice = sc.VolumeAtPriceForBars->GetVAPElementAtPrice(sc.ArraySize - 1, priceInTicks);

if (!volumeAtPrice.IsEmpty())
{
double bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(bidDepthEntry.Price);
if (bidPullingStacking >= volumeThreshold && volumeAtPrice.AskVolume > volumeAtPrice.BidVolume)
{
buyConditionMet = true;
}
}
}
}

// Check top 5 ask levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry askDepthEntry;

if (sc.GetAskMarketDepthEntryAtLevel(askDepthEntry, level))
{
int priceInTicks = sc.PriceValueToTicks(askDepthEntry.Price);
const auto& volumeAtPrice = sc.VolumeAtPriceForBars->GetVAPElementAtPrice(sc.ArraySize - 1, priceInTicks);

if (!volumeAtPrice.IsEmpty())
{
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
if (askPullingStacking >= volumeThreshold && volumeAtPrice.BidVolume > volumeAtPrice.AskVolume)
{
sellConditionMet = true;
}
}
}
}

// Final conditions: Only enter a trade if MBO conditions are also met
if (buyConditionMet && bidMboOrderSum > askMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && askMboOrderSum > bidMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Exit conditions and trailing stop management
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
     // Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

} // End of trade management logic

return;
}

This has resulted in a successful build!

Now to see if it does what its supposed to do!

I cannot thank you enough, anon user! If you have time please add me on discord; username campanariskman, if its okay with you would like to gain more knowledge with this so wanting to surround myself with those who know more
[2024-08-06 15:17:11]
User431178 - Posts: 541

the volume profile at price- i wanted the condition that "if the price level delta from vol profile >0 AND bid pulling stacking (over 5 bid levels)>=threshold, if so then buy.

to differentiate bogus entries entering long when the price level has a displayed delta volume of -1000 for sake of argument.

If you want to access the data from the volume profile a different approach is needed, the way the ocde is written it look only at the volume at price data within the current bar.
[2024-08-06 15:32:26]
User357489 - Posts: 72
i initially tried getarray for studyid, but for each of my trade doms, the study id is different, so that was to allow the user to select the vbp study, but didnt know if it had a subgraph reference and got stuck
[2024-08-06 15:58:31]
User431178 - Posts: 541
i initially tried getarray for studyid, but for each of my trade doms, the study id is different, so that was to allow the user to select the vbp study, but didnt know if it had a subgraph reference and got stuck

You can use one of the inputs to select the coorect VBP studyID.
ACSIL Interface Members - sc.Input Array: sc.Input[].GetStudyID()

To get data for the VBP you would use this function.
sc.GetVolumeAtPriceDataForStudyProfile()
[2024-08-06 16:15:36]
User357489 - Posts: 72
#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

// Set attached order types
order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 0;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

sc.Input[5].Name = "VBP Study ID";
sc.Input[5].SetStudyID(0); // Default study ID, set by user.

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();
int vbpStudyID = sc.Input[5].GetStudyID(); // Get the study ID for the VBP study

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

double bidMboOrderSum = 0;
double askMboOrderSum = 0;

// Check top 5 bid levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry bidDepthEntry; // Default initialization

if (sc.GetBidMarketDepthEntryAtLevel(bidDepthEntry, level))
{
int priceInTicks = sc.PriceValueToTicks(bidDepthEntry.Price);

s_VolumeAtPriceV2 volumeAtPrice;
unsigned int volumeAtPriceIndex;

if (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, priceInTicks, volumeAtPrice, volumeAtPriceIndex) == 1)
{
double bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(bidDepthEntry.Price);
if (bidPullingStacking >= volumeThreshold && volumeAtPrice.AskVolume > volumeAtPrice.BidVolume)
{
buyConditionMet = true;
}
}
}
}

// Check top 5 ask levels
for (int level = 0; level < 5; ++level)
{
s_MarketDepthEntry askDepthEntry; // Default initialization

if (sc.GetAskMarketDepthEntryAtLevel(askDepthEntry, level))
{
int priceInTicks = sc.PriceValueToTicks(askDepthEntry.Price);

s_VolumeAtPriceV2 volumeAtPrice;
unsigned int volumeAtPriceIndex;

if (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, priceInTicks, volumeAtPrice, volumeAtPriceIndex) == 1)
{
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
if (askPullingStacking >= volumeThreshold && volumeAtPrice.BidVolume > volumeAtPrice.AskVolume)
{
sellConditionMet = true;
}
}
}
}

// Final conditions: Only enter a trade if MBO conditions are also met
if (buyConditionMet && bidMboOrderSum > askMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && askMboOrderSum > bidMboOrderSum)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Exit conditions and trailing stop management
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
     // Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

// Additional Exit Logic: Any other conditions for exiting the trade can be added here

} // End of trade management logic

return;
}

applying the above returned:

-- Starting remote build of Custom Studies Source files: sweepgeniehelp2.cpp. 64-bit -- 17:14:41

Allow time for the server to compile the files and build the DLL.

Server: https://build2.sierrachart.com
The remote build is complete.
The build failed.
sweepgeniehelp2.cpp: In function 'void scsf_SweepGenie(SCStudyInterfaceRef)':
sweepgeniehelp2.cpp:112:82: error: cannot convert 's_VolumeAtPriceV2' to 'int' in argument passing
112 | if (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, priceInTicks, volumeAtPrice, volumeAtPriceIndex) == 1)
| ^~~~~~~~~~~~~
| |
| s_VolumeAtPriceV2
sweepgeniehelp2.cpp:135:82: error: cannot convert 's_VolumeAtPriceV2' to 'int' in argument passing
135 | if (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, priceInTicks, volumeAtPrice, volumeAtPriceIndex) == 1)
| ^~~~~~~~~~~~~
| |
|
[2024-08-06 20:06:14]
User431178 - Posts: 541
Yes, makes sense.

Suggest reading this page again: sc.GetVolumeAtPriceDataForStudyProfile()

sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, priceInTicks, volumeAtPrice, volumeAtPriceIndex)

The above does not conform to the specification for that function.

int GetVolumeAtPriceDataForStudyProfile(const int StudyID, const int ProfileIndex, const int PriceIndex, s_VolumeAtPriceV2& VolumeAtPrice);
ProfileIndex is, in this case, 0 as we are interested only in the most recent profile.
For PriceIndex you actually need to loop through the available levels to find the one that you need.

See if you can figure it out, if not I will try to help some more tomorrow.
[2024-08-07 08:31:46]
User357489 - Posts: 72
good morning!

Thanks again your help is invaluable.

Here was this mornings first attempt, followed by (what i thought) was a meaningful explanation to AI

Please see attached and here was the prompt:

"in this example, a buy trade would be opened at the current price (73.66, as the buy conditions have been met at 73.64 (the bidpullingstacking>=threshold - hence the blue highlight AND the volume profile number is a number>0.

The opposite would be true for a sell, as you can see from this example however, the ask highlight (orange) meets the askpullingstacking threshold but does not meet the volume profile condition at the price (73.69) as the volume profile level has a positive integer
imagefile-84uSpCLirUlDuR0bxxefC5gt.png / V - Attached On 2024-08-07 08:30:37 UTC - Size: 18.4 KB - 31 views
[2024-08-07 08:37:15]
User357489 - Posts: 72
such a prompt returned a successsful build:

#include "sierrachart.h"
#include <unordered_map>
#include <chrono>

SCDLLName("Sweep Genie")

struct TradeInfo
{
std::chrono::time_point<std::chrono::steady_clock> startTime;
double startPrice;
bool tradeEntered;
int positionType; // 1 for buy, -1 for sell
bool stopMovedToBreakeven;
bool trailingStopActivated;
int stopOrderID;
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int stopLossTicks, int takeProfitTicks)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = takeProfitTicks * sc.TickSize;
order.Stop1Offset = stopLossTicks * sc.TickSize;

// Set attached order types
order.AttachedOrderTarget1Type = SCT_ORDERTYPE_LIMIT;
order.AttachedOrderStop1Type = SCT_ORDERTYPE_STOP;

int result = (positionType == 1) ? sc.BuyEntry(order) : sc.SellEntry(order);
if (result > 0)
{
tradeInfo.startTime = std::chrono::steady_clock::now();
tradeInfo.startPrice = price;
tradeInfo.tradeEntered = true;
tradeInfo.positionType = positionType;
tradeInfo.stopMovedToBreakeven = false;
tradeInfo.trailingStopActivated = false;

tradeInfo.stopOrderID = order.Stop1InternalOrderID;
}
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.AutoLoop = 0;

sc.Input[0].Name = "Volume Threshold";
sc.Input[0].SetInt(1000);

sc.Input[1].Name = "Order Quantity";
sc.Input[1].SetInt(1);

sc.Input[2].Name = "Stop Loss Ticks";
sc.Input[2].SetInt(10);

sc.Input[3].Name = "Take Profit Ticks";
sc.Input[3].SetInt(20);

sc.Input[4].Name = "Trailing Stop Offset Ticks";
sc.Input[4].SetInt(5);

sc.Input[5].Name = "VBP Study ID";
sc.Input[5].SetStudyID(0); // Default study ID, set by user.

return;
}

int volumeThreshold = sc.Input[0].GetInt();
int orderQuantity = sc.Input[1].GetInt();
int stopLossTicks = sc.Input[2].GetInt();
int takeProfitTicks = sc.Input[3].GetInt();
int trailingStopOffsetTicks = sc.Input[4].GetInt();
int vbpStudyID = sc.Input[5].GetStudyID(); // Get the study ID for the VBP study

SCDateTime currentTime = sc.CurrentSystemDateTime;

auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

double currentPrice = sc.Close[sc.ArraySize - 1];

bool buyConditionMet = false;
bool sellConditionMet = false;

// Check Volume at Price data and Pulling/Stacking for entry conditions
int priceInTicks = sc.PriceValueToTicks(currentPrice);
int profileIndex = 0; // Use 0 for the most recent profile

s_VolumeAtPriceV2 volumeAtPrice;
int priceIndex = -1; // Initial value for searching

// Iterate through the levels in the Volume Profile to find the matching price level
while (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, profileIndex, ++priceIndex, volumeAtPrice) != 0)
{
if (volumeAtPrice.PriceInTicks == priceInTicks)
{
double bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(currentPrice);
double askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(currentPrice);

// Buy condition: PullingStacking >= threshold and VolumeAtPrice BidVolume > 0
if (bidPullingStacking >= volumeThreshold && volumeAtPrice.BidVolume > 0)
{
buyConditionMet = true;
}

// Sell condition: PullingStacking >= threshold and VolumeAtPrice AskVolume > 0
if (askPullingStacking >= volumeThreshold && volumeAtPrice.AskVolume > 0)
{
sellConditionMet = true;
}
break;
}
}

// Execute Buy or Sell based on conditions
if (buyConditionMet && currentPosition == 0)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && currentPosition == 0)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, currentPrice, stopLossTicks, takeProfitTicks);
}

// Rest of the trade management logic
if (tradeInfo.tradeEntered)
{
double stopLossPrice = tradeInfo.startPrice - (tradeInfo.positionType * stopLossTicks * sc.TickSize);
double takeProfitPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * sc.TickSize);
double trailingStopTriggerPrice = tradeInfo.startPrice + (tradeInfo.positionType * takeProfitTicks * 0.7 * sc.TickSize);

if ((tradeInfo.positionType == 1 && (currentPrice <= stopLossPrice || currentPrice >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (currentPrice >= stopLossPrice || currentPrice <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && currentPrice >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= trailingStopTriggerPrice)))
{
tradeInfo.trailingStopActivated = true;

s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = tradeInfo.startPrice + (tradeInfo.positionType * trailingStopOffsetTicks * sc.TickSize);

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
SCString message;
message.Format("Trailing stop activated at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}

// Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && currentPrice >= breakevenPrice) ||
(tradeInfo.positionType == -1 && currentPrice <= breakevenPrice))
{
s_SCNewOrder modifyOrder;
modifyOrder.InternalOrderID = tradeInfo.stopOrderID;
modifyOrder.Price1 = breakevenPrice;

int modifyResult = sc.ModifyOrder(modifyOrder);
if (modifyResult == 1)
{
tradeInfo.stopMovedToBreakeven = true;
SCString message;
message.Format("Stop moved to breakeven at price: %f", modifyOrder.Price1);
sc.AddMessageToLog(message, 0);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
sc.AddMessageToLog(message, 1);
}
}
}

// Additional Exit Logic: Any other conditions for exiting the trade can be added here

} // End of trade management logic

return;
}

now to see if it does what it is meant to...
[2024-08-07 08:41:49]
User357489 - Posts: 72
if its of any help- the study settings that it creates:
imageimage.png / V - Attached On 2024-08-07 08:41:46 UTC - Size: 9.3 KB - 34 views
[2024-08-07 12:29:20]
User357489 - Posts: 72
its definitely not doing what i intended...
[2024-08-07 13:37:14]
User431178 - Posts: 541
its definitely not doing what i intended...

Can you elaborate?
[2024-08-07 13:44:35]
User357489 - Posts: 72
Hi, ive been watching it and when i see the conditions as outlined above, it doesnt appear to be entering the trade

what i am seeing however is increasing drawdown (which means it must be opening trades) however i dont think it is doing so in a manner in which i was trying to get across

I cannot see the bracket orders when they are being openend, so to the naked eye, its opening and closing trades in drawdown, without displaying the bracket (which to me is an indication of the system working, you know)

This led me to wonder- are the current entry conditions too "loose" hence the consistent drawdown (this doesnt bother me as its on sim account for testing, naturally- just stumped)

Partly the reason why i wanted one of the entry conditions to check if the price level has a positive/negative delta at the same time that bid or ask pulling stacking values meet the threshold.

Another condition i was planning to add was; the sum of the mbo orders on bid (5 depth levels in my case, as i have set market depth to 5) > ask sum, bolstering the directional bias of the conditions; yet became overwhelmed on how to do this :)

EDIT: perhaps its becoming confused because the conditions can be met below/ above current price? in the example provided earlier, it was 73.64 that met the buy conditions while current price was 73.66. So my hopes were that conditions met, execute mkt order @ best price (in this case current price)
Date Time Of Last Edit: 2024-08-07 13:46:55

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

Login

Login Page - Create Account