Login Page - Create Account

Support Board


Date/Time: Sat, 23 Nov 2024 17:34:48 +0000



[Programming Help] - ACSIL Custom Autotrading System assistance

View Count: 1814

[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
[2024-08-07 13:49:09]
User357489 - Posts: 72
as it has very consisitently drawdown, to a impressive degree (i added the successful build to several trade doms, different assets, and since has produced approx 800 trades, all losers bar 1!

Which is incredible, never seen that occur in any novice program ive built so far! perhaps i should link it to another platform and reverse direction lol
[2024-08-07 15:53:50]
ForgivingComputers.com - Posts: 960
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)

The Trade Activity Log is your friend. In the [Trade Activity] tab, Use the Display menu to properly filter the results or you may see nothing. For each OCO Bracket, you will see three orders, their types, and prices.
[2024-08-07 15:58:26]
User357489 - Posts: 72
Hi there. I had it open alongside while I was running some tests however thanks for the suggestion, as I didn't actually know it showed that level of detail!

So either something isn't quite correct in the execution logic, or my idea just sucks haha! Possibly the latter
[2024-08-08 10:15:43]
User357489 - Posts: 72
Good morning, to add to this;

so i linked it to copy to an MT4 demo to try some stuff out- if i manually execute a market order, this copies across fine, so I've deduced something is not quite correct in the execution logic and/or it is immediately exiting upon detecting the relevant opposition conditions, it is not allowing the trade to run and only be filled by stop/ target orders.

This was why i wanted to use the volume profile values displayed (set to ask volume- bid volume on the study), to differentiate buys from sells when the price level has VBP value >0/<0.

code for reiteration:
#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;

bool buyConditionMet = false;
bool sellConditionMet = false;
double entryPrice = 0.0;

// Iterate through the market depth levels to check pulling/stacking values
for (int level = 0; level < 10; ++level) // Adjust 10 as necessary for the number of levels to check
{
s_MarketDepthEntry bidDepthEntry, askDepthEntry;
double bidPullingStacking = 0.0, askPullingStacking = 0.0;

if (sc.GetBidMarketDepthEntryAtLevel(bidDepthEntry, level))
{
bidPullingStacking = sc.GetBidMarketDepthStackPullValueAtPrice(bidDepthEntry.Price);
}
if (sc.GetAskMarketDepthEntryAtLevel(askDepthEntry, level))
{
askPullingStacking = sc.GetAskMarketDepthStackPullValueAtPrice(askDepthEntry.Price);
}

int profileIndex = 0; // Use 0 for the most recent profile
s_VolumeAtPriceV2 volumeAtPrice;
int PricesCount = sc.GetNumPriceLevelsForStudyProfile(vbpStudyID, profileIndex);
for (int PriceIndex = 0; PriceIndex < PricesCount; ++PriceIndex)
{
if (sc.GetVolumeAtPriceDataForStudyProfile(vbpStudyID, profileIndex, PriceIndex, volumeAtPrice))
{
// Buy condition: PullingStacking >= threshold and AskVolume - BidVolume > 0
if (volumeAtPrice.PriceInTicks == sc.PriceValueToTicks(bidDepthEntry.Price) &&
bidPullingStacking >= volumeThreshold &&
volumeAtPrice.AskVolume - volumeAtPrice.BidVolume > 0)
{
buyConditionMet = true;
entryPrice = sc.Close[sc.ArraySize - 1]; // Set the entry price to the current price
break;
}

// Sell condition: PullingStacking >= threshold and AskVolume - BidVolume < 0
if (volumeAtPrice.PriceInTicks == sc.PriceValueToTicks(askDepthEntry.Price) &&
askPullingStacking >= volumeThreshold &&
volumeAtPrice.AskVolume - volumeAtPrice.BidVolume < 0)
{
sellConditionMet = true;
entryPrice = sc.Close[sc.ArraySize - 1]; // Set the entry price to the current price
break;
}
}
}

if (buyConditionMet || sellConditionMet)
{
break; // Exit the loop if either condition is met
}
}

// Execute Buy or Sell based on conditions
if (buyConditionMet && currentPosition == 0)
{
PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, entryPrice, stopLossTicks, takeProfitTicks);
}
else if (sellConditionMet && currentPosition == 0)
{
PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, entryPrice, 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 && (sc.Close[sc.ArraySize - 1] <= stopLossPrice || sc.Close[sc.ArraySize - 1] >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (sc.Close[sc.ArraySize - 1] >= stopLossPrice || sc.Close[sc.ArraySize - 1] <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && sc.Close[sc.ArraySize - 1] >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && sc.Close[sc.ArraySize - 1] <= 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 && sc.Close[sc.ArraySize - 1] >= breakevenPrice) ||
(tradeInfo.positionType == -1 && sc.Close[sc.ArraySize - 1] <= 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;
}
, this build is successful but as mentioned above and in previous notes, i am biased towards it not functioning as intended. Hope this is clear, and hope my entry conditions were clear or at least you get the idea of what im trying to achieve :)
[2024-08-08 10:27:12]
User357489 - Posts: 72
PS in previous versions, i have been able to see the open position in the trade window attached to my DOM, and the relevant bracket order drawings it produces eg show order fills.

Yet in this complication; the trade window is reading "FLAT" yet the pnl updates as trades are evidently opening and closing.
Date Time Of Last Edit: 2024-08-08 10:27:38
[2024-08-08 10:34:22]
User431178 - Posts: 541
At this point I would suggest installing Visual Studio and debugging step-by-step.
Run the code and step through it so you can understand where/why it is failing/not doing what you expect.

Step-By-Step ACSIL Debugging


Either or add more logging messages to the code.
Honestly I would recommend the setp-by-step debug, you will get a much better understanding of what is happening.
Date Time Of Last Edit: 2024-08-08 10:35:30
[2024-08-08 12:16:29]
User357489 - Posts: 72
No problem, will have a crack at that! Thank you friend, for your support!

Will return with an update :)
[2024-08-09 15:01:29]
User357489 - Posts: 72
Ok i have taken an alternative approach;

