Квантизированная постепенно взвешенная стратегия торговли DCA

Автор:Чао Чжан, Дата: 2023-11-16 11:32:12
Тэги:

img

Обзор

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

Принципы

Стратегия состоит из трех основных компонентов:

  1. Оценка сигналов входа

    Он использует быстрые и медленные пересечения средних движущихся в качестве входного сигнала. Пользователи могут выбирать между SMA, EMA или HMA для быстрых и медленных средних движущихся. Когда быстрый MA пересекает медленный MA, генерируется сигнал покупки. Когда быстрый MA пересекает медленный MA, генерируется сигнал продажи.

  2. Постепенное взвешенное DCA

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

    Такое постепенное увеличение размера позиции позволяет получать среднюю стоимость, обеспечивая лучшую среднюю стоимость при сохранении рисков под контролем.

  3. Принимать прибыль и останавливать убытки

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

    Линия получения прибыли фиксируется по средней цене базовой позиции * (1 + фиксированный процент).

    Линия стоп-лосса колеблется на основе цены последней позиции безопасности, фиксированный процент ниже нее.

Преимущества

  1. Сочетание тенденции и средних затрат делает его более стабильным

    Использование тенденций позволяет избежать бессмысленных проблем, а среднее значение затрат обеспечивает лучшие затраты на вход.

  2. Постепенное размещение позиции контролирует риск

    Фиксированное увеличение размеров безопасных положений с порогом повторного входа контролирует риск.

  3. Мониторинг использованных средств в реальном времени

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

  4. Отдельный TP/SL для каждой позиции

    Независимые выходы позволяют обеспечить прибыль и сократить убытки.

Риски и улучшения

  1. Убытки в цене могут привести к многочисленным заказам безопасности

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

  2. Передвижные средние параметры нуждаются в оптимизации

    Разные приборы требуют разных периодов скользящей средней.

  3. Уровни TP/SL требуют оптимизации для обратного тестирования

    Отношения TP/SL определяют профиль риска/вознаграждения.

  4. Добавить максимальный вывод или вынужденный выход, основанный на времени хранения

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

Резюме

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


