Login Page - Create Account

Support Board


Date/Time: Sat, 23 Nov 2024 17:56:54 +0000



Post From: ACSIL Custom Autotrading System assistance

[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 - 122 views
attachmentdeltageniebymrb.txt - Attached On 2024-08-12 08:04:55 UTC - Size: 5.19 KB - 118 views