
A estratégia usa um método de ruptura de nível, fazendo mais vazio em determinadas condições de ruptura e tem uma função de feedback automático para encontrar o melhor conjunto de parâmetros.
Os parâmetros de entrada incluem o número de dias de retorno, a porcentagem de parada e a porcentagem de parada, bem como parâmetros de retorno automático, como o número de dias de retorno, o intervalo de parada e outros.
A retrospectiva passa por várias combinações de dias de retrospectiva, percentual de parada e percentual de parada, registrando os ganhos e perdas de cada combinação.
O julgamento de sinais de ruptura: fazer mais no preço de fechamento que atravessa a banda superior e não o período de entrada no mercado; fazer vazio abaixo do preço de fechamento que atravessa a banda inferior e não o período de entrada no mercado.
Determinação das condições de stop loss: se não parar e acionar a linha de stop loss, o jogo é interrompido.
Caso não tenha sofrido danos e tenha acionado a linha de parada, a parada é eliminada.
Apresenta uma tabela detalhada dos resultados dos testes, que pode ser ordenada por taxa de ganho ou lucro líquido ou número de transações, de acordo com a configuração do usuário.
A função de feedback automático permite encontrar rapidamente o melhor conjunto de parâmetros, sem a necessidade de testes manuais.
Os resultados podem ser ordenados de acordo com a taxa de lucro, lucro líquido, número de transações, etc. A escolha flexível corresponde aos parâmetros ideais para as suas necessidades.
Visualizar os lucros e perdas de cada transação.
Os parâmetros de detecção podem ser personalizados, permitindo testar um espaço de parâmetros mais amplo para encontrar o melhor resultado global.
As regras de negociação estratégica são simples, claras e fáceis de entender.
O ciclo de resposta curto pode causar resultados instáveis. Solução: configure um ciclo de resposta mais longo.
A frequência de negociação pode causar desvios que afetam o lucro. Método de solução: relaxar adequadamente o limiar de perda.
Os resultados de um único produto podem não ser representativos. Método de solução: teste diferentes variedades e encontre um conjunto de parâmetros estável.
A otimização excessiva dos parâmetros pode levar a um excesso de adequação. Método de Solução: Verificar a estabilidade dos parâmetros em diferentes variedades e períodos de tempo.
Ignorar os custos de transação pode levar a um desvio nos resultados da retrospectiva. Solução: definir um parâmetro de taxação razoável.
Adicionar dimensões de otimização de parâmetros, como adicionar um stop loss móvel ou um limite de número de transações.
Otimizar as condições de entrada em mercado, combinando filtros de indicadores de tendência.
Optimizar estratégias de stop loss, como stop loss dinâmico ou stop loss de rastreamento.
Otimização de parâmetros auxiliados por algoritmos como aprendizado de máquina.
Otimizar a estrutura do código e aumentar a velocidade de detecção.
Estabilidade dos parâmetros de validação em múltiplos ciclos de várias variedades.
Considere a integração de funções de negociação automática.
O conceito geral da estratégia é claro e fácil de entender, a função de feedback automático pode otimizar rapidamente os parâmetros, mostrando que a situação de lucro e prejuízo é favorável à melhoria da estratégia. Há um certo risco a ser observado, mas pode ser melhorado continuamente através de otimização em vários aspectos, com um forte valor prático. No geral, a estratégia usa uma ideia simples e inovadora, equipada com ferramentas de feedback automático, para auxiliar os comerciantes a estabelecer rapidamente um sistema de negociação estável.
/*backtest
start: 2023-09-16 00:00:00
end: 2023-10-16 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
// © -_-
//@version=5
// strategy("[-_-] LBAB", process_orders_on_close=true, overlay=true, max_labels_count=500, max_lines_count=500, max_boxes_count=500, default_qty_type=strategy.cash, default_qty_value=100, initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.075)
// Inputs
lookback = input.int(2, title="Lookback", minval=2, maxval=15)
tp = input.float(5, title="TP (%)", minval=1, maxval=10000)
sl = input.float(5, title="SL (% from Low)", minval=1, maxval=100)
com = input.float(0.075, title="Commission (%)", minval=0, maxval=50)
min_lookback_tr = input.float(2, title="Min Lookback", minval=1, maxval=500, inline="tr_lookback", group="Optimisation")
max_lookback_tr = input.float(5, title="Max Lookback", minval=1, maxval=500, inline="tr_lookback", group="Optimisation")
min_tp_tr = input.float(5, title="Min TP (%)", minval=1, maxval=10000, inline="tr_tp", group="Optimisation")
max_tp_tr = input.float(10, title="Max TP (%)", minval=1, maxval=10000, inline="tr_tp", group="Optimisation")
min_sl_tr = input.float(1, title="Min SL (%)", minval=1, maxval=100, inline="tr_sl", group="Optimisation")
max_sl_tr = input.float(5, title="Max SL (%)", minval=1, maxval=100, inline="tr_sl", group="Optimisation")
imp_perc_profit = input.bool(true, title="Percentage profitable", group="Optimisation")
imp_netprofit = input.bool(false, title="Net profit", group="Optimisation")
imp_numtrades = input.bool(false, title="Number of trades", group="Optimisation")
table_pos = input.string("Bottom Right", title="Position", options=["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"], group="Table")
table_font_size = input.string("Normal", title="Font size", options=["Auto", "Tiny", "Small", "Normal", "Large"], group="Table")
// Table parameters
table_pos_ = switch table_pos
"Top Left" => position.top_left
"Top Center" => position.top_center
"Top Right" => position.top_right
"Middle Left" => position.middle_left
"Middle Center" => position.middle_center
"Middle Right" => position.middle_right
"Bottom Left" => position.bottom_left
"Bottom Center" => position.bottom_center
"Bottom Right" => position.bottom_right
table_font_size_ = switch table_font_size
"Auto" => size.auto
"Tiny" => size.tiny
"Small" => size.small
"Normal" => size.normal
"Large" => size.large
// Sorting function (first element will be largest)
sortArr(arr, arr_index) =>
n = array.size(arr) - 1
for i = 0 to n - 1
for j = 0 to n - i - 1
if array.get(arr, j) < array.get(arr, j + 1)
temp = array.get(arr, j)
temp_index = array.get(arr_index, j)
array.set(arr, j, array.get(arr, j + 1))
array.set(arr, j + 1, temp)
array.set(arr_index, j, array.get(arr_index, j + 1))
array.set(arr_index, j + 1, temp_index)
// Safe checks
if min_lookback_tr > max_lookback_tr
runtime.error("Min Lookback must be less than Max Lookback")
if min_tp_tr > max_tp_tr
runtime.error("Min Take Profit must be less than Max Take Profit")
if min_sl_tr > max_sl_tr
runtime.error("Min Stop Loss must be less than Max Stop Loss")
//
tp_min_ = int(min_tp_tr / 1)
tp_max_ = int(max_tp_tr / 1)
sl_min_ = int(min_sl_tr / 1)
sl_max_ = int(max_sl_tr / 1)
// Size for arrays
arr_size = int((max_lookback_tr - min_lookback_tr + 1) * (tp_max_ - tp_min_ + 1) * (sl_max_ - sl_min_ + 1))
// Arrays
var arr_bi = array.new_int(arr_size, na) // bar_index of Smash Day
var arr_in_pos = array.new_bool(arr_size, false) // are we in a position?
var arr_params = array.new_string(arr_size, "")
var arr_wonlost = array.new_string(arr_size, "")
var arr_profit = array.new_float(arr_size, 0)
// Testing what parameters are best
index = 0
// Lookback
for lookback_i = min_lookback_tr to max_lookback_tr
// Take profit
for tp_i = tp_min_ to tp_max_
// Stop loss
for sl_i = sl_min_ to sl_max_
// Parameters of current iteration
lookback_ = lookback_i
tp_ = tp_i
sl_ = sl_i
//
if array.get(arr_params, index) == ""
array.set(arr_params, index, str.tostring(lookback_) + " " + str.tostring(tp_) + " " + str.tostring(sl_))
// Was there an entry?
was_edone = false
// If entry price reached
if not array.get(arr_in_pos, index) and not na(array.get(arr_bi, index))
if high >= high[bar_index - array.get(arr_bi, index)] and bar_index != array.get(arr_bi, index)
array.set(arr_in_pos, index, true)
was_edone := true
// If we're in a position
if array.get(arr_in_pos, index) and bar_index != array.get(arr_bi, index) and not was_edone
low_sl = low[bar_index - array.get(arr_bi, index)] * (1 - sl_ / 100)
high_ep = high[bar_index - array.get(arr_bi, index)]
high_tp = high_ep * (1 + tp_ / 100)
amount = 100
// Stop loss
if low <= low_sl
array.set(arr_in_pos, index, false)
array.set(arr_wonlost, index, array.get(arr_wonlost, index) + "0")
array.set(arr_profit, index, array.get(arr_profit, index) - math.abs(amount / high_ep * low_sl - amount) - com / 100 * amount * 2)
array.set(arr_bi, index, na)
// Take profit
if high >= high_tp
array.set(arr_in_pos, index, false)
array.set(arr_wonlost, index, array.get(arr_wonlost, index) + "1")
array.set(arr_profit, index, array.get(arr_profit, index) + math.abs(amount / high_ep * high_tp - amount) - com / 100 * amount * 2)
array.set(arr_bi, index, na)
// Entry condition
cond = barstate.isconfirmed and close < low[1] and high[1] < high[lookback_ + 1] //and not array.get(arr_in_pos, index)
// New entry price
if cond and not array.get(arr_in_pos, index)
array.set(arr_bi, index, bar_index)
// Update index
index := index + 1
// Checking the results
var table t = na
var result_index = array.new_int(0, na)
var result_arr_winrate = array.new_float(0, na)
var result_arr_tradenum = array.new_int(0, na)
var sort_array = array.new_float(0, na)
if (barstate.islast or barstate.islastconfirmedhistory) and na(t)
for i = 0 to array.size(arr_params) - 1
wins = 0
losses = 0
arr = array.get(arr_wonlost, i)
for j = 0 to str.length(arr) - 1
str_ = str.substring(arr, j, j + 1)
if str_ == "0"
losses := losses + 1
if str_ == "1"
wins := wins + 1
// Push percentage profitable trades
perc_profit = math.round(wins / (wins + losses) * 100, 2)
array.push(result_arr_winrate, perc_profit)
// Push number of trades
trade_num = str.length(array.get(arr_wonlost, i))
array.push(result_arr_tradenum, trade_num)
// Push index
array.push(result_index, i)
// For combined sorting
array.push(sort_array, (imp_netprofit ? array.get(arr_profit, i) : 1) * (imp_perc_profit ? perc_profit : 1) * (imp_numtrades ? trade_num : 1))
// Sort
sortArr(array.copy(sort_array), result_index)
t := table.new(columns=6, rows=13, bgcolor=color.white, border_color=color.new(color.blue, 0), border_width=1, frame_color=color.new(color.blue, 0), frame_width=1, position=table_pos_)
table.cell(t, 0, 0, "% Profitable" + (imp_perc_profit ? " ↓" : ""), bgcolor=imp_perc_profit ? color.rgb(23, 18, 25) : color.white, text_color=imp_perc_profit ? color.white : color.black, text_size=table_font_size_)
table.cell(t, 1, 0, "Net Profit" + (imp_netprofit ? " ↓" : ""), bgcolor=imp_netprofit ? color.rgb(23, 18, 25) : color.white, text_color=imp_netprofit ? color.white : color.black, text_size=table_font_size_)
table.cell(t, 2, 0, "# of trades" + (imp_numtrades ? " ↓" : ""), bgcolor=imp_numtrades ? color.rgb(23, 18, 25) : color.white, text_color=imp_numtrades ? color.white : color.black, text_size=table_font_size_)
table.cell(t, 3, 0, "Lookback", text_size=table_font_size_)
table.cell(t, 4, 0, "Take Profit %", text_size=table_font_size_)
table.cell(t, 5, 0, "Stop Loss %", text_size=table_font_size_)
counter = 0
forloop_counter = math.min(array.size(result_index) - 1, 10)
for i = 0 to forloop_counter
i_ = array.get(result_index, i)
params_ = str.split(array.get(arr_params, i_), " ")
col_ = color.new(color.blue, 75)
table.cell(t, 0, i + 1, str.tostring(array.get(result_arr_winrate, i_)) + "%", bgcolor=col_, text_size=table_font_size_)
table.cell(t, 1, i + 1, str.tostring(math.round(array.get(arr_profit, i_), 2)) + "$", bgcolor=col_, text_size=table_font_size_)
table.cell(t, 2, i + 1, str.tostring(array.get(result_arr_tradenum, i_)), bgcolor=col_, text_size=table_font_size_)
table.cell(t, 3, i + 1, array.get(params_, 0), bgcolor=col_, text_size=table_font_size_)
table.cell(t, 4, i + 1, array.get(params_, 1), bgcolor=col_, text_size=table_font_size_)
table.cell(t, 5, i + 1, array.get(params_, 2), bgcolor=col_, text_size=table_font_size_)
counter := counter + 1
// Warn if timeframe is <= 10 minutes
if timeframe.in_seconds(timeframe.period) <= 600
table.cell(t, 0, forloop_counter + 2, "Timeframe might be too low", bgcolor=color.orange, text_size=table_font_size_, tooltip="Selected timeframe might be too low and cause an error")
table.merge_cells(t, 0, forloop_counter + 2, 5, forloop_counter + 2)
// Strategy
var int bi = na
var int pos_bi = na
// Buy condition
cond = barstate.isconfirmed and close < low[1] and high[1] < high[lookback + 1] and strategy.position_size == 0
// Stop loss, Take profit
if strategy.position_size[1] == 0 and strategy.position_size > 0 and bar_index != bi
strategy.exit("TP/SL", "Long", stop=low[bar_index - bi] * (1 - sl / 100), limit=high[bar_index - bi] * (1 + tp / 100))
pos_bi := bar_index
// Buy
if cond
strategy.order("Long", strategy.long, stop=high)
bi := bar_index
// Box
if strategy.position_size[1] != 0 and strategy.position_size == 0
tn = strategy.closedtrades - 1
penp = strategy.closedtrades.entry_price(tn)
pexp = strategy.closedtrades.exit_price(tn)