
이 전략은 Dr. John Ehlers의 트렌드 플렉스 오스실레이터 (Trend Flex Oscillator, TFO) 와 평균 실제 진동 범위 (Average True Range, ATR) 지표에 기반한 트렌드 추적 손실 전략이다. 이 전략은 오버솔드 이후의 가격이 반전될 때 오버솔드 포지션을 열기 위해 적용된다.
이 전략은 TFO와 ATR 두 가지 지표를 결합하여, 구매 조건이 충족되면 상장을 열고, 판매 조건이 충족되면 매각한다.
구매 조건: TFO가 어떤 임계 값보다 낮을 때, 그리고 상위 K 선의 TFO 값이 현재 K 선보다 낮을 때, 그리고 ATR이 설정된 변동 문턱보다 높을 때, 이 세 가지 조건을 충족하면 더 많은 포지션을 열 수 있다.
평정상황: TFO가 어떤 경계를 초과할 때, 그리고 ATR이 설정된 문턱을 초과할 때, 조건이 충족되면, 모든 상장을 평정한다. 또한, 이 전략은 추적 손실을 설정하고, 가격이 설정된 추적 중지 손실 가격을 넘어서는 경우, 모든 상장을 평정한다. 사용자는 지표 신호에 따라 전략을 평정하도록 선택할 수 있습니다. 또는 손실 평정 가격에 따라만 평정한다.
이 전략은 최대 15개의 여러 상점 포지션을 동시에 열 수 있다. 이 전략의 매개 변수는 조정할 수 있으며, 다른 시간 주기에도 적용된다.
트렌드와 변동성을 결합하여 시장 방향을 판단하고, 비교적 안정적이다. TFO는 트렌드 돌파의 초기 신호를 포착할 수 있고, ATR은 시장 변동이 증가하는 시점을 파악할 수 있다.
조정할 수 있는 매매 변수와 스톱로스 변수를 설정하여 조작이 유연하다. 사용자는 시장에 따라 변수를 조정하여 최적화를 달성할 수 있다.
내장된 Stop Loss 기능으로 극한상황의 손실을 줄일 수 있다. Stop Loss 전략은 양적 거래의 매우 중요한 부분이다.
추가 상장 및 일부 평상시 지원, 포지션을 확대하여 수익을 증대할 수 있다.
이 전략은 더 많이 하고, 공백을 두지 않고, 하락시장에서 이익을 얻을 수 없습니다. 끔찍한 곰 시장 상황이 발생하면 엄청난 손실이 발생할 수 있습니다.
잘못된 매개 변수 설정은 과도한 거래 또는 매매를 유도할 수 있다. 최적의 매개 변수 조합을 찾기 위해 반복 테스트가 필요하다.
극단적인 상황에서는 막힘이 무효가 되어 큰 손실을 막을 수 없다. 이것은 모든 막힘 전략이 직면할 수 있는 문제이다.
재검토는 실제 거래 상황을 완전히 반영하지 않으며, 실제 거래 결과에 따라 약간의 편차가있을 수 있습니다.
판매 조건에 모바일 스톱 라인을 추가하는 것을 고려할 수 있습니다. 전략이 적시에 스톱을 하고, 하향 위험을 효과적으로 제어할 수 있도록 합니다.
공백 메커니즘을 확장할 수 있으며, TFO 반전 하락과 ATR이 충분히 커지면 공백 포지션을 열 수 있어 전략이 공백 시장에 적용될 수 있다.
거래량 변화와 같은 더 많은 필터링 조건을 추가하여 비정상적인 행위가 전략에 미치는 영향을 줄일 수 있습니다.
다른 시간 주기들의 파라미터 설정과 재검토 결과를 테스트하여 최적의 주기 및 파라미터 조합을 찾을 수 있다.
이 전략은 트렌드 분석과 변동성 모니터링의 장점을 통합하여 TFO와 ATR의 지표 조합을 통해 시장 방향을 판단합니다. 추가 입장을 개설하고, 일부 입장을 평형하고, 위험을 제어 할 수있는 이동 중지 등의 메커니즘을 설정하여 다자 행정에 적합합니다. 더 많은 지표 필터링과 파라미터 조정 기능을 추가하여 전략 성능을 더욱 향상시킬 수있는 확장 가능한 최적화 공간이 있습니다.
/*backtest
start: 2022-11-27 00:00:00
end: 2023-12-03 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/
// © Chart0bserver
//
// Open Source attributions:
// portions © allanster (date window code)
// portions © Dr. John Ehlers (Trend Flex Oscillator)
//
// READ THIS CAREFULLY!!! ----------------//
// This code is provided for educational purposes only. The results of this strategy should not be considered investment advice.
// The user of this script acknolwedges that it can cause serious financial loss when used as a trading tool
// This strategy has a bias for HODL (Holds on to Losses) meaning that it provides NO STOP LOSS protection!
// Also note that the default behavior is designed for up to 15 open long orders, and executes one order to close them all at once.
// Opening a long position is predicated on The Trend Flex Oscillator (TFO) rising after being oversold, and ATR above a certain volatility threshold.
// Closing a long is handled either by TFO showing overbought while above a certain ATR level, or the Trailing Stop Loss. Pick one or both.
// If the strategy is allowed to sell before a Trailing Stop Loss is triggered, you can set a "must exceed %". Do not mistake this for a stop loss.
// Short positions are not supported in this version. Back-testing should NEVER be considered an accurate representation of actual trading results.
//@version=5
strategy('TFO + ATR Strategy with Trailing Stop Loss', 'TFO ATR Trailing Stop Loss', overlay=true, pyramiding=15, default_qty_type=strategy.cash, default_qty_value=10000, initial_capital=150000, currency='USD', commission_type=strategy.commission.percent, commission_value=0.5)
strategy.risk.allow_entry_in(strategy.direction.long) // There will be no short entries, only exits from long.
// -----------------------------------------------------------------------------------------------------------//
// Back-testing Date Range code ----------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------------------------------//
fromMonth = input.int(defval=9, title='From Month', minval=1, maxval=12, group='Back-Testing Start Date')
fromDay = input.int(defval=1, title='From Day', minval=1, maxval=31, group='Back-Testing Start Date')
fromYear = input.int(defval=2021, title='From Year', minval=1970, group='Back-Testing Start Date')
thruMonth = 1 //input(defval = 1, title = "Thru Month", type = input.integer, minval = 1, maxval = 12, group="Back-Testing Date Range")
thruDay = 1 //input(defval = 1, title = "Thru Day", type = input.integer, minval = 1, maxval = 31, group="Back-Testing Date Range")
thruYear = 2112 //input(defval = 2112, title = "Thru Year", type = input.integer, minval = 1970, group="Back-Testing Date Range")
// === FUNCTION EXAMPLE ===
start = timestamp(fromYear, fromMonth, fromDay, 00, 00) // backtest start window
finish = timestamp(thruYear, thruMonth, thruDay, 23, 59) // backtest finish window
window() => // create function "within window of time
time >= start and time <= finish ? true : false
// Date range code -----//
// -----------------------------------------------------------------------------------------------------------//
// ATR Indicator Code --------------------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------------------------------//
length = 18 //input(title="ATR Length", defval=18, minval=1)
Period = 18 //input(18,title="ATR EMA Period")
basicEMA = ta.ema(close, length)
ATR_Function = ta.ema(ta.tr(true), length)
EMA_ATR = ta.ema(ATR_Function, Period)
ATR = ta.ema(ta.tr(true), length)
ATR_diff = ATR - EMA_ATR
volatility = 100 * ATR_diff / EMA_ATR // measure of spread between ATR and EMA
volatilityAVG = math.round((volatility + volatility[1] + volatility[2]) / 3)
buyVolatility = input.int(3, 'Min Volatility for Buy', minval=-20, maxval=20, step=1, group='Average True Range')
sellVolatility = input.int(13, 'Min Volatility for Sell', minval=-10, maxval=20, step=1, group='Average True Range')
useAvgVolatility = input.bool(defval=false, title='Average the Volatility over 3 bars', group='Average True Range')
// End of ATR ------------/
// -----------------------------------------------------------------------------------------------------------//
// TFO Indicator code --------------------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------------------------------//
trendflex(Series, PeriodSS, PeriodTrendFlex, PeriodEMA) =>
var SQRT2xPI = math.sqrt(8.0) * math.asin(1.0) // 4.44288293815 Constant
alpha = SQRT2xPI / PeriodSS
beta = math.exp(-alpha)
gamma = -beta * beta
delta = 2.0 * beta * math.cos(alpha)
float superSmooth = na
superSmooth := (1.0 - delta - gamma) * (Series + nz(Series[1])) * 0.5 + delta * nz(superSmooth[1]) + gamma * nz(superSmooth[2])
E = 0.0
for i = 1 to PeriodTrendFlex by 1
E += superSmooth - nz(superSmooth[i])
E
epsilon = E / PeriodTrendFlex
zeta = 2.0 / (PeriodEMA + 1.0)
float EMA = na
EMA := zeta * epsilon * epsilon + (1.0 - zeta) * nz(EMA[1])
return_1 = EMA == 0.0 ? 0.0 : epsilon / math.sqrt(EMA)
return_1
upperLevel = input.float(1.2, 'TFO Upper Level', minval=0.1, maxval=2.0, step=0.1, group='Trend Flex Ocillator')
lowerLevel = input.float(-0.9, 'TFO Lower Level', minval=-2.0, maxval=-0.1, step=0.1, group='Trend Flex Ocillator')
periodTrendFlex = input.int(14, 'TrendFlex Period', minval=2, group='Trend Flex Ocillator')
useSuperSmootherOveride = true //input( true, "Apply SuperSmoother Override Below*", input.bool, group="Trend Flex Ocillator")
periodSuperSmoother = 8.0 //input(8.0, "SuperSmoother Period*", input.float , minval=4.0, step=0.5, group="Trend Flex Ocillator")
postSmooth = 33 //input(33.0, "Post Smooth Period**", input.float , minval=1.0, step=0.5, group="Trend Flex Ocillator")
trendFlexOscillator = trendflex(close, periodSuperSmoother, periodTrendFlex, postSmooth)
// End of TFO -------------//
// -----------------------------------------------------------------------------------------------------------//
// HODL Don't sell if losing n% ---------------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------------------//
sellOnStrategy = input.bool(defval=true, title='Allow Stategy to close positions', group='Selling Conditions')
doHoldLoss = true // input(defval = true, title = "Strategy can sell for a loss", type = input.bool, group="Selling Conditions")
holdLoss = input.int(defval=0, title='Value (%) must exceed ', minval=-25, maxval=10, step=1, group='Selling Conditions')
totalInvest = strategy.position_avg_price * strategy.position_size
openProfitPerc = strategy.openprofit / totalInvest
bool acceptableROI = openProfitPerc * 100 > holdLoss
// -----------------------//
// -----------------------------------------------------------------------------------------------------------//
// Buying and Selling conditions -------------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------------------//
if useAvgVolatility
volatility := volatilityAVG
volatility
tfoBuy = trendFlexOscillator < lowerLevel and trendFlexOscillator[1] < trendFlexOscillator // Always make a purchase if TFO is in this lowest range
atrBuy = volatility > buyVolatility
tfoSell = ta.crossunder(trendFlexOscillator, upperLevel)
consensusBuy = tfoBuy and atrBuy
consensusSell = tfoSell and volatility > sellVolatility
if doHoldLoss
consensusSell := consensusSell and acceptableROI
consensusSell
// --------------------//
// -----------------------------------------------------------------------------------------------------------//
// Tracing & Debugging --------------------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------------------------------//
plotchar(strategy.opentrades, 'Number of open trades', ' ', location.top)
plotarrow(100 * openProfitPerc, 'Profit on open longs', color.new(color.green, 75), color.new(color.red, 75))
// plotchar(strategy.position_size, "Shares on hand", " ", location.top)
// plotchar(totalInvest, "Total Invested", " ", location.top)
// plotarrow(strategy.openprofit, "Open profit dollar amount", color.new(color.green,100), color.new(color.red, 100))
// plotarrow(strategy.netprofit, "Net profit for session", color.new(color.green,100), color.new(color.red, 100))
// plotchar(acceptableROI, "Acceptable ROI", " ", location.top)
// plotarrow(volatility, "ATR volatility value", color.new(color.green,75), color.new(color.red, 75))
// plotchar(strategy.position_avg_price, "Avgerage price of holdings", " ", location.top)
// plotchar(volatilityAVG, "AVG volatility", " ", location.top)
// plotchar(fiveBarsVal, "change in 5bars", " ", location.top)
// plotchar(crossingUp, "crossingUp", "x", location.belowbar, textcolor=color.white)
// plotchar(crossingDown, "crossingDn", "x", location.abovebar, textcolor=color.white)
// plotchar(strategy.closedtrades, "closedtrades", " ", location.top)
// plotchar(strategy.wintrades, "wintrades", " ", location.top)
// plotchar(strategy.losstrades, "losstrades", " ", location.top)
// plotchar(close, "close", " ", location.top)
//--------------------//
// -----------------------------------------------------------------------------------------------------------//
// Trade Alert Execution ------------------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------------------------------//
strategy.entry('long', strategy.long, when=window() and consensusBuy, comment='long')
if sellOnStrategy
strategy.close('long', when=window() and consensusSell, qty_percent=100, comment='Strat')
// -----------------------------------------------------------------------------------------------------------//
// Trailing Stop Loss logic -------------------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------------------//
useTrailStop = input.bool(defval=true, title='Set Trailing Stop Loss on avg positon value', group='Selling Conditions')
arm = input.float(defval=15, title='Trailing Stop Arms At (%)', minval=1, maxval=30, step=1, group='Selling Conditions') * 0.01
trail = input.float(defval=2, title='Trailing Stop Loss (%)', minval=0.25, maxval=9, step=0.25, group='Selling Conditions') * 0.1
longStopPrice = 0.0
stopLossPrice = 0.0
if strategy.position_size > 0
longStopPrice := strategy.position_avg_price * (1 + arm)
stopLossPrice := strategy.position_avg_price * ((100 - math.abs(holdLoss)) / 100) // for use with 'stop' in strategy.exit
stopLossPrice
else
longStopPrice := close
longStopPrice
// If you want to hide the Trailing Stop Loss threshold (green line), comment this out
plot(longStopPrice, 'Arm Trail Stop at', color.new(color.green, 60), linewidth=2)
if strategy.position_size > 0 and useTrailStop
strategy.exit('exit', 'long', when=window(), qty_percent=100, trail_price=longStopPrice, trail_offset=trail * close / syminfo.mintick, comment='Trail')
//-----------------------------------------------------------------------------------------------------------//