Chiến lược lãi kép đầu tư cố định chi phí trung bình động


Ngày tạo: 2024-01-04 16:34:10 sửa đổi lần cuối: 2024-01-04 16:34:10
sao chép: 0 Số nhấp chuột: 806
1
tập trung vào
1621
Người theo dõi

Chiến lược lãi kép đầu tư cố định chi phí trung bình động

Tổng quan

Phương pháp này sử dụng hàm chỉ số để tính toán giá dừng cho mỗi lớp và kích hoạt mở lại các vị trí mới để giữ cho đường chi phí giữ vị trí giảm xuống theo chỉ số. Với sự gia tăng độ sâu, chi phí vị trí có thể dần dần giảm xuống, chờ đợi giá đảo ngược sau khi các lô dừng lại và thu được lợi nhuận lớn hơn.

Nguyên tắc chiến lược

Chiến lược này chọn thời gian mở vị trí bằng cách chọn đường cân bằng khi kết hợp các tín hiệu điểm bán tháo RSI đơn giản. Lần đầu tiên tạo ra tín hiệu mở vị trí khi RSI thấp hơn đường bán tháo và giá đóng cửa nhỏ hơn đường trung bình. Sau khi mở vị trí đầu tiên, DCA sẽ được tạo ra dựa trên hàm chỉ số tính toán mức giảm giá. Chi phí nắm giữ giảm dần khi số lần DCA tăng lên, và mỗi lần dừng lại chỉ cần một sự hồi phục rất nhỏ để đạt được lợi nhuận. Sau khi mở nhiều lần liên tiếp, đường dừng sẽ được vẽ trên giá trung bình. Một khi giá đột phá trở lại, vượt quá giá trung bình giữ và đường dừng, thì dừng chơi.

Ưu điểm lớn nhất của chiến lược này là chi phí có thể giảm dần theo chi phí giảm dần, ngay cả khi thị trường được giải quyết. Khi xu hướng đảo ngược, lợi nhuận lớn hơn có thể được thực hiện vì chi phí nắm giữ đã thấp hơn nhiều so với giá thị trường.

Rủi ro và nhược điểm

Rủi ro lớn nhất của chiến lược này là vị trí ban đầu bị giới hạn. Nếu xu hướng giảm liên tục, sẽ có nguy cơ dừng lỗ. Do đó, cần thiết phải thiết lập mức dừng lỗ mà bạn có thể chịu được.

Ngoài ra, thiết lập mức dừng cũng có hai cực. Thiết lập đơn vị dừng quá lớn sẽ không có sự phục hồi đủ sâu. Trong khi đó, thiết lập mức dừng quá nhỏ sẽ có khả năng gặp phải sự đảo ngược giá dừng lại trong điều chỉnh trung hạn. Vì vậy, tùy thuộc vào thị trường khác nhau và sở thích rủi ro của riêng bạn, việc lựa chọn mức dừng thích hợp là rất quan trọng.

Sau một chu kỳ DCA dài và tạo ra nhiều tầng, nếu giá tăng mạnh, bạn sẽ phải đối mặt với chi phí vị trí quá cao và không thể ngăn chặn rủi ro. Điều này cũng cần thiết để thiết lập một DCA hợp lý dựa trên tổng số vị trí của bạn và chi phí vị trí cao nhất có thể chịu được.

Lời khuyên tối ưu hóa

  1. Tối ưu hóa tín hiệu chọn thời gian. Bạn có thể thử nghiệm các tham số khác nhau và các kết hợp chỉ số khác nhau để có thể chọn tín hiệu có tỷ lệ thắng cao hơn.

  2. Cơ chế dừng tối ưu. Bạn có thể thử nghiệm sử dụng dừng kiểu Λ hoặc dừng hình tròn thay vì dừng di động đơn giản, có thể có hiệu quả dừng tốt hơn.

  3. Tối ưu hóa phương thức chặn. Bạn có thể thử nghiệm các loại chặn di động khác nhau, tìm kiếm cơ hội chặn tốt hơn, do đó cải thiện tỷ lệ lợi nhuận tổng thể.

  4. Tham gia vào cơ chế chống phản xạ. Sau khi dừng lỗ, có thể xảy ra tình huống kích hoạt tín hiệu DCA một lần nữa để mở lại vị trí. Tại thời điểm này, bạn có thể xem xét thêm một phạm vi chống phản xạ ở một mức độ nhất định, để tránh dừng lỗ và lập tức xây dựng lại vị trí.

Tóm tắt

