
この戦略の目的は,異なるパラメータを設定することによって,トレーダーの心理と取引のパフォーマンスをバランスさせ,より安定した収益を得ることです. それは,平均線,ブリン帯,ケルトナー通路などの指標を使用して,市場の傾向と変動率を判断し,PSAR指標と組み合わせて,反転信号を判断し,TTM圧縮指標を使用して,動きを判断します.
この戦略の主要な論理は以下の通りです.
傾向判断: EMA平均線を用いて価格の傾向方向を判断する.価格は,EMA上は上昇,下は下落である.
判断逆転:PSARを使用して価格逆転点を判断する.PSAR点は価格の上部に看板信号として現れ,価格下部に看板信号として現れ
判断量:TTM Squeeze指標を用いて市場の波動率と動きを判断する. TTM Squeeze指標はブリン帯とケルトナー通路の幅を比較して波動率を測定し,圧縮は非常に低い波動率を意味する. 圧縮解除は波動率の増加と価格がより大きな方向の動きを起こすことを意味する.
取引シグナルを生成する:価格がEMA平均線,PSARポイントを上を通過し,TTM Squeeze指標が圧縮を解除すると,看多シグナルを生成する;価格がEMA平均線,PSARポイントを下を通過し,TTM Squeeze指標が圧縮に入ると,空看シグナルを生成する
ストップ方式:高低点ストップを使用する. 最新の一定周期の最高値または最低値に応じて倍数をセットしてストップポイントとして掛けます.
ストップ方式:リスク・リターン比率の自動ストップを使用.ストップポイントは,ストップポイントから現在の価格までの比率を設定したリスク・リターン比率のパラメータで掛けることで得られます.
パラメータ設定により,取引頻度,ポジション管理,ストップ・ロスト・ポイント,ストップ・ストップ・ポイントを制御し,取引心理を均衡させることができる.
この戦略の利点は以下の通りです.
複数の指標で判断し,信号の正確性を向上させる
逆転が主,順位が補助,逆転のポイントを捕捉し,上位を突破し,下位を突破し,を撃つ確率を減らす
TTMSqueeze指標は,トレンドの調整を効果的に判断し,調整期間の無効取引を避ける
高低ストップ方法は簡単で実用的で,市場に応じてストップ距離を調整できます.
リスク・リターン・比ストップ方式は,利益・損失比率を数値化して,調整を容易にします.
各種パラメータの設定は柔軟で,個人リスクの好みに合わせて微調整できます.
この戦略には以下のリスクもあります.
複数の指標の組み合わせ判断は,信号の正確性を向上させながらも,エントリーポイントを跳び越す可能性も増加させる.
逆転が主たる戦略で,トレンドの状況ではうまくいかない可能性がある
高低のストップダメージは時として突破され,リスクを完全に回避することはできません.
リスク・リターン比ストラップは,価格の上昇や調整によって失効する可能性があります.
パラメータを正しく設定しない場合,損失または頻繁に停止する可能性があります.
この戦略は以下の点で最適化できます.
信号をより正確にするために指標の重量を追加または調整する
逆転とトレンド判断の指標パラメータを最適化し,利益の確率を向上させる
高低ストップのパラメータを最適化して,ストップを合理的にします.
リスク・リターン・レートをテストして,最適な結果を得ること
ポジション数パラメータを調整し,単一損失の影響を軽減する
この戦略の全体として,指標集合判断とパラメータ調整により,取引心理を効果的にバランスさせ,安定した正利益を得ることができる.改善の余地があるが,実地での応用価値がある.市場のフィードバックとパラメータ微調整により,この戦略は,取引心理を制御し,長期的に安定した利益を得るための効果的なツールになる見込みがある.
/*backtest
start: 2024-01-01 00:00:00
end: 2024-01-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © simwai
strategy('Octopus Nest Strategy 🐙', shorttitle='🐙', overlay=true )
// -- Colors --
color maximumYellowRed = color.rgb(255, 203, 98) // yellow
color rajah = color.rgb(242, 166, 84) // orange
color magicMint = color.rgb(171, 237, 198)
color languidLavender = color.rgb(232, 215, 255)
color maximumBluePurple = color.rgb(181, 161, 226)
color skyBlue = color.rgb(144, 226, 244)
color lightGray = color.rgb(214, 214, 214)
color quickSilver = color.rgb(163, 163, 163)
color mediumAquamarine = color.rgb(104, 223, 153)
color carrotOrange = color.rgb(239, 146, 46)
// -- Inputs --
float src = input.source(close, 'Choose Source', group='General', inline='1')
bool isSignalLabelEnabled = input.bool(title='Show Signal Labels?', defval=true, group='General', inline='2')
bool isPsarAdaptive = input.bool(title='Is PSAR Adaptive?', defval=false, group='General', inline='2')
float highLowStopLossMultiplier = input.float(defval=0.98, step=0.01, minval=0, maxval=1, title='Multiplier', group='High Low Stop Loss', inline='1')
float highLowStopLossBackupMultiplier = input.float(defval=0.98, step=0.01, minval=0, maxval=1, title='Backup Multiplier', group='High Low Stop Loss', inline='1')
int highLowStopLossLookback = input.int(defval=20, step=5, minval=1, title='Lookback', group='High Low Stop Loss', inline='2')
float automaticHighLowTakeProfitRatio = input.float(defval=1.125, step=0.1, minval=0, title='Risk Reward Ratio', group='Automatic High Low Take Profit', inline='2')
int emaLength = input.int(100, minval=2, title='Length', group='EMA', inline='1')
int ttmLength = input.int(title='Length', defval=20, minval=0, group='TTM Squeeze', inline='1')
float psarStart = input.float(0.02, 'Start', step=0.01, minval=0.0, group='PSAR', inline='1')
float psarInc = input.float(0.02, 'Increment', step=0.01, minval=0.01, group='PSAR', inline='1')
float psarMax = input.float(0.2, 'Max', step=0.05, minval=0.0, group='PSAR', inline='2')
startAFactor = input.float(0.02, 'Starting Acceleration Factor', step = 0.001, group='Adaptive PSAR', inline='1')
minStep = input.float(0.0, 'Min Step', step = 0.001, group='Adaptive PSAR', inline='1')
maxStep = input.float(0.02, 'Max Step', step = 0.001, group='Adaptive PSAR', inline='2')
maxAFactor = input.float(0.2, 'Max Acceleration Factor', step = 0.001, group='Adaptive PSAR', inline='2')
hiloMode = input.string('On', 'HiLo Mode', options = ['Off', 'On'], group='Adaptive PSAR')
adaptMode = input.string('Kaufman', 'Adaptive Mode', options = ['Off', 'Kaufman', 'Ehlers'], group='Adaptive PSAR')
adaptSmth = input.int(5, 'Adaptive Smoothing Period', minval = 1, group='Adaptive PSAR')
filt = input.float(0.0, 'Filter in Pips', group='Adaptive PSAR', minval = 0)
minChng = input.float(0.0, 'Min Change in Pips', group='Adaptive PSAR', minval = 0)
SignalMode = input.string('Only Stops', 'Signal Mode', options = ['Only Stops', 'Signals & Stops'], group='Adaptive PSAR')
// -- Functions --
tr(_high, _low, _close) => math.max(_high - _low, math.abs(_high - _close[1]), math.abs(_low - _close[1]))
// -- Calculation --
var string lastTrade = 'initial'
float _low = low
float _high = high
float _close = close
// -- TTM Squeeze – Credits to @Greeny --
bband(ttmLength, mult) =>
ta.sma(src, ttmLength) + mult * ta.stdev(src, ttmLength)
keltner(ttmLength, mult) =>
ta.ema(src, ttmLength) + mult * ta.ema(tr(_high, _low, _close), ttmLength)
e1 = (ta.highest(_high, ttmLength) + ta.lowest(_low, ttmLength)) / 2 + ta.sma(src, ttmLength)
osc = ta.linreg(src - e1 / 2, ttmLength, 0)
diff = bband(ttmLength, 2) - keltner(ttmLength, 1)
osc_color = osc[1] < osc[0] ? osc[0] >= 0 ? #00ffff : #cc00cc : osc[0] >= 0 ? #009b9b : #ff9bff
mid_color = diff >= 0 ? color.green : color.red
// -- PSAR --
// Credits to @Bjorgum
calcBaseUnit() =>
bool isForexSymbol = syminfo.type == 'forex'
bool isYenPair = syminfo.currency == 'JPY'
float result = isForexSymbol ? isYenPair ? 0.01 : 0.0001 : syminfo.mintick
// Credits to @loxx
_afact(mode,input, per, smooth) =>
eff = 0., seff = 0.
len = 0, sum = 0., max = 0., min = 1000000000.
len := mode == 'Kaufman' ? math.ceil(per) : math.ceil(math.max(20, 5 * per))
for i = 0 to len
if (mode == 'Kaufman')
sum += math.abs(input[i] - input[i + 1])
else
max := input[i] > max ? input[i] : max
min := input[i] < min ? input[i] : min
if (mode == 'Kaufman' and sum != 0)
eff := math.abs(input - input[len]) / sum
else
if (mode == 'Ehlers' and (max - min) > 0)
eff := (input - min) / (max - min)
seff := ta.ema(eff, smooth)
seff
hVal2 = nz(high[2]), hVal1 = nz(high[1]), hVal0 = high
lowVal2 = nz(low[2]), lowVal1 = nz(low[1]), lowVal0 = low
hiprice2 = nz(high[2]), hiprice1 = nz(high[1]), hiprice0 = high
loprice2 = nz(low[2]), loprice1 = nz(low[1]), loprice0 = low
upSig = 0., dnSig = 0.
aFactor = 0., step = 0., trend = 0.
upTrndSAR = 0., dnTrndSAR = 0.
length = (2 / maxAFactor - 1)
if (hiloMode == 'On')
hiprice0 := high
loprice0 := low
else
hiprice0 := src
loprice0 := hiprice0
if bar_index == 1
trend := 1
hVal1 := hiprice1
hVal0 := math.max(hiprice0, hVal1)
lowVal1 := loprice1
lowVal0 := math.min(loprice0, lowVal1)
aFactor := startAFactor
upTrndSAR := lowVal0
dnTrndSAR := 0.
else
hVal0 := hVal1
lowVal0 := lowVal1
trend := nz(trend[1])
aFactor := nz(aFactor[1])
inputs = 0.
inprice = src
if (adaptMode != 'Off')
if (hiloMode == 'On')
inprice := src
else
inprice := hiprice0
if (adaptMode == 'Kaufman')
inputs := inprice
else
if (adaptMode == 'Ehlers')
if (nz(upTrndSAR[1]) != 0.)
inputs := math.abs(inprice - nz(upTrndSAR[1]))
else
if (nz(dnTrndSAR[1]) != 0.)
inputs := math.abs(inprice - nz(dnTrndSAR[1]))
step := minStep + _afact(adaptMode, inputs, length, adaptSmth) * (maxStep - minStep)
else
step := maxStep
upTrndSAR := 0., dnTrndSAR := 0., upSig := 0., dnSig := 0.
if (nz(trend[1]) > 0)
if (nz(trend[1]) == nz(trend[2]))
aFactor := hVal1 > hVal2 ? nz(aFactor[1]) + step : aFactor
aFactor := aFactor > maxAFactor ? maxAFactor : aFactor
aFactor := hVal1 < hVal2 ? startAFactor : aFactor
else
aFactor := nz(aFactor[1])
upTrndSAR := nz(upTrndSAR[1]) + aFactor * (hVal1 - nz(upTrndSAR[1]))
upTrndSAR := upTrndSAR > loprice1 ? loprice1 : upTrndSAR
upTrndSAR := upTrndSAR > loprice2 ? loprice2 : upTrndSAR
else
if (nz(trend[1]) == nz(trend[2]))
aFactor := lowVal1 < lowVal2 ? nz(aFactor[1]) + step : aFactor
aFactor := aFactor > maxAFactor ? maxAFactor : aFactor
aFactor := lowVal1 > lowVal2 ? startAFactor : aFactor
else
aFactor := nz(aFactor[1])
dnTrndSAR := nz(dnTrndSAR[1]) + aFactor * (lowVal1 - nz(dnTrndSAR[1]))
dnTrndSAR := dnTrndSAR < hiprice1 ? hiprice1 : dnTrndSAR
dnTrndSAR := dnTrndSAR < hiprice2 ? hiprice2 : dnTrndSAR
hVal0 := hiprice0 > hVal0 ? hiprice0 : hVal0
lowVal0 := loprice0 < lowVal0 ? loprice0 : lowVal0
if (minChng > 0)
if (upTrndSAR - nz(upTrndSAR[1]) < minChng * calcBaseUnit() and upTrndSAR != 0. and nz(upTrndSAR[1]) != 0.)
upTrndSAR := nz(upTrndSAR[1])
if (nz(dnTrndSAR[1]) - dnTrndSAR < minChng * calcBaseUnit() and dnTrndSAR != 0. and nz(dnTrndSAR[1]) != 0.)
dnTrndSAR := nz(dnTrndSAR[1])
dnTrndSAR := trend < 0 and dnTrndSAR > nz(dnTrndSAR[1]) ? nz(dnTrndSAR[1]) : dnTrndSAR
upTrndSAR := trend > 0 and upTrndSAR < nz(upTrndSAR[1]) ? nz(upTrndSAR[1]) : upTrndSAR
if (trend < 0 and hiprice0 >= dnTrndSAR + filt * calcBaseUnit())
trend := 1
upTrndSAR := lowVal0
upSig := SignalMode == 'Signals & Stops' ? lowVal0 : upSig
dnTrndSAR := 0.
aFactor := startAFactor
lowVal0 := loprice0
hVal0 := hiprice0
else if (trend > 0 and loprice0 <= upTrndSAR - filt * calcBaseUnit())
trend := -1
dnTrndSAR := hVal0
dnSig := SignalMode == 'Signals & Stops' ? hVal0 : dnSig
upTrndSAR := 0.
aFactor := startAFactor
lowVal0 := loprice0
hVal0 := hiprice0
psar = upTrndSAR > 0 ? upTrndSAR : dnTrndSAR
psar := isPsarAdaptive ? psar : ta.sar(psarStart, psarInc, psarMax)
plot(psar, title='PSAR', color=src < psar ? rajah : magicMint, style=plot.style_circles)
// -- EMA --
float ema = ta.ema(src, emaLength)
plot(ema, title='EMA', color=languidLavender)
// -- Signals --
var string isTradeOpen = ''
var string signalCache = ''
bool enterLong = src > ema and ta.crossover(src, psar) and ta.crossover(osc, 0)
bool enterShort = src < ema and ta.crossunder(src, psar) and ta.crossunder(osc, 0)
// bool exitLong = ta.crossunder(src, ema)
// bool exitShort = ta.crossover(src, ema)
if (signalCache == 'long entry')
signalCache := ''
enterLong := true
else if (signalCache == 'short entry')
signalCache := ''
enterShort := true
if (isTradeOpen == '')
if (enterLong)
isTradeOpen := 'long'
else if (enterShort)
isTradeOpen := 'short'
else if (isTradeOpen == 'long')
if (enterLong)
enterLong := false
else if (isTradeOpen == 'short')
if (enterShort)
enterShort := false
plotshape((isSignalLabelEnabled and enterLong and (isTradeOpen == 'long')) ? psar : na, title='LONG', text='L', style=shape.labelup, color=mediumAquamarine, textcolor=color.white, size=size.tiny, location=location.absolute)
plotshape((isSignalLabelEnabled and enterShort and (isTradeOpen == 'short')) ? psar : na, title='SHORT', text='S', style=shape.labeldown, color=carrotOrange, textcolor=color.white, size=size.tiny, location=location.absolute)
// -- High Low Stop Loss and Take Profit --
bool isHighLowStopLossEnabled = true
bool isAutomaticHighLowTakeProfitEnabled = true
bool recalculateStopLossTakeProfit = false
bool isStrategyEntryEnabled = false
bool isLongEnabled = true
bool isShortEnabled = true
bool isStopLossTakeProfitRecalculationEnabled = true
bool longStopLossTakeProfitRecalculation = isStopLossTakeProfitRecalculationEnabled ? true : (lastTrade == 'short' or lastTrade == 'initial')
bool shortStopLossTakeProfitRecalculation = isStopLossTakeProfitRecalculationEnabled ? true : (lastTrade == 'long' or lastTrade == 'initial')
var float longHighLowStopLoss = 0
var float shortHighLowStopLoss = 0
float highLowStopLossLowest = ta.lowest(_low, highLowStopLossLookback)
float highLowStopLossHighest = ta.highest(_high, highLowStopLossLookback)
if (isHighLowStopLossEnabled)
if (((enterLong and longStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true))
if (highLowStopLossLowest == _low)
longHighLowStopLoss := _high * highLowStopLossBackupMultiplier
else if (highLowStopLossLowest > 0)
longHighLowStopLoss := highLowStopLossLowest * highLowStopLossMultiplier
if (((enterShort and shortStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size < 0) : true))
if (highLowStopLossHighest == _high)
shortHighLowStopLoss := _high * (1 + (1 - highLowStopLossBackupMultiplier))
else if (highLowStopLossHighest > 0)
shortHighLowStopLoss := highLowStopLossHighest * (1 + (1 - highLowStopLossMultiplier))
plot((isLongEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'long')) ? longHighLowStopLoss : na, 'Long High Low Stop Loss', color=magicMint, style=plot.style_circles, trackprice=false)
plot((isShortEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'short')) ? shortHighLowStopLoss : na, 'Short High Low Stop Loss ', color=rajah, style=plot.style_circles, trackprice=false)
// -- Automatic High Low Take Profit --
var float longAutomaticHighLowTakeProfit = na
var float shortAutomaticHighLowTakeProfit = na
if (isAutomaticHighLowTakeProfitEnabled)
if (((enterLong and longStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true))
longHighLowStopLossPercentage = 1 - (longHighLowStopLoss / _close)
longAutomaticHighLowTakeProfit := _close * (1 + (longHighLowStopLossPercentage * automaticHighLowTakeProfitRatio))
if (((enterShort and shortStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true))
shortHighLowStopLossPercentage = 1 - (_close / shortHighLowStopLoss)
shortAutomaticHighLowTakeProfit := _close * (1 - (shortHighLowStopLossPercentage * automaticHighLowTakeProfitRatio))
plot((isAutomaticHighLowTakeProfitEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'long')) ? longAutomaticHighLowTakeProfit : na, 'Long Automatic High Low Take Profit', color=magicMint, style=plot.style_circles, trackprice=false)
plot((isAutomaticHighLowTakeProfitEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'short')) ? shortAutomaticHighLowTakeProfit : na, 'Short Automatic High Low Take Profit', color=rajah, style=plot.style_circles, trackprice=false)
// log.info('Automatic Long High Low Take Profit: ' + str.tostring(longAutomaticHighLowTakeProfit))
// log.info('Automatic Short High Low Take Profit: ' + str.tostring(shortAutomaticHighLowTakeProfit))
// log.info('Long High Low Stop Loss: ' + str.tostring(longHighLowStopLoss))
// log.info('Short High Low Stop Loss: ' + str.tostring(shortHighLowStopLoss))
bool longHighLowStopLossCondition = ta.crossunder(_close, longHighLowStopLoss)
bool shortHighLowStopLossCondition = ta.crossover(_close, shortHighLowStopLoss)
bool longAutomaticHighLowTakeProfitCondition = ta.crossover(_close, longAutomaticHighLowTakeProfit)
bool shortAutomaticHighLowTakeProfitCondition = ta.crossunder(_close, shortAutomaticHighLowTakeProfit)
bool exitLong = (longHighLowStopLossCondition or longAutomaticHighLowTakeProfitCondition) and strategy.position_size > 0
bool exitShort = (shortHighLowStopLossCondition or shortAutomaticHighLowTakeProfitCondition) and strategy.position_size < 0
plotshape((isSignalLabelEnabled and exitLong and (isTradeOpen == 'long')) ? psar : na, title='LONG EXIT', style=shape.circle, color=magicMint, size=size.tiny, location=location.absolute)
plotshape((isSignalLabelEnabled and exitShort and (isTradeOpen == 'short')) ? psar : na, title='SHORT EXIT', style=shape.circle, color=rajah, size=size.tiny, location=location.absolute)
// Long Exits
if (exitLong)
strategy.close('long', comment=longAutomaticHighLowTakeProfitCondition ? 'EXIT_LONG_TP' : 'EXIT_LONG_SL')
isTradeOpen := ''
// Short Exits
if (exitShort)
strategy.close('short', comment=shortAutomaticHighLowTakeProfitCondition ? 'EXIT_SHORT_TP' : 'EXIT_SHORT_SL')
isTradeOpen := ''
// Long Entries
if (enterLong and (strategy.position_size == 0))
strategy.entry('long', strategy.long, comment='ENTER_LONG')
// Short Entries
if (enterShort and (strategy.position_size == 0))
strategy.entry('short', strategy.short, comment='ENTER_SHORT')
// Save last trade state
if (enterLong or exitLong)
lastTrade := 'long'
if (enterShort or exitShort)
lastTrade := 'short'
barcolor(color=isTradeOpen == 'long' ? mediumAquamarine : isTradeOpen == 'short' ? carrotOrange : na)