Esta estratégia utiliza o método de negociação de rede na teoria do oceano para colocar ordens de compra e venda dentro de uma faixa de preços pré-estabelecida.
A estratégia primeiro calcula os limites superior e inferior da grade de preços com base na escolha do usuário ou configurações padrão. Existem duas maneiras de cálculo: obter os preços mais altos e mais baixos no período de backtesting, ou calcular médias móveis em um período de tempo. Em seguida, as linhas da grade são uniformemente distribuídas de acordo com o número de redes definidas pelo usuário.
Os sinais de negociação são gerados com base na relação entre o preço e as linhas da grade. Quando o preço está abaixo de uma linha da grade, uma posição longa é aberta no preço da linha da grade com quantidade fixa; quando o preço sobe acima de uma linha da grade, a posição é fechada na linha da grade abaixo. À medida que o preço flutua dentro da grade, as posições mudam de acordo para ganhar lucro.
Especificamente, a estratégia mantém uma matriz de preços de linha de grade e uma matriz de bool indicando se as ordens são colocadas em cada linha. Quando o preço está abaixo de uma linha sem ordens, a posição longa é aberta na linha; quando o preço está acima de uma linha enquanto as ordens existem na linha abaixo, as posições são fechadas na linha inferior.
O intervalo da grade é calculado automaticamente, evitando dificuldades de configuração manual.
As linhas da grade são distribuídas uniformemente para evitar o excesso de troca devido às redes densas.
O método de negociação em rede controla efetivamente os riscos. O lucro pode ser obtido enquanto os preços flutuarem dentro da rede.
Nenhuma suposição de direção do preço, adequada para o mercado de intervalo.
O montante da remuneração deve ser calculado de acordo com o método de cálculo da remuneração.
A visualização das linhas da grade ajuda a compreender a situação comercial.
Riscos de ruptura dos preços.
Os riscos de espaço excessivo da rede. As redes demasiado soltas não podem beneficiar facilmente, enquanto as demasiado estreitas aumentam os custos. É necessário equilíbrio.
Riscos de detenção prolongada: a detenção prolongada dificulta o lucro mas aumenta os custos.
Riscos de definição inadequada de parâmetros: o período de ensaio posterior ou o período de média móvel podem afetar o cálculo do intervalo da rede se for definido de forma inadequada.
Riscos sistémicos de mercado, mais adequados para mercados de variação de variação do que para mercados de tendência de longo prazo.
Otimizar os parâmetros da rede. Considerar de forma abrangente as condições do mercado, custos, etc. para otimizar o número de redes, período de revisão, etc.
Introduzir o ajuste dinâmico do intervalo da rede e adaptar os intervalos da rede quando ocorrerem alterações significativas no mercado.
Incorporar mecanismos de stop loss, definir linhas de stop loss adequadas para limitar perdas, pode ser ajustado dinamicamente.
Adicione filtros usando outros indicadores, como Bandas de Bollinger, indicadores de tendência, etc., para evitar negociações inadequadas.
Melhorar a eficiência da utilização do capital e introduzir uma análise de volatilidade para reduzir as transacções durante períodos estáveis.
A estratégia realiza negociação de faixa de risco controlada alavancando princípios de negociação de rede. O cálculo automático da rede e a distribuição uniforme oferecem vantagens que se adequam a vários mercados através do ajuste de parâmetros. Os riscos são limitados e fáceis de operar. No entanto, existem limitações e são necessárias melhorias contínuas para se adaptar aos mercados em evolução.
/*backtest start: 2023-09-12 00:00:00 end: 2023-10-12 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=4 strategy("(IK) Grid Script", overlay=true, pyramiding=14, close_entries_rule="ANY", default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.1) i_autoBounds = input(group="Grid Bounds", title="Use Auto Bounds?", defval=true, type=input.bool) // calculate upper and lower bound of the grid automatically? This will theorhetically be less profitable, but will certainly require less attention i_boundSrc = input(group="Grid Bounds", title="(Auto) Bound Source", defval="Hi & Low", options=["Hi & Low", "Average"]) // should bounds of the auto grid be calculated from recent High & Low, or from a Simple Moving Average i_boundLookback = input(group="Grid Bounds", title="(Auto) Bound Lookback", defval=250, type=input.integer, maxval=500, minval=0) // when calculating auto grid bounds, how far back should we look for a High & Low, or what should the length be of our sma i_boundDev = input(group="Grid Bounds", title="(Auto) Bound Deviation", defval=0.10, type=input.float, maxval=1, minval=-1) // if sourcing auto bounds from High & Low, this percentage will (positive) widen or (negative) narrow the bound limits. If sourcing from Average, this is the deviation (up and down) from the sma, and CANNOT be negative. i_upperBound = input(group="Grid Bounds", title="(Manual) Upper Boundry", defval=0.285, type=input.float) // for manual grid bounds only. The upperbound price of your grid i_lowerBound = input(group="Grid Bounds", title="(Manual) Lower Boundry", defval=0.225, type=input.float) // for manual grid bounds only. The lowerbound price of your grid. i_gridQty = input(group="Grid Lines", title="Grid Line Quantity", defval=8, maxval=15, minval=3, type=input.integer) // how many grid lines are in your grid strategy.initial_capital = 50000 f_getGridBounds(_bs, _bl, _bd, _up) => if _bs == "Hi & Low" _up ? highest(close, _bl) * (1 + _bd) : lowest(close, _bl) * (1 - _bd) else avg = sma(close, _bl) _up ? avg * (1 + _bd) : avg * (1 - _bd) f_buildGrid(_lb, _gw, _gq) => gridArr = array.new_float(0) for i=0 to _gq-1 array.push(gridArr, _lb+(_gw*i)) gridArr f_getNearGridLines(_gridArr, _price) => arr = array.new_int(3) for i = 0 to array.size(_gridArr)-1 if array.get(_gridArr, i) > _price array.set(arr, 0, i == array.size(_gridArr)-1 ? i : i+1) array.set(arr, 1, i == 0 ? i : i-1) break arr var upperBound = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) : i_upperBound // upperbound of our grid var lowerBound = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) : i_lowerBound // lowerbound of our grid var gridWidth = (upperBound - lowerBound)/(i_gridQty-1) // space between lines in our grid var gridLineArr = f_buildGrid(lowerBound, gridWidth, i_gridQty) // an array of prices that correspond to our grid lines var orderArr = array.new_bool(i_gridQty, false) // a boolean array that indicates if there is an open order corresponding to each grid line var closeLineArr = f_getNearGridLines(gridLineArr, close) // for plotting purposes - an array of 2 indices that correspond to grid lines near price var nearTopGridLine = array.get(closeLineArr, 0) // for plotting purposes - the index (in our grid line array) of the closest grid line above current price var nearBotGridLine = array.get(closeLineArr, 1) // for plotting purposes - the index (in our grid line array) of the closest grid line below current price for i = 0 to (array.size(gridLineArr) - 1) if close < array.get(gridLineArr, i) and not array.get(orderArr, i) and i < (array.size(gridLineArr) - 1) buyId = i array.set(orderArr, buyId, true) strategy.entry(id=tostring(buyId), long=true, qty=(strategy.initial_capital/(i_gridQty-1))/close, comment="#"+tostring(buyId)) if close > array.get(gridLineArr, i) and i != 0 if array.get(orderArr, i-1) sellId = i-1 array.set(orderArr, sellId, false) strategy.close(id=tostring(sellId), comment="#"+tostring(sellId)) if i_autoBounds upperBound := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) lowerBound := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) gridWidth := (upperBound - lowerBound)/(i_gridQty-1) gridLineArr := f_buildGrid(lowerBound, gridWidth, i_gridQty) closeLineArr := f_getNearGridLines(gridLineArr, close) nearTopGridLine := array.get(closeLineArr, 0) nearBotGridLine := array.get(closeLineArr, 1)