Your interactive trading laboratory!
 • 
11 users online

Quantacula Help

How-To
C# API Reference
Extensions
Development Blog
API-Extensions
Indicator Spotlights

QCommunity Extensions
The open-source GitHub repository of source code for the QCommunity Extensions library. Contains indicators and other extensions submitted by the Quantacula Community. Look for QCommunity indicators when you create a Building Block model, mark the "QCommunity" library check box to expose them.

TASC-Extensions
The open-source GitHub repository of source code for the TASCExtensions Quantacula extension. Contains indicators and other extensions adapted from the Traders' Tips articles in Technical Analysis of Stocks & Commodities magazine.
Crafting the Exit
Published by Q Glitch 19 days ago

Sometimes we can focus so much on perfecting when to get into the market we neglect to put sufficient thought into when to get out of the trade. Here we'll talk about some general strategies to exit positions, and how they can be implemented in Quantacula Models.

The Technical Exit

This is simply an exit based on some sort of technical criteria. It often mirrors the entry rule of the Model. For example, if our Model goes long when the RSI indicator is oversold, a mirrored exit rule would close the long position when the RSI is overbought. Here's the Model mocked up using Building Blocks on Quantacula.com.

enter image description here

Multiple Exits

It's easy to establish multiple exit rules for a Model. If you're using the Building Blocks, you can drop more than one Exit Block onto an Entry Block. In the Model above, for example, you could have dropped a Sell at Profit Target and a Sell at Stop Loss onto the Buy at Market Open, and all three of the exit rules would have applied.

enter image description here

Exits in C# Code

When you're coding Models in Quantacula's C# framework, you'll use the PlaceTrade method to both enter and exit the market.

public Transaction PlaceTrade(BarHistory bars, TransactionType transType, OrderType orderType, double price = 0, int positionTag = -1)

The code below is a version of the first RSI oversold/overbought Model presented above.

using QuantaculaBacktest;
using QuantaculaCore;
using QuantaculaIndicators;

namespace Quantacula
{
    public class MyModel1 : UserModelBase
    {
        //create indicators and other objects here, this is executed prior to the main trading loop
        public override void Initialize(BarHistory bars)
        {
		rsi = new RSI(bars.Close, 20);
		PlotIndicator(rsi);
        }

        //execute the strategy rules here, this is executed once for each bar in the backtest history
        public override void Execute(BarHistory bars, int idx)
        {
            if (!HasOpenPosition(bars, PositionType.Long))
            {
                if (rsi[idx] < 30)
			PlaceTrade(bars, TransactionType.Buy, OrderType.Market);
            }
            else
            {
                //code your sell conditions here
	        if (rsi[idx] > 65)
			PlaceTrade(bars, TransactionType.Sell, OrderType.Market);
            }
        }

	//declare private variables below
	private RSI rsi;
    }
}

Same Bar Exits

In C# Code Based Models, you can code an exit that can execute on the bar of data the position was established. A typical example is calculating a stop loss level at the time a buy signal triggers. Since the stop level is known, it could be placed in the market right after the buy order executes.

When using same bar exits, you write the code in the typical way, with an if statement that runs one block of code if the Model doesn't have a position (the entry block), and another block of code when it does (the exit block). But the twist is, you code the exit a second time, in the entry block, immediately after the PlaceTrade call that enters the market.

For example, the Model below establishes a stop loss level 4% below the low of the signal bar. It uses PlaceTrade to issue the sell in the entry block, right after the PlaceTrade call to enter the position. It also uses PlaceTrade to exit the position in the exit block.

using QuantaculaBacktest;
using QuantaculaCore;
using QuantaculaIndicators;

namespace Quantacula
{
    public class MyModel1 : UserModelBase
    {
        //create indicators and other objects here, this is executed prior to the main trading loop
        public override void Initialize(BarHistory bars)
        {
		rsi = new RSI(bars.Close, 20);
		PlotIndicator(rsi);
        }

        //execute the strategy rules here, this is executed once for each bar in the backtest history
        public override void Execute(BarHistory bars, int idx)
        {
            if (!HasOpenPosition(bars, PositionType.Long))
            {
	        //entry block
		if (rsi[idx] < 30)
		{
			stopLossLevel = bars.Low[idx] * 0.96;
			PlaceTrade(bars, TransactionType.Buy, OrderType.Market);

			//place the same bar exit
			PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, stopLossLevel);
		}
            }
            else
            {
                //exit block
	        if (rsi[idx] > 65)
			PlaceTrade(bars, TransactionType.Sell, OrderType.Market);

		//this is the stop loss we calculated above
		PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, stopLossLevel);
            }
        }

	//declare private variables below
	private RSI rsi;
	private double stopLossLevel;
    }
}

