定量化 段階的に重量化されたDCA取引戦略

作者: リン・ハーンチャオチャン,日付: 2023-11-16 11:32:12
タグ:

img

概要

定量化段階的な重量化DCA取引戦略は,シグナル誘発のための移動平均指標と段階的な重量化ドルコスト平均化メカニズムを組み合わせた定量的な取引戦略である.この戦略は,傾向の特定とコスト平均化を通じて,強くトレンドする市場で比較的安定した収益を達成することを目的としている.

原則

戦略は以下の3つの主要要素で構成されています.

  1. 入力信号の判断

    低動態平均値は,低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値より低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低動態平均値よりも低

  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)

もっと