i already made a study that "highlights" when bid/ask pullingstacking value >= user defined threshold.

#include "sierrachart.h"

SCDLLName("Flash Genie")

SCSFExport scsf_FlashGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Flash Genie";
sc.GraphRegion = 0;
sc.AutoLoop = 1; // Auto-loop enabled

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

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

sc.Input[2].Name = "Bid Highlight Color";
sc.Input[2].SetColor(RGB(0, 0, 255)); // Default bid highlight color

sc.Input[3].Name = "Ask Highlight Color";
sc.Input[3].SetColor(RGB(255, 0, 0)); // Default ask highlight color

return;
}

int threshold = sc.Input[0].GetInt();
int numLevels = sc.Input[1].GetInt();
COLORREF bidHighlightColor = sc.Input[2].GetColor();
COLORREF askHighlightColor = sc.Input[3].GetColor();
s_MarketDepthEntry depthEntry;

// Remove existing highlights
sc.DeleteACSChartDrawing(sc.ChartNumber, TOOL_DELETE_ALL, 0);

for (int level = 0; level < numLevels; ++level)
{
// Check Ask levels
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingAsk = sc.GetAskMarketDepthStackPullValueAtPrice(depthEntry.Price);
if (pullingStackingAsk >= threshold)
{
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_RECTANGLEHIGHLIGHT;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.BeginValue = depthEntry.Price - sc.TickSize / 2;
tool.EndValue = depthEntry.Price + sc.TickSize / 2;
tool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
tool.EndDateTime = sc.BaseDateTimeIn[0];
tool.Color = askHighlightColor;
tool.SecondaryColor = askHighlightColor;
tool.TransparencyLevel = 70;
tool.LineWidth = 1;
sc.UseTool(tool);
}
}

