Login Page - Create Account

Support Board


Date/Time: Tue, 26 Nov 2024 18:25:09 +0000



Post From: Automated Trading System not working properly.

[2023-11-08 19:03:10]
User733147 - Posts: 3
I wrote a simple C++ code (I copied almost all the code from TradingSystem.cpp in C:\SierraChart\ACS_Source folder). It uses Simply Moving Average with length 10 applied on 1 min chart for NQZ23 (futures). It should enter a Buy order when last closed Close price crosses up SMA, and enter a Sell order when last closed Close price crosses down SMA.

However the C++ code does function properly. Please see the attached screenshot
https://www.sierrachart.com/image.php?Image=1699469383754.png
which shows that multiple Buy orders were entered when last closed Close prices were far below SAM, and multiple Sell orders were entered when last closed Close price were above SAM. Buy orders should only be entered when last closed Close price crosses up SMA, and Sell orders should only be entered when last closed Close price crosses down SMA. (https://www.sierrachart.com/image.php?Image=1699469383754.png)

I first found the issue when I tried to use system study "Trading System Based on Alert Condition", and submitted a ticket around 2 months ago, but I got no answer to this issue. So I looked the C++ codes in TradingSystem.cpp, and created the code "!!SMATradingSystem_Test.cpp" based on TradingSystem.cpp (the code is attached too along with the screenshot).

Please let me know what caused the Buy and Sell orders wrongly entered. Thank you very much for your help!

Below is my C++ code:

///////////////////////////
#include "sierrachart.h"

SCDLLName("SMATradingSystem_Test")

/*==========================================================================*/
SCSFExport scsf_TradingExample(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];  
  
  SCInputRef Input_SendOrdersToTradeService = sc.Input[23];
  SCInputRef Input_CancelAllOrdersOnEntriesAndReversals = sc.Input[24];  
  
  //Define references to the Subgraphs and Inputs for easy reference
  SCSubgraphRef Subgraph_BuyEntry = sc.Subgraph[0];
  SCSubgraphRef Subgraph_BuyExit = sc.Subgraph[1];
  SCSubgraphRef Subgraph_SellEntry = sc.Subgraph[2];
  SCSubgraphRef Subgraph_SellExit = sc.Subgraph[3];

  SCSubgraphRef Subgraph_SimpMovAvg = sc.Subgraph[4];

  //SCInputRef Input_Enabled = sc.Input[0];
  //SCInputRef Input_TargetValue = sc.Input[1];
  //SCInputRef Input_StopValue = sc.Input[2];


  if (sc.SetDefaults)
  {
    // Set the study configuration and defaults.

    //sc.GraphName = "Trading Example: Using Moving Average and Target and Stop";
    sc.GraphName = "SMATradingSystem_Test";

    Subgraph_BuyEntry.Name = "Buy Entry";
    Subgraph_BuyEntry.DrawStyle = DRAWSTYLE_ARROW_UP;
    //Subgraph_BuyEntry.PrimaryColor = RGB(0, 255, 0);
        Subgraph_BuyEntry.PrimaryColor = RGB(255, 0, 255);
    Subgraph_BuyEntry.LineWidth = 2;
    Subgraph_BuyEntry.DrawZeros = false;

    Subgraph_BuyExit.Name = "Buy Exit";
    Subgraph_BuyExit.DrawStyle = DRAWSTYLE_ARROW_DOWN;
    Subgraph_BuyExit.PrimaryColor = RGB(255, 128, 128);
    Subgraph_BuyExit.LineWidth = 2;
    Subgraph_BuyExit.DrawZeros = false;

    Subgraph_SellEntry.Name = "Sell Entry";
    Subgraph_SellEntry.DrawStyle = DRAWSTYLE_ARROW_DOWN;
    Subgraph_SellEntry.PrimaryColor = RGB(255, 0, 0);
    Subgraph_SellEntry.LineWidth = 2;
    Subgraph_SellEntry.DrawZeros = false;

    Subgraph_SellExit.Name = "Sell Exit";
    Subgraph_SellExit.DrawStyle = DRAWSTYLE_ARROW_UP;
    Subgraph_SellExit.PrimaryColor = RGB(128, 255, 128);
    Subgraph_SellExit.LineWidth = 2;
    Subgraph_SellExit.DrawZeros = false;

    Subgraph_SimpMovAvg.Name = "Simple Moving Average";
    Subgraph_SimpMovAvg.DrawStyle = DRAWSTYLE_LINE;
    Subgraph_SimpMovAvg.DrawZeros = false;

    Input_Enabled.Name = "Enabled";
    Input_Enabled.SetYesNo(1);

    //Input_TargetValue.Name = "Target Value";
    //Input_TargetValue.SetFloat(2.0f);

    //Input_StopValue.Name = "Stop Value";
    //Input_StopValue.SetFloat(1.0f);
    
    Input_NumBarsToCalculate.Name = "Number of Bars to Calculate";
    Input_NumBarsToCalculate.SetInt(20);
    //Input_NumBarsToCalculate.SetIntLimits(1, MAX_STUDY_LENGTH);

    //Input_DrawStyleOffsetType.Name = "Draw Style Offset Type";
    //Input_DrawStyleOffsetType.SetCustomInputStrings("Percentage;Number of Ticks");

    //Input_PercentageOrTicksOffset.Name = "Percentage or Ticks Offset";
    //Input_PercentageOrTicksOffset.SetFloat(0);

    //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(200);

    Input_MaximumShortTradesPerDay.Name = "Maximum Short Trades Per Day";
    Input_MaximumShortTradesPerDay.SetInt(200);

    Input_CancelAllWorkingOrdersOnExit.Name = "Cancel All Working Orders On Exit";
    Input_CancelAllWorkingOrdersOnExit.SetYesNo(false);

    Input_EnableDebuggingOutput.Name = "Enable Debugging Output";
    Input_EnableDebuggingOutput.SetYesNo(true);

    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_SendOrdersToTradeService.Name = "Send Orders To Trade Service";
    Input_SendOrdersToTradeService.SetYesNo(false);

    Input_CancelAllOrdersOnEntriesAndReversals.Name = "Cancel All Orders On Entries And Reversals";
    Input_CancelAllOrdersOnEntriesAndReversals.SetYesNo(false);      
    

    sc.StudyDescription = "This study function is an example of how to use the ACSIL Trading Functions. This function will display a simple moving average and perform a Buy Entry when the Last price crosses the moving average from below and a Sell Entry when the Last price crosses the moving average from above. A new entry cannot occur until the Target or Stop has been hit. When an order is sent, a corresponding arrow will appear on the chart to show that an order was sent. This study will do nothing until the Enabled Input is set to Yes.";

    sc.AutoLoop = 1;
    sc.GraphRegion = 0;


    sc.AllowOppositeEntryWithOpposingPositionOrOrders = false;
    sc.SupportAttachedOrdersForTrading = false;

    sc.MaintainTradeStatisticsAndTradesData = true;


    return;
  }

  if (!Input_Enabled.GetYesNo())
    return;
  
  SCFloatArrayRef Last = sc.Close;
  
  // Calculate the moving average
    SCFloatArrayRef SMA = sc.SimpleMovAvg(Last, Subgraph_SimpMovAvg, sc.Index, 10);
  

  if (sc.IsFullRecalculation)
    return;

  // Get the Trade Position data to be used for position exit processing.
  s_SCPositionData PositionData;
  sc.GetTradePosition(PositionData) ;

  int64_t& r_BuyEntryInternalOrderID = sc.GetPersistentInt64(1);

  // Create an s_SCNewOrder object.
  s_SCNewOrder NewOrder1;
  NewOrder1.OrderQuantity = 1;
  NewOrder1.OrderType = SCT_ORDERTYPE_MARKET;
  //NewOrder.TextTag = "Trading example tag";
  NewOrder1.TextTag = "";
  //NewOrder.Symbol = "Test";
  NewOrder1.TimeInForce = SCT_TIF_GOOD_TILL_CANCELED;
  
  s_SCNewOrder NewOrder2;
  NewOrder2.OrderQuantity = 1;
  NewOrder2.OrderType = SCT_ORDERTYPE_MARKET;
  //NewOrder.TextTag = "Trading example tag";
  NewOrder2.TextTag = "";
  //NewOrder.Symbol = "Test";
  NewOrder2.TimeInForce = SCT_TIF_GOOD_TILL_CANCELED;

  int Result1 = 0;
  int Result2 = 0;


  //Optional: Check if within allowed time range. In this example we will use 10:00 through 14:00. This is according to the time zone of the chart.
  //int BarTime = sc.BaseDateTimeIn[sc.Index].GetTime();
  //bool TradingAllowed = BarTime >= HMS_TIME(10, 0, 0) && BarTime < HMS_TIME(14, 0, 0);

  
  // only process at the close of the bar. If it has not closed do not do anything
  if (//Input_EvaluateOnBarCloseOnly.GetYesNo()
    sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_NOT_CLOSED)
  {
    return;
  }
  
  // Buy when the last price crosses up the moving average from below.
  if (sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_CLOSED && sc.Close[0] >= SMA[0] && sc.Close[-1] <= SMA[-1])
  {
      Result1 = static_cast<int>(sc.BuyEntry(NewOrder1));

      //If there has been a successful order entry, then draw an arrow at the close of the bar.
      if (Result1 > 0)
      {
        r_BuyEntryInternalOrderID = NewOrder1.InternalOrderID;
        SCString InternalOrderIDNumberString;
        InternalOrderIDNumberString.Format("BuyEntry Internal Order1 ID: %d", r_BuyEntryInternalOrderID);
        sc.AddMessageToLog(InternalOrderIDNumberString, 0);

        Subgraph_BuyEntry[sc.Index] = sc.Close[sc.Index];
      }

  }
  // When there is a long position, Sell when the last price crosses down the moving average from above.
  if (sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_CLOSED && PositionData.PositionQuantity > 0 && sc.Close[0] <= SMA[0] && sc.Close[-1] >= SMA[-1] )
  {
      Result2 = static_cast<int>(sc.BuyExit(NewOrder2));

      //If there has been a successful order entry, then draw an arrow at the close of the bar.
      if (Result2 > 0)
      {
        r_BuyEntryInternalOrderID = NewOrder2.InternalOrderID;
        SCString InternalOrderIDNumberString;
        InternalOrderIDNumberString.Format("BuyEntry Internal Order2 ID: %d", r_BuyEntryInternalOrderID);
        sc.AddMessageToLog(InternalOrderIDNumberString, 0);

        Subgraph_BuyExit[sc.Index] = sc.Close[sc.Index];
      }
  }
  
}

/*==========================================================================*/
Attachment Deleted.
attachmentSMATradingSystem_Test.CPP - Attached On 2023-11-08 18:53:15 UTC - Size: 10.7 KB - 350 views