#include "sierrachart.h"
SCSFExport scsf_TradingSystemBasedOnAlertCondition(SCStudyInterfaceRef sc)
{
SCInputRef Input_Enabled = sc.Input[0];
SCInputRef Input_NumBarsToCalculate = sc.Input[1];
SCInputRef Input_DrawStyleOffsetType = sc.Input[2];
SCInputRef Input_PercentageOrTicksOffset = sc.Input[3];
SCInputRef Input_OrderActionOnAlert = sc.Input[4];
SCInputRef Input_EvaluateOnBarCloseOnly = sc.Input[5];
SCInputRef Input_SendTradeOrdersToTradeService = sc.Input[6];
SCInputRef Input_MaximumPositionAllowed = sc.Input[7];
SCInputRef Input_MaximumLongTradesPerDay = sc.Input[8];
SCInputRef Input_MaximumShortTradesPerDay = sc.Input[9];
SCInputRef Input_EnableDebuggingOutput = sc.Input[10];
SCInputRef Input_CancelAllWorkingOrdersOnExit = sc.Input[11];
SCInputRef Input_AllowTradingOnlyDuringTimeRange = sc.Input[12];
SCInputRef Input_StartTimeForAllowedTimeRange = sc.Input[13];
SCInputRef Input_EndTimeForAllowedTimeRange = sc.Input[14];
SCInputRef Input_AllowOnlyOneTradePerBar = sc.Input[15];
SCInputRef Input_Version = sc.Input[16];
SCInputRef Input_SupportReversals = sc.Input[17];
SCInputRef Input_AllowMultipleEntriesInSameDirection = sc.Input[18];
SCInputRef Input_AllowEntryWithWorkingOrders = sc.Input[19];
SCInputRef Input_ControlBarButtonNumberForEnableDisable = sc.Input[20];
SCInputRef Input_CancelAllOrdersOnEntries = sc.Input[21];
SCInputRef Input_CancelAllOrdersOnReversals = sc.Input[22];
SCSubgraphRef Subgraph_BuyEntry = sc.Subgraph[0];
SCSubgraphRef Subgraph_SellEntry = sc.Subgraph[1];
if (sc.SetDefaults)
{
sc.GraphName = "Trading System Based on Alert Condition";
sc.StudyDescription = "";
sc.AutoLoop = 0;
sc.GraphRegion = 0;
sc.CalculationPrecedence = LOW_PREC_LEVEL;
Input_Enabled.Name = "Enabled";
Input_Enabled.SetYesNo(false);
Input_NumBarsToCalculate.Name = "Number of Bars to Calculate";
Input_NumBarsToCalculate.SetInt(2000);
Input_NumBarsToCalculate.SetIntLimits(1, MAX_STUDY_LENGTH);
Input_OrderActionOnAlert.Name = "Order Action on Alert";
Input_OrderActionOnAlert.SetCustomInputStrings("Buy Entry;Buy Exit;Sell Entry;Sell Exit;Flatten");
Input_OrderActionOnAlert.SetCustomInputIndex(0);
Input_EvaluateOnBarCloseOnly.Name = "Evaluate on Bar Close Only";
Input_EvaluateOnBarCloseOnly.SetYesNo(true);
Input_SendTradeOrdersToTradeService.Name = "Send Trade Orders to Trade Service";
Input_SendTradeOrdersToTradeService.SetYesNo(false);
Input_MaximumPositionAllowed.Name = "Maximum Position Allowed";
Input_MaximumPositionAllowed.SetInt(1);
Input_MaximumLongTradesPerDay.Name = "Maximum Long Trades Per Day";
Input_MaximumLongTradesPerDay.SetInt(2);
Input_MaximumShortTradesPerDay.Name = "Maximum Short Trades Per Day";
Input_MaximumShortTradesPerDay.SetInt(2);
Input_CancelAllWorkingOrdersOnExit.Name = "Cancel All Working Orders On Exit";
Input_CancelAllWorkingOrdersOnExit.SetYesNo(false);
Input_EnableDebuggingOutput.Name = "Enable Debugging Output";
Input_EnableDebuggingOutput.SetYesNo(false);
Input_AllowTradingOnlyDuringTimeRange.Name = "Allow Trading Only During Time Range";
Input_AllowTradingOnlyDuringTimeRange.SetYesNo(false);
Input_StartTimeForAllowedTimeRange.Name = "Start Time For Allowed Time Range";
Input_StartTimeForAllowedTimeRange.SetTime(HMS_TIME(0, 0, 0));
Input_EndTimeForAllowedTimeRange.Name = "End Time For Allowed Time Range";
Input_EndTimeForAllowedTimeRange.SetTime(HMS_TIME(23, 59, 59));
Input_AllowOnlyOneTradePerBar.Name = "Allow Only One Trade per Bar";
Input_AllowOnlyOneTradePerBar.SetYesNo(true);
Input_SupportReversals.Name = "Support Reversals";
Input_SupportReversals.SetYesNo(false);
Input_AllowMultipleEntriesInSameDirection.Name = "Allow Multiple Entries In Same Direction";
Input_AllowMultipleEntriesInSameDirection.SetYesNo(false);
Input_AllowEntryWithWorkingOrders.Name = "Allow Entry With Working Orders";
Input_AllowEntryWithWorkingOrders.SetYesNo(false);
Input_ControlBarButtonNumberForEnableDisable.Name = "ACS Control Bar Button # for Enable/Disable";
Input_ControlBarButtonNumberForEnableDisable.SetInt(1);
Input_ControlBarButtonNumberForEnableDisable.SetIntLimits(1, MAX_ACS_CONTROL_BAR_BUTTONS);
Input_CancelAllOrdersOnEntries.Name = "Cancel All Orders on Entries";
Input_CancelAllOrdersOnEntries.SetYesNo(false);
Input_CancelAllOrdersOnReversals.Name = "Cancel All Orders on Reversals";
Input_CancelAllOrdersOnReversals.SetYesNo(false);
Input_Version.SetInt(2);
Subgraph_BuyEntry.Name = "Buy";
Subgraph_BuyEntry.DrawStyle = DRAWSTYLE_POINT_ON_HIGH;
Subgraph_BuyEntry.LineWidth = 5;
Subgraph_SellEntry.Name = "Sell";
Subgraph_SellEntry.DrawStyle = DRAWSTYLE_POINT_ON_LOW;
Subgraph_SellEntry.LineWidth = 5;
sc.AllowMultipleEntriesInSameDirection = false;
sc.SupportReversals = false;
sc.AllowOppositeEntryWithOpposingPositionOrOrders = false;
sc.SupportAttachedOrdersForTrading = false;
sc.UseGUIAttachedOrderSetting = true;
sc.CancelAllOrdersOnEntriesAndReversals = false;
sc.AllowEntryWithWorkingOrders = false;
sc.AllowOnlyOneTradePerBar = true;
sc.MaintainTradeStatisticsAndTradesData = true;
return;
}
if (Input_Version.GetInt() < 2)
{
Input_AllowOnlyOneTradePerBar.SetYesNo(true);
Input_Version.SetInt(2);
}
sc.AllowOnlyOneTradePerBar = Input_AllowOnlyOneTradePerBar.GetYesNo();
sc.SupportReversals = false;
sc.MaximumPositionAllowed = Input_MaximumPositionAllowed.GetInt();
sc.SendOrdersToTradeService = Input_SendTradeOrdersToTradeService.GetYesNo();
sc.CancelAllWorkingOrdersOnExit = Input_CancelAllWorkingOrdersOnExit.GetYesNo();
sc.CancelAllOrdersOnEntries = Input_CancelAllOrdersOnEntries.GetYesNo();
sc.CancelAllOrdersOnReversals = Input_CancelAllOrdersOnReversals.GetYesNo();
sc.SupportReversals = Input_SupportReversals.GetYesNo();
sc.AllowMultipleEntriesInSameDirection = Input_AllowMultipleEntriesInSameDirection.GetYesNo();
sc.AllowEntryWithWorkingOrders = Input_AllowEntryWithWorkingOrders.GetYesNo();
if (sc.MenuEventID == Input_ControlBarButtonNumberForEnableDisable.GetInt())
{
const int ButtonState = (sc.PointerEventType == SC_ACS_BUTTON_ON) ? 1 : 0;
Input_Enabled.SetYesNo(ButtonState);
}
if (!Input_Enabled.GetYesNo() || sc.LastCallToFunction)
return;
int& r_LastDebugMessageType = sc.GetPersistentInt(1);
int& r_PriorFormulaState = sc.GetPersistentInt(2);
if (sc.IsFullRecalculation)
{
r_LastDebugMessageType = 0;
r_PriorFormulaState = 0;
sc.SetCustomStudyControlBarButtonHoverText(Input_ControlBarButtonNumberForEnableDisable.GetInt(), "Enable/Disable Trade System Based on Alert Condition");
sc.SetCustomStudyControlBarButtonEnable(Input_ControlBarButtonNumberForEnableDisable.GetInt(), Input_Enabled.GetBoolean());
}
int LastIndex = sc.ArraySize - 1;
if (Input_EvaluateOnBarCloseOnly.GetYesNo())
--LastIndex;
const int EarliestIndexToCalculate = LastIndex - Input_NumBarsToCalculate.GetInt() + 1;
int CalculationStartIndex = sc.UpdateStartIndex;
if (CalculationStartIndex < EarliestIndexToCalculate)
CalculationStartIndex = EarliestIndexToCalculate;
sc.EarliestUpdateSubgraphDataArrayIndex = CalculationStartIndex;
s_SCPositionData PositionData;
n_ACSIL::s_TradeStatistics TradeStatistics;
SCString TradeNotAllowedReason;
const bool IsDownloadingHistoricalData = sc.ChartIsDownloadingHistoricalData(sc.ChartNumber) != 0;
bool IsTradeAllowed = !sc.IsFullRecalculation && !IsDownloadingHistoricalData;
if (Input_EnableDebuggingOutput.GetYesNo())
{
if (sc.IsFullRecalculation)
TradeNotAllowedReason = "Is full recalculation";
else if (IsDownloadingHistoricalData)
TradeNotAllowedReason = "Downloading historical data";
}
if (Input_AllowTradingOnlyDuringTimeRange.GetYesNo())
{
const SCDateTime LastBarDateTime = sc.LatestDateTimeForLastBar;
const int LastBarTimeInSeconds = LastBarDateTime.GetTimeInSeconds();
bool LastIndexIsInAllowedTimeRange = false;
if (Input_StartTimeForAllowedTimeRange.GetTime() <= Input_EndTimeForAllowedTimeRange.GetTime())
{
LastIndexIsInAllowedTimeRange = (LastBarTimeInSeconds >= Input_StartTimeForAllowedTimeRange.GetTime()
&& LastBarTimeInSeconds <= Input_EndTimeForAllowedTimeRange.GetTime()
);
}
else
{
LastIndexIsInAllowedTimeRange = (LastBarTimeInSeconds >= Input_StartTimeForAllowedTimeRange.GetTime()
|| LastBarTimeInSeconds <= Input_EndTimeForAllowedTimeRange.GetTime()
);
}
if (!LastIndexIsInAllowedTimeRange)
{
IsTradeAllowed = false;
TradeNotAllowedReason = "Not within allowed time range";
}
}
bool ParseAndSetFormula = sc.IsFullRecalculation;
SCString DateTimeString;
for (int BarIndex = CalculationStartIndex; BarIndex <= LastIndex; ++BarIndex)
{
if (Input_EnableDebuggingOutput.GetYesNo())
{
DateTimeString = ". BarDate-Time: ";
DateTimeString += sc.DateTimeToString(sc.BaseDateTimeIn[BarIndex], FLAG_DT_COMPLETE_DATETIME_US);
}
int FormulaResult = sc.EvaluateAlertConditionFormulaAsBoolean(BarIndex, ParseAndSetFormula);
ParseAndSetFormula = false;
bool StateHasChanged = true;
if (FormulaResult == r_PriorFormulaState)
{
TradeNotAllowedReason = "Formula state has not changed. Current state: ";
TradeNotAllowedReason += FormulaResult ? "True" : "False";
StateHasChanged = false;
}
r_PriorFormulaState = FormulaResult;
if (FormulaResult != 0)
{
if (IsTradeAllowed)
{
sc.GetTradePosition(PositionData);
sc.GetTradeStatisticsForSymbolV2(n_ACSIL::STATS_TYPE_DAILY_ALL_TRADES, TradeStatistics);
}
if (Input_OrderActionOnAlert.GetIndex() == 0)
{
Subgraph_BuyEntry[BarIndex] = 1;
Subgraph_SellEntry[BarIndex] = 0;
if (IsTradeAllowed && StateHasChanged)
{
if (PositionData.PositionQuantityWithAllWorkingOrders == 0
|| Input_AllowMultipleEntriesInSameDirection.GetYesNo()
|| Input_SupportReversals.GetYesNo())
{
if (TradeStatistics.LongTrades < Input_MaximumLongTradesPerDay.GetInt())
{
s_SCNewOrder NewOrder;
NewOrder.OrderQuantity = sc.TradeWindowOrderQuantity;
NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
int Result = static_cast<int>(sc.BuyEntry(NewOrder, BarIndex));
if (Result < 0)
sc.AddMessageToTradeServiceLog(sc.GetTradingErrorTextMessage(Result), false, true);
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Buy Entry signal ignored. Maximum Long Trades reached.", false, true);
}
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Buy Entry signal ignored. Position exists.", false, true);
}
}
else if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 1)
{
SCString MessageText("Trading is not allowed. Reason: ");
MessageText += TradeNotAllowedReason;
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 1;
}
}
else if (Input_OrderActionOnAlert.GetIndex() == 1)
{
Subgraph_BuyEntry[BarIndex] = 0;
Subgraph_SellEntry[BarIndex] = 1;
if (IsTradeAllowed && StateHasChanged)
{
if (PositionData.PositionQuantity > 0)
{
s_SCNewOrder NewOrder;
NewOrder.OrderQuantity = sc.TradeWindowOrderQuantity;
NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
int Result = static_cast<int>(sc.BuyExit(NewOrder, BarIndex));
if (Result < 0)
sc.AddMessageToTradeServiceLog(sc.GetTradingErrorTextMessage(Result), false, true);
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Buy Exit signal ignored. Long position does not exist.", false, true);
}
else
r_PriorFormulaState = 0;
}
else if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 1)
{
SCString MessageText("Trading is not allowed. Reason: ");
MessageText += TradeNotAllowedReason;
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 1;
}
}
else if(Input_OrderActionOnAlert.GetIndex() == 2)
{
Subgraph_BuyEntry[BarIndex] = 0;
Subgraph_SellEntry[BarIndex] = 1;
if (IsTradeAllowed && StateHasChanged)
{
if (PositionData.PositionQuantityWithAllWorkingOrders == 0
|| Input_AllowMultipleEntriesInSameDirection.GetYesNo()
|| Input_SupportReversals.GetYesNo())
{
if (TradeStatistics.ShortTrades < Input_MaximumShortTradesPerDay.GetInt())
{
s_SCNewOrder NewOrder;
NewOrder.OrderQuantity = sc.TradeWindowOrderQuantity;
NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
int Result = static_cast<int>(sc.SellEntry(NewOrder, BarIndex));
if (Result < 0)
sc.AddMessageToTradeServiceLog(sc.GetTradingErrorTextMessage(Result), false, true);
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Sell Entry signal ignored. Maximum Short Trades reached.", false, true);
}
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Sell Entry signal ignored. Position exists.", false, true);
}
}
else if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 1)
{
SCString MessageText("Trading is not allowed. Reason: ");
MessageText += TradeNotAllowedReason;
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 1;
}
}
else if (Input_OrderActionOnAlert.GetIndex() == 3)
{
Subgraph_BuyEntry[BarIndex] = 1;
Subgraph_SellEntry[BarIndex] = 0;
if (IsTradeAllowed && StateHasChanged)
{
if (PositionData.PositionQuantity < 0)
{
s_SCNewOrder NewOrder;
NewOrder.OrderQuantity = sc.TradeWindowOrderQuantity;
NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
int Result = static_cast<int>(sc.SellExit(NewOrder, BarIndex));
if (Result < 0)
sc.AddMessageToTradeServiceLog(sc.GetTradingErrorTextMessage(Result), false, true);
}
else if (Input_EnableDebuggingOutput.GetYesNo())
{
sc.AddMessageToTradeServiceLog("Sell Exit signal ignored. Short position does not exist.", false, true);
}
else
r_PriorFormulaState = 0;
}
else if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 1)
{
SCString MessageText("Trading is not allowed. Reason: ");
MessageText += TradeNotAllowedReason;
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 1;
}
}
else if (Input_OrderActionOnAlert.GetIndex() == 4)
{
if (IsTradeAllowed && StateHasChanged)
{
int Result = sc.FlattenAndCancelAllOrders();
if (Result < 0)
{
sc.AddMessageToTradeServiceLog(sc.GetTradingErrorTextMessage(Result), false, true);
}
}
else if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 3)
{
SCString MessageText("Trading is not allowed. Reason: ");
MessageText += TradeNotAllowedReason;
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 3;
}
}
}
else
{
Subgraph_BuyEntry[BarIndex] = 0;
Subgraph_SellEntry[BarIndex] = 0;
if (Input_EnableDebuggingOutput.GetYesNo() && r_LastDebugMessageType != 2)
{
SCString MessageText("Formula is not true");
if (!TradeNotAllowedReason.IsEmpty())
{
MessageText += ". ";
MessageText += TradeNotAllowedReason;
}
MessageText += DateTimeString;
sc.AddMessageToTradeServiceLog(MessageText, 0);
r_LastDebugMessageType = 2;
}
}
if (!IsTradeAllowed)
r_PriorFormulaState = 0;
}
if (sc.IsFullRecalculation)
r_LastDebugMessageType = 0;
}