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 thelong
position is placed below thelow
of the candle
long_stop_loss = price_area.low
The
take profit
for thelong
position is placed at a RRR of 2.We find the difference between the
close
andstoploss
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 theshort
position is above thehigh
of the candle.
short_stop_loss = price_area.high
The
take profit
for theshort
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 thelow
of the current candle is less than the stop loss price.
price_area.low <= long_stop_loss
The Long
take profit
is hit 🎯 when thehigh
of the current candle is greater than thetake profit
price.
price_area.high >= long_take_profit
Short 🟥
The Short
stop loss
is hit when thehigh
of the current candle is greater than the stop loss price
price_area.high >= short_stop_loss
The Short
take profit
is hit when thelow
of the current candle is less than thetake profit
price.
price_area.low <= short_take_profit
In the code below you can see the implmentation of the
stop loss
andtake 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 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.