Login Page - Create Account

Support Board


Date/Time: Mon, 16 Sep 2024 19:14:13 +0000



Post From: Trading NQ, ES and YM from one single chart in a single account - Programming help needed

[2024-07-26 11:29:59]
User357489 - Posts: 67
Hi there, looking to do something similar, did you manage to resolve your issue? i have a crude chart (being the main price graph) and 2 additional symbols (es and eurofx).

Just wanted something "simple" in my mind, that when commodities cross equites/ currencies etc and the permutations thereof, then enter 2 trades, opposing eg +1 crude -1 es if crude crosses es from below etc. With that being said im not sure if it can be done, as they use independent scaling.

I have a skeleton code of sorts, compiles but doesn't output result and im stuck! any help, tips, pointers much appreciated, welcome to the code for your own use.


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

SCDLLName("Cross Trading System with Brackets and Crossover Markers")

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; // To track if stop loss has been moved to breakeven
int stopOrderID; // To store the stop order ID
int tradeSystemID; // Unique ID for the trading system
const char* symbol; // Symbol for the trade
};

std::unordered_map<int, TradeInfo> g_TradeInfo;

void PlaceBracketOrder(SCStudyInterfaceRef& sc, TradeInfo& tradeInfo, int positionType, int orderQuantity, double price, int tradeSystemID, double tickSize, const char* symbol)
{
s_SCNewOrder order;
order.OrderType = SCT_ORDERTYPE_MARKET;
order.OrderQuantity = orderQuantity;
order.TimeInForce = SCT_TIF_GTC;

// Define the attached orders
order.Target1Offset = 50 * tickSize; // 50 ticks profit target
order.Stop1Offset = -10 * tickSize; // 10 ticks stop loss

// 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; // Initialize to false when trade is entered
tradeInfo.tradeSystemID = tradeSystemID; // Store the trade system ID
tradeInfo.symbol = symbol; // Store the symbol for logging

// Store the stop order ID
tradeInfo.stopOrderID = order.Stop1InternalOrderID;

// Add a marker on the chart at the entry point
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_MARKER;
tool.BeginIndex = sc.Index;
tool.BeginValue = price;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.MarkerType = (positionType == 1) ? MARKER_ARROWUP : MARKER_ARROWDOWN;
tool.MarkerSize = 6;
tool.Color = (positionType == 1) ? RGB(0, 255, 0) : RGB(255, 0, 0); // Green for Buy, Red for Sell
sc.UseTool(tool);

// Log the trade entry
SCString message;
message.Format("Trade entered: %s %s at price %.2f", (positionType == 1) ? "Buy" : "Sell", symbol, price);
sc.AddMessageToLog(message, 0);
}
}

void AddCrossoverMarker(SCStudyInterfaceRef& sc, int index, double price, const char* symbol1, const char* symbol2)
{
s_UseTool tool;
tool.Clear();
tool.ChartNumber = sc.ChartNumber;
tool.DrawingType = DRAWING_MARKER;
tool.BeginIndex = index;
tool.BeginValue = price;
tool.AddMethod = UTAM_ADD_OR_ADJUST;
tool.MarkerType = MARKER_X;
tool.MarkerSize = 6;
tool.Color = RGB(255, 255, 255); // White color for crossover marker
tool.Text.Format("Crossover %s/%s", symbol1, symbol2);
sc.UseTool(tool);
}

