【Pine】自前コードでトレイリングストップ

July 25, 2020

strategy.exitに実装されているトレイリングストップは不具合があるため自前でトレイリングストップを実装してみた。

zimae_trail

トレイリングストップを実装したい

【Pine】strategy.exitでトレイリングストップ【Trading View】 | Blog

私の書いたこちらの記事ではstrategy.exitに標準搭載されているトレイリングストップ機能を試したが

内部ロジックに不具合があり正しい損益が計上されていないことが分かった。

そこで練習も兼ねて不具合を解消したトレイリングストップを自前で実装してみることとした。

ロジック

簡単にロジックを解説する。

トレイリングストップとは何か...に関しては私の過去の記事を読むか自前で知っておく必要がある。

メインのエントリーロジック

Pine Scriptのデフォルト戦略である「移動平均線のクロスによる売買」をベースにトレイリングストップを実装する。

新規作成空のストラテジースクリプトと同じもの

実装できるトレイリングストップの限界精度

おそらくトレイリングストップは現在進行中の足high, lowも加味しながらアクティブに利確ラインが上下するのが一般的だと思われるがTrading Viewのバックテストでは対象の足が内部でどのような動きをしたかを考慮できない(現在見ている足の中で価格がどのように上下したかが分からない)

そこで、一つ前の足を参考にして現在の足の利確ポイントを設定するロジックとする。

つまり現在の足がオープンした直後に利確する価格は指定済みというロジックだ。

1.トリガーとなる価格を超えたか

まずエントリーがロングかショートかを判断。

「利益」となる方向に指定された価格動いた時点でトレイリングストップが発動。

例はロングなので、エントリーより高い価格にトリガーが現れる(ショートは逆)

今回はtrail_priceという変数で指定する。

image-20200725173550093

2.不利な方向へ反発した価格で利確

トリガーとなる価格を超えた後trail_offsetに指定した価格押し戻されたら利確する。

このときexitstop(逆指値)オプションで利確するのでバーの途中に決済ポイントが現れる。

image-20200725181042644

大枠はexitのトレイリングストップに同じ

この仕組の大枠はstrategy.exitに付属しているトレイリングストップと同じロジックである。

違うのは現在の足を利確判定に使うか使わないかの違い(私のロジックは「使わない」)

コード

//@version=4
strategy("移動平均線クロス売買のトレイリングストップ例", overlay=true)

//ユーザー入力変数
var isTrail = input(true, title="ON/OFF")
var trail_price = input(28000, title="Trail Price")
var trail_offset = input(20000, title="Trail Offset")

//内部変数
var float trigger_price = 0 //トレイリングストップが発動する価格
var position = 0 //現在のポジション | 1:ロング | -1:ショート |0:ノーポジのつもりだが未使用
var float entry_price = 0 //エントリーした価格
var float trail_high_and_low = 0 //トレイリングトップ発動中の高値or安値
var float trail_take_profit_line = 0 //利確ライン
var c = color.gray //プロット用の色 | 赤:ショート利確ライン | 青:ロング利確ライン | 灰:無効

//エントリー条件
longCondition = crossover(sma(close, 14), sma(close, 28))
shortCondition = crossunder(sma(close, 14), sma(close, 28))

//メインエントリー
if (longCondition and position != 1)
    strategy.entry("long", strategy.long)
    position := 1
    entry_price := close
    trail_high_and_low := high
    c := color.gray
    strategy.cancel("Trailing Stop(Long Close)")
    
else if (shortCondition and position != -1)
    strategy.entry("short", strategy.short)
    position := -1
    entry_price := close
    trail_high_and_low := low
    c := color.gray
    strategy.cancel("Trailing Stop(Short Close)")

//トレイリングストップ
if(position == 1) //ロング中
    trigger_price := entry_price + trail_price
    if(high > trigger_price)
        c := color.blue
        if(high >= trail_high_and_low)
            trail_high_and_low := high
            trail_take_profit_line := trail_high_and_low - trail_offset
            if(isTrail)
                strategy.exit("Trailing Stop(Long Close)","long",stop=trail_take_profit_line)
            else
                strategy.cancel_all()
        
else if(position == -1) //ショート中
    trigger_price := entry_price - trail_price
    if(low <= trigger_price)
        c := color.red
        if(low < trail_high_and_low)
            trail_high_and_low := low
            trail_take_profit_line := trail_high_and_low + trail_offset
            if(isTrail)
                strategy.exit("Trailing Stop(Short Close)","short",stop=trail_take_profit_line)
            else
                strategy.cancel_all()

//プロット
plot(trail_take_profit_line, style=plot.style_cross, color=c, title="利確ライン")

