이중적 돌파구 전략

저자:차오장, 날짜: 2024-01-30 17:27:01
태그:

img

전반적인 설명

이것은 K 라인을 기반으로 한 이중 돌파구 거래 전략입니다. 현재 K 라인의 폐쇄 가격이 이전 두 K 라인의 최고 및 최저 가격에 비해 돌파구를 가질 때 거래 신호를 생성합니다.

전략 원칙

전략의 기본 논리는 다음과 같습니다.

  1. 황소 신호를 정의합니다.bull = close > open and close > math.max(close[2], open[2]) and low[1] < low[2] and high[1] < high[2]즉, 현재 K 라인의 종료 가격은 개시 가격보다 크며 이전 두 K 라인의 최고 가격보다 크며, 현재 K 라인의 최저 가격은 이전 K 라인의 최저 가격보다 낮습니다.

  2. 곰 신호 정의:bear = close < open and close < math.min(close[2], open[2]) and low[1] > low[2] and high[1] > high[2]즉, 현재 K 라인의 종료 가격은 개시 가격보다 낮고 이전 두 K 라인의 최저 가격보다 낮으며, 현재 K 라인의 최고 가격은 이전 K 라인의 최고 가격보다 높습니다.

  3. 황소 신호가 발사되면, 길게 가십시오. 곰 신호가 발사되면, 짧게 가십시오.

  4. 스톱 손실과 수익을 설정할 수 있습니다.

이 전략은 두 개의 돌파구의 특성을 활용하여 주요 가격 영역의 돌파구를 통해 트렌드 변화를 판단하여 거래 신호를 생성합니다.

이점 분석

이것은 다음과 같은 장점을 가진 비교적 간단하고 직관적인 브레이크아웃 전략입니다.

  1. 이 논리는 명확하고 이해하기 쉽고 적용하기 쉽고, 진입 장벽이 낮습니다.

  2. 돌파구는 트렌드를 쉽게 형성하는 일반적인 거래 신호입니다.

  3. 장기화와 단축이 두 방향의 거래를 가능하게 하고 수익 기회를 증가시킵니다.

  4. 유연한 스톱 로스 및 수익 설정은 위험을 조절하는 데 도움이 됩니다.

위험 분석

이 전략은 또한 몇 가지 위험을 안고 있습니다.

  1. 쌍방향 거래는 더 높은 위험을 초래하고 면밀한 모니터링이 필요합니다.

  2. 탈출자들은 함정에 취약할 수 있고, 잠재적으로 잘못된 신호를 형성할 수 있습니다.

  3. 부적절한 매개 변수 설정은 오버 트레이딩으로 이어질 수 있습니다.

  4. 부적절한 스톱 로스 설정과 수익 취득 설정도 수익 잠재력에 영향을 줄 수 있습니다.

위험은 매개 변수를 최적화하고 제품을 적절하게 필터링함으로써 줄일 수 있습니다.

최적화 방향

이 전략은 다음과 같은 측면에서 최적화 될 수 있습니다.

  1. 브레이크아웃 사이클, 스톱 로스/프로프트 레인지 등과 같은 매개 변수를 최적화합니다.

  2. 필터링 조건을 추가하여 중재, 옆으로 움직이는 등의 오류를 피합니다.

  3. 통합 범위를 피하기 위해 트렌드 지표를 포함합니다.

  4. 자본 관리 최적화, 위치 알고리즘 개선

  5. 다른 제품에 대한 다른 매개 변수, 개별적으로 테스트하고 최적화.

요약

이 방법은 이중 브레이크아웃 개념을 기반으로 한 간단한 전략이다. 명확한 논리와 쉬운 구현의 장점이 있지만 특정 모니터링 리스크도 가지고 있다. 매개 변수 및 조건 최적화를 통해 더 나은 전략 결과를 기대할 수 있다.


/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5

// # ========================================================================= #
// #                   |   Strategy  |
// # ========================================================================= #

