这是一个基于K线的双向突破交易策略。它会在当前K线收盘价相对前两根K线的最高价和最低价都有突破时,产生交易信号。
该策略的基本逻辑是:
定义公牛信号: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线的最低价。
定义熊信号: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线的最高价。
当触发公牛信号时,做多;当触发熊信号时,做空。
可设置止损位和止盈位。
该策略利用了双向突破的特征,通过突破关键价格区间来判断趋势的变化,从而产生交易信号。
这是一个相对简单直观的突破策略,具有如下优势:
逻辑清晰,易于理解实现,门槛不高。
突破是常见的交易信号,容易形成趋势。
同时做多做空,可以双向交易,增加获利机会。
可灵活设置止损止盈,控制风险。
该策略也存在一些风险:
双向交易风险较大,需要密切监控。
突破容易被套,可能形成虚假信号。
参数设置不当可能导致过度交易。
止损止盈设置不当也会影响盈利空间。
可以优化参数,适当筛选品种来降低风险。
该策略可以从以下几个方面进行优化:
优化参数,如突破周期参数、止损止盈幅度等。
增加过滤条件,避免套利、震荡等行情的错误信号。
结合趋势指标,避开盘整范围。
优化资金管理,改进仓位算法。
不同品种参数不一样,可以分别测试优化。
这是一个基于双向突破思想的简单策略。具有逻辑清晰、易于实现的优点,也存在一定的监控风险。通过参数和条件优化,可望获得较好的策略效果。
/*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 | // # ========================================================================= #