トレンドブレイク 移動平均追跡戦略

作者: リン・ハーンチャオチャン, 日付: 2023年11月3日 15:57:11
タグ:

img

概要

この戦略は,単純な移動平均値のゴールデンクロスとデッドクロスによってトレンド方向を特定し,トレンドの開始時に完全なポジションサイズでロングまたはショートで走り,リスクを制御するためにストップ・ロストとテイク・プロフィートオーダーを設定します.ポジションに入ると,移動平均値を使用してトレンドを追跡し,トレンド逆転があるときに時間をかけて損失を削減します.この戦略には,ストップ・ロスト,テイク・プロフィート,ポジションサイジングの構成可能なモジュールもあり,異なる製品のためのパラメータの柔軟な調整を可能にします.

戦略の論理

この戦略の核心は,単純な移動平均値の金十字と死十字を使用してトレンド開始と終止を決定することです.まず,高速SMA (例えば21期) と遅いSMA (例えば49期) の関係に基づいてトレンド方向を特定します.高速SMAが遅いSMAを超えると,上昇傾向を示し,戦略は長くなります.高速SMAが遅いSMAを下回ると,ダウントレンドを示し,戦略は短くなります.

ポジションに入ると,戦略はリアルタイムでSMAとの関係価格をモニターし続けます.価格がSMAを上から破るとロングポジションを閉じて,価格がSMAを下から破るとショートポジションを閉じて,トレンド逆転信号となります.

リスクを制御するために,戦略は,ポジションを開く時に同時にストップ・ロストとプロフィート・オーダーを設定する.ストップ・ロスト距離はATRに基づいているが,プロフィート・ロスト距離はパーセントまたはATR倍数として設定できる.ポジションを開いた後,ストップ・ロスはトレンドをたどる価格を追跡し続けます.プロフィート・ロストが触れたとき,完全に閉じるまで残りを追跡し続けながら,最初に部分的なポジションを閉じます.

この戦略には,各取引に使用される資金を制限し,取引リスクの露出を制御するためのポジションサイジングモジュールもあります. さらに,最大引き上げ制限は,全体的な戦略リスクを制限するのに役立ちます.

利点

  • 簡単で理解しやすい,SMAクロスを使ってトレンド方向を決定する
  • ストップ・ロスのリアルタイム追跡は,ほとんどの利益をロックすることができます.
  • ストップ・ロストと利益引き換えは,異なる製品で調整できます.
  • 管理可能な取引リスクごとに,完全なポジション取引がない
  • 総損失を制限する最大引き上げ制限

リスク と 解決策

  • トレンド開始時のベストエントリーを見逃すかもしれない
  • パラメータを繰り返し調整し,異なる SMA 期間をテストする必要性
  • SMAクロスにはいくつかのウィップソーがあります,入力精度は100%することはできません
  • トレイリングストップロスは簡単にヒットし,全利益をロックすることはできません.
  • 価格リトラセーションのための合理的なストップ損失距離が必要
  • 最大引き上げ制限が保守すぎると 上向きの可能性が欠けている
  • 戦略の許容性を増やすために最大抽出を緩和できる

増進 の 機会

  • 最適のSMA期間を見つけるために異なるパラメータの組み合わせをテストする
  • 入力精度を向上させるためにトレンド強度指標を追加
  • ストップ・ロスの戦略を最適化し,上向きと下向きのトレンドをできるだけ追いかける
  • 最適の出口点を探すために,異なる利益戦略をテスト
  • 資本利用を改善するためのポジションサイズ化スキームを改良する
  • 最大引き上げ設定をバランス・リターン対リスクに調整する

結論

概要すると,これは初心者にとって非常に適したスタート戦略であり,シンプルな論理と理解が容易である.また,大きな損失を減らすために適切なリスク管理能力を持っています.パラメータチューニングによって良い結果が得られます.しかし,その内在的な弱点は,高精度で動作することができないことを決定します.初心者が練習することをお勧めしますが,高効率と勝利率を追求する高度なトレーダーには合致しない可能性があります.より良い取引パフォーマンスを獲得するには,より強力な予測力を持つ戦略を探すべきです.


