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 lossfor thelongposition is placed below thelowof the candle
long_stop_loss = price_area.low
The
take profitfor thelongposition is placed at a RRR of 2.We find the difference between the
closeandstoplossprices.Multiply it by 2 and then add the the
closingprice.This gives us the price for the
take profitlevel 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 lossfor theshortposition is above thehighof the candle.
short_stop_loss = price_area.high
The
take profitfor theshortposition is placed at a RRR of 2.Similarly the
short take profitis 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 lossis hit when thelowof the current candle is less than the stop loss price.
price_area.low <= long_stop_loss
The Long
take profitis hit 🎯 when thehighof the current candle is greater than thetake profitprice.
price_area.high >= long_take_profit
Short 🟥
The Short
stop lossis hit when thehighof the current candle is greater than the stop loss price
price_area.high >= short_stop_loss
The Short
take profitis hit when thelowof the current candle is less than thetake profitprice.
price_area.low <= short_take_profit
In the code below you can see the implmentation of the
stop lossandtake profitas 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 profitis hit , both variables have to be set toNone. -
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.