// Check Bid levels
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingBid = sc.GetBidMarketDepthStackPullValueAtPrice(depthEntry.Price);
if (pullingStackingBid >= threshold)
{
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_RECTANGLEHIGHLIGHT;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.BeginValue = depthEntry.Price - sc.TickSize / 2;
tool.EndValue = depthEntry.Price + sc.TickSize / 2;
tool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
tool.EndDateTime = sc.BaseDateTimeIn[0];
tool.Color = bidHighlightColor;
tool.SecondaryColor = bidHighlightColor;
tool.TransparencyLevel = 70;
tool.LineWidth = 1;
sc.UseTool(tool);
}
}
}
}

so another bright idea was to replace the logic of checking the pullingstacking to the volume at price from the VBP (still set at askvolume-bidvolume), i spoonfed AI the sc.Get.... from the documentation and we created:
#include "sierrachart.h"

SCDLLName("Volume Difference Highlight with Market Depth")

SCSFExport scsf_VolumeDifferenceHighlightWithMarketDepth(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Volume Difference Highlight with Market Depth";
sc.GraphRegion = 0;
sc.AutoLoop = 1;

sc.Input[0].Name = "Volume Profile Study ID";
sc.Input[0].SetInt(7); // Set this to the actual study ID of the Volume Profile

sc.Input[1].Name = "Bid Highlight Color";
sc.Input[1].SetColor(RGB(0, 255, 0)); // Default bid highlight color

sc.Input[2].Name = "Ask Highlight Color";
sc.Input[2].SetColor(RGB(255, 0, 0)); // Default ask highlight color

sc.Input[3].Name = "Number of Levels to Check";
sc.Input[3].SetInt(5); // Number of bid/ask levels to check

return;
}

int volumeProfileStudyID = sc.Input[0].GetInt();
COLORREF bidHighlightColor = sc.Input[1].GetColor();
COLORREF askHighlightColor = sc.Input[2].GetColor();
int numLevelsToCheck = sc.Input[3].GetInt();

s_MarketDepthEntry depthEntry;
s_VolumeAtPriceV2 volumeAtPriceData;

// Remove existing highlights
sc.DeleteACSChartDrawing(sc.ChartNumber, TOOL_DELETE_ALL, 0);

// Get the number of price levels in the VBP profile
int numPriceLevels = sc.GetNumPriceLevelsForStudyProfile(volumeProfileStudyID, 0);

// Loop through Ask levels and highlight based on volume difference
for (int level = 0; level < numLevelsToCheck; ++level)
{
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
double price = depthEntry.Price;

for (int priceIndex = 0; priceIndex < numPriceLevels; ++priceIndex)
{
if (sc.GetVolumeAtPriceDataForStudyProfile(volumeProfileStudyID, 0, priceIndex, volumeAtPriceData))
{
double vbpPrice = volumeAtPriceData.PriceInTicks * sc.TickSize;

if (fabs(vbpPrice - price) < sc.TickSize / 2)
{
double volumeDifference = volumeAtPriceData.AskVolume - volumeAtPriceData.BidVolume;

if (volumeDifference < 0) // Highlight Ask levels with negative volume difference
{
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_RECTANGLEHIGHLIGHT;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.BeginValue = price - sc.TickSize / 2;
tool.EndValue = price + sc.TickSize / 2;
tool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
tool.EndDateTime = sc.BaseDateTimeIn[0];
tool.Color = askHighlightColor;
tool.SecondaryColor = askHighlightColor;
tool.TransparencyLevel = 70;
tool.LineWidth = 1;
sc.UseTool(tool);
}
break;
}
}
}
}
}

