Strategi Komposisi Biaya Rata-rata Dinamis

Penulis:ChaoZhang, Tanggal: 2024-01-04 16:34:10
Tag:

img

Gambaran umum

Strategi gabungan biaya rata-rata dinamis DCA secara dinamis menyesuaikan kuantitas setiap posisi pembukaan. Pada awal tren, pertama-tama membuka posisi kecil untuk membangun posisi. Ketika kedalaman konsolidasi meningkat, secara bertahap meningkatkan ukuran posisi. Strategi ini menggunakan fungsi eksponensial untuk menghitung tingkat harga stop loss, dan membuka kembali batch baru ketika dipicu, yang dapat menyebabkan biaya memegang posisi terus menurun secara eksponensial. Ketika kedalaman meningkat, biaya posisi dapat secara bertahap dikurangi. Ketika harga terbalik, mengambil keuntungan batch memungkinkan pengembalian yang lebih besar.

Logika Strategi

Strategi ini menggunakan kombinasi sederhana dari sinyal oversold RSI dan waktu rata-rata bergerak untuk menentukan peluang masuk. Pesan masuk pertama dikirimkan ketika RSI turun di bawah level oversold dan harga ditutup di bawah rata-rata bergerak. Setelah entri pertama, fungsi eksponensial menghitung persentase penurunan harga untuk level berikutnya. Setiap kali memicu pesanan DCA, ukuran posisi dihitung ulang untuk menjaga jumlah yang sama per entri. Saat ukuran posisi dan biaya berubah secara dinamis, itu menciptakan efek leverage.

Dengan meningkatnya jumlah DCA, biaya pegangan rata-rata terus menurun. Hanya rebound kecil yang cukup untuk mengambil keuntungan dari setiap posisi. Setelah entri berkelanjutan dikirim, garis stop loss digambarkan di atas harga pegangan rata-rata. Setelah harga pecah di atas harga rata-rata dan garis stop loss, semua posisi ditutup.

Keuntungan terbesarnya adalah karena biaya kepemilikan terus menurun, bahkan selama konsolidasi, biaya masih dapat dikurangi secara kumulatif langkah demi langkah.

Risiko dan Cacat

Risiko terbesar adalah ukuran posisi yang terbatas pada awalnya. selama penurunan terus menerus, mungkin ada risiko stop loss. jadi persentase stop loss perlu ditetapkan secara wajar berdasarkan selera risiko pribadi.

Selain itu, pengaturan level stop loss memiliki dua ekstrem. Jika terlalu longgar, tidak cukup retracement dapat ditangkap. Tetapi jika terlalu ketat, kemungkinan berhenti selama koreksi pertengahan jangka meningkat. Jadi memilih tingkat stop loss yang tepat sesuai dengan kondisi pasar yang berbeda dan preferensi risiko sangat penting.

Jika ada terlalu banyak tingkat DCA, ketika harga naik secara substansial, biaya kepemilikan yang sangat tinggi dapat mencegah stop loss yang efektif.

Saran Optimalisasi

  1. Mengoptimalkan sinyal waktu masuk, dengan menguji kombinasi parameter dan indikator lainnya untuk sinyal tingkat kemenangan yang lebih tinggi.

  2. Mengoptimalkan mekanisme stop loss, dengan menguji Λ trailing stop loss atau curve fitted trailing stop loss untuk mendapatkan hasil yang lebih baik.

  3. Mengoptimalkan cara mengambil keuntungan. Berbagai jenis mengambil keuntungan dapat diperiksa untuk peluang keluar yang lebih baik dan total laba yang lebih tinggi.

  4. Tambahkan mekanisme anti-whipsaw. Kadang-kadang sinyal DCA dapat dipicu lagi segera setelah stop loss. Jangkauan whipsaw dapat ditambahkan untuk menghindari re-entry agresif segera setelah berhenti.

Kesimpulan

Strategi ini menggunakan RSI untuk menentukan entri, mekanisme stop loss DCA dinamis eksponensial untuk menyesuaikan ukuran posisi dan biaya rata-rata secara dinamis, untuk mendapatkan keuntungan harga selama konsolidasi. Area optimasi utama difokuskan pada sinyal masuk / keluar, stop loss dan take profit. Konsep inti dari DCA eksponensial diimplementasikan untuk memindahkan biaya kepemilikan lebih rendah terus-menerus, sehingga memberikan lebih banyak ruang selama konsolidasi, dan mencapai pengembalian berlipat ganda ketika tren muncul.


/*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




Lebih banyak