#include "sierrachart.h" /*==========================================================================*/ SCSFExport scsf_BidAskQuantityTriggeredStopOrder(SCStudyInterfaceRef sc) { SCSubgraphRef Subgraph_OrderLine = sc.Subgraph[0]; SCInputRef Input_NumberOfBarsBack = sc.Input[3]; SCInputRef Input_BidAskQuantityThreshold = sc.Input[4]; SCInputRef Input_DebuggingOutput = sc.Input[5]; if (sc.SetDefaults) { sc.GraphName = "Trading: Bid/Ask Quantity Triggered Stop Order"; sc.AutoLoop = 0;//Manual looping sc.GraphRegion = 0; sc.ScaleRangeType= SCALE_SAMEASREGION; Subgraph_OrderLine.Name = "Stop Order"; Subgraph_OrderLine.PrimaryColor = COLOR_GREEN; Subgraph_OrderLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_LEFT_EDGE | LL_VALUE_ALIGN_BELOW | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_ABOVE; Subgraph_OrderLine.DrawZeros = false; Input_NumberOfBarsBack.Name = "Number of Bars Back to Display"; Input_NumberOfBarsBack.SetInt(20); Input_BidAskQuantityThreshold.Name = "Bid Ask Quantity Threshold"; Input_BidAskQuantityThreshold.SetInt(100); Input_DebuggingOutput.Name = "Debugging Output"; Input_DebuggingOutput.SetYesNo(false); sc.ReceivePointerEvents = ACS_RECEIVE_POINTER_EVENTS_ALWAYS; sc.AllowMultipleEntriesInSameDirection = 1; sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1; sc.CancelAllOrdersOnEntriesAndReversals = 0; sc.AllowOnlyOneTradePerBar = 0; sc.SupportReversals = 0; sc.AllowEntryWithWorkingOrders = 1; sc.SupportAttachedOrdersForTrading = 0; sc.UseGUIAttachedOrderSetting = 1; //use a high-value to effectively not put any Position Quantity restrictions sc.MaximumPositionAllowed = 100000000; return; } int& r_SetSellOrderPriceMenuID = sc.GetPersistentInt(1); int& r_SetBuyOrderPriceMenuID = sc.GetPersistentInt(2); int& r_CancelOrderMenuID = sc.GetPersistentInt(3); int& r_OrderType = sc.GetPersistentInt(4); int& r_LastSubgraphUpdateIndex = sc.GetPersistentInt(5); double& r_OrderPrice = sc.GetPersistentDouble(6); int& r_OrderModifyMode = sc.GetPersistentInt(7); int& r_LastDebugMessageType = sc.GetPersistentInt(8); int& r_OrderEvaluationCount = sc.GetPersistentInt(9); int& r_StopOrderActive = sc.GetPersistentInt(10); __int64& r_LastTimeAndSalesRecordSequence = sc.GetPersistentInt64(11); if (sc.LastCallToFunction) { // Be sure to remove the menu commands when study is removed sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_SetBuyOrderPriceMenuID); sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_SetSellOrderPriceMenuID); sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); return; } if (sc.UpdateStartIndex == 0) { if (r_SetBuyOrderPriceMenuID <= 0) r_SetBuyOrderPriceMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Set Buy Stop Price"); if (r_SetSellOrderPriceMenuID <= 0) r_SetSellOrderPriceMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Set Sell Stop Price"); r_LastSubgraphUpdateIndex = 0; r_LastDebugMessageType = 0; r_LastTimeAndSalesRecordSequence = 0; } if (sc.MenuEventID != 0) { if (!sc.ChartTradeModeEnabled) { sc.AddMessageToLog("Chart Trade Mode is not active. No action performed.", 1); return; } } // handle set trigger price menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_SetBuyOrderPriceMenuID) { // Get price that the user selected. This is already rounded to the nearest price tick r_OrderPrice = sc.ChartTradingOrderPrice; r_OrderType = 1; // Buy if (r_CancelOrderMenuID <=0) r_CancelOrderMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Cancel Stop Order"); Subgraph_OrderLine.Name.Format("Buy Stop (%d)", Input_BidAskQuantityThreshold.GetInt()); } else if (sc.MenuEventID != 0 && sc.MenuEventID == r_SetSellOrderPriceMenuID) { // Get price that the user selected. This is already rounded to the nearest price tick r_OrderPrice = sc.ChartTradingOrderPrice; r_OrderType = -1; // Sell if (r_CancelOrderMenuID <=0) r_CancelOrderMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Cancel Stop Order"); Subgraph_OrderLine.Name.Format("Sell Stop (%d)", Input_BidAskQuantityThreshold.GetInt()); } // handle cancel order menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_CancelOrderMenuID) { r_OrderType = 0; r_OrderPrice = 0.0; r_StopOrderActive = 0; sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID) ; r_CancelOrderMenuID = 0; r_LastTimeAndSalesRecordSequence = 0; } //Handle order modifications if (r_OrderType != 0) { if (sc.PointerEventType == SC_POINTER_BUTTON_DOWN && r_OrderPrice >= sc.ChartTradingOrderPrice - sc.TickSize && r_OrderPrice <= sc.ChartTradingOrderPrice + sc.TickSize) r_OrderModifyMode = 1; else if (sc.PointerEventType == SC_POINTER_BUTTON_UP) r_OrderModifyMode = 0; if (r_OrderModifyMode == 1 && sc.PointerEventType == SC_POINTER_MOVE) { r_OrderPrice = sc.ChartTradingOrderPrice; } } //Update the subgraph int StartingOutputIndex = sc.ArraySize - Input_NumberOfBarsBack.GetInt(); for (int BarIndex = r_LastSubgraphUpdateIndex; BarIndex < StartingOutputIndex; BarIndex++) { Subgraph_OrderLine[BarIndex] = 0.0f; } r_LastSubgraphUpdateIndex = StartingOutputIndex; for (int BarIndex = StartingOutputIndex; BarIndex < sc.ArraySize; BarIndex++) { Subgraph_OrderLine[BarIndex] = static_cast(r_OrderPrice); } //Evaluate for order triggering //For safety we must never do any order management while historical data is being downloaded. if (sc.ChartIsDownloadingHistoricalData(sc.ChartNumber)) { if (Input_DebuggingOutput.GetYesNo() && r_LastDebugMessageType != 1) { sc.AddMessageToLog("Chart is downloading historical data. Order evaluation not performed.", 0); r_LastDebugMessageType = 1; } return; } if (r_OrderType == 0) { if (Input_DebuggingOutput.GetYesNo() && r_LastDebugMessageType != 2) { sc.AddMessageToLog("Order price is not set. Order evaluation not performed.", 0); r_LastDebugMessageType = 2; } return; } sc.SendOrdersToTradeService = !sc.GlobalTradeSimulationIsOn; bool PerformReset = false; //Iterate through new time and sales data c_SCTimeAndSalesArray TimeSalesArray; sc.GetTimeAndSales(TimeSalesArray); if (TimeSalesArray.Size() == 0) return;//do nothing. if (r_LastTimeAndSalesRecordSequence == 0) { r_LastTimeAndSalesRecordSequence = TimeSalesArray[TimeSalesArray.Size()-1].Sequence; return; } for (int TSIndex = 0; TSIndex < TimeSalesArray.Size(); ++TSIndex) { s_TimeAndSales Record = TimeSalesArray[TSIndex]; Record *= sc.RealTimePriceMultiplier; //Do not process already processed sequence numbers. if (Record.Sequence <= r_LastTimeAndSalesRecordSequence) continue; r_LastTimeAndSalesRecordSequence = Record.Sequence; if (Record.Type != SC_TS_ASK && Record.Type != SC_TS_BID) continue; //Check for triggering. Order price needs to equal bid or ask to be triggered. if (!r_StopOrderActive) { if (r_OrderType == -1 ) { if (sc.FormattedEvaluateUsingDoubles( r_OrderPrice, sc.BaseGraphValueFormat, EQUAL_OPERATOR, sc.Bid , sc.BaseGraphValueFormat)) r_StopOrderActive = 1; } else if (r_OrderType == 1 ) { if (sc.FormattedEvaluateUsingDoubles( r_OrderPrice, sc.BaseGraphValueFormat, EQUAL_OPERATOR, sc.Ask , sc.BaseGraphValueFormat)) r_StopOrderActive = 1; } } } // Check for sell stop order trigger conditions. Best Bid Quantity if it is a sell stop if (r_StopOrderActive != 0 && r_OrderType == -1 && sc.Bid != 0.0) { float CurrentPriceToOrderPriceDifference = static_cast(r_OrderPrice) - sc.Bid; if ((sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, EQUAL_OPERATOR, 0.0 , sc.BaseGraphValueFormat) && sc.BidSize <= Input_BidAskQuantityThreshold.GetInt()) || (sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, GREATER_OPERATOR, 0.0 , sc.BaseGraphValueFormat) && sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, static_cast(8) * sc.TickSize , sc.BaseGraphValueFormat)) ) { if (Input_DebuggingOutput.GetYesNo()) sc.AddMessageToLog("Sell stop is triggered. Sending sell Market order.", 0); s_SCNewOrder Order; //Need to use a market order type since the price triggering is determined within this function and to avoid possible rejection of a stop order by the external trading service based upon the price. Order.OrderType = SCT_ORDERTYPE_MARKET; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.SellOrder(Order)); PerformReset = true; if (Result <= 0) { SCString ErrorText; ErrorText = "Sell order error. "; ErrorText += sc.GetTradingErrorTextMessage(Result); sc.AddMessageToLog(ErrorText, 1); } } else { if (Input_DebuggingOutput.GetYesNo() && r_OrderEvaluationCount % 10 == 0) { SCString MessageText; MessageText.Format( "Sell stop order not triggered. Bid=%f, OrderPrice=%f, BidQuantity=%d, BidQuantityThreshold=%d.", sc.Bid, r_OrderPrice, sc.BidSize , Input_BidAskQuantityThreshold.GetInt()); sc.AddMessageToLog(MessageText, 0); } } } // Check for buy stop order trigger conditions. Best Ask Quantity if it is a buy stop if (r_StopOrderActive != 0 && r_OrderType == 1 && sc.Ask != 0.0) { float CurrentPriceToOrderPriceDifference = sc.Ask - static_cast(r_OrderPrice); if ((sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, EQUAL_OPERATOR, 0.0 , sc.BaseGraphValueFormat) && sc.AskSize <= Input_BidAskQuantityThreshold.GetInt()) || (sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, GREATER_OPERATOR, 0.0 , sc.BaseGraphValueFormat) && sc.FormattedEvaluate( CurrentPriceToOrderPriceDifference, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, static_cast(8) * sc.TickSize , sc.BaseGraphValueFormat)) ) { if (Input_DebuggingOutput.GetYesNo()) sc.AddMessageToLog("Buy stop is triggered. Sending buy Market order.", 0); s_SCNewOrder Order; Order.OrderType = SCT_ORDERTYPE_MARKET; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.BuyOrder(Order)); PerformReset = true; if (Result <= 0) { SCString ErrorText; ErrorText = "Buy order error. "; ErrorText += sc.GetTradingErrorTextMessage(Result); sc.AddMessageToLog(ErrorText, 1); } } else { if (Input_DebuggingOutput.GetYesNo() && r_OrderEvaluationCount % 10 == 0) { SCString MessageText; MessageText.Format( "Buy stop order not triggered. Ask=%f, OrderPrice=%f, AskQuantity=%d, AskQuantityThreshold=%d.", sc.Ask, r_OrderPrice, sc.AskSize , Input_BidAskQuantityThreshold.GetInt()); sc.AddMessageToLog(MessageText, 0); } } } ++r_OrderEvaluationCount; if (PerformReset) { sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); r_CancelOrderMenuID = 0; r_OrderPrice = 0.0; r_OrderType = 0; r_OrderEvaluationCount = 0; r_StopOrderActive = 0; for (int ArrayIndex = r_LastSubgraphUpdateIndex; ArrayIndex < sc.ArraySize; ArrayIndex++) Subgraph_OrderLine[ArrayIndex] = 0; } } /*==========================================================================*/ SCSFExport scsf_MarketIfTouchedOrder(SCStudyInterfaceRef sc) { SCSubgraphRef Subgraph_OrderLine = sc.Subgraph[0]; SCInputRef Input_NumberOfBarsBack = sc.Input[0]; if (sc.SetDefaults) { sc.GraphName = "Trading: Market if Touched Order"; sc.AutoLoop = 0;//Manual looping sc.GraphRegion = 0; sc.ScaleRangeType= SCALE_SAMEASREGION; Input_NumberOfBarsBack.Name = "Number of Bars Back to Display"; Input_NumberOfBarsBack.SetInt(20); Subgraph_OrderLine.Name = "MIT Order"; Subgraph_OrderLine.PrimaryColor = COLOR_GREEN; Subgraph_OrderLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_LEFT_EDGE | LL_VALUE_ALIGN_BELOW | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_ABOVE; Subgraph_OrderLine.DrawZeros = false; sc.AllowMultipleEntriesInSameDirection = 1; sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1; sc.CancelAllOrdersOnEntriesAndReversals = 0; sc.AllowOnlyOneTradePerBar = 0; sc.SupportReversals = 0; sc.AllowEntryWithWorkingOrders = 1; sc.SupportAttachedOrdersForTrading = 0; sc.UseGUIAttachedOrderSetting = 1; //use a high-value to effectively not put any Position Quantity restrictions sc.MaximumPositionAllowed = 100000000; sc.ReceivePointerEvents = ACS_RECEIVE_POINTER_EVENTS_ALWAYS; return; } int& r_SetSellOrderPriceMenuID = sc.GetPersistentInt(1); int& r_SetBuyOrderPriceMenuID = sc.GetPersistentInt(2); int& r_CancelOrderMenuID = sc.GetPersistentInt(3); int& r_OrderType = sc.GetPersistentInt(4); int& r_LastSubgraphUpdateIndex = sc.GetPersistentInt(5); double& r_OrderPrice = sc.GetPersistentDouble(6); int& r_OrderModifyMode = sc.GetPersistentInt(7); if (sc.LastCallToFunction) { // Be sure to remove the menu commands when study is removed sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_SetBuyOrderPriceMenuID); sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_SetSellOrderPriceMenuID); sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); return; } if (sc.UpdateStartIndex == 0) { if (r_SetBuyOrderPriceMenuID <= 0) r_SetBuyOrderPriceMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Set Buy MIT Price"); if (r_SetSellOrderPriceMenuID <= 0) r_SetSellOrderPriceMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Set Sell MIT Price"); r_LastSubgraphUpdateIndex = 0; } if (sc.MenuEventID != 0) { if (!sc.ChartTradeModeEnabled) { sc.AddMessageToLog("Chart Trade Mode is not active. No action performed.", 1); return; } } // handle set order price menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_SetBuyOrderPriceMenuID) { // Get price that the user selected. This is already rounded to the nearest price tick r_OrderPrice = sc.ChartTradingOrderPrice; r_OrderType = 1; // Buy if (r_CancelOrderMenuID <=0) r_CancelOrderMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Cancel MIT Order"); Subgraph_OrderLine.Name = "Buy MIT Order"; } else if (sc.MenuEventID != 0 && sc.MenuEventID == r_SetSellOrderPriceMenuID) { // Get price that the user selected. This is already rounded to the nearest price tick r_OrderPrice = sc.ChartTradingOrderPrice; r_OrderType = -1; // Sell if (r_CancelOrderMenuID <=0) r_CancelOrderMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Cancel MIT Order"); Subgraph_OrderLine.Name = "Sell MIT Order"; } // handle cancel order menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_CancelOrderMenuID) { r_OrderType = 0; r_OrderPrice = 0.0; sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID) ; r_CancelOrderMenuID = 0; } //Handle order modifications if (r_OrderType != 0) { if(sc.PointerEventType == SC_POINTER_BUTTON_DOWN && r_OrderPrice >= sc.ChartTradingOrderPrice - sc.TickSize && r_OrderPrice <= sc.ChartTradingOrderPrice + sc.TickSize) r_OrderModifyMode = 1; else if(sc.PointerEventType == SC_POINTER_BUTTON_UP) r_OrderModifyMode = 0; if (r_OrderModifyMode == 1 && sc.PointerEventType == SC_POINTER_MOVE) { r_OrderPrice = sc.ChartTradingOrderPrice; } } //Update the subgraph int StartingOutputIndex = sc.ArraySize - Input_NumberOfBarsBack.GetInt(); for (int BarIndex = r_LastSubgraphUpdateIndex; BarIndex < StartingOutputIndex; BarIndex++) { Subgraph_OrderLine[BarIndex] = 0.0f; } r_LastSubgraphUpdateIndex = StartingOutputIndex; for (int BarIndex = StartingOutputIndex; BarIndex < sc.ArraySize; BarIndex++) { Subgraph_OrderLine[BarIndex] = static_cast(r_OrderPrice); } //Evaluate for order triggering //For safety we must never do any order management while historical data is being downloaded. if (sc.ChartIsDownloadingHistoricalData(sc.ChartNumber)) return; // If the order is zero there is nothing to do if (r_OrderPrice == 0.0 || sc.LastTradePrice == 0.0) return; sc.SendOrdersToTradeService = !sc.GlobalTradeSimulationIsOn; bool PerformReset = false; // check for sell order trigger conditions if (r_OrderType == -1 && sc.FormattedEvaluate( sc.LastTradePrice, sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, static_cast(r_OrderPrice), sc.BaseGraphValueFormat)) { s_SCNewOrder Order; Order.OrderType = SCT_ORDERTYPE_MARKET; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.SellOrder(Order)); if (Result > 0) PerformReset = true; } // check for buy order trigger conditions if (r_OrderType == 1 && sc.FormattedEvaluate(sc.LastTradePrice, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, static_cast(r_OrderPrice), sc.BaseGraphValueFormat)) { s_SCNewOrder Order; Order.OrderType = SCT_ORDERTYPE_MARKET; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.BuyOrder(Order)); if (Result > 0) PerformReset = true; } if (PerformReset) { sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); r_CancelOrderMenuID = 0; r_OrderPrice = 0.0; r_OrderType = 0; for (int ArrayIndex = r_LastSubgraphUpdateIndex; ArrayIndex < sc.ArraySize; ArrayIndex++) Subgraph_OrderLine[ArrayIndex] = 0; } } /*==========================================================================*/ SCSFExport scsf_TradingTriggeredStopOrderEntry(SCStudyInterfaceRef sc) { SCSubgraphRef Subgraph_TriggerLine = sc.Subgraph[0]; SCSubgraphRef Subgraph_OrderLine = sc.Subgraph[1]; SCInputRef Input_NumberOfBarsBack = sc.Input[0]; SCInputRef Input_AutoSetStopPrice = sc.Input[1]; SCInputRef Input_StopPriceOffsetInTicks = sc.Input[2]; if (sc.SetDefaults) { sc.GraphName = "Trading: Triggered Stop Order"; sc.AutoLoop = 0;//Manual looping sc.GraphRegion = 0; sc.ScaleRangeType= SCALE_SAMEASREGION; Input_NumberOfBarsBack.Name = "Number of Bars Back to Display"; Input_NumberOfBarsBack.SetInt(20); //AutoSetStopPrice.Name = "Auto Set Stop Price"; //AutoSetStopPrice.SetYesNo(true); Input_StopPriceOffsetInTicks.Name = "Stop Price Offset from Trigger Price in Ticks"; Input_StopPriceOffsetInTicks.SetInt(4); Subgraph_OrderLine.Name = "Order Line"; Subgraph_OrderLine.PrimaryColor = COLOR_GREEN; Subgraph_OrderLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_LEFT_EDGE | LL_VALUE_ALIGN_BELOW | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_ABOVE; Subgraph_OrderLine.DrawZeros = false; Subgraph_TriggerLine.Name = "Stop Order Trigger"; Subgraph_TriggerLine.PrimaryColor = COLOR_CYAN; Subgraph_TriggerLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_LEFT_EDGE | LL_VALUE_ALIGN_BELOW | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_ABOVE; Subgraph_TriggerLine.DrawZeros = false; sc.ReceivePointerEvents = false; sc.AllowMultipleEntriesInSameDirection = 1; sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1; sc.CancelAllOrdersOnEntriesAndReversals = 0; sc.AllowOnlyOneTradePerBar = 0; sc.SupportReversals = 0; sc.AllowEntryWithWorkingOrders = 1; sc.SupportAttachedOrdersForTrading = 0; sc.UseGUIAttachedOrderSetting = 1; //use a high-value to effectively not put any Position Quantity restrictions sc.MaximumPositionAllowed = 100000000; return; } int& r_SetTriggerPriceMenuID = sc.GetPersistentInt(1); int& r_CancelOrderMenuID = sc.GetPersistentInt(2); int& r_OrderType = sc.GetPersistentInt(3);//1 = buy stop, -1 = sell stop int& r_LastSubgraphUpdateIndex = sc.GetPersistentInt(4); double& r_TriggerPrice = sc.GetPersistentDouble(5); double& r_OrderPrice = sc.GetPersistentDouble(6); if (sc.LastCallToFunction) { // Be sure to remove the menu commands when study is removed sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_SetTriggerPriceMenuID); sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); return; } if (sc.UpdateStartIndex == 0)//Perform initialization { if (r_SetTriggerPriceMenuID <= 0) { r_SetTriggerPriceMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Set Stop Trigger Price"); } r_LastSubgraphUpdateIndex = 0; } //Handle pointer events from the user if (sc.MenuEventID != 0) { if (!sc.ChartTradeModeEnabled) { sc.AddMessageToLog("Chart Trade Mode is not active. No action performed.", 1); return; } } // handle set trigger price menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_SetTriggerPriceMenuID) { const double CurrentPrice = sc.GetLastPriceForTrading(); // Get price that the user selected. This is already rounded to the nearest price tick r_TriggerPrice =sc.ChartTradingOrderPrice; if (sc.ChartTradingOrderPrice >= CurrentPrice) // Buy { r_OrderPrice = sc.ChartTradingOrderPrice + Input_StopPriceOffsetInTicks.GetInt() * sc.TickSize; r_OrderType = 1; } else // Sell { r_OrderPrice = sc.ChartTradingOrderPrice - Input_StopPriceOffsetInTicks.GetInt() * sc.TickSize; r_OrderType = -1; } if (r_CancelOrderMenuID == 0) r_CancelOrderMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Cancel Stop Order"); } // handle cancel order menu clicks if (sc.MenuEventID != 0 && sc.MenuEventID == r_CancelOrderMenuID) { r_OrderType = 0; r_OrderPrice = 0.0; r_TriggerPrice= 0.0; sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID) ; r_CancelOrderMenuID = 0; } //Update the horizontal subgraph line int StartingOutputIndex = sc.ArraySize - Input_NumberOfBarsBack.GetInt(); for (int BarIndex = r_LastSubgraphUpdateIndex; BarIndex < StartingOutputIndex; BarIndex++) { Subgraph_TriggerLine[BarIndex] = 0.0f; Subgraph_OrderLine[BarIndex] = 0.0f; } r_LastSubgraphUpdateIndex = StartingOutputIndex; for (int BarIndex = StartingOutputIndex; BarIndex < sc.ArraySize; BarIndex++) { Subgraph_TriggerLine[BarIndex] = static_cast(r_TriggerPrice); Subgraph_OrderLine[BarIndex] = static_cast(r_OrderPrice); } if (r_OrderType == -1) Subgraph_OrderLine.Name = "Sell Stop Order"; else if(r_OrderType == 1) Subgraph_OrderLine.Name = "Buy Stop Order"; //For safety must never do any order management while historical data is being downloaded. if (sc.ChartIsDownloadingHistoricalData(sc.ChartNumber)) return; // If the order price is zero there is nothing to do if (r_OrderPrice == 0.0 || r_OrderType == 0) return; sc.SendOrdersToTradeService = !sc.GlobalTradeSimulationIsOn; bool PerformReset = false; // check for sell order trigger conditions if (r_OrderType == -1 && sc.FormattedEvaluate(sc.LastTradePrice, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, static_cast(r_TriggerPrice), sc.BaseGraphValueFormat)) { s_SCNewOrder Order; Order.Price1 = r_OrderPrice; Order.OrderType = SCT_ORDERTYPE_STOP; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.SellOrder(Order)); if (Result > 0) PerformReset= true; } // check for buy order trigger conditions if (r_OrderType == 1 && sc.FormattedEvaluate( sc.LastTradePrice, sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, static_cast(r_TriggerPrice), sc.BaseGraphValueFormat)) { s_SCNewOrder Order; Order.Price1 = r_OrderPrice; Order.OrderType = SCT_ORDERTYPE_STOP; Order.OrderQuantity = sc.TradeWindowOrderQuantity; int Result = static_cast(sc.BuyOrder(Order)); if (Result > 0) PerformReset= true; } if (PerformReset) { if (r_CancelOrderMenuID != 0) sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_CancelOrderMenuID); r_CancelOrderMenuID = 0; r_OrderPrice = 0.0; r_TriggerPrice = 0.0; r_OrderType = 0; for (int ArrayIndex = r_LastSubgraphUpdateIndex; ArrayIndex < sc.ArraySize; ArrayIndex++) { Subgraph_TriggerLine[ArrayIndex] =0; Subgraph_OrderLine[ArrayIndex] = 0; } } } /*==========================================================================*/ /************************************************************************/ /* XYZ has a market price of $16.45. You decide to buy 100 shares, but you don't want to pay more than $16.35 and you don't want to enter the market until the price drops to $16.40. Create a BUY order, and select LIT in the Type field to specify a limit if touched order. In the Lmt Price field, enter a limit price of $16.35, and in the Trigger Price field, enter the trigger price of $16.40. Transmit the order, which will be held in the system until the trigger price is touched, and will then be submitted as a limit order. It will only execute at $16.35 or better. */ /************************************************************************/ SCSFExport scsf_LimitIfTouchedOrder(SCStudyInterfaceRef sc) { SCSubgraphRef Subgraph_OrderLine = sc.Subgraph[0]; SCInputRef Input_NumberOfBarsBack = sc.Input[0]; if (sc.SetDefaults) { sc.GraphName = "Trading: Limit if Touched Order"; sc.AutoLoop = 0;//Manual looping sc.GraphRegion = 0; sc.ScaleRangeType= SCALE_SAMEASREGION; Input_NumberOfBarsBack.Name = "Number of Bars Back to Display"; Input_NumberOfBarsBack.SetInt(20); Subgraph_OrderLine.Name = "LIT Order"; Subgraph_OrderLine.PrimaryColor = COLOR_GREEN; Subgraph_OrderLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_LEFT_EDGE | LL_VALUE_ALIGN_BELOW | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_ABOVE; Subgraph_OrderLine.DrawZeros = false; sc.AllowMultipleEntriesInSameDirection = 1; sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1; sc.CancelAllOrdersOnEntriesAndReversals = 0; sc.AllowOnlyOneTradePerBar = 0; sc.SupportReversals = 0; sc.AllowEntryWithWorkingOrders = 1; sc.SupportAttachedOrdersForTrading = 0; sc.UseGUIAttachedOrderSetting = 1; //use a high-value to effectively not put any Position Quantity restrictions sc.MaximumPositionAllowed = 100000000; sc.ReceivePointerEvents = ACS_RECEIVE_POINTER_EVENTS_ALWAYS; return; } } /*==========================================================================*/