// Loop through Bid levels and highlight based on volume difference
for (int level = 0; level < numLevelsToCheck; ++level)
{
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
double price = depthEntry.Price;

for (int priceIndex = 0; priceIndex < numPriceLevels; ++priceIndex)
{
if (sc.GetVolumeAtPriceDataForStudyProfile(volumeProfileStudyID, 0, priceIndex, volumeAtPriceData))
{
double vbpPrice = volumeAtPriceData.PriceInTicks * sc.TickSize;

if (fabs(vbpPrice - price) < sc.TickSize / 2)
{
double volumeDifference = volumeAtPriceData.AskVolume - volumeAtPriceData.BidVolume;

if (volumeDifference > 0) // Highlight Bid levels with positive volume difference
{
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_RECTANGLEHIGHLIGHT;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.BeginValue = price - sc.TickSize / 2;
tool.EndValue = price + sc.TickSize / 2;
tool.BeginDateTime = sc.BaseDateTimeIn[sc.ArraySize - 1];
tool.EndDateTime = sc.BaseDateTimeIn[0];
tool.Color = bidHighlightColor;
tool.SecondaryColor = bidHighlightColor;
tool.TransparencyLevel = 70;
tool.LineWidth = 1;
sc.UseTool(tool);
}
break;
}
}
}
}
}
}
Kinda works, but doesnt work. please see attached screenshots. The user can input the StudyID for the VBP (i tried altering this and it indeed stopped highlighting completely so it recognised the VBP study - i think ) ps ignore the orange highlight, this is from the working study mentioned first. so you see it has highlighted all of the bid levels ( i realise in this example, the bid level VBP values are indeed all >0, however they dont "delete" when bid levels has VBP<0), however not included the ask levels and also the logic for vol>0, vol<0 hasnt been implemented correctly, if the VBP value on the bid levels is <0, then theres no need to highlight so ignore. likewise with VBP value on ask levels >0, ignore. so only ask levels will highlight when VBP values <0 and vice versa.

Gone over the docs and read thru what each member does and structure etc and hit the wall again (learning has taken place this week however thanks to your guidance and help! so again , TYVM!)


EDIT: PS; taken this approach to make "standalone" conditions, make sure they work as intended, them throw them all together (logically of course) think ive been running before i can walk here, so this could prove a beneficial course of action
Date Time Of Last Edit: 2024-08-09 15:04:56
imageimage.png / V - Attached On 2024-08-09 15:01:04 UTC - Size: 9.09 KB - 43 views
imageimage1.png / V - Attached On 2024-08-09 15:01:08 UTC - Size: 7.27 KB - 37 views
[2024-08-09 15:54:30]
User431178 - Posts: 541

double volumeDifference = volumeAtPriceData.AskVolume - volumeAtPriceData.BidVolume;

Both volumeAtPriceData.AskVolume and volumeAtPriceData.BidVolume are unsigned integers (uint32_t), so you will not get a correct result if BV > AV.
Even though you have the result as a double, the subtraction on the right hand side happens first, the result of which is then converted to double.

For it to work correctly for negative numbers you would need to do somthing like one of the options below.


double volumeDifference = (volumeAtPriceData.AskVolume * 1.0) - volumeAtPriceData.BidVolume;


double volumeDifference = static_cast<double>(volumeAtPriceData.AskVolume) - volumeAtPriceData.BidVolume;


int64_t volumeDifference = static_cast<int64_t>(volumeAtPriceData.AskVolume) - volumeAtPriceData.BidVolume;

[2024-08-10 10:36:33]
User357489 - Posts: 72
Beautiful thats worked, thanks pal! :)
[2024-08-12 08:06:12]
User357489 - Posts: 72
Good morning, no rest for the wicked!

Since breaking it down into smaller chunks so to speak, i have got 2 "entry" condition studies working as i wanted them to.

So- i tried as best i could to take the logic from each one, and use them as entry conditions in the auto trading system;

The build succeeded, however; its doing the same thing as before regarding trade mgt.

PFA screenshots; 1 is the Trade DOM; so what i see is "FLAT" and the PNL is highlighted green, which it shouldnt if flat for a start, and the D:pnl box below, updates sporadically without seemingly opening a trade; ie i cant see the attached order fills on chart (the chart settings are correct)


Here's the iteration of the auto trade, having taken the "highlighting" logic from the two other working code (attached as txt files for convenience)

#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 LogDebugMessage(SCStudyInterfaceRef& sc, const SCString& message)
{
sc.AddMessageToLog(message, 0);
}