//参考用プロット
//plot(trigger_price,style=plot.style_stepline,color=c,title="トリガー価格")
//plot(trail_high_and_low, style=plot.style_stepline, color=color.yellow,title="トレイル発動中の高値or安値ライン")
    

実行結果

image-20200725181447890

※設定でオンオフと価格を調整できる

トレイリングストップなし。

ビットコインFX(bitFlyer)

image-20200725181402547

image-20200725181609128

トレイリングストップあり

image-20200725181509746

image-20200725181553387

PFとSRが僅かに上昇

補足:スクリーンショット時にif(high >= trail_high_and_low)の条件のイコールを設定しわすれていた。

こちらを書き換えたところPF,SRはもう少しよくなった

image-20200725184924742

尚、ここをif(high > trail_high_and_low)

としてしまうと、ロング中highを超えた足でexitが発注されないため利確ラインが僅かに変化する。

トレイリングストップは万能ではない

image-20200725190345631

トレイリングストップを入れれば必ずPF,SRが上昇するわけではない。

ビットフライヤーのチャートに当てはめた場合1h足では調子が良いがそれ以外の足では

ほぼ全て「逆に成績が悪くなる」という結果となる。

この結果からビットコインは利益を早急に確定せず、持ち越していったほうが基本的には儲かるという性質が窺える。

余談:トレイリングストップと関係ないが私の経験上「とりあえず絶対値で損切りラインを設定」すると損失が膨らむ傾向がある。損切りをするならもっと複雑な線引きが必要。

BTCの場合、基本的に損切りはしないほうがトータルでは儲かる結果となっているのでトレイリングストップも同様のことが言えるかもしれない。

コード解説

重要なポイントだけ解説する

トレイリングストップ用の決済コード

strategy.exit("Trailing Stop(Long Close)","long",stop=trail_take_profit_line)

strategy.exitのstopオプションは「逆指値」を意味する。不利な方向で決済。ロングであれば価格がさがったら決済だ。

つまり一度上昇した価格が、利確ラインまでさがってきてしまった(不利な方向へ移動した)時に決済。

全て過去に解説しているが

第一引数"Trailing Stop(Long Close)"はexit注文自体のID

第2引数"long"は決済対象となるエントリーのIDである。

メインエントリー中にトレイリングストップをcancel

メインのエントリー内にある次のコード

strategy.cancel("Trailing Stop(Long Close)")

なぜこれが必要?と疑問になるだろう。

これがないとトレイリングストップで利確が走ったあとも逆指値が残ってしまい

ドテンが発動したときの価格によってはドテン後即クローズというバグが発生するからである。

cancelの第一引数はキャンセルする対象のID。

exitの不具合回避について

このコードは一つ前の足を参考にクローズするので

【Pine】strategy.exitでトレイリングストップ【Trading View】 | Blog

こちらで解説したexit内部の不具合を回避できているはずだ。

これで(私が見落としているバグがなければ)正しいバックテスト結果が得られる。

今後の課題

image-20200725190510034

パっと思いつくもので2つの課題が残っている

アラートにするには

2020/07/31更新:

完全にTVのバージョンアップを失念していた。

以前はできなかったのだがストラテジから直接アラートが打てるようTV側内部のバージョンアップがされているので記事を打ち消した。

ただしalertcondition関数自体はstrategyの中で使えないのである程度自由度は制限されている。

ストラテジーアラートの詳細は次を参照

Strategy Alerts — TradingView

このコードはstrategyentry, exit, cancelを利用している。

これをTrading Viewのアラートに変換してメールなどで知らせてくれるコードにするにはどうしたらいいだろうか。

はむとれ利用者はよく知っていると思うがstrategy系のコードは直接アラートに設定できない。

さらに自前で擬似的なエントリーとクローズのコードを実装する必要がある。

特にexitstopを使っている場合は「どこでstopしたのか」を正確に把握する必要があるため1段コーディングレベルがあがる。

こちらも時間があれば取り組んでみたいが、正直私も逆指値を含むコードのアラート化は慣れていないので頭が混乱する。

汎用化するには

既存のストラテジに対して気軽にトレイリングストップを埋め込めるコード整理もやっておきたい。

ちょっと変数周りが複雑なのでじっくり考えればもうすこしなんとかなるかもしれない。

さいごに

可能であればこの記事は続きを書いていきたい。

単純にエントリータイミングだけでなく「利確 / 損切り」にもロジックが存在し、色々研究しなければいけない。

投資の難しさは無限大である。

この記事をシェア:

author icon

仮想トイレ @CrypticToilet
プログラミングや仮想通貨のシステムトレードに関する情報を更新中!どんな情報を流しても詰まらないトイレ。