#include "sierrachart.h"
SCSFExport scsf_TradeManagementByStudy(SCStudyInterfaceRef sc)
{
SCInputRef Input_Enabled = sc.Input[0];
SCInputRef Input_OrderType = sc.Input[1];
SCInputRef Input_ControlSubgraphRef = sc.Input[2];
SCInputRef Input_AdjustmentTiming = sc.Input[3];
SCInputRef Input_AdjustmentFrequency = sc.Input[4];
SCInputRef Input_TrailingOffset = sc.Input[5];
SCInputRef Input_ACSButtonNumber = sc.Input[6];
SCInputRef Input_PositionType = sc.Input[7];
SCInputRef Input_DetailedLogging = sc.Input[8];
SCInputRef Input_OnlyModifyInOneDirection = sc.Input[9];
SCInputRef Input_Version = sc.Input[10];
SCInputRef Input_AllowZeroValues = sc.Input[11];
SCInputRef Input_AllowNegativeValues= sc.Input[12];
SCInputRef Input_AllowCustomPropertiesForControlBarButton = sc.Input[13];
SCInputRef Input_AttachedOrderToManage = sc.Input[14];
SCInputRef Input_ChangeToOffAllOtherCustomStudyButtonsOnEnable = sc.Input[15];
if (sc.SetDefaults)
{
sc.GraphName = "Trade Management by Study";
sc.AutoLoop = 0;
sc.GraphRegion = 0;
sc.CalculationPrecedence = VERY_LOW_PREC_LEVEL;
Input_Enabled.Name = "Enabled";
Input_Enabled.SetYesNo(0);
Input_OrderType.Name = "Order Type To Manage";
Input_OrderType.SetCustomInputStrings("Stops;Targets");
Input_OrderType.SetCustomInputIndex(0);
Input_ControlSubgraphRef.Name = "Controlling Subgraph Reference";
Input_ControlSubgraphRef.SetStudySubgraphValues(0, 0);
Input_AdjustmentTiming.Name = "Order Adjustment Timing";
Input_AdjustmentTiming.SetCustomInputStrings("Every N Seconds;On Bar Close");
Input_AdjustmentTiming.SetCustomInputIndex(1);
Input_AdjustmentFrequency.Name = "Adjustment Frequency (in Seconds)";
Input_AdjustmentFrequency.SetInt(5);
Input_TrailingOffset.Name = "Trailing Offset (in Ticks)";
Input_TrailingOffset.SetInt(2);
Input_ACSButtonNumber.Name = "ACS Control Bar Button # for Enable/Disable";
Input_ACSButtonNumber.SetInt(1);
Input_ACSButtonNumber.SetIntLimits(1, MAX_ACS_CONTROL_BAR_BUTTONS);
Input_PositionType. Name = "Position Type";
Input_PositionType.SetCustomInputStrings("All Positions;Long Only;Short Only");
Input_PositionType.SetCustomInputIndex(0);
Input_DetailedLogging.Name = "Detailed Logging (for debugging)";
Input_DetailedLogging.SetYesNo(0);
Input_OnlyModifyInOneDirection.Name = "Only Modify Stops In One Direction";
Input_OnlyModifyInOneDirection.SetYesNo(false);
Input_Version.SetInt(2);
Input_AllowZeroValues.Name = "Allow Zero Values";
Input_AllowZeroValues.SetYesNo(false);
Input_AllowNegativeValues.Name = "Allow Negative Values";
Input_AllowNegativeValues.SetYesNo(false);
Input_AllowCustomPropertiesForControlBarButton.Name = "Allow Custom 'Properties' for Control Bar Button";
Input_AllowCustomPropertiesForControlBarButton.SetYesNo(false);
Input_AttachedOrderToManage.Name = "Attached Order to Manage";
Input_AttachedOrderToManage.SetCustomInputStrings("Nearest;OCO Group 1;OCO Group 2;OCO Group 3;OCO Group 4;OCO Group 5;OCO Group 6;OCO Group 7;OCO Group 8");
Input_AttachedOrderToManage.SetCustomInputIndex(0);
Input_ChangeToOffAllOtherCustomStudyButtonsOnEnable.Name = "Change To Off All Other Custom Study Buttons On Enable";
Input_ChangeToOffAllOtherCustomStudyButtonsOnEnable.SetYesNo(false);
sc.ReceivePointerEvents = false;
return;
}
SCDateTime& LastAdjustmentDateTime = sc.GetPersistentSCDateTime(1);
int& MenuID = sc.GetPersistentInt(1);
int & LastLogMessageIdentifier =sc.GetPersistentInt(2);
if (sc.IsFullRecalculation)
{
sc.SetCustomStudyControlBarButtonHoverText(Input_ACSButtonNumber.GetInt(), "Enable/Disable Trade Management by Study");
if (!Input_AllowCustomPropertiesForControlBarButton.GetYesNo())
{
sc.SetCustomStudyControlBarButtonShortCaption(Input_ACSButtonNumber.GetInt(), "TradeMan\nStudy");
}
sc.SetCustomStudyControlBarButtonEnable(Input_ACSButtonNumber.GetInt(), Input_Enabled.GetBoolean() );
LastLogMessageIdentifier = 0;
}
if (Input_ChangeToOffAllOtherCustomStudyButtonsOnEnable.GetYesNo())
{
if (sc.MenuEventID >= ACS_BUTTON_1 && sc.MenuEventID <= ACS_BUTTON_150)
{
sc.SetCustomStudyControlBarButtonEnable(sc.PriorSelectedCustomStudyControlBarButtonNumber, false);
}
}
if (sc.MenuEventID == Input_ACSButtonNumber.GetInt())
{
const int ButtonState = (sc.PointerEventType == SC_ACS_BUTTON_ON) ? 1 : 0;
Input_Enabled.SetYesNo(ButtonState);
}
if (Input_Enabled.GetYesNo() == 0)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 1)
{
LastLogMessageIdentifier = 1;
sc.AddMessageToLog("Study not enabled.", 0);
}
return;
}
if (sc.ChartIsDownloadingHistoricalData(sc.ChartNumber))
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 2)
{
LastLogMessageIdentifier = 2;
sc.AddMessageToLog("No order adjustments performed because historical data is being downloaded for chart.", 0);
}
return;
}
sc.SendOrdersToTradeService = !sc.GlobalTradeSimulationIsOn;
s_SCPositionData PositionData;
sc.GetTradePosition (PositionData);
if (PositionData.PositionQuantity == 0)
{
LastAdjustmentDateTime.Clear();
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 3)
{
LastLogMessageIdentifier = 3;
sc.AddMessageToLog("Position does not exist.", 0);
}
return;
}
if (Input_PositionType.GetIndex() == 1 && PositionData.PositionQuantity < 0)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 4)
{
LastLogMessageIdentifier = 4;
SCString LogText("Position Type input is set to 'Long Only' and Position is Short. Position: ");
SCString QuantityString;
sc.OrderQuantityToString(PositionData.PositionQuantity, QuantityString);
LogText += QuantityString;
sc.AddMessageToLog(LogText, 0);
}
return;
}
if (Input_PositionType.GetIndex() == 2 && PositionData.PositionQuantity > 0)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 5)
{
LastLogMessageIdentifier = 5;
SCString LogText("Position Type input is set to 'Short Only' and Position is Long. Position: ");
SCString QuantityString;
sc.OrderQuantityToString(PositionData.PositionQuantity, QuantityString);
LogText += QuantityString;
sc.AddMessageToLog(LogText, 0);
}
return;
}
if (Input_AdjustmentTiming.GetInt() == 0 && (sc.LatestDateTimeForLastBar - LastAdjustmentDateTime) < SCDateTime::SECONDS_Fraction(Input_AdjustmentFrequency.GetFloat()))
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 6)
{
LastLogMessageIdentifier = 6;
sc.AddMessageToLog("Time interval has not elapsed yet for 'Every N Seconds'.", 0);
}
return;
}
LastAdjustmentDateTime = sc.LatestDateTimeForLastBar;
SCFloatArray ControllingSubgraph;
sc.GetStudyArrayUsingID(Input_ControlSubgraphRef.GetStudyID(), Input_ControlSubgraphRef.GetSubgraphIndex(), ControllingSubgraph);
s_SCTradeOrder ExistingTargetOrStopOrder;
int Result = 0;
if (Input_OrderType.IntValue == 0)
{
if (Input_AttachedOrderToManage.GetIndex() == 0)
{
Result = sc.GetNearestStopOrder(ExistingTargetOrStopOrder);
}
else
{
Result = sc.GetStopOrderInOCOGroupNumber(Input_AttachedOrderToManage.GetIndex(), ExistingTargetOrStopOrder);
}
}
else
{
if (Input_AttachedOrderToManage.GetIndex() == 0)
{
Result = sc.GetNearestTargetOrder(ExistingTargetOrStopOrder);
}
else
{
Result = sc.GetTargetOrderInOCOGroupNumber(Input_AttachedOrderToManage.GetIndex(), ExistingTargetOrStopOrder);
}
}
if (Result == SCTRADING_ORDER_ERROR)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 7)
{
LastLogMessageIdentifier = 7;
sc.AddMessageToLog("There is no Stop/Target Attached Order found.", 0);
}
return;
}
if (ExistingTargetOrStopOrder.OrderStatusCode != SCT_OSC_OPEN
&& ExistingTargetOrStopOrder.OrderStatusCode != SCT_OSC_HELD)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 8)
{
LastLogMessageIdentifier = 8;
sc.AddMessageToLog("The found Stop/Target order is not in an Open/Held state.", 0);
}
return;
}
int BarIndex = sc.ArraySize - 1;
const bool AdjustmentTimingIsOnBarClose = Input_AdjustmentTiming.GetIndex() == 1;
if(AdjustmentTimingIsOnBarClose)
{
BarIndex = sc.ArraySize - 2;
}
if (!Input_AllowZeroValues.GetYesNo() && ControllingSubgraph[BarIndex] == 0.0)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 9)
{
LastLogMessageIdentifier = 9;
if (AdjustmentTimingIsOnBarClose)
{
sc.AddMessageToLog("The 'Controlling Subgraph Reference' value is 0 at the bar prior to the last bar.", 0);
}
else
{
sc.AddMessageToLog("The 'Controlling Subgraph Reference' value is 0 at the last bar.", 0);
}
}
return;
}
if (!Input_AllowNegativeValues.GetYesNo() && ControllingSubgraph[BarIndex] < 0)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 15)
{
LastLogMessageIdentifier = 15;
sc.AddMessageToLog("The 'Controlling Subgraph Reference' value is < 0 at the last bar.", 0);
}
return;
}
double NewPrice = 0.0;
if (ExistingTargetOrStopOrder.BuySell == BSE_SELL)
{
NewPrice = ControllingSubgraph[BarIndex] - Input_TrailingOffset.GetInt() * sc.TickSize;
}
else if (ExistingTargetOrStopOrder.BuySell == BSE_BUY)
{
NewPrice = ControllingSubgraph[BarIndex] + Input_TrailingOffset.GetInt() * sc.TickSize;
}
else
return;
NewPrice= sc.RoundToTickSize(NewPrice);
if (sc.FormattedEvaluateUsingDoubles(ExistingTargetOrStopOrder.Price1, sc.BaseGraphValueFormat, EQUAL_OPERATOR, NewPrice, sc.BaseGraphValueFormat )
|| sc.FormattedEvaluateUsingDoubles(ExistingTargetOrStopOrder.LastModifyPrice1, sc.BaseGraphValueFormat, EQUAL_OPERATOR, NewPrice, sc.BaseGraphValueFormat)
)
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 10)
{
LastLogMessageIdentifier = 10;
SCString LogMessage;
LogMessage.Format("There is not a new price to modify the order to. Existing order: Price1=%f, LastModifyPrice1 =%f. New study subgraph price with offset=%f.", ExistingTargetOrStopOrder.Price1, ExistingTargetOrStopOrder.LastModifyPrice1, NewPrice);
sc.AddMessageToLog(LogMessage, 0);
}
return;
}
if (Input_OrderType.IntValue == 0
&& Input_OnlyModifyInOneDirection.GetYesNo() &&
((PositionData.PositionQuantity < 0 && sc.FormattedEvaluateUsingDoubles(NewPrice, sc.BaseGraphValueFormat, GREATER_OPERATOR, ExistingTargetOrStopOrder.Price1, sc.BaseGraphValueFormat)) ||
(PositionData.PositionQuantity > 0 && sc.FormattedEvaluateUsingDoubles(NewPrice, sc.BaseGraphValueFormat, LESS_OPERATOR, ExistingTargetOrStopOrder.Price1, sc.BaseGraphValueFormat)) ) )
{
if (Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 14)
{
LastLogMessageIdentifier = 14;
sc.AddMessageToLog("Modify stop price is in wrong direction.", 0);
}
return;
}
s_SCNewOrder ModifyOrder;
ModifyOrder.InternalOrderID = ExistingTargetOrStopOrder.InternalOrderID;
ModifyOrder.Price1 = NewPrice;
Result = sc.ModifyOrder(ModifyOrder);
if (Result == 1 && Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 11)
{
LastLogMessageIdentifier = 11;
SCString LogText;
LogText.Format("The Stop/Target order has been modified. Internal Order ID: %d. New Price: %f", ExistingTargetOrStopOrder.InternalOrderID, NewPrice);
sc.AddMessageToLog( LogText , 0);
}
else if (Result == SCT_SKIPPED_AUTO_TRADING_DISABLED && Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 13)
{
LastLogMessageIdentifier = 13;
SCString LogText;
LogText.Format("'Trade >> Auto Trading Enabled' is disabled.");
sc.AddMessageToLog( LogText , 0);
}
else if (Result != 1 && Input_DetailedLogging.GetYesNo() && LastLogMessageIdentifier != 12)
{
LastLogMessageIdentifier = 12;
SCString LogText;
LogText.Format("There was an error modifying the Stop/Target order. Internal Order ID: %d. New Price: %f. Error Code %d.", ExistingTargetOrStopOrder.InternalOrderID, NewPrice, Result);
sc.AddMessageToLog( LogText , 0);
}
}