
A estratégia é uma estratégia de negociação quantitativa baseada nos indicadores Bollinger Bands e MACD. Combina dois indicadores técnicos principais para identificar oportunidades de negociação com o objetivo de obter uma maior taxa de vitória em situações de tendência.
A estratégia pode ser criada para buscar o Trend Following quando o preço quebra o Bollinger Bandwagon, e fechar a posição quando o preço quebra o trajeto; ao mesmo tempo, usar o indicador MACD para determinar a direção do movimento e filtrar as falsas rupturas. O indicador RSI pode ser configurado para auxiliar a decisão de comprar ou vender para evitar mais perdas.
A estratégia é composta principalmente por indicadores de Bollinger Bands e MACD.
A faixa de Bollinger é um sinal de compra quando o preço da ação sobe e desce, e de venda quando desce. Esta estratégia faz mais quando o preço desce e desce.
O indicador MACD determina a dinâmica e a direção do preço das ações. A ruptura da média de curto prazo é um sinal de compra, e não de venda. Esta estratégia combina o indicador MACD para filtrar a falsa ruptura da faixa de Bollinger.
Além disso, o indicador RSI pode auxiliar a determinar se está a ser comprado ou vendido. Quando o RSI é baixo, significa que está a ser vendido e pode aumentar o sinal de compra. Quando o RSI é alto, significa que está a ser comprado e pode aumentar o sinal de venda.
A estratégia combina três indicadores, Bollinger Bands, MACD e RSI, para determinar com eficiência as tendências e oscilações dos preços. Tem as seguintes vantagens:
A estratégia também apresenta alguns riscos que devem ser alertas:
Resposta:
A estratégia tem as seguintes principais melhorias:
Esta estratégia é, em geral, uma estratégia típica de acompanhamento de tendências. Combina vários indicadores técnicos para aumentar a estabilidade, obtendo uma boa taxa de vitória quando julgado com precisão. Mas também há um certo risco a ser observado.
/*backtest
start: 2022-12-12 00:00:00
end: 2023-12-18 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=4
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tedwardd
// This strategy is intended to help users of the 3commas.io platform backtest bot performance based on a Bollinger Strategy.
// It can also be used to signal a bot to open a deal by providing the Bot ID, email token and trading pair in the strategy settings screen.
// As currently written, this strategy uses a basic Bollinger Band strategy, recommening a deal start when the closing price crosses under the lower band.
// The thick red line plotted on the chart shows the average entry price of the current deal.
strategy("[v1.3laoowai]BNB_USDT_3m_3Commas_Bollinger_Strategy_by_tedwardd", overlay=true, default_qty_type=strategy.cash, default_qty_value=1000, initial_capital=900, currency="USD", commission_value=0.1)
// 3Commas Bot settinsg
bot_type = input(title="Simple bot", defval="simple", options=["simple", "composite"])
bot_id = input(title="3Commas Bot ID", defval="")
email_token = input(title="Bot Email Token", defval="")
base_order_size = input(title="Base order size",minval=10, step=1, defval=10)
safety_order_size = input(title="Safety order size", minval=15, step=1, defval=400)
volume_scale = input(title="Safety Order Vol Scale (%)", minval=0.00, step=0.01, defval=1.83)
safety_step = input(title="Safety Order Step Scale (%)", minval=0.00, step=0.1, defval=1.55)
safety_max = input(title="Max Number of Safety Orders", minval=0, step=1, defval=2)
initial_deviation_input = input(title="Initial SO Deviation (%)", minval=0, step=0.01, defval=1.54) * 0.01
stoploss_input = input(title="Long Stop Loss (%)", minval=0, step=1, defval=15) * 0.01
takeprofit_input = input(title="Long Take Profit (%)", minval=0, step=1, defval=1.4) * 0.01
// USER INPUTS
sma_short_val = input(title="Short MA Window", defval=21)
sma_long_val = input(title="Long MA Window", defval=100)
ubOffset = input(title="Upper Band Offset", defval=2.2, step=0.5)
lbOffset = input(title="Lower Band Offset", defval=2.40, step=0.5)
cross = input(title="Entrry at Cross Over/Under Lower", defval="under", options=["over", "under"])
// Backtesting Date Ranges
startDate = input(title="Start Date", defval=1, minval=1, maxval=31)
startMonth = input(title="Start Month", defval=1, minval=1, maxval=12)
startYear = input(title="Start Year", defval=2016, minval=1800, maxval=2100)
endDate = input(title="End Date", defval=31, minval=1, maxval=31)
endMonth = input(title="End Month", defval=12, minval=1, maxval=12)
endYear = input(title="End Year", defval=2022, minval=1800, maxval=2100)
// VARS
short_sma = sma(close, sma_short_val)
long_sma = sma(close, sma_long_val)
stdDev = stdev(close, sma_short_val)
upperBand = short_sma + (stdDev * ubOffset)
lowerBand = short_sma - (stdDev * lbOffset)
stoploss_value = strategy.position_avg_price * (1 - stoploss_input)
takeprofit_value = strategy.position_avg_price * (1 + takeprofit_input)
initial_dev_val = strategy.position_avg_price * (1 - initial_deviation_input)
inDateRange = true
initial_deviation = close < initial_dev_val
// Market Conditions
goodBuy = cross=="over"?crossover(close, lowerBand):crossunder(close, lowerBand) // Buy when close crossing lower band
safety = initial_deviation and (1-(close/strategy.position_avg_price))/.01 > strategy.opentrades-1 * safety_step and strategy.opentrades <= safety_max // SO when price deviates below SO threshold %
stoploss = close <= stoploss_value // Stoploss condition - true if closing price for current bar drops below stoploss %
takeprofit = close >= takeprofit_value // Take profit condition - true if closing price for current bar is >= take profit percentage
goodSell = crossover(high, upperBand)
// goodSell is currently unused for any practical purpose. If you wish to try it, switch these two values.
// Doing so will make sell suggestions at high crossover upper bollinger but it does not trigger the bot to sell as written but may affect backtest results
// Plot some lines
plot(short_sma, color=color.green)
plot(upperBand)
plot(lowerBand, color=color.yellow)
plot(strategy.position_avg_price, color=color.red, linewidth=3)
// Webhook message. Defaults to string. To signal 3c bot, fill in bot_id and email_token in user settings
var enter_msg = "Enter Position"
var exit_msg = "Exit Position"
var close_all = "Exit Position"
if bot_id != "" and email_token != ""
if bot_type == "composite"
enter_msg := '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "' + email_token + '", "delay_seconds": 0, "pair": "' + syminfo.currency + "_" + syminfo.basecurrency + '"}'
else
enter_msg := '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "' + email_token + '", "delay_seconds": 0}'
if bot_type == "composite"
exit_msg := '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "' + email_token + '", "delay_seconds": 0, "pair": "' + syminfo.currency + "_" + syminfo.basecurrency + '", "action": "close_at_market_price"}'
else
exit_msg := '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "' + email_token + '", "delay_seconds": 0, "action": "close_at_market_price"}'
close_all := '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "' + email_token + '", "delay_seconds": 0, "action": "close_at_market_price_all"}'
actual_safety_size = float(safety_order_size) // Set safety order size to starting safety
if strategy.opentrades > 1 // If we have more than two open trades we need to start scaling the safety size by the volume_scale
actual_safety_size := (strategy.position_size - base_order_size) * volume_scale // Remove base order from total position size and scale it for next safety order
// Momentum Strategy (BTC/USDT; 1h) - MACD (with source code) by Drun30
//@version=4
// Getting inputs
fast_length = input(title="Fast Length", type=input.integer, defval=23,group="MACD")
slow_length = input(title="Slow Length", type=input.integer, defval=16,group="MACD")
src = input(title="Source", type=input.source, defval=open,group="MACD")
signal_length = input(title="Signal Smoothing", type=input.integer, minval = 1, maxval = 50, defval = 9,group="MACD")
sma_source1 = input(title="Simple MA FAST (Oscillator)", defval="EMA", options=["HMA","DHMA","THMA","FHMA","WMA","DWMA","TWMA","FWMA","SMA","DSMA","TSMA","FSMA","EMA","DEMA","TEMA","FEMA","RMA","DRMA","TRMA","FRMA"],group="MACD")
sma_source2 = input(title="Simple MA SLOW (Oscillator)", defval="EMA", options=["HMA","DHMA","THMA","FHMA","WMA","DWMA","TWMA","FWMA","SMA","DSMA","TSMA","FSMA","EMA","DEMA","TEMA","FEMA","RMA","DRMA","TRMA","FRMA"],group="MACD")
sma_signal = input(title="Simple MA(Signal Line)",defval="EMA", options=["HMA","DHMA","THMA","FHMA","WMA","DWMA","TWMA","FWMA","SMA","DSMA","TSMA","FSMA","EMA","DEMA","TEMA","FEMA","RMA","DRMA","TRMA","FRMA"],group="MACD")
// Calculating
ma(source,length,type)=>
type=="FEMA"?4*ema(source,length)-ema(ema(ema(ema(source,length),length),length),length):type=="FSMA"?4*sma(source,length)-sma(sma(sma(sma(source,length),length),length),length):type=="FWMA"?4*wma(source,length)-wma(wma(wma(wma(source,length),length),length),length):type=="FRMA"?4*rma(source,length)-rma(rma(rma(rma(source,length),length),length),length):type=="TEMA"?3*ema(source,length)-ema(ema(ema(source,length),length),length):type=="TSMA"?3*sma(source,length)-sma(sma(sma(source,length),length),length):type=="TWMA"?3*wma(source,length)-wma(wma(wma(source,length),length),length):type=="TRMA"?3*rma(source,length)-rma(rma(rma(source,length),length),length):type=="EMA"?ema(source,length):type=="SMA"?sma(source,length):type=="WMA"?wma(source,length):type=="RMA"?rma(source,length):type=="DEMA"?2*ema(source,length)-ema(ema(source,length),length):type=="DSMA"?2*sma(source,length)-sma(sma(source,length),length):type=="DWMA"?2*wma(source,length)-wma(wma(source,length),length):type=="DRMA"?2*rma(source,length)-rma(rma(source,length),length):type=="HMA"?hma(source,length):type=="DHMA"?2*hma(source,length)-hma(hma(source,length),length):type=="THMA"?3*hma(source,length)-hma(hma(hma(source,length),length),length):type=="FHMA"?4*hma(source,length)-hma(hma(hma(hma(source,length),length),length),length):ema(source,length)
fast_ma = ma(src,fast_length,sma_source1)
slow_ma = ma(src,slow_length,sma_source2)
macd = fast_ma - slow_ma //Differenza tra la media mobile veloce e quella lenta
signal = ma(macd,signal_length,sma_signal) //usa o la SMA oppure la EMA sulla differenza tra la media mobile veloce e lenta
hist = macd - signal //Differenza tra la differenza precedente e la media mobile della differenza
use_stress=input(true,title="Use stress on recent bars",group="Stress")
recent_stress=input(0.41,title="Stress on recent bars",group="Stress",step=0.01,minval=0.01,maxval=0.99)
level=input(6,title="Level of stress",group="Stress")
if use_stress
macd:=macd*(1/(1-recent_stress))
if not na(macd[1])
macd:=pow((macd*(recent_stress)),level)+(1-recent_stress*macd[1])
use_ma= input(true,title="Use moving average (MACD)?",group="Moving Average")
if use_ma
macd:=ma(macd,input(36,title="Length",group="Moving Average"),input(title="Type MA",defval="THMA", options=["HMA","DHMA","THMA","FHMA","WMA","DWMA","TWMA","FWMA","SMA","DSMA","TSMA","FSMA","EMA","DEMA","TEMA","FEMA","RMA","DRMA","TRMA","FRMA"],group="Moving Average"))
use_linreg= input(true,title="Use linear regression (MACD)?",group="Linear Regression")
if use_linreg
macd:=linreg(macd,input(10,title="Length",group="Linear Regression"),input(1,title="Offset",group="Linear Regression"))
//macd == linea blu (differenza tra media mobile veloce e media mobile lenta)
//signal == linea arancione (media mobile dell'macd)
//hist == istogramma (differenza tra macd e media mobile)
on_cross = input(false,title="Use cross macd and signal",group="Condition entry/exit")
on_minmax = input(true,title="Use min/max macd",group="Condition entry/exit")
aperturaLong = change(macd)>0//crossover(macd,signal)
aperturashort=not (change(macd)>0)//crossunder(macd,signal)
if on_cross
on_minmax:=false
aperturaLong := crossover(macd,signal)
aperturashort := crossunder(macd,signal)
if on_minmax
on_cross:=false
aperturaLong := change(macd)>0//crossover(macd,signal)
aperturashort:=change(macd)<0//crossunder(macd,signal)
rsiFilter = input(false,title="Use RSI filter?",group="RSI")
rsiTP = input(true,title="Use RSI Take Profit?",group="RSI")
len=input(22,title="RSI period",group="RSI")
srcr=input(close,title="RSI source",group="RSI")
rsi=rsi(srcr,len)
ovb=input(90,title="Overbought height",group="RSI")
ovs=input(45,title="Oversold height",group="RSI")
okLong=rsi<ovb and change(macd)>0 and change(macd)[1]<=0
okShort=rsi>ovs and change(macd)<0 and change(macd)[1]>=0
if not rsiFilter
okLong:=true
okShort:=true
usiLong=input(true,title="Use long?")
usiShort=input(true,title="Use short?")
chiusuraShort=rsi<ovs or (aperturaLong)
chiusuraLong=rsi>ovb or (aperturashort)
if rsiTP
aperturaLong := change(macd)>0 and change(macd)[1]<=0 and rsi<ovb//crossover(macd,signal)
aperturashort:=change(macd)<0 and change(macd)[1]>=0 and rsi>ovs//crossunder(macd,signal)
if not rsiTP
chiusuraShort:=okLong and aperturaLong
chiusuraLong:=okShort and aperturashort
//if chiusuraShort
// strategy.close("SHORTISSIMO")
//if usiLong and strategy.position_size<=0 and okLong and aperturaLong
// strategy.entry("LONGHISSIMO",true)
//if chiusuraLong
// strategy.close("LONGHISSIMO")
//if usiShort and strategy.position_size>=0 and okShort and aperturashort
// strategy.entry("SHORTISSIMO",false)
// Strategy Actions
//Buy
if inDateRange and goodBuy
strategy.entry("Good Buy", strategy.long, base_order_size, when = strategy.opentrades <= 0, alert_message=enter_msg)
if inDateRange and safety
strategy.order("Good Buy", strategy.long, actual_safety_size, when = strategy.opentrades > 0, comment = "safety order", alert_message=enter_msg)
// Sell
if inDateRange and goodSell
strategy.close_all(comment="Good sell point", alert_message=exit_msg)
if inDateRange and stoploss
strategy.close_all(comment="Stoploss", alert_message=exit_msg)
//if inDateRange and takeprofit
// strategy.close_all(comment="TP Target", alert_message=exit_msg)
if usiShort and strategy.position_size>=0 and okShort and aperturashort
strategy.close_all(comment="SHORTISSIMO", alert_message=exit_msg)
//if chiusuraShort
// strategy.close_all(comment="SHORTISSIMO1")