Динамическая стратегия средней стоимости фиксированных инвестиций с использованием сложных процентов


Дата создания: 2024-01-04 16:34:10 Последнее изменение: 2024-01-04 16:34:10
Копировать: 0 Количество просмотров: 806
1
Подписаться
1621
Подписчики

Динамическая стратегия средней стоимости фиксированных инвестиций с использованием сложных процентов

Обзор

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

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

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

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

Риски и недостатки

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

Кроме того, существуют две крайности в установке стоп-магнитности: установка слишком больших стоп-единиц не дает достаточно глубокого отскока. В то время как установка слишком маленьких стоп-магнитностей при среднесрочной корректировке имеет более высокую вероятность столкнуться с возобновлением стоп-поворота цен. Поэтому очень важно выбрать подходящую стоп-магнитность в зависимости от различных рынков и собственных предпочтений в отношении риска.

После длительного и многоуровневого цикла DCA, если цены резко возрастут, возникает риск слишком высокой стоимости позиции, которую невозможно остановить. Это также требует разумной установки уровня DCA в соответствии с общим объемом своих позиций и максимальной приемлемой стоимостью позиции.

Рекомендации по оптимизации

  1. Оптимизируйте выбор сигналов. Можно тестировать различные параметры и различные комбинации показателей, чтобы выбрать сигнал с более высокой вероятностью успеха.

  2. Оптимизация механизмов стоп-порогов. Можно тестировать использование стоп-порогов типа Λ или стоп-порогов в виде арочных. Вместо простого движущегося стоп-порога, возможно, получат лучший эффект от стоп-порогов.

  3. Оптимизируйте методы блокировки. Можно тестировать различные типы мобильных блокировок, чтобы найти лучшие возможности для блокировки, что повышает общую доходность.

  4. Включение механизма защиты от отскока. После остановки убытков, может возникнуть ситуация, когда снова будет задействован сигнал DCA, что приведет к повторному открытию позиции. В этом случае можно рассмотреть возможность добавления определенного размера защиты от отскока, чтобы избежать немедленного возобновления активного строительства позиций после остановки убытков.

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

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

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