/*backtest
start: 2023-01-01 00:00:00
end: 2023-11-02 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5
//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 
//  -----------------------------------------------------------------------------
//  Copyright 2022 Iason Nikolas | jason5480
//  Template Strategy script may be freely distributed under the MIT license.
//
//  Permission is hereby granted, free of charge, 
//  to any person obtaining a copy of this software and associated documentation files (the "Software"), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
//  publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
//  subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
//  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//  -----------------------------------------------------------------------------
//
//  Authors:  @jason5480
//  Revision: v0.0.1
//  Date:     26-Feb-2022
//
//  Description
//  =============================================================================
//  This script is designed to be used as a template for building new strategies.
//  The framework provide you with a configurable implementation of the entry, exit,
//  stop loss and take profit trailing logic. The user of this script has to copy
//  it and replace the openLongPosition, openShortPosition, closeLongPosition and
//  closeShortPosition variables in the STRATEGY module according to his needs! 
//  
//  -----------------------------------------------------------------------------
//  Disclaimer:
//    1. I am not licensed financial advisors or broker dealer. I do not tell you 
//       when or what to buy or sell. I developed this software which enables you 
//       execute manual or automated trades using TradingView. The 
//       software allows you to set the criteria you want for entering and exiting 
//       trades.
//    2. Do not trade with money you cannot afford to lose.
//    3. I do not guarantee consistent profits or that anyone can make money with no 
//       effort. And I am not selling the holy grail.
//    4. Every system can have winning and losing streaks.
//    5. Money management plays a large role in the results of your trading. For 
//       example: lot size, account size, broker leverage, and broker margin call 
//       rules all have an effect on results. Also, your Take Profit and Stop Loss 
//       settings for individual pair trades and for overall account equity have a 
//       major impact on results. If you are new to trading and do not understand 
//       these items, then I recommend you seek education materials to further your
//       knowledge.
//
//    YOU NEED TO FIND AND USE THE TRADING SYSTEM THAT WORKS BEST FOR YOU AND YOUR 
//    TRADING TOLERANCE.
//
//    I HAVE PROVIDED NOTHING MORE THAN A TOOL WITH OPTIONS FOR YOU TO TRADE WITH THIS PROGRAM ON TRADINGVIEW.
//    
//    I accept suggestions to improve the script.
//    If you encounter any problems I will be happy to share with me.
//  -----------------------------------------------------------------------------
//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// SETUP ============================================================================================================
strategy(title = 'Template Trailing Strategy',
         shorttitle = 'TTS',
         overlay = true,
         pyramiding = 0,
         default_qty_type = strategy.percent_of_equity,
         default_qty_value = 100,
         initial_capital = 100000)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// FILTERS ==========================================================================================================

// INPUT ============================================================================================================
usefromDate = input.bool(defval = true, title = 'From', inline = "From Date", group = "Filters")
fromDate = input(defval = timestamp('01 Jan 2021 00:00 UTC'), title = '', inline = "From Date", group = 'Filters')
usetoDate = input.bool(defval = false, title = 'To ', inline = "To Date", group = "Filters")
toDate = input(defval = timestamp('31 Dec 2121 23:59 UTC'), title = '', inline = "To Date", group = 'Filters')

longTradesEnabled = input.bool(defval = true, title = 'Long Trades', inline = 'Trades', group = 'Filters')
shortTradesEnabled = input.bool(defval = true, title = 'Short Trades', tooltip = 'Enable long/short trades.', inline = 'Trades', group = 'Filters')

emaFilterEnabled = input.bool(defval = true, title = 'EMA Filter', tooltip = 'Enable long/short trades based on EMA.', group = 'Filters')
emaResolution = input.timeframe(defval = 'D', title = 'EMA Res/Len/Src', inline = 'EMA Filter', group = 'Filters')
emaLength = input.int(defval = 200, title = '', inline = 'EMA Filter', group = 'Filters')
emaSrc = input.source(defval = close, title = '', tooltip = 'The timeframe, period and source for the EMA calculation.', inline = 'EMA Filter', group = 'Filters')
emaAtrBandEnabled = input.bool(defval = true, title = 'EMA ATR Band', tooltip = 'Enable ATR band for EMA filter.', group = 'Filters')
filterAtrLength = input.int(defval = 5, title = 'EMA ATR Len/Mul', minval = 1, inline = 'EMA ATR', group = 'Filters')
filterAtrMul = input.float(defval = 1.0, title = '', tooltip = 'ATR length and multiplier to be used for the ATR calculation that will be added on top of the EMA filter.', minval = 0.1, step = 0.1, inline = 'EMA ATR', group = 'Filters')

// LOGIC ============================================================================================================
isWithinPeriod() => true

emaLine = request.security(syminfo.tickerid, emaResolution, ta.ema(emaSrc, emaLength))
emaAtr = ta.atr(filterAtrLength)
emaUpperBand = emaLine + filterAtrMul * emaAtr
emaLowerBand = emaLine - filterAtrMul * emaAtr
bool emaLongApproval = emaFilterEnabled ? close > (emaAtrBandEnabled ? emaUpperBand : emaLine) and open > (emaAtrBandEnabled ? emaUpperBand : emaLine) : true
bool emaShortApproval = emaFilterEnabled ? close < (emaAtrBandEnabled ? emaLowerBand : emaLine) and open < (emaAtrBandEnabled ? emaLowerBand : emaLine) : true

bool longFiltersApproval = longTradesEnabled and emaLongApproval and isWithinPeriod()
bool shortFiltersApproval = shortTradesEnabled and emaShortApproval and isWithinPeriod()

// PLOT =============================================================================================================
bgcolor(color = isWithinPeriod() ? color.new(color.gray, 90) : na, title = 'Period')

showEma = input.bool(defval = true, title = 'Show EMA Line', inline = 'EMA Show', group = 'Plot')
showEmaBand = input.bool(defval = false, title = 'Show EMA Band', tooltip = 'Show the EMA Line/Band.', inline = 'EMA Show', group = 'Plot')

emaLineColor = emaLongApproval ? color.teal : emaShortApproval ? color.maroon : color.gray
plot(series = emaFilterEnabled and showEma ? emaLine : na, color = emaLineColor, style = plot.style_line, linewidth = 2, title = 'EMA Line')
emaUpperBandPlot = plot(series = emaUpperBand, color = na, style = plot.style_line, linewidth = 1, title = 'EMA Upper Band')
emaLowerBandPlot = plot(series = emaLowerBand, color = na, style = plot.style_line, linewidth = 1, title = 'EMA Lower Band')
emaBandFillColor = emaFilterEnabled and emaAtrBandEnabled and showEmaBand ? color.new(emaLineColor, 95) : na
fill(plot1 = emaUpperBandPlot, plot2 = emaLowerBandPlot, color = emaBandFillColor, title = 'EMA Band')

// INPUT ============================================================================================================

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// STRATEGY =========================================================================================================

// INPUT ============================================================================================================
fastMALen = input.int(defval = 21, title = 'Fast/Slow SMA Length', inline = 'MA Length', group = 'Strategy')
slowMALen = input.int(defval = 49, title = '', tooltip = 'How many candles back to calculte the fast/slow SMA.', inline = 'MA Length', group = 'Strategy')

// LOGIC ============================================================================================================
fastMA = ta.sma(close, fastMALen)
slowMA = ta.sma(close, slowMALen)

bool openLongPosition = longFiltersApproval and ta.crossover(fastMA, slowMA)
bool openShortPosition = shortFiltersApproval and ta.crossunder(fastMA, slowMA)

bool closeLongPosition = longTradesEnabled and ta.crossunder(fastMA, slowMA)
bool closeShortPosition = shortTradesEnabled and ta.crossover(fastMA, slowMA)

// PLOT =============================================================================================================
var fastColor = color.new(#0056BD, 0)
plot(series = fastMA, title = 'Fast SMA', color = fastColor, linewidth = 1, style = plot.style_line)
var slowColor = color.new(#FF6A00, 0)
plot(series = slowMA, title = 'Slow SMA', color = slowColor, linewidth = 1, style = plot.style_line)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// SHARED VARIABLES =================================================================================================

// INPUT ============================================================================================================
atrLength = input.int(defval = 14, title = 'ATR Length', minval = 1, tooltip = 'How many previous candles to use for the ATR calculation.', group = 'General')

// LOGIC ============================================================================================================
// the open signals when not already into a position
bool validOpenLongPosition = openLongPosition and not (strategy.position_size > 0)
bool validOpenShortPosition = openShortPosition and not (strategy.position_size < 0)
bool validCloseLongPosition = closeLongPosition and strategy.position_size > 0
bool validCloseShortPosition = closeShortPosition and strategy.position_size < 0

// count how far are the last valid open and regular close signals
int barsSinceValidOpenLong = nz(ta.barssince(validOpenLongPosition), 999999)
int barsSinceValidOpenShort = nz(ta.barssince(validOpenShortPosition), 999999)
int barsSinceCloseLong = nz(ta.barssince(closeLongPosition), 999999)
int barsSinceCloseShort = nz(ta.barssince(closeShortPosition), 999999)

// take profit has to communicate its execution with the stop loss logic when 'TP' mode is selected
var bool longTrailingTakeProfitExecuted = false
var bool shortTrailingTakeProfitExecuted = false

// close price when the valid open signal was triggered
float openPrice = ta.valuewhen(validOpenLongPosition or validOpenShortPosition, close, 0)

float openAtr = ta.valuewhen(validOpenLongPosition or validOpenShortPosition, ta.atr(atrLength), 0)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ENTRY ============================================================================================================

// INPUT ============================================================================================================
enableEntryTrailing = input.bool(defval = false, title = 'Enable Trailing', tooltip = 'Enable or disable the trailing for entry position.', group = 'Entry')
devEntryMethod = input.string(defval = 'PERC', title = 'Deviation Method', options = ['PERC', 'ATR'], tooltip = 'The method to calculate the Deviation for the Trailing Entry.', group = 'Entry')
devEntryPerc = input.float(defval = 1.0, title = 'Deviation %', minval = 0.01, maxval = 100, step = 0.05, tooltip = 'The step to follow the price when the open position condition is met.', group = 'Entry') / 100
devEntryAtrMul = input.float(defval = 0.5, title = 'Deviation ATR Mul', minval = 0.01, step = 0.05, tooltip = 'Multiplier to be used on the initial entrys` ATR to calculate the step for following the price, when the entry target is reached.', group = 'Entry')
ctrLongEntrySrc = input.source(defval = high, title = 'Long/Short Entry Control', inline = 'Control', group = 'Entry')
ctrShortEntrySrc = input.source(defval = low, title = '', tooltip = 'The price source to check with the entry target to trigger the entry order for Long/Short position.', inline = 'Control', group = 'Entry')

// LOGIC ============================================================================================================
var bool enterLongPosition = false

int barsSinceEnterLong = nz(ta.barssince(enterLongPosition), 999999)
bool openLongIsActive = barsSinceCloseLong >= barsSinceValidOpenLong
bool enterLongIsPending = barsSinceEnterLong >= barsSinceValidOpenLong
bool tryEnterLongPosition = longFiltersApproval and openLongIsActive and enterLongIsPending

getLongEntryPrice(baseSrc) =>
    switch devEntryMethod
        'PERC' => baseSrc * (1 + devEntryPerc)
        'ATR' => baseSrc + devEntryAtrMul * openAtr
        => na

float longEntryPrice = na
longEntryPrice := if validOpenLongPosition
    getLongEntryPrice(close)
else if tryEnterLongPosition
    math.min(getLongEntryPrice(low), nz(longEntryPrice[1], 999999))
else
    na

enterLongPosition := enableEntryTrailing ? longFiltersApproval and ta.crossover(openLongPosition ? close : ctrLongEntrySrc, longEntryPrice) : openLongPosition
bool validEnterLongPosition = enterLongPosition and not (strategy.position_size > 0)

var bool enterShortPosition = false

int barsSinceEnterShort = nz(ta.barssince(enterShortPosition), 999999)
bool openShortIsActive = barsSinceCloseShort >= barsSinceValidOpenShort
bool enterShortIsPending = barsSinceEnterShort >= barsSinceValidOpenShort
bool tryEnterShortPosition = shortFiltersApproval and openShortIsActive and enterShortIsPending

getShortEntryPrice(baseSrc) =>
    switch devEntryMethod
        'PERC' => baseSrc * (1 - devEntryPerc)
        'ATR' => baseSrc - devEntryAtrMul * openAtr
        => na
        
float shortEntryPrice = na
shortEntryPrice := if validOpenShortPosition
    getShortEntryPrice(close)
else if tryEnterShortPosition
    math.max(getShortEntryPrice(high), nz(shortEntryPrice[1]))
else
    na

enterShortPosition := enableEntryTrailing ? shortFiltersApproval and ta.crossunder(openShortPosition ? close : ctrShortEntrySrc, shortEntryPrice) : openShortPosition
bool validEnterShortPosition = enterShortPosition and not (strategy.position_size < 0)

// PLOT =============================================================================================================
var buyColor = color.new(color.green, 0)
plot(series = enableEntryTrailing ? longEntryPrice : na, title = 'Long Buy Price', color = buyColor, linewidth = 1, style = plot.style_linebr)
plot(series = enableEntryTrailing ? shortEntryPrice : na, title = 'Short Sell Price', color = buyColor, linewidth = 1, style = plot.style_linebr)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// EXIT ============================================================================================================

// INPUT ============================================================================================================
enableExitTrailing = input.bool(defval = false, title = 'Enable Trailing', tooltip = 'Enable or disable the trailing for exit position.', group = 'Exit')
devExitMethod = input.string(defval = 'PERC', title = 'Deviation Method', options = ['PERC', 'ATR'], tooltip = 'The method to calculate the Deviation for the Trailing Exit.', group = 'Exit')
devExitPerc = input.float(defval = 3.0, title = 'Deviation %', minval = 0.01, maxval = 100, step = 0.05, tooltip = 'The step to follow the price when the close position condition is met.', group = 'Exit') / 100
devExitAtrMul = input.float(defval = 0.5, title = 'Deviation ATR Mul', minval = 0.01, step = 0.05, tooltip = 'Multiplier to be used on the initial entrys` ATR to calculate the step for following the price, when the exit target is reached.', group = 'Exit')
ctrLongExitSrc = input.source(defval = low, title = 'Long/Short Exit Control', inline = 'Control', group = 'Exit')
ctrShortExitSrc = input.source(defval = high, title = '', tooltip = 'The price source to check with the entry target to trigger the entry order for Long/Short position.', inline = 'Control', group = 'Exit')

// LOGIC ============================================================================================================
var bool exitLongPosition = false

int barsSinceExitLong = nz(ta.barssince(exitLongPosition), 999999)
bool closeLongIsActive = barsSinceValidOpenLong >= barsSinceCloseLong
bool exitLongIsPending = barsSinceExitLong >= barsSinceCloseLong
bool tryExitLongPosition = isWithinPeriod() and closeLongIsActive and exitLongIsPending

getLongExitPrice(baseSrc) =>
    switch devExitMethod
        'PERC' => baseSrc * (1 - devExitPerc)
        'ATR' => baseSrc - devExitAtrMul * openAtr
        => na

float longExitPrice = na
longExitPrice := if validCloseLongPosition
    getLongExitPrice(close)
else if tryExitLongPosition
    math.max(getLongExitPrice(high), nz(longExitPrice[1], 999999))
else
    na

exitLongPosition := enableExitTrailing ? isWithinPeriod() and ta.crossunder(closeLongPosition ? close : ctrLongExitSrc, longExitPrice) : closeLongPosition

bool longIsActive = enterLongPosition or strategy.position_size > 0 and not exitLongPosition

var bool exitShortPosition = false

int barsSinceExitShort = nz(ta.barssince(exitShortPosition), 999999)
bool closeShortIsActive = barsSinceValidOpenShort >= barsSinceCloseShort
bool exitShortIsPending = barsSinceExitShort >= barsSinceCloseShort
bool tryExitShortPosition = isWithinPeriod() and closeShortIsActive and exitShortIsPending

getShortExitPrice(baseSrc) =>
    switch devExitMethod
        'PERC' => baseSrc * (1 + devExitPerc)
        'ATR' => baseSrc + devExitAtrMul * openAtr
        => na

float shortExitPrice = na
shortExitPrice := if validCloseShortPosition
    getShortExitPrice(close)
else if tryExitShortPosition
    math.min(getShortExitPrice(low), nz(shortExitPrice[1], 999999))
else
    na

exitShortPosition := enableExitTrailing ? isWithinPeriod() and ta.crossunder(closeShortPosition ? close : ctrShortExitSrc, shortExitPrice) : closeShortPosition

bool shortIsActive = enterShortPosition or strategy.position_size < 0 and not exitShortPosition

// PLOT =============================================================================================================
var sellColor = color.new(color.red, 0)
plot(series = enableExitTrailing ? longExitPrice : na, title = 'Long Sell Price', color = sellColor, linewidth = 1, style = plot.style_linebr)
plot(series = enableExitTrailing ? shortExitPrice : na, title = 'Short Sell Price', color = sellColor, linewidth = 1, style = plot.style_linebr)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// STOP LOSS ========================================================================================================

// INPUT ============================================================================================================
stopLossMethod = input.string(defval = 'PERC', title = 'Stop Loss Method', options = ['PERC', 'ATR'], tooltip = 'The method to calculate the Stop Loss (percentagewise, based on initial ATR or based on ATR changing over time).', group = 'Stop Loss - Target')
longTrailingStopLossPerc = input.float(defval = 7.5, title = 'Long/Short Stop Loss %', minval = 0.05, maxval = 100, step = 0.05, inline = 'Trailing Stop Loss Perc', group = 'Stop Loss - Target') / 100
shortTrailingStopLossPerc = input.float(defval = 7.5, title = '', minval = 0.05, maxval = 100, step = 0.05, tooltip = 'The percentage of the price decrease/increase to set the Stop Loss price target for long/short positions.', inline = 'Trailing Stop Loss Perc', group = 'Stop Loss - Target') / 100
longStopLossAtrMul = input.float(defval = 3.0, title = 'ATR Long/Short Mul ', minval = 0.1, step = 0.1, inline = 'Trailing Stop Loss ATR Multiplier', group = 'Stop Loss - Target')
shortStopLossAtrMul = input.float(defval = 3.0, title = '', minval = 0.1, step = 0.1, tooltip = 'ATR multiplier to be used for the long/short Stop Loss.', inline = 'Trailing Stop Loss ATR Multiplier', group = 'Stop Loss - Target')
enableStopLossTrailing = input.string(defval = 'TP', title = 'Enable Trailing', options = ['TP', 'ON', 'OFF'], tooltip = 'Enable the trailing for Stop Loss when Take Profit order is executed (TP) or from the start of the entry order (ON) or not at all (OFF).', group = 'Stop Loss - Trailing')
breakEvenEnabled = input.bool(defval = false, title = 'Break Even', tooltip = 'When Take Profit price target is hit, move the Stop Loss to the entry price (or to a more strict price defined by the Stop Loss %/ATR Multiplier).', group = 'Stop Loss - Trailing')

// LOGIC ============================================================================================================
getLongStopLossPrice(baseSrc) =>
    switch stopLossMethod
        'PERC' => baseSrc * (1 - longTrailingStopLossPerc)
        'ATR' => baseSrc - longStopLossAtrMul * openAtr
        => na

getLongStopLossPerc(baseSrc) =>
    (baseSrc - getLongStopLossPrice(baseSrc)) / baseSrc
    
// trailing starts when the take profit price is reached if 'TP' mode is set or from the very begining if 'ON' mode is selected
bool enableLongTakeProfitTrailing = enableStopLossTrailing == 'ON' or enableStopLossTrailing == 'TP' and longTrailingTakeProfitExecuted

// calculate trailing stop loss price when enter long position and peserve its value until the position closes
float longTrailingStopLossPrice = na
longTrailingStopLossPrice := if longIsActive
    if validEnterLongPosition
        getLongStopLossPrice(openPrice)
    else
        stopPrice = getLongStopLossPrice(enableLongTakeProfitTrailing ? high : openPrice)
        stopPrice := breakEvenEnabled and longTrailingTakeProfitExecuted ? math.max(stopPrice, openPrice) : stopPrice
        math.max(stopPrice, nz(longTrailingStopLossPrice[1]))
else
    na

getShortStopLossPrice(baseSrc) =>
    switch stopLossMethod
        'PERC' => baseSrc * (1 + shortTrailingStopLossPerc)
        'ATR' => baseSrc + shortStopLossAtrMul * openAtr
        => na

getShortStopLossPerc(baseSrc) =>
    (getShortStopLossPrice(baseSrc) - baseSrc) / baseSrc

// trailing starts when the take profit price is reached if 'TP' mode is set or from the very begining if 'ON' mode is selected
bool enableShortTakeProfitTrailing = enableStopLossTrailing == 'ON' or enableStopLossTrailing == 'TP' and shortTrailingTakeProfitExecuted

// calculate trailing stop loss price when enter short position and peserve its value until the position closes
float shortTrailingStopLossPrice = na
shortTrailingStopLossPrice := if shortIsActive
    if validEnterShortPosition
        getShortStopLossPrice(openPrice)
    else
        stopPrice = getShortStopLossPrice(enableShortTakeProfitTrailing ? low : openPrice)
        stopPrice := breakEvenEnabled and shortTrailingTakeProfitExecuted ? math.min(stopPrice, openPrice) : stopPrice
        math.min(stopPrice, nz(shortTrailingStopLossPrice[1], 999999.9))
else
    na

// PLOT =============================================================================================================
var stopLossColor = color.new(#e25141, 0)
plot(series = longTrailingStopLossPrice, title = 'Long Trail Stop', color = stopLossColor, linewidth = 1, style = plot.style_linebr, offset = 1)
plot(series = shortTrailingStopLossPrice, title = 'Short Trail Stop', color = stopLossColor, linewidth = 1, style = plot.style_linebr, offset = 1)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// TAKE PROFIT ======================================================================================================

// INPUT ============================================================================================================
takeProfitMethod = input.string(defval = 'PERC', title = 'Take Profit Method', options = ['PERC', 'ATR', 'RR'], tooltip = 'The method to calculate the Take Profit price.', group = 'Take Profit - Target')
longTakeProfitPerc = input.float(defval = 10.0, title = 'Long/Short Take Profit %', minval = 0.05, step = 0.05, inline = 'Take Profit Perc', group = 'Take Profit - Target') / 100
shortTakeProfitPerc = input.float(defval = 10.0, title = '', minval = 0.05, step = 0.05, tooltip = 'The percentage of the price increase/decrease to set the take profit price target for long/short positions.', inline = 'Take Profit Perc', group = 'Take Profit - Target') / 100
longTakeProfitAtrMul = input.float(defval = 9.0, title = 'ATR Long/Short Mul ', minval = 0.1, step = 0.1, inline = 'Take Profit ATR Multiplier', group = 'Take Profit - Target')
shortTakeProfitAtrMul = input.float(defval = 9.0, title = '', minval = 0.1, step = 0.1, tooltip = 'ATR multiplier to be used for the long/short Take Profit.', inline = 'Take Profit ATR Multiplier', group = 'Take Profit - Target')
longRiskRewardRatio = input.float(defval = 1.5, title = 'Long/Short RR Ratio ', minval = 0.1, step = 0.1, inline = 'Risk Reward Ratio', group = 'Take Profit - Target')
shortRiskRewardRatio = input.float(defval = 1.5, title = '', minval = 0.1, step = 0.1, tooltip = 'The Risk/Reward Ratio to be used for the long/short Take Profit based on the Stop Loss Price.', inline = 'Risk Reward Ratio', group = 'Take Profit - Target')

enableTakeProfitTrailing = input.bool(defval = true, title = 'Enable Trailing', tooltip = 'Enable or disable the trailing for take profit.', group = 'Take Profit - Trailing')
devTakeProfitMethod = input.string(defval = 'PERC', title = 'Deviation Method', options = ['PERC', 'ATR'], tooltip = 'The method to calculate the Deviation for the Trailing Take Profit.', group = 'Take Profit - Trailing')
devTakeProfitPerc = input.float(defval = 1.0, title = 'Deviation %', minval = 0.01, maxval = 100, step = 0.05, tooltip = 'The percentage wise step to be used for following the price, when the take profit target is reached.', group = 'Take Profit - Trailing') / 100
devTakeProfitAtrMul = input.float(defval = 1.0, title = 'Deviation ATR Mul', minval = 0.01, step = 0.05, tooltip = 'Multiplier to be used on the initial entrys` ATR to calculate the step for following the price, when the take profit target is reached.', group = 'Take Profit - Trailing')

// LOGIC ============================================================================================================
getLongTakeProfitPrice(baseSrc) =>
    switch takeProfitMethod
        'PERC' => baseSrc * (1 + longTakeProfitPerc)
        'ATR' => baseSrc + longTakeProfitAtrMul * openAtr
        'RR' => baseSrc + longRiskRewardRatio * (baseSrc - getLongStopLossPrice(baseSrc))
        => na

getLongTakeProfitPerc(baseSrc) =>
    (baseSrc - getLongTakeProfitPrice(baseSrc)) / baseSrc

// calculate take profit price when enter long position and peserve its value until the position closes
float longTakeProfitPrice = na
longTakeProfitPrice := if longIsActive and not longTrailingTakeProfitExecuted
    if validEnterLongPosition
        getLongTakeProfitPrice(openPrice)
    else
        nz(longTakeProfitPrice[1], getLongTakeProfitPrice(close))
else
    na

longTrailingTakeProfitExecuted := strategy.position_size > 0 and (longTrailingTakeProfitExecuted[1] or strategy.position_size < strategy.position_size[1] or strategy.position_size[1] == 0 and high >= longTakeProfitPrice)

longTrailingTakeProfitStepTicks = switch devTakeProfitMethod
    'PERC' => longTakeProfitPrice * devTakeProfitPerc / syminfo.mintick
    'ATR' => devTakeProfitAtrMul * openAtr / syminfo.mintick
    => na

getShortTakeProfitPrice(baseSrc) =>
    switch takeProfitMethod
        'PERC' => baseSrc * (1 - shortTakeProfitPerc)
        'ATR' => baseSrc - shortTakeProfitAtrMul * openAtr
        'RR' => baseSrc - shortRiskRewardRatio * (getShortStopLossPrice(baseSrc) - baseSrc)
        => na

getShortTakeProfitPerc(baseSrc) =>
    (getShortTakeProfitPrice(baseSrc) - baseSrc) / baseSrc

// calculate take profit price when enter short position and peserve its value until the position closes
float shortTakeProfitPrice = na
shortTakeProfitPrice := if shortIsActive and not shortTrailingTakeProfitExecuted
    if validEnterShortPosition
        getShortTakeProfitPrice(openPrice)
    else
        nz(shortTakeProfitPrice[1], getShortTakeProfitPrice(close))
else
    na

shortTrailingTakeProfitExecuted := strategy.position_size < 0 and (shortTrailingTakeProfitExecuted[1] or strategy.position_size > strategy.position_size[1] or strategy.position_size[1] == 0 and low <= shortTakeProfitPrice)

shortTrailingTakeProfitStepTicks = switch devTakeProfitMethod
    'PERC' => shortTakeProfitPrice * devTakeProfitPerc / syminfo.mintick
    'ATR' => devTakeProfitAtrMul * openAtr / syminfo.mintick
    => na

// PLOT =============================================================================================================
var takeProfitColor = color.new(#419388, 0) 
plot(series = longTakeProfitPrice, title = 'Long Take Profit', color = takeProfitColor, linewidth = 1, style = plot.style_linebr, offset = 1)
plot(series = shortTakeProfitPrice, title = 'Short Take Profit', color = takeProfitColor, linewidth = 1, style = plot.style_linebr, offset = 1)

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// QUANTITY MANAGEMENT ==============================================================================================

// INPUT ============================================================================================================
takeProfitQuantityPerc = input.float(defval = 50, title = 'Take Profit Quantity %', minval = 0.0, maxval = 100, step = 1.0, tooltip = 'The percentage of the position that will be withdrawn when the take profit price target is reached.', group = 'Quantity/Risk Management')

riskPerc = input.float(defval = 2, title = 'Capital at Risk %', minval = 1, tooltip = 'The maximum percentage of the equity to risk in every trade when no leverage is used.', group = "Quantity/Risk Management") / 100
minTrade = input.int(defval = 10, title = 'Minimum Trade Price', minval = 1, tooltip = 'The minimum trade price in Quote currency that is allowed in the exchange for a valid new position.', group = "Quantity/Risk Management")
longLeverage = input.int(defval = 1, title = 'Leverage Long/Short ', minval = 1, inline = 'Leverage', group = "Quantity/Risk Management")
shortLeverage = input.int(defval = 1, title = '', minval = 1, tooltip = 'Leverage factor used to multiply the initial risk quantity of each trade (by borrowing the remaining amount). Thus, the profits and losses are multiplied respectivelly.', inline = 'Leverage', group = "Quantity/Risk Management")

// LOGIC ============================================================================================================
var int quoteDecimalDigits = math.max(math.ceil(-1 * math.log10(syminfo.mintick * syminfo.pointvalue)), 0)

floor(number, precision) =>
    fact = math.pow(10,  precision)
    num = number * fact
    math.floor(num) / fact

ceil(number, precision) =>
    fact = math.pow(10,  precision)
    num = number * fact
    math.ceil(num) / fact
    
clamp(number, lower, highest, precision) =>
    ceil(math.max(floor(math.min(number, highest), precision), lower), precision)

getLongRiskQuoteQuantity() =>
    clamp(strategy.equity * riskPerc * longLeverage / getLongStopLossPerc(close), minTrade, strategy.equity * longLeverage, quoteDecimalDigits)
    
getLongRiskQuoteQuantityPerc() =>
    getLongRiskQuoteQuantity() / strategy.equity

getLongRiskBaseQuantity() =>
    getLongRiskQuoteQuantity() / close

float longEntryBaseQuantity = na
longEntryBaseQuantity := if longIsActive
    if validOpenLongPosition
        getLongRiskBaseQuantity()
    else
        nz(longEntryBaseQuantity[1], getLongRiskBaseQuantity())
else
    na

getShortRiskQuoteQuantity() =>
    clamp(strategy.equity * riskPerc * shortLeverage / getShortStopLossPerc(close), minTrade, strategy.equity * shortLeverage, quoteDecimalDigits)
    
getShortRiskQuoteQuantityPerc() =>
    getShortRiskQuoteQuantity() / strategy.equity

getShortRiskBaseQuantity() =>
    getShortRiskQuoteQuantity() / close

float shortEntryBaseQuantity = na
shortEntryBaseQuantity := if shortIsActive
    if validOpenShortPosition
        getShortRiskBaseQuantity()
    else
        nz(shortEntryBaseQuantity[1], getShortRiskBaseQuantity())
else
    na

// PLOT =============================================================================================================
label.new(x = validOpenLongPosition ? bar_index : na, y = na, text = 'Buy\n' + str.tostring(100 * getLongRiskQuoteQuantityPerc(), '#.##') + '%', yloc = yloc.belowbar, color = buyColor, style = label.style_label_up, textcolor = color.new(color.white, 0))
label.new(x = validOpenShortPosition ? bar_index : na, y = na, text = 'Sell\n' + str.tostring(100 * getShortRiskQuoteQuantityPerc(), '#.##') + '%', yloc = yloc.abovebar, color = sellColor, style = label.style_label_down, textcolor = color.new(color.white, 0))
label.new(x = validCloseShortPosition ? bar_index : na, y = na, text = 'Buy', yloc = yloc.belowbar, color = buyColor, style = label.style_label_up, textcolor = color.new(color.white, 0))
label.new(x = validCloseLongPosition ? bar_index : na, y = na, text = 'Sell', yloc = yloc.abovebar, color = sellColor, style = label.style_label_down, textcolor = color.new(color.white, 0))

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ALERT MESSAGES ===================================================================================================

// INPUT ============================================================================================================
msgOpenLong = input.string(defval = 'Long: Started', title = 'Open Long/Short', inline = 'Open Message', group = 'Alert Messages')
msgOpenShort = input.string(defval = 'Short: Started', title = '', tooltip = 'Alert messages emited when open long/short position.', inline = 'Open Message', group = 'Alert Messages')
msgCloseLong = input.string(defval = 'Long: Closed at market price', title = 'Close Long/Short', inline = 'Close Message', group = 'Alert Messages')
msgCloseShort = input.string(defval = 'Short: Closed at market price', title = '', tooltip = 'Alert messages emited when close long/short position.', inline = 'Close Message', group = 'Alert Messages')
msgTPSLLong = input.string(defval = 'Long: Take Profit or Stop Loss executed', title = 'TP/SL Long/Short', inline = 'TP/SL Message', group = 'Alert Messages')
msgTPSLShort = input.string(defval = 'Short: Take Profit or Stop Loss executed', title = '', tooltip = 'Alert message emited when the first quantity target (take profit or stop loss) for long/short position is hit.', inline = 'TP/SL Message', group = 'Alert Messages')
msgSLLong = input.string(defval = 'Long: Stop Loss executed', title = 'SL Long/Short ', inline = 'SL Message', group = 'Alert Messages')
msgSLShort = input.string(defval = 'Short: Stop Loss executed', title = '', tooltip = 'Alert message emited when the second quantity stop loss target for long/short position is hit.', inline = 'SL Message', group = 'Alert Messages')
msgMaxDrawdown= input.string(defval = 'Death is the new beginning', title = 'Max Drawdown', tooltip = 'Alert message emited when the max drawdown limit is hit.', group = 'Alert Messages')

//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// POSITION ORDERS ==================================================================================================

// INPUT ============================================================================================================
maxDrawdown = input.int(defval = 25, title = 'Max Drawdown %', minval = 1, maxval = 100, tooltip = 'The maximum drawdown to stop trading.', group = "Quantity/Risk Management")

highlighting = input.bool(defval = false, title = 'Show Position Highlighter', tooltip = 'Highlight winning/lossing position.', group = 'Plot')

// LOGIC ============================================================================================================
// close on trend reversal
strategy.close(id = 'Long Entry', when = exitLongPosition, comment = 'Close Long', alert_message = msgCloseLong)

// close on trend reversal
strategy.close(id = 'Short Entry', when = exitShortPosition, comment = 'Close Short', alert_message = msgCloseShort)

// getting into LONG position
strategy.entry(id = 'Long Entry', direction = strategy.long, qty = longEntryBaseQuantity, when = enterLongPosition, alert_message = msgOpenLong)
// submit exit order for trailing take profit price also set the stop loss for the take profit percentage in case that stop loss it reached first
strategy.exit(id = 'Long Take Profit / Stop Loss', from_entry = 'Long Entry', qty_percent = takeProfitQuantityPerc, limit = enableTakeProfitTrailing ? na : longTakeProfitPrice, stop = longTrailingStopLossPrice, trail_price = enableTakeProfitTrailing ? longTakeProfitPrice : na, trail_offset = enableTakeProfitTrailing ? longTrailingTakeProfitStepTicks : na, when = longIsActive, alert_message = msgTPSLLong)
// submit exit order for trailing stop loss price for the remaining percent of the quantity not reserved by the take profit order
strategy.exit(id = 'Long Stop Loss', from_entry = 'Long Entry', stop = longTrailingStopLossPrice, when = longIsActive, alert_message = msgSLLong)

// getting into SHORT position
strategy.entry(id = 'Short Entry', direction = strategy.short, qty = shortEntryBaseQuantity, when = enterShortPosition, alert_message = msgOpenShort)
// submit exit order for trailing take profit price also set the stop loss for the take profit percentage in case that stop loss it reached first
strategy.exit(id = 'Short Take Profit / Stop Loss', from_entry = 'Short Entry', qty_percent = takeProfitQuantityPerc, limit = enableTakeProfitTrailing ? na : shortTakeProfitPrice, stop = shortTrailingStopLossPrice, trail_price = enableTakeProfitTrailing ? shortTakeProfitPrice : na, trail_offset = enableTakeProfitTrailing ? shortTrailingTakeProfitStepTicks : na, when = shortIsActive, alert_message = msgTPSLShort)
// submit exit order for trailing stop loss price for the remaining percent of the quantity not reserved by the take profit order
strategy.exit(id = 'Short Stop Loss', from_entry = 'Short Entry', stop = shortTrailingStopLossPrice, when = shortIsActive, alert_message = msgSLShort)

// limit the maximum drawdown
// strategy.risk.max_drawdown(value = maxDrawdown, type = strategy.percent_of_equity, alert_message = msgMaxDrawdown)

// PLOT =============================================================================================================
lowHighPrice = high > strategy.position_avg_price and low < strategy.position_avg_price ? longIsActive ? high : shortIsActive ? low : na
             : high > strategy.position_avg_price ? high
             : low < strategy.position_avg_price ? low
             : na

pricePlot = plot(series = lowHighPrice, title = 'Price', color = na, linewidth = 1, style = plot.style_linebr)
var posColor = color.new(color.white, 0)
posPlot = plot(series = strategy.position_avg_price, title = 'Position', color = posColor, linewidth = 1, style = plot.style_linebr)

highlightColor = lowHighPrice > strategy.position_avg_price and longIsActive or lowHighPrice < strategy.position_avg_price and shortIsActive ? takeProfitColor
               : lowHighPrice < strategy.position_avg_price and longIsActive or lowHighPrice > strategy.position_avg_price and shortIsActive ? stopLossColor
               : na

fill(plot1 = posPlot, plot2 = pricePlot, color = highlighting ? color.new(highlightColor, 90) : na, title = 'Highlight trades')

// ==================================================================================================================

もっと