Chiến lược này sử dụng chỉ số RSI để xác định thời gian mua, và chiến lược DCA dừng động được tính theo hàm chỉ số, để có thể điều chỉnh số lượng và chi phí giữ vị trí một cách động, do đó có lợi thế về giá trong thị trường dải. Chương trình tối ưu hóa tập trung chủ yếu vào các tín hiệu đầu vào, đầu ra, dừng lỗ và cách dừng. Nói chung, chiến lược này sử dụng tâm lý của chỉ số DCA, khiến chi phí giữ vị trí di chuyển liên tục, có thể có thêm không gian hoạt động trong thời gian khép lại và thu được lợi nhuận cao hơn trong tình huống xu hướng.

Mã nguồn chiến lược
/*backtest
start: 2023-12-04 00:00:00
end: 2024-01-03 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///
// © A3Sh
//@version=5

// Study of a Simple RSI based, PA (priceaveraging) and DCA strategy that opens a new position everytime it hits a specified price level below the first entry.
// The first entry is opened when the specified rsi and moving average conditions are met. 
// The following DCA levels are calculated exponentially and set, starting with a specified % of price drop. 
// The disctance between the dca levels can be changed with the exponential scale.
// Each position closes individually when it reaches a specified take profit.
// The position can re-open again when it hits the price level again.
// Each time a position is closed and reopened, the average price drops a little.
// The position stays open until the first entry closes or when the price reaches the Stop level.
// When the price reaches the Stop level, all positions will close at once.

// The RSI and MA code for opening the entry is adapted from the Optimized RSI Buy the Dips strategy, by Coinrule.
// This code is used for study purposes, but any other low/ dip finding indicator can be used.
// https://www.tradingview.com/script/Pm1WAtyI-Optimized-RSI-Strategy-Buy-The-Dips-by-Coinrule/

// Dynamic DCA layers are inspired by the Backtesting 3commas DCA Bot v2, by rouxam
// This logic gives more flexibility because you can dyanically change the amount of dca entries.
// https://www.tradingview.com/script/8d6Auyst-Backtesting-3commas-DCA-Bot-v2/

// The use of for loops to (re)open and close different entries separately is based on the Simple_Pyramiding strategy.
// https://www.tradingview.com/script/t6cNLqDN-Simple-Pyramiding/


strategy('Simple_RSI+PA+DCA', overlay=true, pyramiding=20, initial_capital=500, calc_on_order_fills=true, default_qty_type=strategy.percent_of_equity, commission_type=strategy.commission.percent, commission_value=0.075, close_entries_rule='FIFO')

// Backtest Window //
start_time   = input(defval=timestamp("01 April 2021 20:00"), group = "Backtest Window", title="Start Time")
end_time     = input(defval=timestamp("01 Aug 2030 20:00"),   group = "Backtest Window", title="End Time")
window() => true

// Inputs //
takeProfit      = input.float  (3,           group = 'Risk',           title = 'Take Profit %', step=0.1)
takeProfitAll   = input.float  (6,           group = "Risk",           title = 'Close All %',   step=0.1)
posCount        = input.int    (8,           group = 'DCA Settings',   title = 'Max Amount of Entries')
increment       = input.float  (2,           group = 'DCA Settings',   title = 'Price Drop % to open First DCA Order', step=0.5)/100 
exponent_scale  = input.float  (1.4,         group = 'DCA Settings',   title = 'Exponential Scale DCA levels', step=0.1, minval=1.1) 
bar_lookback    = input.int    (4999,        group = 'DCA Settings',   title = 'Lines Bar Lookback', maxval = 4999)
plotMA          = input.bool   (false,       group = 'Moving Average', title = 'Plot Moving Average')
moving_average  = input.int    (100,         group = 'Moving Average', title = 'MA Length' )
rsiLengthInput  = input.int    (14,          group = 'RSI Settings',   title = "RSI Length", minval=1)
rsiSourceInput  = input.source (close,       group = 'RSI Settings',   title = 'Source')
overSold        = input.int    (29,          group = 'RSI Settings',   title = 'Oversold, Trigger to Enter First Position')

// variables //
var open_position    = true   // true when there are open positions
var entry_price      = 0.0    // the entry price of the first entry
var dca_price        = 0.0    // the price of the different dca layers
var int count        = 0      // bar counter since first open position
var int max_bar      = 0      // max bar buffer variable for DCA lines, stop lines, average price
var line dca_line    = na     // lines variable for creating dca lines

// arrays //
linesArray = array.new_float(posCount,na)  // array to store different dca price levels for creating the dca lines

// Create max bar buffer for DCA lines, Stop and average price lines //
max_bar := count >= bar_lookback ? bar_lookback : count

// Order size based on first entry and amount of DCA layers
q = (strategy.equity  / posCount + 1) / open


// Calculate Moving Averages
movingaverage_signal = ta.sma(close ,moving_average)
plot (plotMA ? movingaverage_signal : na, color = color.new(#f5ff35, 0))


// RSI calculations //
up   = ta.rma(math.max(ta.change(rsiSourceInput), 0), rsiLengthInput)
down = ta.rma(-math.min(ta.change(rsiSourceInput), 0), rsiLengthInput)
rsi  = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))


// Buy Signal (co)
co = ta.crossover(rsi, overSold) and close < movingaverage_signal


// Create a white line for average price, since the last opened position //
// average_price = line.new(x1 = bar_index - max_bar, y1 = strategy.position_avg_price, x2 = bar_index, y2 = strategy.position_avg_price, color = color.white)
    

// Stop //
// Create a red Stop level line based on a specified % above the average price //
stop_level = strategy.position_avg_price + (strategy.position_avg_price / 100 * takeProfitAll)
// stop_line  = line.new(x1 = bar_index - max_bar, y1 = stop_level, x2 = bar_index, y2 = stop_level, color = color.red)
    

// Take profit definition per open position //
take_profit_price = close * takeProfit / 100 / syminfo.mintick


// Make sure the Stop level and average price level don't excied the bar buffer to avoid errors //
// if count <= bar_lookback
//     line.set_x1(stop_line,     strategy.opentrades.entry_bar_index(strategy.opentrades - 1))
//     line.set_x1(average_price, strategy.opentrades.entry_bar_index(strategy.opentrades - 1))


// Exponential DCA Layer Calculation fucntion --> First try, needs more experimentation //
dca_price_level(index,entry_price) =>   
    entry_price * (1 - (increment * math.pow(exponent_scale, index)))


// Set  Entries //
// Open the first entry and set the entry price //
if co and strategy.position_size == 0 and window() 
    open_position := true
    entry_price   := close
    strategy.entry(id = 'FE1', direction = strategy.long, qty = q)  
    
// first_entry_line = line.new(x1 = bar_index - max_bar, y1 = entry_price, x2 = bar_index, y2 = entry_price, color = color.blue)


// Start bar counting since the position is open //
if open_position == true
    count := count + 1


// Set the DCA entries //
// Prices below 1 are not set to avoid negative prices //
if strategy.position_size > 0 and window()
    for i = 0 to strategy.opentrades
        if strategy.opentrades == i and i < posCount
            dca_price := dca_price_level(i,entry_price) > 1 ? dca_price_level(i,entry_price) : na
            entry_id = 'DCA' + str.tostring(i + 1) 
            strategy.entry(id = entry_id, direction = strategy.long, limit = dca_price, qty = q)  


// Store the values of the different dca price levels in an array and create the dca lines // 
// Prices below 1 are not stored//
if open_position==true and window() 
    for i = 1 to posCount -1
        array.push(linesArray, dca_price_level(i,entry_price) > 1 ? dca_price_level(i,entry_price) : na) 
    
    // for i = 1 to array.size(linesArray) - 1
    //     dca_line := line.new(x1 = bar_index - max_bar, y1 = array.get(linesArray, i), x2 = bar_index, y2 = array.get(linesArray, i),color = color.blue)


// Create thick line to show the last Entry price //
// last_entry_price = line.new(x1 = bar_index[5], y1 = strategy.opentrades.entry_price(strategy.opentrades - 1), x2 = bar_index, y2 = strategy.opentrades.entry_price(strategy.opentrades - 1),color = color.rgb(255, 0, 204), width = 5)


// Exit the first entry when the take profit triggered //   
if strategy.opentrades > 0 and window() 
    strategy.exit(id = 'Exit FE', from_entry = 'FE1', profit = take_profit_price)


// Exit DCA entries when take profit is triggered //
if strategy.opentrades > 0 and window() 
    for i = 0 to strategy.opentrades 
        exit_from = 'DCA' + str.tostring(i + 1)
        exit_id = 'Exit_' + str.tostring(i + 1)
        strategy.exit(id = exit_id, from_entry = exit_from, profit = take_profit_price)


// Close all positions at once when Stop is crossed //
if strategy.opentrades > 0 and ta.crossover(close,stop_level) and window() 
    strategy.close_all()


// Make sure nothing is open after alle positions are closed and set the condiftion back to be open for new entries //
if strategy.position_size[1] > 0 and strategy.position_size == 0
    strategy.cancel_all()
    strategy.close_all()
    // line.delete(average_price)
    // line.delete(stop_line)
    // line.delete(dca_line)
    open_position := false   // All position are closed, so back to false
    count := 0               // Reset bar counter