SCSFExport scsf_CrossoverAutoTrading(SCStudyInterfaceRef sc)
{
if (sc.SetDefaults)
{
sc.GraphName = "Cross Trading System with Brackets and Crossover Markers";
sc.GraphRegion = 0;
sc.AutoLoop = 1;

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

sc.Input[1].Name = "Trade System ID";
sc.Input[1].SetInt(1); // Unique ID for this trading system

sc.Input[2].Name = "Start Time (HHMM)";
sc.Input[2].SetInt(930); // Default start time is 9:30 AM

sc.Input[3].Name = "End Time (HHMM)";
sc.Input[3].SetInt(1600); // Default end time is 4:00 PM

return;
}

int orderQuantity = sc.Input[0].GetInt();
int tradeSystemID = sc.Input[1].GetInt();
int startTime = sc.Input[2].GetInt();
int endTime = sc.Input[3].GetInt();

SCDateTime currentDateTime = sc.BaseDateTimeIn[sc.Index];
int currentTime = currentDateTime.GetTimeAsSCDateTime().GetTimeInSeconds() / 100; // Get time as HHMM

// Check if current time is within the specified trading window
if (currentTime < startTime || currentTime > endTime) {
return;
}

// Define tick sizes for different symbols
std::unordered_map<int, double> tickSizes;
tickSizes[2] = 0.25; // SP tick size
tickSizes[3] = 0.00005; // Euro tick size

// Variables to store the price data from the studies
SCFloatArray spData;
SCFloatArray euroData;

// Get the data from the specified studies
sc.GetStudyArrayUsingID(2, 4, spData);
sc.GetStudyArrayUsingID(3, 4, euroData);

// Ensure the data arrays are valid
if (spData.GetArraySize() == 0 || euroData.GetArraySize() == 0) {
return;
}

// Variables to store the price data
float oilPrice = sc.BaseDataIn[SC_LAST][sc.Index]; // Crude oil last price
float spPrice = spData[sc.Index];
float euroPrice = euroData[sc.Index];

// Check for crossover conditions
auto CheckCrossover = [&](float price1, float prevPrice1, float price2, float prevPrice2)
{
return (price1 > price2 && prevPrice1 <= prevPrice2) || (price1 < price2 && prevPrice1 >= prevPrice2);
};

// Function to execute trades with bracket orders
auto ExecuteBracketTrade = [&](float current1, float current2, int positionType1, int positionType2, const char* symbol1, const char* symbol2, double tickSize1, double tickSize2)
{
double price1 = current1;
double price2 = current2;

auto& tradeInfo1 = g_TradeInfo[sc.ChartNumber * 10 + positionType1];
auto& tradeInfo2 = g_TradeInfo[sc.ChartNumber * 10 + positionType2];

if (CheckCrossover(current1, sc.BaseDataIn[SC_LAST][sc.Index - 1], current2, sc.BaseDataIn[SC_LAST][sc.Index - 1]))
{
// Buy the first asset with a bracket order
PlaceBracketOrder(sc, tradeInfo1, 1, orderQuantity, price1, tradeSystemID, tickSize1, symbol1);

// Sell the second asset with a bracket order
PlaceBracketOrder(sc, tradeInfo2, -1, orderQuantity, price2, tradeSystemID, tickSize2, symbol2);

SCString message;
message.Format("+1 %s, -1 %s", symbol1, symbol2);
sc.AddMessageToLog(message, 0);

// Add crossover marker
AddCrossoverMarker(sc, sc.Index, price1, symbol1, symbol2);
}
else if (CheckCrossover(current2, sc.BaseDataIn[SC_LAST][sc.Index - 1], current1, sc.BaseDataIn[SC_LAST][sc.Index - 1]))
{
// Sell the first asset with a bracket order
PlaceBracketOrder(sc, tradeInfo1, -1, orderQuantity, price1, tradeSystemID, tickSize1, symbol1);

// Buy the second asset with a bracket order
PlaceBracketOrder(sc, tradeInfo2, 1, orderQuantity, price2, tradeSystemID, tickSize2, symbol2);

SCString message;
message.Format("-1 %s, +1 %s", symbol1, symbol2);
sc.AddMessageToLog(message, 0);

// Add crossover marker
AddCrossoverMarker(sc, sc.Index, price2, symbol1, symbol2);
}
};

ExecuteBracketTrade(oilPrice, spPrice, 1, -1, "CL", "ES", 0.01, 0.25); // Oil vs SP
ExecuteBracketTrade(oilPrice, euroPrice, 1, -1, "CL", "EUR", 0.01, 0.00005); // Oil vs Euro
ExecuteBracketTrade(spPrice, euroPrice, 1, -1, "ES", "EUR", 0.25, 0.00005); // SP vs Euro
}

imageScreenshot 2024-07-26 122641.png / V - Attached On 2024-07-26 11:27:22 UTC - Size: 23.31 KB - 31 views