Here's a chart of the Model on TSLA, showing the same bar exit hitting on one bar, followed by a profitable trade that did not stop out.

enter image description here

Bracketed Exits (OCO)

Many brokers allow OCO orders (one-cancels-other) as a way to "bracket" a position with a limit exit and a stop exit. To simulate these in Quantacula, just use multiple exits like we explained above for Building Block Models. To accomplish this in code, just write multiple PlaceTrade exits. Here's a code based version of the RSI Model above that uses three exits, an RSI overbought, a profit target, and a stop loss.

To establish the profit target (10%) and stop loss (20%) levels, we access the LastPosition property, which returns an instance of the Position class which represents the currently open position. The Position class has properties that return the entry/exit dates and prices of the position. We use the position's EntryPrice to calculate the limit and stop levels.

using QuantaculaBacktest;
using QuantaculaCore;
using QuantaculaIndicators;

namespace Quantacula
{
	public class MyModel1 : UserModelBase
	{
		//create indicators and other objects here, this is executed prior to the main trading loop
		public override void Initialize(BarHistory bars)
		{
			rsi = new RSI(bars.Close, 20);
			PlotIndicator(rsi);
		}

		//execute the strategy rules here, this is executed once for each bar in the backtest history
		public override void Execute(BarHistory bars, int idx)
		{
			if (!HasOpenPosition(bars, PositionType.Long))
			{
				if (rsi[idx] < 30)
					PlaceTrade(bars, TransactionType.Buy, OrderType.Market);
			}
			else
			{
				//code your sell conditions here
				if (rsi[idx] > 65)
					PlaceTrade(bars, TransactionType.Sell, OrderType.Market);
				Position pos = LastPosition;
				double profitTarget = pos.EntryPrice * 1.1;
				PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, profitTarget);
				double stopLoss = pos.EntryPrice * 0.8;
				PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, stopLoss);
			}
		}

		//declare private variables below
		private RSI rsi;
	}
}

Trailing Stops

Quantacula has built-in support for modelling trailing stops, in the form of the CloseAtTrailingStop method.

public void CloseAtTrailingStop(Position pos, TrailingStopTypes tst, double amount)

You'd call this method in the exit block, like any other exit, passing it the instance of the Position to close. This can be obtained using the LastPosition property, as explained previously. The method has two additional parameters:

  • TrailingStopTypes tst - an enum that describes what type of trailing stop to employ. Possible values are:
    • PercentC - a percentage trailing stop pegged to the closing price
    • PointC - a point based trailing stop pegged to the closing price
    • PercentHL - a percentage trailing stop pegged to the high/low price
    • PointHL - a point based trailing stop pegged to the high/low price
  • double amount - either the percentage value (for percentage based trailing stops) or the raw point value (for point based trailing stops)

Plotting Stops

It's helpful to visualize stop levels on the chart. As of Quantacula Studio Q190 you can use the DrawDot method to easily plot your stop levels. The example below illustrates an RSI oversold/overbought Model that uses a percentage based trailing stop (10% trailing closing price) as well as a 20% profit target. The profit target level is plotted in green and the trailing stop in red.

Note that to obtain the current level of the trailing stop, we use the TrailingStopPrice property of the Position. The backtester automatically sets the value of the Position's TrailingStopPrice when you can CloseAtTrailingStop.

using QuantaculaBacktest;
using QuantaculaCore;
using QuantaculaIndicators;
using System.Drawing;

namespace Quantacula
{
    public class MyModel1 : UserModelBase
    {
        //create indicators and other objects here, this is executed prior to the main trading loop
        public override void Initialize(BarHistory bars)
        {
		rsi = new RSI(bars.Close, 20);
        }

        //execute the strategy rules here, this is executed once for each bar in the backtest history
        public override void Execute(BarHistory bars, int idx)
        {
            if (!HasOpenPosition(bars, PositionType.Long))
            {
                //code your buy conditions here
	            if (rsi[idx] < 30)
			PlaceTrade(bars, TransactionType.Buy, OrderType.Market);
            }
            else
            {
                //code your sell conditions here
	        if (rsi[idx] > 55)
			PlaceTrade(bars, TransactionType.Sell, OrderType.Market);
				Position pos = LastPosition;
	            
	            //profit target
		    double profitTarget = pos.EntryPrice * 1.2;
		    PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, profitTarget);
	            DrawDot(idx, profitTarget, Color.Green, 2);
	            
	            //trailing stop
		    CloseAtTrailingStop(pos, TrailingStopTypes.PercentC, 10);
	            DrawDot(idx, pos.TrailingStopPrice, Color.Red, 2);
            }
        }

	//declare private variables below
	private RSI rsi;
    }
}

Here's how the stop looks when plotted on the chart. In this case, the RSI overbought exit occurred before either the profit target or stop loss was hit.

enter image description here