Il s'agit d'une stratégie de trading quantitative basée sur les bandes de Bollinger et les indicateurs MACD.
L'indicateur MACD est utilisé pour filtrer la fausse rupture en jugeant la direction de l'élan. L'indicateur RSI peut être configuré pour aider à identifier les niveaux de surachat et de survente afin d'éviter davantage les pertes.
La stratégie est principalement constituée d'indicateurs Bollinger Bands et MACD.
Les bandes de Bollinger calculent les bandes supérieures et inférieures en fonction de l'écart type des prix. La rupture vers le haut de la bande supérieure indique une condition de surachat, tandis que la rupture vers le bas de la bande inférieure indique une condition de survente.
L'indicateur MACD juge l'élan et la direction des prix. Le croisement de la moyenne mobile à court terme au-dessus de la moyenne mobile à long terme est un signal d'achat, tandis que le croisement en dessous est un signal de vente.
En outre, l'indicateur RSI peut aider à identifier les niveaux de surachat / survente.
La stratégie combine des bandes de Bollinger, des indicateurs MACD et RSI qui peuvent déterminer efficacement la tendance et la volatilité des prix.
Il y a aussi des risques à prendre en compte:
Les contre-mesures:
Les principales orientations pour optimiser la stratégie sont les suivantes:
Dans l'ensemble, c'est une tendance typique suivant la stratégie. En combinant plusieurs indicateurs techniques, il améliore la robustesse et peut atteindre un taux de gain décent lorsque les signaux sont précis. Cependant, les risques doivent être surveillés. D'autres améliorations peuvent être apportées grâce à une optimisation et à un ajustement continus.
/*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")