Strategi Kos Purata Dinamik Kos Purata Dolar

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

img

Ringkasan

Strategi gabungan kos purata dinamik DCA secara dinamik menyesuaikan kuantiti setiap kedudukan pembukaan. Pada permulaan trend, ia mula-mula membuka kedudukan kecil untuk membina kedudukan. Apabila kedalaman penyatuan meningkat, ia secara beransur-ansur meningkatkan saiz kedudukan. Strategi ini menggunakan fungsi eksponensial untuk mengira tahap harga stop loss, dan membuka semula kumpulan baru apabila dicetuskan, yang boleh menyebabkan kos memegang kedudukan terus menurun secara eksponensial. Apabila kedalaman meningkat, kos kedudukan dapat beransur-ansur dikurangkan. Apabila harga terbalik, mengambil keuntungan kumpulan membolehkan pulangan yang lebih besar.

Logika Strategi

Strategi ini menggunakan gabungan mudah isyarat oversold RSI dan masa purata bergerak untuk menentukan peluang kemasukan. Perintah kemasukan pertama dihantar apabila RSI jatuh di bawah tahap oversold dan harga ditutup di bawah purata bergerak. Selepas kemasukan pertama, fungsi eksponensial mengira peratusan penurunan harga untuk tahap seterusnya. Setiap kali ia mencetuskan pesanan DCA, saiz kedudukan dikira semula untuk mengekalkan jumlah yang sama setiap kemasukan. Apabila saiz kedudukan dan kos berubah secara dinamik, ia mewujudkan kesan leverage.

Apabila jumlah DCA meningkat, kos pegangan purata terus menurun. Hanya rebound kecil yang cukup untuk mengambil keuntungan dari setiap kedudukan. Selepas entri berterusan yang dikemukakan, garis stop loss digambarkan di atas harga pegangan purata. Sebaik sahaja harga pecah di atas harga purata dan garis stop loss, semua kedudukan ditutup.

Kelebihan terbesarnya adalah bahawa apabila kos pegangan terus menurun, walaupun semasa penyatuan, kos masih boleh dikurangkan secara kumulatif langkah demi langkah.

Risiko dan Kelemahan

Risiko terbesar adalah saiz kedudukan yang terhad pada mulanya. semasa penurunan berterusan, terdapat risiko stop loss. jadi peratusan stop loss perlu ditetapkan dengan munasabah berdasarkan selera risiko peribadi.

Di samping itu, menetapkan tahap stop loss mempunyai dua ekstrem. Jika terlalu longgar, tidak cukup retracement dapat ditangkap. Tetapi jika terlalu ketat, kebarangkalian berhenti semasa pembetulan pertengahan jangka meningkat. Jadi memilih tahap stop loss yang betul mengikut keadaan pasaran yang berbeza dan keutamaan risiko adalah penting.

Jika terdapat terlalu banyak tahap DCA, apabila harga meningkat dengan ketara, kos pegangan yang sangat tinggi boleh menghalang kerugian berhenti yang berkesan.

Cadangan Pengoptimuman

  1. Mengoptimumkan isyarat masa kemasukan, dengan menguji kombinasi parameter dan penunjuk lain untuk isyarat kadar kemenangan yang lebih tinggi.

  2. Mengoptimumkan mekanisme stop loss, dengan menguji L trailing stop loss atau kurva dipasang trailing stop loss untuk mendapatkan hasil yang lebih baik.

  3. Mengoptimumkan mengambil keuntungan cara. Jenis-jenis yang berlainan mengambil keuntungan boleh diperiksa untuk peluang keluar yang lebih baik dan pulangan keseluruhan yang lebih tinggi.

  4. Tambah mekanisme anti-whipsaw. Kadang-kadang isyarat DCA boleh dicetuskan semula sejurus selepas stop loss. Julat whipsaw boleh ditambah untuk mengelakkan kemasukan semula agresif sejurus selepas berhenti.

Kesimpulan

Strategi ini menggunakan RSI untuk menentukan kemasukan, mekanisme DCA stop loss dinamik eksponensial untuk menyesuaikan saiz kedudukan dan kos purata secara dinamik, untuk mendapatkan kelebihan harga semasa penyatuan. Kawasan pengoptimuman utama memberi tumpuan kepada isyarat masuk / keluar, menghentikan kerugian dan mengambil keuntungan. Konsep teras DCA eksponensial dilaksanakan untuk mengalihkan kos pegangan lebih rendah secara berterusan, dengan itu memberikan lebih banyak ruang semasa penyatuan, dan mencapai pulangan berlipat ganda apabila trend muncul. Tetapi parameter masih perlu ditetapkan dengan teliti berdasarkan rancangan peruntukan modal untuk mengawal risiko kedudukan keseluruhan.


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