
Chiến lược này là chiến lược giao dịch định lượng dựa trên các chỉ số Bollinger Bands và MACD. Nó kết hợp hai chỉ số kỹ thuật chính thống để xác định cơ hội giao dịch, nhằm đạt được tỷ lệ thắng cao hơn trong các tình huống xu hướng.
Chiến lược này được thiết lập để tìm kiếm xu hướng theo dõi khi giá phá vỡ Bollinger dẫn xuống đường, khi giá phá vỡ đường dẫn; đồng thời sử dụng chỉ số MACD để xác định động lực hướng lọc phá vỡ giả. Chỉ số RSI có thể được cấu hình để hỗ trợ xác định quá mua quá bán để tránh tổn thất hơn nữa.
Chiến lược này chủ yếu bao gồm chỉ số Bollinger Bands và MACD.
Bollinger Bands được tính theo chênh lệch tiêu chuẩn của giá cổ phiếu trên và xuống đường, giá cổ phiếu là tín hiệu mua quá mức khi nó phá vỡ đường lên, và là tín hiệu bán quá mức khi nó phá vỡ đường xuống. Chiến lược này làm nhiều hơn khi giá xuống và phá vỡ đường xuống.
Chỉ số MACD đánh giá động lực và hướng của giá cổ phiếu. Đường trung bình ngắn hạn phá vỡ đường trung bình dài hạn là tín hiệu mua, ngược lại là tín hiệu bán. Chiến lược này kết hợp với chỉ số MACD để lọc các đợt phá vỡ giả của dải Bollinger.
Ngoài ra, chỉ số RSI có thể hỗ trợ trong việc xác định xem có quá mua hay quá bán không. RSI thấp có thể tăng cường tín hiệu mua và RSI cao có thể tăng cường tín hiệu bán.
Chiến lược này kết hợp ba chỉ số Bollinger Bands, MACD và RSI để xác định hiệu quả xu hướng và biến động của giá. Nó có những lợi thế sau:
Chiến lược này cũng có một số rủi ro cần lưu ý:
Phản ứng:
Chiến lược này có một số hướng tối ưu hóa chính:
Chiến lược này nói chung là một chiến lược theo dõi xu hướng điển hình. Nó kết hợp nhiều chỉ số kỹ thuật để tăng sự ổn định, có thể đạt được tỷ lệ thắng tốt khi phán đoán chính xác.
/*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")