SystemName = "Strategy Template Autoview"
TradeId = "S"
// These values are used both in the strategy() header and in the script's relevant inputs as default values so they match.
// Unless these values match in the script's Inputs and the TV backtesting Properties, results between them cannot be compared.
InitCapital = 1000000
InitPosition = 2
InitCommission = 0.075
InitPyramidMax = 1
CalcOnorderFills = false
ProcessOrdersOnClose = true // display the signals one candle earlier
CalcOnEveryTick = true // forward testing
//CloseEntriesRule = "ANY"

strategy(title=SystemName, shorttitle=SystemName, 
 overlay=true, pyramiding=InitPyramidMax, initial_capital=InitCapital, default_qty_type=strategy.fixed, process_orders_on_close=ProcessOrdersOnClose,
 default_qty_value=InitPosition, commission_type=strategy.commission.percent, commission_value=InitCommission, calc_on_order_fills=CalcOnorderFills, 
 calc_on_every_tick=CalcOnEveryTick, 
 precision=6, max_lines_count=500, max_labels_count=500)

// # ========================================================================= #
// # ========================================================================= #
// #                   ||   Alerts  ||
// # ========================================================================= #
// # ========================================================================= #

show_alerts_debug = input.bool(true, title = "Show Alerts Debug Label?", group = "Debug")

//i_alert_txt_entry_long = input.text_area(defval = "", title = "Long Entry Message", group = "Alerts")
//i_alert_txt_entry_short = input.text_area(defval = "", title = "Short Entry Message", group = "Alerts")
//i_alert_txt_exit_long = input.text_area(defval = "", title = "Long Exit Message", group = "Alerts")
//i_alert_txt_exit_short = input.text_area(defval = "", title = "Short Exit Message", group = "Alerts")

i_broker_mode = input.string("DEMO", title = "Use Demo or Live Broker", options=["DEMO", "LIVE"], group = "Automation")
i_broker_name = input.string("Tradovate", title = "Broker Name", options=["Tradovate", "AscendEX", "Binance", "Binance Futures", "Binance US", "Binance Delivery", "Kraken", "Deribit", "Poloniex", "Okcoin", "Bitfinex", "Oanda", "Kucoin", "Okex", "Bybit", "FTX", "Bitmex", "Alpaca", "Gemini"], group = "Automation")

i_enable_trades = input.bool(true, title = "Enable trades?", group = "Automation", tooltip = "If not enabled, disables live trades, but more importantly, it will output what Autoview is going to do when you go live.")

i_account_name = input.string("*", title = "Account Name", group = "Automation")
i_symbol_name  = input.string("btcusd_perp", title = "Symbol Name", group = "Automation")
nb_contracts = input.int(2, title = "Nb Contracts", group = "Automation")

use_delay = input.bool(false, title = "Use Delay between orders", group = "Automation", inline = "delay")
i_delay_qty = input.int(1, title = "Delay in seconds", group = "Automation", inline = "delay")

i_use_borrow_repay   = input.bool(false, title = "Use Borrow/Repay Mode?", group = "Binance Automation")
i_asset_borrow_repay = input.string("BTC", title = "Asset to Borrow/Repay", group = "Binance Automation")
i_qty_borrow_repay   = input.float(1., title = "Quantity of assets to borrow?", group = "Binance Automation")

// # ========================================================================= #
// # ========================================================================= #
// #                   ||   Dates Range Filtering  ||
// # ========================================================================= #
// # ========================================================================= #

DateFilter = input(false, "Date Range Filtering", group="Date")

// ————— Syntax coming from https://www.tradingview.com/blog/en/new-parameter-for-date-input-added-to-pine-21812/
i_startTime = input(defval = timestamp("01 Jan 2019 13:30 +0000"), title = "Start Time", group="Date")
i_endTime = input(defval = timestamp("30 Dec 2021 23:30 +0000"), title = "End Time", group="Date")

TradeDateIsAllowed() => true


// # ========================================================================= #
// #                   |   Custom Exits |
// # ========================================================================= #

//use_custom_exit = input.bool(true, title = "Use Custom Exits?", group = "Custom Exits")

// # ========================================================================= #
// #                   |   Stop Loss |
// # ========================================================================= #

use_sl        = input.string("None", title = "Select Stop Loss Mode", options=["None", "Percent", "Price"], group = "Stop Loss")
sl_input_perc = input.float(3, minval = 0, title = "Stop Loss (%)", group = "Stop Loss (%)") * 0.01
sl_input_pips = input.float(30, minval = 0, title = "Stop Loss (USD)", group = "Stop Loss (USD)")

