本策略利用RSI指标识别超卖机会,在价格下跌时分批入场,通过不断均值降低持仓成本实现长期获利。同时,策略加入DCA机制,进一步控制风险。
本策略首先计算RSI指标判断市场是否超卖。当RSI低于30时,标志着超卖机会的出现。此时,如果价格低于100周期均线,则做多开仓。
开仓后,策略会设置6个均值回归价格,分别是当前价格的98%、97%、95%、90%、84%和70%。当价格触及这些价格时,会继续追加仓位。这样通过不断均值,可以降低持仓成本。
此外,策略还计算持仓的平均价格。当价格上涨超过平均价格5%后,开始止盈。同时,如果价格继续上涨,超过平均价格的5%止盈价格,则全部止盈。
最后,本策略还加入DCA机制。每周一如果有持仓,且价格低于平均价格,则追加固定金额的仓位。这进一步降低了持仓成本。
本策略最大的优势在于利用均值和DCA机制控制了风险。具体来说,包括以下几点:
采用分批入场策略,可以分散开仓风险,避免错过最低点。
设置多个均值回归价格,可以不断降低持仓成本,有效控制下跌风险。
计算持仓平均价格,实现盈利后及时止盈,锁定收益。
应用DCA机制,进一步降低持仓成本,控制风险。
采用RSI指标判断市场时点,避免高点开仓。
利用均线过滤,避免反转开仓。
本策略也存在一定的风险,主要包括:
策略无法确定市场反转点,如果遇到长期维持低位的市场,持续做多会增大亏损。
策略没有考虑止损机制,无法有效控制单笔亏损。
策略没有限制开仓次数,如果行情剧烈下跌,仓位会不断增加。
DCA机制存在时间风险,不能保证一定在最低点开仓。
对应解决方法:
可以结合其他指标判断市场结构,避免单一依赖RSI。
增加移动止损或者缩量止损。
限制开仓层数,避免仓位过大。
优化DCA开仓时机,采用更稳定的方式。
本策略可以从以下几个方面进行优化:
优化均值回归算法,采用更科学的方式计算价格回归值。
优化止盈方式,可以采用移动止盈或者阶梯止盈。
增加止损策略,更好控制单笔亏损。
结合其他指标判断市场结构,避免单一依赖RSI。
优化DCA开仓逻辑,避免固定时间开仓的风险。
添加仓位管理模块,优化仓位大小。
优化参数设置,使得策略更适应市场统计特性。
加入切换逻辑,在不同市场环境中切换策略方式。
本策略总体上是一个利用RSI判断时点,分批入场进行均值的长线投资策略。它非常适合目前高波动的数字货币市场,可以有效利用震荡区间进行持仓成本管理。同时,策略机制也存在可以优化的地方,如果加入更多技术指标判断和风险控制模块,可以进一步改进策略效果,使得其足以应对更加复杂的市场环境。
/*backtest
start: 2023-08-26 00:00:00
end: 2023-09-25 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//@version=4
// © A3Sh
// RSI Strategy that buys the dips, works with Price Averaging and has a Dollar Cost Average option.
// When the price drops below specified percentages of the price (6 PA layers), new entries are openend to average the price of the assets.
// Open entries are closed by a specified take profit.
// Entries can be reopened, after closing and consequently crossing a PA layer again.
// The idea is to lower the average position price to a point that when the market rises, the current price crosses over the average position price.
// When the current price crosses the average position size and reaches the specified take profit, all entries are closed at once.
// In case the market drops significantly, there is an option to activate DCA to lower the average price further.
// RSI code adapted from the Optimized RSI Buy the Dips strategy, by Coinrule
// https://www.tradingview.com/script/Pm1WAtyI-Optimized-RSI-Strategy-Buy-The-Dips-by-Coinrule/
// Pyramiding entries code adapted from Pyramiding Entries on Early Trends startegy, by Coinrule
// https://www.tradingview.com/script/7NNJ0sXB-Pyramiding-Entries-On-Early-Trends-by-Coinrule/
// Plot entry layers code adapted from HOWTO Plot Entry Price by vitvlkv
// https://www.tradingview.com/script/bHTnipgY-HOWTO-Plot-Entry-Price/
// Buy every week code based on the following question in Stack Overflow
// https://stackoverflow.com/questions/59870411/in-pine-script-how-can-you-do-something-once-per-day-or-keep-track-if-somethin
strategy(title = "RSI+PA+DCA", pyramiding = 16, overlay = true, initial_capital = 400, default_qty_type = strategy.percent_of_equity, default_qty_value = 15, commission_type = strategy.commission.percent, commission_value = 0.075)
port = input(15, title = "Portfolio %", type = input.float, step = 0.1, minval = 0.1, maxval = 100)
q = (strategy.equity / 100 * port) / open
// Long position entry layers. Percentage from the entry price of the the first long
PositionInputs = input("++++", title = "+++++ Long Positions VA Layers +++++")
ps2 = input(2, title = "2nd Long Entry %", step = 0.1)
ps3 = input(3, title = "3rd Long Entry %", step = 0.1)
ps4 = input(5, title = "4th Long Entry %", step = 0.1)
ps5 = input(10, title = "5th Long Entry %", step = 0.1)
ps6 = input(16, title = "6th Long Entry %", step = 0.1)
// Calculate Moving Averages
maInput = input("++++", title = "+++++ Moving Average Filter +++++")
plotMA = input(title = "Plot Moving Average", defval = false)
movingaverage_signal = sma(close, input(100))
plot (plotMA ? movingaverage_signal : na, color = color.white)
// RSI inputs and calculations
rsiInput = input( "++++", title = "+++++ RSI Inputs +++++" )
length = input( 14 )
overSold = input( 30, title = "oversold, entry trigger long position" )
overBought = input( 70, title = "overbought, has no specific function")
price = close
vrsi = rsi(price, length)
// Long trigger (co)
co = crossover(vrsi, overSold) and close < movingaverage_signal
// Take profit
takeprofit = input("++++", title = "+++++ Take Profit +++++")
ProfitTarget_Percent = input(5)
// Store values to create and plot the different DCA layers
long1 = valuewhen(co, close, 0)
long2 = valuewhen(co, close - (close / 100 * ps2), 0)
long3 = valuewhen(co, close - (close / 100 * ps3), 0)
long4 = valuewhen(co, close - (close / 100 * ps4), 0)
long5 = valuewhen(co, close - (close / 100 * ps5), 0)
long6 = valuewhen(co, close - (close / 100 * ps6), 0)
eps1 = 0.00
eps1 := na(eps1[1]) ? na : eps1[1]
eps2 = 0.00
eps2 := na(eps2[1]) ? na : eps2[1]
eps3 = 0.00
eps3 := na(eps3[1]) ? na : eps3[1]
eps4 = 0.00
eps4 := na(eps4[1]) ? na : eps4[1]
eps5 = 0.00
eps5 := na(eps5[1]) ? na : eps5[1]
eps6 = 0.00
eps6 := na(eps6[1]) ? na : eps6[1]
plot (strategy.position_size > 0 ? eps1 : na, title = "Long entry 1", style = plot.style_linebr)
plot (strategy.position_size > 0 ? eps2 : na, title = "Long entry 2", style = plot.style_linebr)
plot (strategy.position_size > 0 ? eps3 : na, title = "Long entry 3", style = plot.style_linebr)
plot (strategy.position_size > 0 ? eps4 : na, title = "Long entry 4", style = plot.style_linebr)
plot (strategy.position_size > 0 ? eps5 : na, title = "Long entry 5", style = plot.style_linebr)
plot (strategy.position_size > 0 ? eps6 : na, title = "Long entry 6", style = plot.style_linebr)
// Plot position average price
plot (strategy.position_avg_price, title = "Average price", style = plot.style_linebr, color = color.red, linewidth = 2)
// Take profit and exit all on take profit above position average price
tpv = strategy.position_avg_price + (strategy.position_avg_price / 100 * ProfitTarget_Percent)
tpl1 = close < tpv ? eps1 + close * (ProfitTarget_Percent / 100) : tpv
tpl2 = close < tpv ? eps2 + close * (ProfitTarget_Percent / 100) : tpv
tpl3 = close < tpv ? eps3 + close * (ProfitTarget_Percent / 100) : tpv
tpl4 = close < tpv ? eps4 + close * (ProfitTarget_Percent / 100) : tpv
tpl5 = close < tpv ? eps5 + close * (ProfitTarget_Percent / 100) : tpv
tpl6 = close < tpv ? eps6 + close * (ProfitTarget_Percent / 100) : tpv
// Open DCA order once at the start of the week
dcaWeek = input("++++", title = "+++++ Open DCA order once every week +++++")
newWeek = change(time("W"))
dcatime = input(title = "Buy a fixed amount every Monday", defval = false)
fixedAmount = input(40, title = "Fixed amount currency for DCA orders", step = 0.1)
dcaq = fixedAmount / open
plotchar (dcatime ? newWeek : na, "buy at Week start", "▼", location.top, size = size.tiny, color = color.white)
bgcolor (dcatime and newWeek ? color.white : na, transp = 50)
// Submit entry orders
if (co and strategy.opentrades == 0)
eps1 := long1
eps2 := long2
eps3 := long3
eps4 := long4
eps5 := long5
eps6 := long6
strategy.entry("Long1", strategy.long, q)
if (strategy.opentrades == 1)
strategy.entry("Long2", strategy.long, q, limit = eps2)
if (strategy.opentrades == 2)
strategy.entry("Long3", strategy.long, q, limit = eps3)
if (strategy.opentrades == 3)
strategy.entry("Long4", strategy.long, q, limit = eps4)
if (strategy.opentrades == 4)
strategy.entry("Long5", strategy.long, q, limit = eps5)
if (strategy.opentrades == 5)
strategy.entry("Long6", strategy.long, q, limit = eps6)
// Submit Weekly DCA order, only when price is below position average price and when a position is open
if (dcatime and newWeek and strategy.position_size > 0 and close < strategy.position_avg_price)
strategy.entry("DCA", strategy.long, dcaq)
// Exit orders
if (strategy.position_size > 0)
strategy.exit(id = "Exit 1", from_entry = "Long1", limit = tpl1)
strategy.exit(id = "Exit 2", from_entry = "Long2", limit = tpl2)
strategy.exit(id = "Exit 3", from_entry = "Long3", limit = tpl3)
strategy.exit(id = "Exit 4", from_entry = "Long4", limit = tpl4)
strategy.exit(id = "Exit 5", from_entry = "Long5", limit = tpl5)
strategy.exit(id = "Exit 6", from_entry = "Long6", limit = tpl6)
strategy.exit(id = "Exit DCA", from_entry = "DCA", limit = tpv)
// Make sure that all open limit orders are canceled after exiting all the positions
longClose = strategy.position_size[1] > 0 and strategy.position_size == 0 ? 1 : 0
if longClose
strategy.cancel_all()