Login Page - Create Account

Support Board


Date/Time: Mon, 06 May 2024 18:09:42 +0000



Post From: ACSIL - trailing stop loss and orders

[2019-09-16 22:48:44]
MattK - Posts: 42
Hi guys!

I'm working on an automated trading system. Simply put: trying to buy one tick above the previous candle and trail the stop loss one tick under the previous low.

However, it is not behaving as I would like. I'm trying to debug and put messages in the activity log but can't figure out what is wrong with my orders and stop loss.

If you could help me I would love it. When I backtest the system, I end up with trades where the loss is $400 or $5k, etc even though I put a stop loss at 6 ticks under the price.

Thanks in advance.
Matt

-- UPDATED CODE --

// The top of every source code file must include this line
#include "sierrachart.h"

// For reference, refer to this page:
// Advanced Custom Study Interface and Language (ACSIL)

// This line is required. Change the text within the quote
// marks to what you want to name your group of custom studies.
SCDLLName("Reversal strategy")

//This is the basic framework of a study function. Change the name 'TemplateFunction' to what you require.
SCSFExport scsf_ReversalStrategy(SCStudyInterfaceRef sc)
{
  //Define references to the Subgraphs and Inputs for easy reference
  SCSubgraphRef BuyEntrySubgraph = sc.Subgraph[0];
  SCSubgraphRef BuyExitSubgraph = sc.Subgraph[1];
  SCSubgraphRef ATRSubgraph = sc.Subgraph[2];
  SCSubgraphRef EMASubgraph = sc.Subgraph[3];
  
  SCString DebugMessage;
  
  // Section 1 - Set the configuration variables and defaults
  if (sc.SetDefaults)
  {
    sc.GraphName = "Reversal long strategy";

    sc.AutoLoop = 1; //Automatic looping is enabled.
    
    BuyEntrySubgraph.Name = "Buy Entry";
    BuyEntrySubgraph.DrawStyle = DRAWSTYLE_ARROW_UP;
    BuyEntrySubgraph.PrimaryColor = RGB(0, 255, 0);
    BuyEntrySubgraph.LineWidth = 2;
    BuyEntrySubgraph.DrawZeros = false;

    BuyExitSubgraph.Name = "Buy Exit";
    BuyExitSubgraph.DrawStyle = DRAWSTYLE_ARROW_DOWN;
    BuyExitSubgraph.PrimaryColor = RGB(255, 128, 128);
    BuyExitSubgraph.LineWidth = 2;
    BuyExitSubgraph.DrawZeros = false;
    
    sc.Input[0].Name = "Float Input";
    sc.Input[0].SetFloat(0.0f);
    
    return;
  }
  
  // Section 2 - Do data processing here
  float currentPrice = sc.BaseData[SC_LAST][sc.Index];
  float currentHigh = sc.BaseData[SC_HIGH][sc.Index];
  float previousHigh = sc.BaseData[SC_HIGH][sc.Index-1];
  float previous2High = sc.BaseData[SC_HIGH][sc.Index-2];
  float currentLow = sc.BaseData[SC_LOW][sc.Index];
  float previousLow = sc.BaseData[SC_LOW][sc.Index-1];
  float previous2Low = sc.BaseData[SC_LOW][sc.Index-2];
  float previousClose = sc.BaseData[SC_CLOSE][sc.Index-1];
  float previous2Close = sc.BaseData[SC_CLOSE][sc.Index-2];
  float previousHighCloseDiff = sc.BaseData[SC_HIGH][sc.Index-1] - sc.BaseData[SC_CLOSE][sc.Index-1];
  
  // Calculate the Average True Range
  sc.ATR(sc.BaseDataIn, ATRSubgraph, 10, MOVAVGTYPE_SIMPLE);
  float ATR = ATRSubgraph[sc.Index]; // Value of the current ATR
  
  // Calculate the EMA
  sc.ExponentialMovAvg(sc.BaseDataIn[SC_LAST], EMASubgraph, 100);
  float EMA = EMASubgraph[sc.Index]; // Value of the current EMA
  
  s_SCPositionData PositionData;
  sc.GetTradePosition(PositionData);
  
  // Use persistent variables to remember attached order IDs so they can be modified or canceled.
  int& OrderId = sc.GetPersistentInt(1);
  int& Stop1OrderID = sc.GetPersistentInt(2);
  
  float orderPrice = sc.GetPersistentFloat(1);
  float NewPossibleStop = sc.GetPersistentFloat(2);
  float orderStop = sc.GetPersistentFloat(3);
  float currentStop = sc.GetPersistentFloat(4);
  
  int Hour = sc.BaseDateTimeIn[sc.Index].GetHour();
  int Minute = sc.BaseDateTimeIn[sc.Index].GetMinute();
  
  // Data processing once the bar has closed.
  if(sc.GetBarHasClosedStatus()==BHCS_BAR_HAS_CLOSED)
  {
    
    // Cancel the pending order
    if (PositionData.PositionQuantity == 0 && OrderId != 0)
    {
      sc.FlattenAndCancelAllOrders();
      OrderId = 0;
      Stop1OrderID = 0;
    }
    
    if (PositionData.PositionQuantity == 0 && ATR >= 1.8 && currentLow > EMA && currentLow <= previousLow)
    {
      // Mark the signal on the chart
      BuyEntrySubgraph[sc.Index] = sc.Low[sc.Index];
      
      // Create a market order and enter long.
      s_SCNewOrder NewOrder;
      NewOrder.OrderQuantity = 1;
      NewOrder.OrderType = SCT_ORDERTYPE_STOP_LIMIT;
      NewOrder.TimeInForce = SCT_TIF_DAY;
      NewOrder.Price1 = currentHigh + 1*sc.TickSize;
      NewOrder.Price2 = currentHigh + 4*sc.TickSize;
      NewOrder.OCOGroup1Quantity = 1;
      NewOrder.Stop1Price = currentHigh - 3*sc.TickSize;
      
      // This is a common setting and applies to all Stop Attached Orders set on the main order.
      NewOrder.MoveToBreakEven.Type=MOVETO_BE_ACTION_TYPE_OFFSET_TRIGGERED;

      //After 5 ticks of profit, the stop order will be moved to breakeven
      NewOrder.MoveToBreakEven.TriggerOffsetInTicks= 4;
      NewOrder.MoveToBreakEven.BreakEvenLevelOffsetInTicks= 0;
      
      // Using this variable to log a message
      orderPrice = currentHigh + 1*sc.TickSize;
      DebugMessage.Format("Signal at: %f", orderPrice);
      sc.AddMessageToLog(DebugMessage, 1);

      sc.BuyEntry(NewOrder);
      
      // Remember the order ID for subsequent modification and cancellation
      Stop1OrderID = NewOrder.Stop1InternalOrderID;
      OrderId = NewOrder.InternalOrderID;
      
      orderStop = currentHigh - 3*sc.TickSize;
      
    }
    
    // Update the trailing stop loss if the new low is higher than the previous low.
    // Gotta make sure the new stop loss is not lower than the initial one
    NewPossibleStop = currentLow - 2*sc.TickSize;
    
    // COMPARE INITIAL STOP TO NEW STOP IS NOT WORKING RIGHT NOW
    
    if (PositionData.PositionQuantity == 1 && currentLow > previousLow && currentHigh > previousHigh && currentStop < NewPossibleStop && NewPossibleStop > orderStop)
    {
      s_SCTradeOrder ExistingOrder;
      if (sc.GetOrderByOrderID(Stop1OrderID, ExistingOrder) != SCTRADING_ORDER_ERROR)
      {
        
        s_SCNewOrder ModifyOrder;
        ModifyOrder.InternalOrderID = Stop1OrderID;
        ModifyOrder.Price1 = NewPossibleStop;

        sc.ModifyOrder(ModifyOrder);
        DebugMessage.Format("Current time: %d:%d", Hour, Minute);
        sc.AddMessageToLog(DebugMessage, 1);
        DebugMessage.Format("Updating stop loss to: %f on entry: %f", NewPossibleStop, orderPrice);
        sc.AddMessageToLog(DebugMessage, 1);
        DebugMessage.Format("Order price: %f", orderPrice);
        sc.AddMessageToLog(DebugMessage, 1);
        
        currentStop = currentLow - 2*sc.TickSize;
      }
    }
    
    // Flatten and cancel all if there is a current position but no stop
    if (PositionData.PositionQuantity == 1 && Stop1OrderID == 0)
    {
      sc.FlattenAndCancelAllOrders();
    }
    
    // Flatten and cancel all orders if it is right before the session ending.
    if (Hour == 14 && Minute ==59)
    {
      sc.FlattenAndCancelAllOrders();
    }
  }
  
}


Date Time Of Last Edit: 2019-09-17 17:46:57