// # ========================================================================= #
// #                   |   Take Profit |
// # ========================================================================= #

use_tp       = input.string("None", title = "Select Take Profit Mode", options=["None", "Percent", "Price"], group = "Take Profit")
tp_input_perc = input.float(3, minval = 0, title = "Take Profit (%)", group = "Take Profit (%)") * 0.01
tp_input_pips = input.float(30, minval = 0, title = "Take Profit (USD)", group = "Take Profit (USD)")


// # ========================================================================= #
// #                   |   Consolidated Entries |
// # ========================================================================= #

bull = close > open and close > math.max(close[2], open[2]) and low[1] < low[2] and high[1] < high[2] // low < low[1] and low[1] < low[2] 
bear = close < open and close < math.min(close[2], open[2]) and low[1] > low[2] and high[1] > high[2] // low < low[1] and low[1] < low[2] 

// # ========================================================================= #
// #       |   Entry Price |
// # ========================================================================= #

entry_long_price  = ta.valuewhen(condition=bull and strategy.position_size[1] <= 0, source=close, occurrence=0)
entry_short_price = ta.valuewhen(condition=bear and strategy.position_size[1] >= 0, source=close, occurrence=0)

var float entry_price = 0.

if bull
    entry_price := entry_long_price
if bear
    entry_price := entry_short_price

// # ========================================================================= #
// #                   ||   Global Trend Variables ||
// # ========================================================================= #

T1_sinceUP = ta.barssince(bull)
T1_sinceDN = ta.barssince(bear)

T1_nUP = ta.crossunder(T1_sinceUP,T1_sinceDN)
T1_nDN = ta.crossover(T1_sinceUP,T1_sinceDN)

T1_sinceNUP = ta.barssince(T1_nUP)
T1_sinceNDN = ta.barssince(T1_nDN)

T1_BuyTrend  = T1_sinceDN > T1_sinceUP
T1_SellTrend = T1_sinceDN < T1_sinceUP

T1_SellToBuy   = T1_BuyTrend and T1_SellTrend[1]
T1_BuyToSell   = T1_SellTrend and T1_BuyTrend[1]
T1_ChangeTrend = T1_BuyToSell or T1_SellToBuy

// # ========================================================================= #
// #                   |   Stop Loss |
// # ========================================================================= #

var float final_SL_Long  = 0.
var float final_SL_Short = 0.

if use_sl == "Percent"
    final_SL_Long := entry_long_price * (1 - sl_input_perc)
    final_SL_Short := entry_short_price * (1 + sl_input_perc)
else if use_sl == "Price"
    final_SL_Long := entry_long_price - (sl_input_pips)
    final_SL_Short := entry_short_price + (sl_input_pips)

plot(strategy.position_size > 0 and use_sl != "None" ? final_SL_Long : na, title = "SL Long", color = color.fuchsia, linewidth=2, style=plot.style_linebr)
plot(strategy.position_size < 0 and use_sl != "None" ? final_SL_Short : na, title = "SL Short", color = color.fuchsia, linewidth=2, style=plot.style_linebr)

// # ========================================================================= #
// #                   |   Take Profit |
// # ========================================================================= #

var float final_TP_Long  = 0.
var float final_TP_Short = 0.

if use_tp == "Percent"
    final_TP_Long := entry_long_price   * (1 + tp_input_perc)
    final_TP_Short := entry_short_price * (1 - tp_input_perc)
else if use_tp == "Price"
    final_TP_Long := entry_long_price   + (tp_input_pips)
    final_TP_Short := entry_short_price - (tp_input_pips)

plot(strategy.position_size > 0 and use_tp != "None" ? final_TP_Long : na, title = "TP Long", color = color.orange, linewidth=2, style=plot.style_linebr)
plot(strategy.position_size < 0 and use_tp != "None" ? final_TP_Short : na, title = "TP Short", color = color.orange, linewidth=2, style=plot.style_linebr)

// # ========================================================================= #
// #                   |   AutoView Calls |
// # ========================================================================= #