void LogErrorMessage(SCStudyInterfaceRef& sc, const SCString& message)
{
sc.AddMessageToLog(message, 1);
}

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_DAY;

// 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;

SCString message;
message.Format("Trade entered: PositionType=%d, Price=%f", positionType, price);
LogDebugMessage(sc, message);
}
else
{
SCString message;
message.Format("Failed to enter trade: PositionType=%d, Error=%d", positionType, result);
LogErrorMessage(sc, message);
}
}

bool CheckFlashGenieHighlight(SCStudyInterfaceRef& sc, bool isBid)
{
int numLevels = sc.Input[1].GetInt();
double threshold = sc.Input[0].GetInt();

s_MarketDepthEntry depthEntry;
for (int level = 0; level < numLevels; ++level)
{
if (isBid)
{
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingBid = sc.GetBidMarketDepthStackPullValueAtPrice(depthEntry.Price);
if (pullingStackingBid >= threshold)
{
LogDebugMessage(sc, "Flash Genie bid highlight condition met.");
return true;
}
}
}
else
{
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
double pullingStackingAsk = sc.GetAskMarketDepthStackPullValueAtPrice(depthEntry.Price);
if (pullingStackingAsk >= threshold)
{
LogDebugMessage(sc, "Flash Genie ask highlight condition met.");
return true;
}
}
}
}
return false;
}

bool CheckDeltaGenieHighlight(SCStudyInterfaceRef& sc, bool isBid)
{
int volumeProfileStudyID = sc.Input[0].GetInt();
int numLevelsToCheck = sc.Input[3].GetInt();

s_MarketDepthEntry depthEntry;
s_VolumeAtPriceV2 volumeAtPriceData;

for (int level = 0; level < numLevelsToCheck; ++level)
{
if (isBid)
{
if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
{
for (int priceIndex = 0; priceIndex < sc.GetNumPriceLevelsForStudyProfile(volumeProfileStudyID, 0); ++priceIndex)
{
if (sc.GetVolumeAtPriceDataForStudyProfile(volumeProfileStudyID, 0, priceIndex, volumeAtPriceData))
{
double vbpPrice = volumeAtPriceData.PriceInTicks * sc.TickSize;
if (fabs(vbpPrice - depthEntry.Price) < sc.TickSize / 2)
{
if (volumeAtPriceData.AskVolume < volumeAtPriceData.BidVolume)
{
LogDebugMessage(sc, "Delta Genie bid highlight condition met.");
return true;
}
}
}
}
}
}
else
{
if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
{
for (int priceIndex = 0; priceIndex < sc.GetNumPriceLevelsForStudyProfile(volumeProfileStudyID, 0); ++priceIndex)
{
if (sc.GetVolumeAtPriceDataForStudyProfile(volumeProfileStudyID, 0, priceIndex, volumeAtPriceData))
{
double vbpPrice = volumeAtPriceData.PriceInTicks * sc.TickSize;
if (fabs(vbpPrice - depthEntry.Price) < sc.TickSize / 2)
{
if (volumeAtPriceData.AskVolume > volumeAtPriceData.BidVolume)
{
LogDebugMessage(sc, "Delta Genie ask highlight condition met.");
return true;
}
}
}
}
}
}
}
return false;
}

SCSFExport scsf_SweepGenie(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Sweep Genie";
sc.GraphRegion = 0;
sc.AutoLoop = 0; // Manual loop enabled

// User inputs
sc.Input[0].Name = "Use Start/Stop Time";
sc.Input[0].SetYesNo(0); // Default to No

sc.Input[1].Name = "Start Time (HH:MM:SS)";
sc.Input[1].SetTime(HMS_TIME(9, 30, 0)); // Default start time

sc.Input[2].Name = "Stop Time (HH:MM:SS)";
sc.Input[2].SetTime(HMS_TIME(16, 0, 0)); // Default stop time

sc.Input[3].Name = "Volume Profile Study ID";
sc.Input[3].SetInt(7); // Set this to the actual study ID of the Volume Profile

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

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

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

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

sc.Input[8].Name = "Trade Type";
sc.Input[8].SetCustomInputStrings("Long;Short;Long & Short");
sc.Input[8].SetCustomInputIndex(2); // Default to Long & Short

sc.Input[9].Name = "Maximum Positions Allowed";
sc.Input[9].SetInt(1); // Default to 1 position

return;
}

