VectorBT Pro - Custom Simulator 2: Candlestick Strategy + StopLoss + TakeProfit
3 min read

VectorBT Pro - Custom Simulator 2: Candlestick Strategy + StopLoss + TakeProfit

VectorBT Pro - Custom Simulator 2: Candlestick Strategy + StopLoss + TakeProfit

Importing the Dependencies

import vectorbtpro as vbt
import numpy as np
import pandas as pd
from numba import njit
import talib
import datetime as dt
import time
from collections import namedtuple
import itertools
import math
from vectorbtpro.records.nb import col_map_nb
from vectorbtpro.portfolio import nb as pf_nb, enums as pf_enums
import plotly.io as pio
from numba import njit

Strategy Rules 📐

We will build upon the previous strategy

Stop Loss Below / Above The Entry Candle

Take Profit Level at a RRR (Risk and Reward Ratio of 2)

Long 🟩 Stop Loss ⬇ and Take Profit ⬆

The stop loss for the long position is placed below the low of the candle

    long_stop_loss = price_area.low

The take profit for the long position is placed at a RRR of 2.

We find the difference between the close and stoploss prices.

Multiply it by 2 and then add the the closing price.

This gives us the price for the take profit level corresponding to a RRR of 2.

long_take_profit = price_area.close + ( 2 * (price_area.close - long_stop_loss) )

Short 🟥 Stop Loss ⬆ and Take Profit ⬇

The stop loss for the short position is above the high of the candle.

short_stop_loss = price_area.high

The take profit for the short position is placed at a RRR of 2.

Similarly the short take profit is placed at a RRR of 2 below the closing price.

The calculation can be seen below.

short_take_profit = price_area.close - ( 2 * (price_area.high - short_stop_loss) )

Detecting When Stop Loss and Take Profit Is Hit

Long 🟩

The Long stop loss is hit when the low of the current candle is less than the stop loss price.

price_area.low <= long_stop_loss


The Long take profit is hit 🎯 when the high of the current candle is greater than the take profit price.

price_area.high >= long_take_profit


Short 🟥

The Short stop loss is hit when the high of the current candle is greater than the stop loss price

price_area.high >= short_stop_loss


The Short take profit is hit when the low of the current candle is less than the take profit price.

price_area.low <= short_take_profit


In the code below you can see the implmentation of the stop loss and take profit as part of the entire strategy.

Custom Simulator