float quantity = nb_contracts

string product_type_ticker = i_symbol_name

var string broker_mode = ""

if i_broker_mode == "DEMO"

    broker_mode := switch i_broker_name
        "Tradovate" => "tradovatesim"
        "Ascendex"  => "ascendex-sandbox"
        "Binance Futures" => "binancefuturestestnet"
        "Binance Delivery" => "binancedeliverytestnet"
        "Oanda" => "oandapractice"
        "Bitmex" => "bitmextestnet"
        "Bybit" => "bybittestnet"
        "Alpaca" => "alpacapaper"
        "Kucoin" => "kucoinsandbox"
        "Deribit" => "deribittestnet"
        "Gemini" => "gemini-sandbox"
        => i_broker_name

else // "LIVE"

    broker_mode := switch i_broker_name
        "Tradovate" => "tradovate"
        "Ascendex"  => "ascendex"
        "Binance Futures" => "binancefutures"
        "Binance Delivery" => "binancedelivery"
        "Binance" => "binance"
        "Oanda" => "oanda"
        "Kraken" => "kraken"
        "Deribit" => "deribit"
        "Bitfinex" => "bitfinex"
        "Poloniex" => "poloniex"
        "Bybit" => "bybit"
        "Okcoin" => "okcoin"
        "Kucoin" => "kucoin"
        "FTX" => "ftx"
        "Bitmex" => "bitmex"
        "Alpaca" => "alpaca"
        "Gemini" => "gemini"
        => i_broker_name

enable_trades = i_enable_trades ? "" : " d=1"
string delay_qty = use_delay ? " delay=" + str.tostring(i_delay_qty) : ""

i_alert_txt_entry_long = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + enable_trades + " b=short c=position t=market" + 
 "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=long q=" + str.tostring(quantity, "#") + " t=market" + enable_trades + delay_qty
 
i_alert_txt_entry_short = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + enable_trades + " b=long c=position t=market" + 
 "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=short q=" + str.tostring(quantity, "#") + " t=market" + enable_trades + delay_qty

var string temp_txt_SL_long = ""
var string temp_txt_SL_short = ""

var string temp_txt_TP_long = ""
var string temp_txt_TP_short = ""

if use_sl == "Percent"

    temp_txt_SL_long  := "sl=-" + str.tostring(sl_input_perc * 100) + "%"
    temp_txt_SL_short := "sl=" + str.tostring(sl_input_perc * 100) + "%"

else if use_sl == "Price"

    temp_txt_SL_long  := "fsl=" + str.tostring(final_SL_Long)
    temp_txt_SL_short := "fsl=" + str.tostring(final_SL_Short)

if use_tp == "Percent"

    temp_txt_TP_long := "p=" + str.tostring(tp_input_perc * 100) + "%" 
    temp_txt_TP_short := "p=-" + str.tostring(tp_input_perc * 100) + "%" 

else if use_tp == "Price"

    temp_txt_TP_long  := "fpx=" + str.tostring(final_TP_Long)
    temp_txt_TP_short := "fpx=" + str.tostring(final_TP_Short)  

i_alert_txt_exit_SL_long  = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=long c=position t=market " + temp_txt_SL_long + enable_trades 
i_alert_txt_exit_SL_short = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=short c=position t=market " + temp_txt_SL_short + enable_trades 
i_alert_txt_exit_TP_long  = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=long c=position t=market " + temp_txt_TP_long + enable_trades 
i_alert_txt_exit_TP_short = "a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=short c=position t=market " + temp_txt_TP_short + enable_trades 

string final_alert_txt_entry_long = i_alert_txt_entry_long
string final_alert_txt_entry_short = i_alert_txt_entry_short

