Support Board
Date/Time: Sat, 23 Nov 2024 18:02:15 +0000
Post From: ACSIL Custom Autotrading System assistance
[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" , 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 :)
#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; } |