//@version=5
strategy('dca-bb12 bist', overlay=true, pyramiding=99, process_orders_on_close=true, commission_type=strategy.commission.percent, commission_value=0.04, initial_capital=100000)
// Fibonacci Levels
fib_0 = input.float(0.382, "Fib Level 0")
fib_1 = input.float(0.618, "Fib Level 1")
// Calculate Fibonacci levels
fib_range = ta.highest(high, 2) - ta.lowest(low, 2)
fib_level_0 = ta.highest(high, 2) - (fib_range * fib_0)
fib_level_1 = ta.highest(high, 2) - (fib_range * fib_1)
// RSI
rsi_length = input(14, "RSI Length")
rsi_overbought = input(70, "RSI Overbought Level")
rsi_oversold = input(30, "RSI Oversold Level")
rsi_value = ta.rsi(close, rsi_length)
// Determine buy and sell conditions
buy_condition = ta.crossover(rsi_value, rsi_oversold) and close > fib_level_1
sell_condition = ta.crossunder(rsi_value, rsi_overbought) and close < fib_level_0
import TradingView/ta/7
atr_len = input.int(10, "ATR Length", group = "SuperTrend Settings")
fact = input.float(3, "SuperTrend Factor", group = "SuperTrend Settings")
training_data_period = input.int(100, "Training Data Length", group = "K-Means Settings")
highvol = input.float(0.75, "Initial High volatility Percentile Guess", maxval = 1, group = "K-Means Settings", tooltip = "The initial guess of where the potential 'high volatility' area is, a value of 0.75 will take the 75th percentile of the range of ATR values over the training data period")
midvol = input.float(0.5, "Initial Medium volatility Percentile Guess", maxval = 1, group = "K-Means Settings", tooltip = "The initial guess of where the potential 'medium volatility' area is, a value of 0.5 will take the 50th percentile of the range of ATR values over the training data period")
lowvol = input.float(0.25, "Initial Low volatility Percentile Guess", maxval = 1, group = "K-Means Settings", tooltip = "The initial guess of where the potential 'low volatility' area is, a value of 0.25 will take the 25th percentile of the range of ATR values over the training data period")
green = input.color(#00ffbb, "Bullish Color", group = "Appearance")
red = input.color(#ff1100, "Bearish Color", group = "Appearance")
pine_supertrend(factor, atr) =>
src = hl2
upperBand = src + factor * atr
lowerBand = src - factor * atr
prevLowerBand = nz(lowerBand[1])
prevUpperBand = nz(upperBand[1])
lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
int _direction = na
float superTrend = na
prevSuperTrend = superTrend[1]
if na(atr[1])
_direction := 1
else if prevSuperTrend == prevUpperBand
_direction := close > upperBand ? -1 : 1
else
_direction := close < lowerBand ? 1 : -1
superTrend := _direction == -1 ? lowerBand : upperBand
[superTrend, _direction]
volatility = ta.atr(atr_len)
upper = ta.highest(volatility, training_data_period)
lower = ta.lowest(volatility, training_data_period)
high_volatility = lower + (upper-lower) * highvol
medium_volatility = lower + (upper-lower) * midvol
low_volatility = lower + (upper-lower) * lowvol
iterations = 0
size_a = 0
size_b = 0
size_c = 0
hv = array.new_float()
mv = array.new_float()
lv = array.new_float()
amean = array.new_float(1,high_volatility)
bmean = array.new_float(1,medium_volatility)
cmean = array.new_float(1,low_volatility)
if nz(volatility) > 0 and bar_index >= training_data_period-1
while ((amean.size() == 1 ? true : (amean.first() != amean.get(1))) or (bmean.size() == 1 ? true : (bmean.first() != bmean.get(1))) or (cmean.size() == 1 ? true : (cmean.first() != cmean.get(1))))
hv.clear()
mv.clear()
lv.clear()
for i = training_data_period-1 to 0
if math.abs(volatility[i] - amean.first()) < math.abs(volatility[i] - bmean.first()) and math.abs(volatility[i] - amean.first()) < math.abs(volatility[i] - cmean.first())
hv.unshift(volatility[i])
if math.abs(volatility[i] - bmean.first()) < math.abs(volatility[i] - amean.first()) and math.abs(volatility[i] - bmean.first()) < math.abs(volatility[i] - cmean.first())
mv.unshift(volatility[i])
if math.abs(volatility[i] - cmean.first()) < math.abs(volatility[i] - amean.first()) and math.abs(volatility[i] - cmean.first()) < math.abs(volatility[i] - bmean.first())
lv.unshift(volatility[i])
amean.unshift(hv.avg())
bmean.unshift(mv.avg())
cmean.unshift(lv.avg())
size_a := hv.size()
size_b := mv.size()
size_c := lv.size()
iterations := iterations + 1
hv_new = amean.first()
mv_new = bmean.first()
lv_new = cmean.first()
vdist_a = math.abs(volatility - hv_new)
vdist_b = math.abs(volatility - mv_new)
vdist_c = math.abs(volatility - lv_new)
distances = array.new_float()
centroids = array.new_float()
distances.push(vdist_a)
distances.push(vdist_b)
distances.push(vdist_c)
centroids.push(hv_new)
centroids.push(mv_new)
centroids.push(lv_new)
cluster = distances.indexof(distances.min()) // 0 for high, 1 for medium, 2 for low
assigned_centroid = cluster == -1 ? na : centroids.get(cluster)
[ST, dir] = pine_supertrend(fact, assigned_centroid)
t1 = 70
t2 = 95
// ----------------------------------
// Strategy Inputs
// ----------------------------------
kat=input(1.618)
take_profit = input.float(2, title='Take Profit (%)', minval=0.0, step=0.1) / 100
take_profit_type = input.string(defval='% from total volume', title='Take Profit Type', options=['% from total volume', '% from base order'])
ttp = input.float(0.0, title='Trailing Take Profit (%) [0 = Disabled]', minval=0.0, step=0.1) / 100
stop_loss = input.float(0.0, title='Stop Loss (%) [0 = Disabled]', minval=0.0, step=0.1) / 100
order_size_type = input.string(defval='Fixed', title='Order Size Type', options=['Fixed', '% of equity'])
base_order = input(1200, title='Base Order')
safe_order = input(300, title='Safety Order')
max_safe_order = input.int(10, title='Max Safety Trades Count', minval=0, maxval=99, step=1)
price_deviation = input.float(1.2, title='Price deviation to open safety order (%)', minval=0.0, step=0.1) / 100
safe_order_volume_scale = input.float(1.7, title='Safety Order Volume Scale', step=0.1)
safe_order_step_scale = input.float(1.3, title='Safety Order Step Scale', step=0.1)
dsc = input.string(defval='Start ASAP', title='Deal Start Condition', options=['Start ASAP', 'RSI-7', 'TV presets'])
dsc_rsi_threshold = input.int(defval=30, title='[RSI-7 only] RSI Threshold', minval=1, maxval=99)
dsc_technicals = input.string(defval='Strong', title='[TV presets only] Strength', options=['Strong', 'Weak'])
dsc_res = input.timeframe('', title='[RSI-7 and TV presets Only] Indicator Timeframe')
bot_direction = input.string(defval='Long', title='Bot Direction', options=['Long', 'Short'])
start_time = input.time(defval=timestamp('15 June 2000 06:00'), title='Start Time')
end_time = input.time(defval=timestamp('31 Dec 2099 20:00'), title='End Time')
// ----------------------------------
// Declarations
// ----------------------------------
var bo_level = 0.0
var last_so_level = 0.0
var so_level = 0.0
var ttp_active = false
var ttp_extremum = 0.0
var ttp_level = 0.0
var stop_level = 0.0
var take_profit_level = 0.0
var deal_counter = 0
var stop_loss_counter = 0
var stop_loss_on_bar = false
var latest_price = close
var deal_start_condition = false
var start_time_actual = start_time
var end_time_actual = start_time
// CONSTANTS
var float init_price = na
var IS_LONG = bot_direction == 'Long'
// ----------------------------------
// Utilities functions
// ----------------------------------
pretty_date(t) =>
str.tostring(dayofmonth(t)) + '/' + str.tostring(month(t)) + '/' + str.tostring(year(t))
within_window() =>
time >= start_time and time <= end_time
base_order_size() =>
order_size_type == 'Fixed' ? base_order : base_order / 100 * strategy.equity
safe_order_size() =>
order_size_type == 'Fixed' ? safe_order : safe_order / 100 * strategy.equity
safety_order_deviation(index) =>
price_deviation * math.pow(safe_order_step_scale, index - 1)
safety_order_price(index, last_safety_order_price) =>
if IS_LONG
last_safety_order_price * (1 - safety_order_deviation(index))
else
last_safety_order_price * (1 + safety_order_deviation(index))
safety_order_qty(index) =>
safe_order_size() * math.pow(safe_order_volume_scale, index - 1)
max_amount_for_bot_usage() =>
var total_qty = 0.0
var last_order_qty = 0.0
total_qty := base_order_size()
last_order_qty := safe_order_size()
if max_safe_order > 0
for index = 1 to max_safe_order by 1
total_qty += safety_order_qty(index)
total_qty
total_qty // returned value
max_deviation() =>
var total_deviation = 0.0
total_deviation := 0.0
for index = 1 to max_safe_order by 1
total_deviation += safety_order_deviation(index)
total_deviation
currency_format() =>
if syminfo.currency == 'USDT' or syminfo.currency == 'USD' or syminfo.currency == 'TUSD' or syminfo.currency == 'BUSD' or syminfo.currency == 'USDC' or syminfo.currency == 'EUR' or syminfo.currency == 'AUD'
'#.##'
else if syminfo.currency == 'BTC'
'#.########'
else
// TODO (rouxam) list more options
'#.####'
// ***********************************
// Deal Start Condition Strategies
// ***********************************
// RSI-7
// ***********************************
rsi_signal() =>
// Regular strat would be crossover but not for 3C DCA Bot
rsi7 = ta.rsi(close, 7)
if IS_LONG
[rsi7 < dsc_rsi_threshold, close]
else
[rsi7 > dsc_rsi_threshold, close]
// ----------------------------------
// (Re-)Initialize
// ----------------------------------
var max_amount = max_amount_for_bot_usage()
var max_dev = max_deviation()
init_price := na(init_price) and within_window() ? open : init_price
latest_price := within_window() ? close : latest_price
// Actualize the start and end time of the backtesting window because number of bars is limited.
// NOTE: limits on number of available bars:
// TradingView FREE account: 5000 bars available,
// TradingView PRO/PRO+ account: 10000 bars available,
// TradingView PREMIUM account: 20000 bars available.
start_time_actual := barstate.isfirst and time > start_time_actual ? time : start_time_actual
end_time_actual := time > end_time_actual and time <= end_time ? time : end_time_actual
if strategy.position_size == 0.0
ttp_extremum := 0.0
ttp_active := false
deal_start_condition := false
deal_start_condition
// ----------------------------------
// Open deal with Base Order on Deal Start Condition
// ----------------------------------
[dsc_rsi, bo_level_rsi] = request.security(syminfo.tickerid, dsc_res, rsi_signal())
[dsc_ta, bo_level_ta] = request.security(syminfo.tickerid, dsc_res, ta_presets_signal())
bop=ta.valuewhen(strategy.opentrades==0,close,0)
so1p=safety_order_price(1,bop)
so2p=safety_order_price(2,so1p)
so3p=safety_order_price(3,so2p)
so4p=safety_order_price(4,so3p)
so5p=safety_order_price(5,so4p)
so6p=safety_order_price(6,so5p)
so7p=safety_order_price(7,so6p)
so8p=safety_order_price(8,so7p)
so9p=safety_order_price(9,so8p)
so10p=safety_order_price(10,so9p)
so11p=safety_order_price(11,so10p)
so12p=safety_order_price(12,so11p)
so13p=safety_order_price(13,so12p)
so14p=safety_order_price(14,so13p)
so15p=safety_order_price(15,so14p)
so16p=safety_order_price(16,so15p)
so17p=safety_order_price(17,so16p)
so18p=safety_order_price(18,so17p)
so19p=safety_order_price(19,so18p)
so20p=safety_order_price(20,so19p)
so21p=safety_order_price(21,so20p)
bot=ta.valuewhen(strategy.opentrades==1,time,0)
so1t=ta.valuewhen(max_safe_order>=1 and ta.crossunder(low,so1p),time,0)
so2t=ta.valuewh