bool useStartStopTime = sc.Input[0].GetYesNo();
SCDateTime startTime = sc.Input[1].GetTime();
SCDateTime stopTime = sc.Input[2].GetTime();
int volumeProfileStudyID = sc.Input[3].GetInt();
int orderQuantity = sc.Input[4].GetInt();
int stopLossTicks = sc.Input[5].GetInt();
int takeProfitTicks = sc.Input[6].GetInt();
int trailingStopOffsetTicks = sc.Input[7].GetInt();
int tradeType = sc.Input[8].GetIndex();
int maxPositionsAllowed = sc.Input[9].GetInt();

SCDateTime currentTime = sc.CurrentSystemDateTime;

// Check if current time is within trading hours
if (useStartStopTime && (currentTime < startTime || currentTime > stopTime))
{
LogDebugMessage(sc, "Outside of trading hours. No trades will be executed.");
return;
}

// Get current position size
s_SCPositionData positionData;
sc.GetTradePosition(positionData);
int currentPosition = positionData.PositionQuantity;

// Access the trade information
auto& tradeInfo = g_TradeInfo[sc.ChartNumber];

bool buyConditionMet = false;
bool sellConditionMet = false;
double entryPrice = sc.Close[sc.ArraySize - 1]; // Using the current price for entry
  // Calculate the sum of bid and ask market depth quantities and pulling/stacking values
  double bidSum = 0.0;
  double askSum = 0.0;
  double pullingStackingBidSum = 0.0;
  double pullingStackingAskSum = 0.0;

  s_MarketDepthEntry depthEntry;

  for (int level = 0; level < sc.GetBidMarketDepthNumberOfLevels(); ++level)
  {
    if (sc.GetBidMarketDepthEntryAtLevel(depthEntry, level))
    {
      bidSum += depthEntry.Quantity;
      pullingStackingBidSum += sc.GetBidMarketDepthStackPullValueAtPrice(depthEntry.Price);
    }
  }

  for (int level = 0; level < sc.GetAskMarketDepthNumberOfLevels(); ++level)
  {
    if (sc.GetAskMarketDepthEntryAtLevel(depthEntry, level))
    {
      askSum += depthEntry.Quantity;
      pullingStackingAskSum += sc.GetAskMarketDepthStackPullValueAtPrice(depthEntry.Price);
    }
  }

  double totalDepthSum = bidSum + askSum;
  double bidSumPercentage = (totalDepthSum > 0) ? (bidSum / totalDepthSum) * 100 : 0;
  double askSumPercentage = (totalDepthSum > 0) ? (askSum / totalDepthSum) * 100 : 0;

  double bidPullStackPercentage = (pullingStackingBidSum / (pullingStackingBidSum + pullingStackingAskSum)) * 100;
  double askPullStackPercentage = (pullingStackingAskSum / (pullingStackingBidSum + pullingStackingAskSum)) * 100;

// Buy Entry Conditions
  if (bidSumPercentage > askSumPercentage && // Bid sum percentage > ask sum percentage
    bidPullStackPercentage > askPullStackPercentage && // Bid pulling/stacking sum percentage > ask pulling/stacking sum percentage
    currentPosition < maxPositionsAllowed && // Current position below max positions allowed
    CheckFlashGenieHighlight(sc, true) && // Flash Genie bid highlight condition met
    CheckDeltaGenieHighlight(sc, true) && // Delta Genie bid highlight condition met
    tradeType != 1) // Long or Long & Short allowed
  {
    buyConditionMet = true;
  }