/*backtest
start: 2022-11-09 00:00:00
end: 2023-11-15 00:00:00
period: 1d
basePeriod: 1h
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/
// © MGTG

//@version=5
Strategy = input.string('Long', options=['Long'], group='Strategy', inline='1',
 tooltip='Long bots profit when asset prices rise, Short bots profit when asset prices fall'
 + '\n\n' + 'Please note: to run a Short bot on a spot exchange account, you need to own the asset you want to trade. The bot will sell the asset at the current chart price and buy it back at a lower price - the profit made is actually trapped equity released from an asset you own that is declining in value.')

Profit_currency = input.string('Quote (USDT)', 'Profit currency', options=['Quote (USDT)', 'Quote (BTC)', 'Quote (BUSD)'], group='Strategy', inline='1')
Base_order_size = input.int(10, 'Base order Size', group='Strategy', inline='2', 
 tooltip='The Base Order is the first order the bot will create when starting a new deal.')
Safety_order_size = input.int(20, 'Safety order Size', group='Strategy', inline='2',
 tooltip="Enter the amount of funds your Safety Orders will use to Average the cost of the asset being traded, this can help your bot to close deals faster with more profit. Safety Orders are also known as Dollar Cost Averaging and help when prices moves in the opposite direction to your bot's take profit target.")

Triger_Type = input.string('Over', 'Entry at Cross Over / Under', options=['Over', 'Under'], group='Deal start condition > Trading View custom signal', inline='1',
 tooltip='Deal start condition decision')

Short_Moving_Average  = input.string('SMA', 'Short Moving Average', group='Deal start condition > Trading View custom signal', inline='2',
 options=["SMA", "EMA", "HMA"])
Short_Period         = input.int(5, 'Period', group='Deal start condition > Trading View custom signal', inline='2')
Long_Moving_Average  = input.string('HMA', 'Long Moving Average', group='Deal start condition > Trading View custom signal', inline='3',
 options=["SMA", "EMA", "HMA"])

Long_Period          = input.int(50, 'Period', group='Deal start condition > Trading View custom signal', inline='3')

Target_profit = input.float(1.5, 'Target profit (%)', step=0.05, group='Take profit / Stop Loss', inline='1') * 0.01
Stop_Loss = input.int(15, 'Stop Loss (%)', group='Take profit / Stop Loss', inline='1',
 tooltip='This is the percentage that price needs to move in the opposite direction to your take profit target, at which point the bot will execute a Market Order on the exchange account to close the deal for a smaller loss than keeping the deal open.'
 + '\n' + 'Please note, the Stop Loss is calculated from the price the Safety Order at on the exchange account and not the Dollar Cost Average price.') * 0.01

Max_safety_trades_count = input.int(10, 'Max safety trades count', maxval=10, group='Safety orders', inline='1')
Price_deviation = input.float(0.4, 'Price deviation to open safety orders (% from initial order)', step=0.01, group='Safety orders', inline='2') * 0.01
Safety_order_volume_scale = input.float(1.8, 'Safety order volume scale', step=0.01, group='Safety orders', inline='3')
Safety_order_step_scale = input.float(1.19, 'Safety order step scale', step=0.01, group='Safety orders', inline='3')

// daily_volume  = input.int(500, "Don't start deal(s) if the daily volume is less than", group='Advanced settings', inline='1')
// Minimum_price  = input.int(500, "Minimum price to open deal", group='Advanced settings', inline='1')
// Maximum_price  = input.int(500, "Maximum price to open deal", group='Advanced settings', inline='1')

// Close_deal_after_timeout  = input.int(5, "Close deal after timeout (Hrs)", group='Advanced settings', inline='1')

initial_capital = 8913

strategy(
 title='3Commas Visible DCA Strategy', 
 overlay=true, 
 initial_capital=initial_capital, 
 pyramiding=11, 
 process_orders_on_close=true, 
 commission_type=strategy.commission.percent, 
 commission_value=0.01, 
 max_bars_back=5000, 
 max_labels_count=50)


// Position
status_none  = strategy.position_size == 0
status_long  = strategy.position_size[1] == 0 and strategy.position_size > 0
status_long_offset  = strategy.position_size[2] == 0 and strategy.position_size[1] > 0
status_short = strategy.position_size[1] == 0 and strategy.position_size < 0
status_increase = strategy.opentrades[1] < strategy.opentrades

Short_Moving_Average_Line = 
 Short_Moving_Average == 'SMA' ? ta.sma(close, Short_Period) :
 Short_Moving_Average == 'EMA' ? ta.ema(close, Short_Period) :
 Short_Moving_Average == 'HMA' ? ta.sma(close, Short_Period) : na

Long_Moving_Average_Line = 
 Long_Moving_Average == 'SMA' ? ta.sma(close, Long_Period) :
 Long_Moving_Average == 'EMA' ? ta.ema(close, Long_Period) :
 Long_Moving_Average == 'HMA' ? ta.sma(close, Long_Period) : na
 
Base_order_Condition      = Triger_Type == "Over" ? ta.crossover(Short_Moving_Average_Line, Long_Moving_Average_Line) : ta.crossunder(Short_Moving_Average_Line, Long_Moving_Average_Line) // Buy when close crossing lower band

safety_order_deviation(index) => Price_deviation * math.pow(Safety_order_step_scale,  index - 1)

pd = Price_deviation
ss = Safety_order_step_scale

step(i) =>
 i == 1 ? pd :
 i == 2 ? pd + pd * ss :
 i == 3 ? pd + (pd + pd * ss) * ss :
 i == 4 ? pd + (pd + (pd + pd * ss) * ss) * ss : 
 i == 5 ? pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss : 
 i == 6 ? pd + (pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss) * ss : 
 i == 7 ? pd + (pd + (pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss) * ss) * ss : 
 i == 8 ? pd + (pd + (pd + (pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss) * ss) * ss) * ss : 
 i == 9 ? pd + (pd + (pd + (pd + (pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss) * ss) * ss) * ss) * ss : 
 i == 10 ? pd + (pd + (pd + (pd + (pd + (pd + (pd + (pd + (pd + pd * ss) * ss) * ss) * ss) * ss) * ss) * ss) * ss) * ss : na

long_line(i) =>
 close[1] - close[1] * (step(i))


Safe_order_line(i) =>
 i == 0 ? ta.valuewhen(status_long, long_line(0), 0) :
 i == 1 ? ta.valuewhen(status_long, long_line(1), 0) :
 i == 2 ? ta.valuewhen(status_long, long_line(2), 0) :
 i == 3 ? ta.valuewhen(status_long, long_line(3), 0) :
 i == 4 ? ta.valuewhen(status_long, long_line(4), 0) :
 i == 5 ? ta.valuewhen(status_long, long_line(5), 0) :
 i == 6 ? ta.valuewhen(status_long, long_line(6), 0) :
 i == 7 ? ta.valuewhen(status_long, long_line(7), 0) :
 i == 8 ? ta.valuewhen(status_long, long_line(8), 0) : 
 i == 9 ? ta.valuewhen(status_long, long_line(9), 0) :
 i == 10 ? ta.valuewhen(status_long, long_line(10), 0) : na

TP_line = strategy.position_avg_price * (1 + Target_profit) 

SL_line = Safe_order_line(Max_safety_trades_count) * (1 - Stop_Loss)

safety_order_size(i) => Safety_order_size * math.pow(Safety_order_volume_scale, i - 1)


plot(Short_Moving_Average_Line, 'Short MA', color=color.new(color.white, 0), style=plot.style_line)
plot(Long_Moving_Average_Line, 'Long MA', color=color.new(color.green, 0), style=plot.style_line)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 1 ? Safe_order_line(1) : na, 'Safety order1', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 2 ? Safe_order_line(2) : na, 'Safety order2', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 3 ? Safe_order_line(3) : na, 'Safety order3', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 4 ? Safe_order_line(4) : na, 'Safety order4', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 5 ? Safe_order_line(5) : na, 'Safety order5', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 6 ? Safe_order_line(6) : na, 'Safety order6', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 7 ? Safe_order_line(7) : na, 'Safety order7', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 8 ? Safe_order_line(8) : na, 'Safety order8', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 9 ? Safe_order_line(9) : na, 'Safety order9', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 and Max_safety_trades_count >= 10 ? Safe_order_line(10) : na, 'Safety order10', color=color.new(#009688, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 ? TP_line : na, 'Take Profit', color=color.new(color.orange, 0), style=plot.style_linebr)
plot(strategy.position_size > 0 ? SL_line : na, 'Safety', color=color.new(color.aqua, 0), style=plot.style_linebr)


currency = 
 Profit_currency == 'Quote (USDT)' ? ' USDT' :
 Profit_currency == 'Quote (BTC)'  ? ' BTC' :
 Profit_currency == 'Quote (BUSD)' ? ' BUSD' : na
 

if Base_order_Condition
    strategy.entry('Base order', strategy.long, qty=Base_order_size/close, when=Base_order_Condition and strategy.opentrades == 0,
     comment='BO' + ' - ' + str.tostring(Base_order_size) + str.tostring(currency))

for i = 1 to Max_safety_trades_count by 1
    i_s = str.tostring(i)
    strategy.entry('Safety order' + i_s, strategy.long, qty=safety_order_size(i)/close,
     limit=Safe_order_line(i), when=(strategy.opentrades <= i) and strategy.position_size > 0, 
     comment='SO' + i_s + ' - ' + str.tostring(safety_order_size(i))  + str.tostring(currency))


for i = 1 to Max_safety_trades_count by 1
    i_s = str.tostring(i)
    // strategy.close('Base order', when=shortCondition)
    // strategy.close('Safety order' + i_s, when=shortCondition)
    // strategy.cancel('Safety order' + i_s, when=shortCondition)
    strategy.cancel('SO' + i_s, when=ta.crossunder(low, SL_line) or ta.crossover(high, TP_line) or status_none)
    strategy.exit('TP/SL','Base order', limit=TP_line, stop=SL_line, comment = Safe_order_line(100) > close ? 'SL' + i_s + ' - ' +  str.tostring(Base_order_size) + str.tostring(currency) : 'TP' + i_s + ' - ' +  str.tostring(Base_order_size) + str.tostring(currency)) 
    strategy.exit('TP/SL','Safety order' + i_s, limit=TP_line, stop=SL_line, comment = Safe_order_line(100) > close ? 'SL' + i_s + ' - ' +  str.tostring(safety_order_size(i)) + str.tostring(currency) : 'TP' + i_s + ' - ' +  str.tostring(safety_order_size(i)) + str.tostring(currency)) 
    // strategy.cancel('TP/SP' + i_s, when=Base_order_Condition)
    // strategy.exit('Stop Loss','Base order', stop=SL_line)
    // strategy.exit('Stop Loss','Safety order' + i_s, stop=SL_line)
    
//----------------label A----------------//

bot_usage(i) =>
 i == 1 ? Base_order_size + safety_order_size(1) :
 i == 2 ? Base_order_size + safety_order_size(1) + safety_order_size(2) :
 i == 3 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) :
 i == 4 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) : 
 i == 5 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) :
 i == 6 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) + safety_order_size(6) : 
 i == 7 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) + safety_order_size(6) + safety_order_size(7) : 
 i == 8 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) + safety_order_size(6) + safety_order_size(7) + safety_order_size(8) : 
 i == 9 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) + safety_order_size(6) + safety_order_size(7) + safety_order_size(8) + safety_order_size(9) :
 i == 10 ? Base_order_size + safety_order_size(1) + safety_order_size(2) + safety_order_size(3) + safety_order_size(4) + safety_order_size(5) + safety_order_size(6) + safety_order_size(7) + safety_order_size(8) + safety_order_size(9) + safety_order_size(10) : na

equity = strategy.equity
bot_use = bot_usage(Max_safety_trades_count)
bot_dev = float(step(Max_safety_trades_count)) * 100
bot_ava = (bot_use / equity) * 100

string label_A = 
 'Balance                                      : ' + str.tostring(math.round(equity, 0), '###,###,###,###') + ' USDT' + '\n' + 
 'Max amount for bot usage           : ' + str.tostring(math.round(bot_use, 0), '###,###,###,###') + ' USDT' + '\n' + 
 'Max safety order price deviation : ' + str.tostring(math.round(bot_dev, 0), '##.##') + ' %' + '\n' + 
 '% of available balance                : ' + str.tostring(math.round(bot_ava, 0), '###,###,###,###') + ' %' 
 + (bot_ava > 100 ? '\n \n' +  '⚠ Warning! Bot will use amount greater than you have on exchange' : na) 


if status_long
    day_label = 
     label.new(
     x=time[1], 
     y=high * 1.03, 
     text=label_A, 
     xloc=xloc.bar_time, 
     yloc=yloc.price, 
     color=bot_ava > 100 ? color.new(color.yellow, 0) : color.new(color.black, 50), 
     style=label.style_label_lower_right, 
     textcolor=bot_ava > 100 ? color.new(color.red, 0) : color.new(color.silver, 0), 
     size=size.normal, 
     textalign=text.align_left)

Больше