
이 전략의 핵심 아이디어는 내부 기둥 모양과 이동 평균 지표를 결합하여 자동 거래를 구현하는 것입니다. 내부 기둥 모양이 나타나면 현재 추세가 변할 수 있음을 나타냅니다. 이 때 우리는 이동 평균의 위치를 사용하여 최종 거래 방향을 판단합니다.
내부 기둥 선 형태를 찾는다. 내부 기둥 선 형태는 K 선의 최고값과 최저값이 전의 K 선의 실체 부분 사이에 있다는 것을 의미한다. 실체 색에 따라 내부 기둥을 다중 머리 내부 기둥 또는 공허 머리 내부 기둥으로 판단할 수 있다.
이동 평균 위치를 판단한다. 내부 기둥을 찾는 데 있어서, 이동 평균보다 높은 값은 다목표 신호이며, 이동 평균보다 낮은 값은 공수 신호이다.
내부 기둥 줄 모양과 이동 평균의 다공간 신호를 결합하여 최종 거래 방향을 얻습니다. 즉, 하락 내부 기둥 아래의 평균을 뚫고 공백을 만들고, 보 내부 기둥 위의 평균을 뚫고 더 많이합니다.
기술 지표와 가격 형태를 결합하여 거래 의사 결정의 정확성을 향상시킵니다.
내부 기둥 모양 자체는 강력한 가격 전환 신호를 포함하고 있으며, 트렌드 전환점을 조기에 결정할 수 있습니다.
이동 평균은 부분적인 소음을 제거하여 간격 진동에서 잡히지 않도록 합니다.
완전히 자동화된 거래는 수동 거래의 시간과 노력의 비용을 크게 줄여줍니다.
가격이 평균선 근처에서 흔들릴 때 더 많은 잘못된 신호가 발생하여 과도한 거래가 발생합니다. 이동 평균 변수를 최적화하거나 필터링 조건을 추가하여 잘못된 신호를 줄일 수 있습니다.
이 전략은 비교적 분명한 추세가 있는 시장에 더 적합하며, 불안정한 상황에서는 효과가 저하될 수 있다. 추세를 판단하는 지표인 ADX와 결합하여 알고리즘의 시작을 제어할 수 있다.
일정 시간 지연이 있다. 지연을 줄이기 위해 파라미터를 적절히 줄이거나 이동 평균의 계산 방법을 최적화 할 수 있다.
회수 위험은 크다. 손실 위험을 제어하기 위해 스톱을 설정할 수 있으며, 적절한 포지션 관리를 조정하는 것도 회수를 줄이는 데 도움이됩니다.
내부 기둥을 최적화하여 주기 변수를 결정하고 최적의 변수 조합을 찾습니다.
EMA, SMA 등과 같은 다른 유형의 이동 평균을 시도하여 가장 적합한 이동 평균 지표를 결정하십시오.
MACD, KDJ와 같은 보조 지표를 추가하여 공백 판단 기반을 풍부하게 하고, 신호 정확도를 향상시킨다.
ADX, ATR 등의 필터링 지표를 추가하여 알고리즘이 열리는 환경을 제어하고 부적절한 시장에서 작동하는 것을 피하십시오.
리스크 포지션 제어, 손실 수익을 보상 포지션 등과 같은 포지션 관리 전략을 최적화하여 위험을 제어하고 더 높은 수익을 추구하십시오.
이 전략은 동적으로 내부 기둥 선 신호와 이동 평균 지표를 추적하여 완전히 자동화된 정량 거래 프로그램을 구현합니다. 전략 신호는 간단하고 명확하게 생성되어 쉽게 이해하고 추적됩니다. 전략은 추세가 뚜렷한 시장에서 우수한 성능을 발휘합니다.
/*backtest
start: 2023-11-20 00:00:00
end: 2023-12-20 00:00:00
period: 1h
basePeriod: 15m
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/
// © myn
//@version=5
strategy('Strategy Myth-Busting #10 - InsideBar+EMA - [MYN]', max_bars_back=5000, overlay=true, pyramiding=0, initial_capital=20000, currency='USD', default_qty_type=strategy.percent_of_equity, default_qty_value=100.0, commission_value=0.075, use_bar_magnifier = false)
/////////////////////////////////////
//* Put your strategy logic below *//
/////////////////////////////////////
//short if: inside bar and bearish & below 50 ema & price falls below low of inside bar. Opposite for long. on 4H TF
// Inside Bar
//░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
f_priorBarsSatisfied(_objectToEval, _numOfBarsToLookBack) =>
returnVal = false
for i = 0 to _numOfBarsToLookBack
if (_objectToEval[i] == true)
returnVal = true
i_numLookbackBars = input(2,title="Lookback for Inside Bar")
// This source code is subject to the terms of the GNU License 2.0 at https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
// © cma
//@version=5
//indicator('Inside Bar Ind/Alert', overlay=true)
bullishBar = 1
bearishBar = -1
isInside() =>
previousBar = 1
bodyStatus = close >= open ? 1 : -1
isInsidePattern = high < high[previousBar] and low > low[previousBar]
isInsidePattern ? bodyStatus : 0
barcolor(isInside() == bullishBar ? color.green : na)
barcolor(isInside() == bearishBar ? color.red : na)
// When is bullish bar paint green
plotshape(isInside() == bullishBar, style=shape.triangleup, location=location.abovebar, color=color.new(color.green, 0))
// When is bearish bar paint red
plotshape(isInside() == bearishBar, style=shape.triangledown, location=location.belowbar, color=color.new(color.red, 0))
isInsideBarMade = isInside() == bullishBar or isInside() == bearishBar
alertcondition(isInsideBarMade, title='Inside Bar', message='Inside Bar came up!')
i_srcInsideBarLong = input.source(close, title = "_____ falls above HIGH of inside bar (Long condition)")
i_srcInsideBarShort = input.source(close, title = "_____ falls below LOW of inside bar (Short condition)")
//if: inside bar and falls below low of inside bar. I think.
insideBarLongEntry = f_priorBarsSatisfied(isInside() == bullishBar,i_numLookbackBars) and i_srcInsideBarLong > high[i_numLookbackBars] //isInside() == bullishBar
insideBarShortEntry = f_priorBarsSatisfied(isInside() == bearishBar,i_numLookbackBars) and i_srcInsideBarShort < low[i_numLookbackBars] //isInside() == bearishBar
// EMA
//░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
i_src = input.source(close, title = "EMA Source")
i_emaLength = input(50,title="EMA Length")
ema = ta.ema(i_src, i_emaLength)
emaPlot = plot(series=ema,color=color.blue, linewidth=2)
emaLongEntry = i_src > ema
emaShortEntry = i_src < ema
//////////////////////////////////////
//* Put your strategy rules below *//
/////////////////////////////////////
longCondition = insideBarLongEntry and emaLongEntry
shortCondition = insideBarShortEntry and emaShortEntry
//define as 0 if do not want to use
closeLongCondition = 0
closeShortCondition = 0
// ADX
//░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
adxEnabled = input.bool(defval = false , title = "Average Directional Index (ADX)", tooltip = "", group ="ADX" )
adxlen = input(14, title="ADX Smoothing", group="ADX")
adxdilen = input(14, title="DI Length", group="ADX")
adxabove = input(25, title="ADX Threshold", group="ADX")
adxdirmov(len) =>
adxup = ta.change(high)
adxdown = -ta.change(low)
adxplusDM = na(adxup) ? na : (adxup > adxdown and adxup > 0 ? adxup : 0)
adxminusDM = na(adxdown) ? na : (adxdown > adxup and adxdown > 0 ? adxdown : 0)
adxtruerange = ta.rma(ta.tr, len)
adxplus = fixnan(100 * ta.rma(adxplusDM, len) / adxtruerange)
adxminus = fixnan(100 * ta.rma(adxminusDM, len) / adxtruerange)
[adxplus, adxminus]
adx(adxdilen, adxlen) =>
[adxplus, adxminus] = adxdirmov(adxdilen)
adxsum = adxplus + adxminus
adx = 100 * ta.rma(math.abs(adxplus - adxminus) / (adxsum == 0 ? 1 : adxsum), adxlen)
adxsig = adxEnabled ? adx(adxdilen, adxlen) : na
isADXEnabledAndAboveThreshold = adxEnabled ? (adxsig > adxabove) : true
//Backtesting Time Period (Input.time not working as expected as of 03/30/2021. Giving odd start/end dates
//░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
useStartPeriodTime = input.bool(true, 'Start', group='Date Range', inline='Start Period')
startPeriodTime = input(timestamp('1 Jan 2019'), '', group='Date Range', inline='Start Period')
useEndPeriodTime = input.bool(true, 'End', group='Date Range', inline='End Period')
endPeriodTime = input(timestamp('31 Dec 2030'), '', group='Date Range', inline='End Period')
start = useStartPeriodTime ? startPeriodTime >= time : false
end = useEndPeriodTime ? endPeriodTime <= time : false
calcPeriod = true
// Trade Direction
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
tradeDirection = input.string('Long and Short', title='Trade Direction', options=['Long and Short', 'Long Only', 'Short Only'], group='Trade Direction')
// Percent as Points
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
per(pcnt) =>
strategy.position_size != 0 ? math.round(pcnt / 100 * strategy.position_avg_price / syminfo.mintick) : float(na)
// Take profit 1
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
tp1 = input.float(title='Take Profit 1 - Target %', defval=10.5, minval=0.0, step=0.5, group='Take Profit', inline='Take Profit 1')
q1 = input.int(title='% Of Position', defval=25, minval=0, group='Take Profit', inline='Take Profit 1')
// Take profit 2
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
tp2 = input.float(title='Take Profit 2 - Target %', defval=11, minval=0.0, step=0.5, group='Take Profit', inline='Take Profit 2')
q2 = input.int(title='% Of Position', defval=25, minval=0, group='Take Profit', inline='Take Profit 2')
// Take profit 3
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
tp3 = input.float(title='Take Profit 3 - Target %', defval=11.5, minval=0.0, step=0.5, group='Take Profit', inline='Take Profit 3')
q3 = input.int(title='% Of Position', defval=25, minval=0, group='Take Profit', inline='Take Profit 3')
// Take profit 4
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
tp4 = input.float(title='Take Profit 4 - Target %', defval=12, minval=0.0, step=0.5, group='Take Profit')
/// Stop Loss
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
stoplossPercent = input.float(title='Stop Loss (%)', defval=4, minval=0.01, group='Stop Loss') * 0.01
slLongClose = close < strategy.position_avg_price * (1 - stoplossPercent)
slShortClose = close > strategy.position_avg_price * (1 + stoplossPercent)
/// Leverage
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
leverage = input.float(1, 'Leverage', step=.5, group='Leverage')
contracts = math.min(math.max(.000001, strategy.equity / close * leverage), 1000000000)
/// Trade State Management
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
isInLongPosition = strategy.position_size > 0
isInShortPosition = strategy.position_size < 0
/// ProfitView Alert Syntax String Generation
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
alertSyntaxPrefix = input.string(defval='CRYPTANEX_99FTX_Strategy-Name-Here', title='Alert Syntax Prefix', group='ProfitView Alert Syntax')
alertSyntaxBase = alertSyntaxPrefix + '\n#' + str.tostring(open) + ',' + str.tostring(high) + ',' + str.tostring(low) + ',' + str.tostring(close) + ',' + str.tostring(volume) + ','
/// Trade Execution
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
longConditionCalc = (longCondition and isADXEnabledAndAboveThreshold)
shortConditionCalc = (shortCondition and isADXEnabledAndAboveThreshold)
if calcPeriod
if longConditionCalc and tradeDirection != 'Short Only' and isInLongPosition == false
strategy.entry('Long', strategy.long, qty=contracts)
alert(message=alertSyntaxBase + 'side:long', freq=alert.freq_once_per_bar_close)
if shortConditionCalc and tradeDirection != 'Long Only' and isInShortPosition == false
strategy.entry('Short', strategy.short, qty=contracts)
alert(message=alertSyntaxBase + 'side:short', freq=alert.freq_once_per_bar_close)
//Inspired from Multiple %% profit exits example by adolgo https://www.tradingview.com/script/kHhCik9f-Multiple-profit-exits-example/
strategy.exit('TP1', qty_percent=q1, profit=per(tp1))
strategy.exit('TP2', qty_percent=q2, profit=per(tp2))
strategy.exit('TP3', qty_percent=q3, profit=per(tp3))
strategy.exit('TP4', profit=per(tp4))
strategy.close('Long', qty_percent=100, comment='SL Long', when=slLongClose)
strategy.close('Short', qty_percent=100, comment='SL Short', when=slShortClose)
strategy.close_all(when=closeLongCondition or closeShortCondition, comment='Close Postion')
/// Dashboard
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// Inspired by https://www.tradingview.com/script/uWqKX6A2/ - Thanks VertMT
showDashboard = input.bool(group="Dashboard", title="Show Dashboard", defval=false)
f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
_cellText = _title + "\n" + _value
table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor, text_size=size.auto)
// Draw dashboard table
if showDashboard
var bgcolor = color.new(color.black,0)
// Keep track of Wins/Losses streaks
newWin = (strategy.wintrades > strategy.wintrades[1]) and (strategy.losstrades == strategy.losstrades[1]) and (strategy.eventrades == strategy.eventrades[1])
newLoss = (strategy.wintrades == strategy.wintrades[1]) and (strategy.losstrades > strategy.losstrades[1]) and (strategy.eventrades == strategy.eventrades[1])
varip int winRow = 0
varip int lossRow = 0
varip int maxWinRow = 0
varip int maxLossRow = 0
if newWin
lossRow := 0
winRow := winRow + 1
if winRow > maxWinRow
maxWinRow := winRow
if newLoss
winRow := 0
lossRow := lossRow + 1
if lossRow > maxLossRow
maxLossRow := lossRow
// Prepare stats table
var table dashTable = table.new(position.bottom_right, 1, 15, border_width=1)
if barstate.islastconfirmedhistory
// Update table
dollarReturn = strategy.netprofit
f_fillCell(dashTable, 0, 0, "Start:", str.format("{0,date,long}", strategy.closedtrades.entry_time(0)) , bgcolor, color.white) // + str.format(" {0,time,HH:mm}", strategy.closedtrades.entry_time(0))
f_fillCell(dashTable, 0, 1, "End:", str.format("{0,date,long}", strategy.opentrades.entry_time(0)) , bgcolor, color.white) // + str.format(" {0,time,HH:mm}", strategy.opentrades.entry_time(0))
_profit = (strategy.netprofit / strategy.initial_capital) * 100
f_fillCell(dashTable, 0, 2, "Net Profit:", str.tostring(_profit, '##.##') + "%", _profit > 0 ? color.green : color.red, color.white)
_numOfDaysInStrategy = (strategy.opentrades.entry_time(0) - strategy.closedtrades.entry_time(0)) / (1000 * 3600 * 24)
f_fillCell(dashTable, 0, 3, "Percent Per Day", str.tostring(_profit / _numOfDaysInStrategy, '#########################.#####')+"%", _profit > 0 ? color.green : color.red, color.white)
_winRate = ( strategy.wintrades / strategy.closedtrades ) * 100
f_fillCell(dashTable, 0, 4, "Percent Profitable:", str.tostring(_winRate, '##.##') + "%", _winRate < 50 ? color.red : _winRate < 75 ? #999900 : color.green, color.white)
f_fillCell(dashTable, 0, 5, "Profit Factor:", str.tostring(strategy.grossprofit / strategy.grossloss, '##.###'), strategy.grossprofit > strategy.grossloss ? color.green : color.red, color.white)
f_fillCell(dashTable, 0, 6, "Total Trades:", str.tostring(strategy.closedtrades), bgcolor, color.white)
f_fillCell(dashTable, 0, 8, "Max Wins In A Row:", str.tostring(maxWinRow, '######') , bgcolor, color.white)
f_fillCell(dashTable, 0, 9, "Max Losses In A Row:", str.tostring(maxLossRow, '######') , bgcolor, color.white)