// Sell Entry Conditions
  else if (askSumPercentage > bidSumPercentage && // Ask sum percentage > bid sum percentage
      askPullStackPercentage > bidPullStackPercentage && // Ask pulling/stacking sum percentage > bid pulling/stacking sum percentage
      currentPosition > -maxPositionsAllowed && // Current position below max positions allowed
      CheckFlashGenieHighlight(sc, false) && // Flash Genie ask highlight condition met
      CheckDeltaGenieHighlight(sc, false) && // Delta Genie ask highlight condition met
      tradeType != 0) // Short or Long & Short allowed
  {
    sellConditionMet = true;
  }

// Execute Buy or Sell based on conditions
  if (buyConditionMet && !tradeInfo.tradeEntered)
  {
    PlaceBracketOrder(sc, tradeInfo, 1, orderQuantity, entryPrice, stopLossTicks, takeProfitTicks);
  }
  else if (sellConditionMet && !tradeInfo.tradeEntered)
  {
    PlaceBracketOrder(sc, tradeInfo, -1, orderQuantity, entryPrice, 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);

// Check for stop loss or take profit condition
if ((tradeInfo.positionType == 1 && (sc.Close[sc.ArraySize - 1] <= stopLossPrice || sc.Close[sc.ArraySize - 1] >= takeProfitPrice)) ||
(tradeInfo.positionType == -1 && (sc.Close[sc.ArraySize - 1] >= stopLossPrice || sc.Close[sc.ArraySize - 1] <= takeProfitPrice)))
{
sc.FlattenAndCancelAllOrders();
tradeInfo.tradeEntered = false;
tradeInfo.positionType = 0;
SCString message;
message.Format("Trade exited: PositionType=%d, Price=%f", tradeInfo.positionType, sc.Close[sc.ArraySize - 1]);
LogDebugMessage(sc, message);
}
else if (!tradeInfo.trailingStopActivated && tradeInfo.stopOrderID > 0 &&
((tradeInfo.positionType == 1 && sc.Close[sc.ArraySize - 1] >= trailingStopTriggerPrice) ||
(tradeInfo.positionType == -1 && sc.Close[sc.ArraySize - 1] <= 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);
LogDebugMessage(sc, message);
}
else
{
SCString message;
message.Format("Failed to modify stop order for trailing stop. Error: %d", modifyResult);
LogErrorMessage(sc, message);
}
}

// Manage Breakeven Stop Logic
if (!tradeInfo.stopMovedToBreakeven && tradeInfo.positionType != 0)
{
double breakevenPrice = tradeInfo.startPrice;
if ((tradeInfo.positionType == 1 && sc.Close[sc.ArraySize - 1] >= breakevenPrice) ||
(tradeInfo.positionType == -1 && sc.Close[sc.ArraySize - 1] <= 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);
LogDebugMessage(sc, message);
}
else
{
SCString message;
message.Format("Failed to modify stop order to breakeven. Error: %d", modifyResult);
LogErrorMessage(sc, message);
}
}
}

// Additional Exit Logic: Any other conditions for exiting the trade can be added here
} // End of trade management logic

return;
}


its almost like it is on "auto DRAIN" mode haha, i added the condition of sumbidmarketdepth/sumask marketdepth comparisons to try bolster and make entry logic a bit more robust, but unsure as to why its buggering up, because its like it isnt giving the trade a chance , i wanted to add sum bid mbo >/<sumask mbo or something to that effect (as in a sum of all bid/ask mbo queues over X levels), again to try make the system differentiatie between a buy and a sell without it consistently drawing down while appearing FLAT, almost like daylight robbery.
Date Time Of Last Edit: 2024-08-12 11:35:42
image1.png / V - Attached On 2024-08-12 08:00:32 UTC - Size: 52.67 KB - 37 views
attachmentflashgeniebymrb.txt - Attached On 2024-08-12 08:04:42 UTC - Size: 3.17 KB - 121 views
attachmentdeltageniebymrb.txt - Attached On 2024-08-12 08:04:55 UTC - Size: 5.19 KB - 118 views

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

Login

Login Page - Create Account