def custom_simulator_candlestick_sl_tp(open_ , high_ , low_ , close_ , IsBullArray, init_cash = 10000):

    order_records = np.empty((2663,1), dtype = vbt.pf_enums.order_dt)
    order_counts = np.full(1, 0, dtype=np.int_)

    long_stop_loss = None
    long_take_profit = None
    
    short_stop_loss = None
    short_take_profit = None
    
    exec_state = vbt.pf_enums.ExecState(
                        cash = float(init_cash),
                        position = 0.0,
                        debt = 0.0,
                        locked_cash = 0.0,
                        free_cash = float(init_cash),
                        val_price = np.nan,
                        value = np.nan)
    
    
    
    for i in range(len(close_)):
        price_area = vbt.pf_enums.PriceArea(open = open_[i], 
                                            high = high_[i], 
                                            low = low_[i], 
                                            close = close_[i])
        
        value_price = price_area.close
        value = exec_state.cash + (exec_state.position * value_price)
        
        exec_state = vbt.pf_enums.ExecState(
                                            cash = exec_state.cash,
                                            position = exec_state.position,
                                            debt = exec_state.debt,
                                            locked_cash = exec_state.locked_cash,
                                            free_cash = exec_state.free_cash,
                                            val_price = value_price,
                                            value = value)


        if IsBullArray[i] and exec_state.position == 0:
            long_stop_loss = price_area.low #Stop Loss Placed Below The Low Of The Candle
            long_take_profit = price_area.close + ( 2 * (price_area.close - long_stop_loss) ) 
            
            order_result , exec_state = enter_position(
                                                        execution_state_ = exec_state,
                                                        price_area_ = price_area,
                                                        percent_risk_ = 1,
                                                        group_ = 0, column_= 0, bar_ = i,
                                                        direction = 'Buy',
                                                        order_records_= order_records,
                                                        order_counts_ = order_counts)

        elif not IsBullArray[i] and exec_state.position == 0:
            
            short_stop_loss = price_area.high #Stop Loss Placed Above The High Of The Candle
            short_take_profit = price_area.close - ( 2 * (price_area.high - short_stop_loss) ) #Stop Loss At 2RRR
            
            order_result , exec_state = enter_position(
                                                        execution_state_ = exec_state,
                                                        price_area_ = price_area,
                                                        percent_risk_ = 1,
                                                        group_ = 0, column_= 0, bar_ = i,
                                                        direction = 'Sell',
                                                        order_records_= order_records,
                                                        order_counts_ = order_counts)

        elif exec_state.position > 0 and not IsBullArray[i]:
            #Closing Long Position
            order_result , exec_state = close_full_position(
                                                            execution_state_ = exec_state,
                                                            price_area_ = price_area,
                                                            group_ = 0, column_= 0, bar_ = i,
                                                            order_records_ = order_records,
                                                            order_counts_  = order_counts)  
            
            
            
        
        elif exec_state.position < 0 and IsBullArray[i]:
            #Closing Short Position
            order_result , exec_state = close_full_position(
                                                            execution_state_ = exec_state,
                                                            price_area_ = price_area,
                                                            group_ = 0, column_= 0, bar_ = i,
                                                            order_records_= order_records,
                                                            order_counts_ = order_counts)
        
        else:
            
            if exec_state.position > 0: #In Long
                if (price_area.low <= long_stop_loss): 
                    #long stop loss has been hit
                    #Code To Close The Long Position
                    order_result , exec_state = close_full_position(
                                                                execution_state_ = exec_state,
                                                                price_area_ = price_area,
                                                                group_ = 0, column_= 0, bar_ = i,
                                                                order_records_= order_records,
                                                                order_counts_ = order_counts)
                    
                    
                    long_stop_loss = None
                    long_take_profit = None
                
                elif (price_area.high >= long_take_profit): 
                    #Long Take Profit Has Been Hit
                    #Code To Close Long Position Goes Here
                    
                    order_result , exec_state = close_full_position(
                                                                execution_state_ = exec_state,
                                                                price_area_ = price_area,
                                                                group_ = 0, column_= 0, bar_ = i,
                                                                order_records_= order_records,
                                                                order_counts_ = order_counts)
                    
                    
                    long_stop_loss = None
                    long_take_profit = None
                
                else:
                    continue
            
            elif exec_state.position < 0: #In Short
                if (price_area.high >= short_stop_loss): 
                    #Short Stop Loss Has Been Hit
                    #Code That Closes Out The Short Position Goes Here
                    order_result , exec_state = close_full_position(
                                                                execution_state_ = exec_state,
                                                                price_area_ = price_area,
                                                                group_ = 0, column_= 0, bar_ = i,
                                                                order_records_= order_records,
                                                                order_counts_ = order_counts)
          
                    short_stop_loss = None
                    short_take_profit = None
                
                elif (price_area.low <= short_take_profit): 
                    #Short Take Profit Has Been Hit
                    #Code That Closes Out The Short Position Goes Here
                    order_result , exec_state = close_full_position(
                                                                execution_state_ = exec_state,
                                                                price_area_ = price_area,
                                                                group_ = 0, column_= 0, bar_ = i,
                                                                order_records_= order_records,
                                                                order_counts_ = order_counts)
                    
                    short_stop_loss = None
                    short_take_profit = None
                
                else:
                    continue
        
    
    return vbt.nb.repartition_nb(order_records, order_counts)

Key Points / Summary 💡

  • When the stop loss / take profit is hit , both variables have to be set to None.

  • When we are in a position we must check at each bar (candle) whether the stop loss / take profit has been hit and then deploy the approporatiate function to fulfill the logic of our strategy.