if i_use_borrow_repay and i_broker_name == "Binance"

    final_alert_txt_entry_long := "a=" + i_account_name + " e=" + broker_mode + "y=borrow w=" + i_asset_borrow_repay + " q=" + str.tostring(i_qty_borrow_repay, "#") + enable_trades +
     "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + enable_trades + " b=short c=position t=market" + delay_qty +
     "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=long q=" + str.tostring(quantity, "#") + " t=market" + enable_trades + delay_qty +
     "\n a=" + i_account_name + " e=" + broker_mode + "y=repay w=" + i_asset_borrow_repay + " q=" + str.tostring(i_qty_borrow_repay, "#") + enable_trades

    final_alert_txt_entry_short := "a=" + i_account_name + " e=" + broker_mode + "y=borrow w=" + i_asset_borrow_repay + " q=" + str.tostring(i_qty_borrow_repay, "#") + enable_trades +
     "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + enable_trades + " b=long c=position t=market" + delay_qty +
     "\n a=" + i_account_name + " e=" + broker_mode + " s=" + product_type_ticker + " b=short q=" + str.tostring(quantity, "#") + " t=market" + enable_trades + delay_qty +
     "\n a=" + i_account_name + " e=" + broker_mode + "y=repay w=" + i_asset_borrow_repay + " q=" + str.tostring(i_qty_borrow_repay, "#") + enable_trades

//i_alert_txt_entry_long  := final_alert_txt_entry_long
//i_alert_txt_entry_short := final_alert_txt_entry_short

if show_alerts_debug and barstate.islastconfirmedhistory

    var label lblTest = na

    label.delete(lblTest)

    string label_txt = i_alert_txt_entry_long

    if use_sl != "None"
        label_txt := label_txt + "\n" + i_alert_txt_exit_SL_long

    if use_tp != "None"
        label_txt := label_txt + "\n" + i_alert_txt_exit_TP_long

    t = time + (time - time[1]) * 25

    lblTest := label.new(
     x            = t,
     y            = ta.highest(50),
     text         = label_txt,
     xloc         = xloc.bar_time,
     yloc         = yloc.price,
     color        = color.new(color = color.gray, transp = 0),
     style        = label.style_label_left,
     textcolor    = color.new(color = color.white, transp = 0),
     size         =  size.large
     )

// # ========================================================================= #
// #                   |   Strategy Calls and Alerts |
// # ========================================================================= #

if bull and TradeDateIsAllowed() 

    strategy.entry(id = "Long", direction =  strategy.long, comment = "Long", alert_message = i_alert_txt_entry_long, qty = nb_contracts)
    alert(i_alert_txt_entry_long, alert.freq_once_per_bar)
    
else if bear and TradeDateIsAllowed()
    strategy.entry(id = "Short", direction =  strategy.short, comment = "Short", alert_message = i_alert_txt_entry_short, qty = nb_contracts)
    alert(i_alert_txt_entry_short, alert.freq_once_per_bar)

//quantity := quantity * 2

strategy.exit(id = "Exit Long",  from_entry = "Long",  stop = (use_sl != "None") ? final_SL_Long : na,  comment_loss = "Long Exit SL", alert_loss  = (use_sl != "None") ? i_alert_txt_exit_SL_long : na,   limit = (use_tp != "None") ? final_TP_Long  : na, comment_profit = "Long Exit TP", alert_profit = (use_tp != "None") ? i_alert_txt_exit_TP_long : na)   
strategy.exit(id = "Exit Short", from_entry = "Short", stop = (use_sl != "None") ? final_SL_Short : na, comment_loss = "Short Exit SL", alert_loss = (use_sl != "None") ? i_alert_txt_exit_SL_short : na, limit = (use_tp != "None") ? final_TP_Short : na, comment_profit = "Short Exit TP", alert_profit = (use_tp != "None") ? i_alert_txt_exit_TP_short : na)   

if strategy.position_size > 0 and low < final_SL_Long and use_sl != "None"
    alert(i_alert_txt_exit_SL_long, alert.freq_once_per_bar)

else if strategy.position_size < 0 and high > final_SL_Short and use_sl != "None"
    alert(i_alert_txt_exit_SL_short, alert.freq_once_per_bar)

if strategy.position_size > 0 and high > final_TP_Long and use_tp != "None"
    alert(i_alert_txt_exit_TP_long, alert.freq_once_per_bar)

else if strategy.position_size < 0 and low < final_TP_Short and use_tp != "None"
    alert(i_alert_txt_exit_TP_short, alert.freq_once_per_bar)

// # ========================================================================= #
// #                   |   Reset Variables |
// # ========================================================================= #

더 많은