Стратегия Momentum Oscillator Crossover Bollinger Band Moving Average


Дата создания: 2023-12-19 11:34:46 Последнее изменение: 2023-12-19 11:34:46
Копировать: 0 Количество просмотров: 652
1
Подписаться
1621
Подписчики

Стратегия Momentum Oscillator Crossover Bollinger Band Moving Average

Обзор

Эта стратегия является количественной торговой стратегией, основанной на индикаторах Bollinger Bands и MACD. Она объединяет два основных технических показателя для выявления торговых возможностей с целью получения более высокой выигрышной ставки в трендовых ситуациях.

Стратегия будет создавать многоголовый поиск Trend Following, когда цена прорвется вниз по Bollinger Bandwagon, а при прорыве цены на сверху она будет закрываться; в то же время используйте индикатор MACD, чтобы определить направление движения и фильтровать ложные прорывы. Можно настроить индикатор RSI, чтобы помочь определить, что перекуп и перепродажу, чтобы избежать дальнейших убытков.

Стратегический принцип

Стратегия состоит из Bollinger Bands и MACD.

Bollinger Bands - это отклонения от стандартной разницы цены на акции, при которых цена на акцию является сигналом о перекупке, когда она пробивается вверх, и сигналом о перепродаже, когда она падает вниз. Эта стратегия делает больше, когда цена пробивается вниз, и останавливает позицию, когда она падает.

MACD определяет динамику и направление цен на акции. Прорыв краткосрочных средних и долгосрочных средних является сигналом покупки, а не продажи. Эта стратегия в сочетании с MACD фильтрует ложные прорывы в полосе Боллинджера.

Кроме того, RSI может помочь определить, является ли перекуп перепродажей. Низкий RSI означает перепродажу, что может усилить сигнал покупки, а высокий RSI означает перекуп, что может усилить сигнал продажи.

Стратегические преимущества

Эта стратегия, объединяющая три индикатора: Bollinger Bands, MACD и RSI, позволяет эффективно оценивать тенденции и колебания цен. Она имеет следующие преимущества:

  1. Bollinger может определить диапазон колебаний цены, чтобы уловить Trend Following
  2. MACD определяет направление движения, отфильтровывает ошибочные сообщения Bollinger
  3. RSI помогает определить перекуп и перепродажу, чтобы избежать повышения позиций
  4. Повышенная вероятность победы с помощью оптимизации параметров

Стратегический риск

Однако есть и другие риски, о которых следует помнить:

  1. При резких колебаниях цен на акции риск остановки больше
  2. Если параметры не установлены вовремя, то снижается рентабельность
  3. MACD может ошибаться при обратном тренде

Ответ:

  1. Приемлемая смягченная остановка
  2. Необходимо многократное повторение, чтобы найти оптимальную комбинацию параметров
  3. Дополнительные индикаторы для прогнозирования ценовых поворотов

Направление оптимизации стратегии

Стратегия включает в себя следующие основные направления оптимизации:

  1. Оптимизация Bollinger Bands для большего количества рынков
  2. Добавление большего количества показателей, повышение стабильности стратегии
  3. Автоматическая оптимизация параметров с помощью алгоритмов машинного обучения
  4. Тестирование эффективности стратегии на высокочастотных данных
  5. Добавление модуля управления капиталом, чтобы контролировать одиночные потери

Подвести итог

Эта стратегия в целом является типичной стратегией отслеживания тенденций. Она сочетает в себе несколько технических показателей, повышающих стабильность, и при правильном суждении может получить хороший коэффициент победы. Но также существует определенный риск, о котором следует помнить.

Исходный код стратегии
/*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")