【Pine】strategy.exitでトレイリングストップ【Trading View】 | Blog
私の書いたこちらの記事ではstrategy.exit
に標準搭載されているトレイリングストップ機能を試したが
内部ロジックに不具合があり正しい損益が計上されていないことが分かった。
そこで練習も兼ねて不具合を解消したトレイリングストップを自前で実装してみることとした。
簡単にロジックを解説する。
トレイリングストップとは何か...に関しては私の過去の記事を読むか自前で知っておく必要がある。
Pine Scriptのデフォルト戦略である「移動平均線のクロスによる売買」をベースにトレイリングストップを実装する。
※新規作成
> 空のストラテジースクリプト
と同じもの
おそらくトレイリングストップは現在進行中の足のhigh
, low
も加味しながらアクティブに利確ラインが上下するのが一般的だと思われるがTrading Viewのバックテストでは対象の足が内部でどのような動きをしたかを考慮できない(現在見ている足の中で価格がどのように上下したかが分からない)
そこで、一つ前の足を参考にして現在の足の利確ポイントを設定するロジックとする。
つまり現在の足がオープンした直後に利確する価格は指定済みというロジックだ。
まずエントリーがロングかショートかを判断。
「利益」となる方向に指定された価格動いた時点でトレイリングストップが発動。
例はロングなので、エントリーより高い価格にトリガーが現れる(ショートは逆)
今回はtrail_price
という変数で指定する。
トリガーとなる価格を超えた後trail_offset
に指定した価格押し戻されたら利確する。
このときexit
のstop
(逆指値)オプションで利確するのでバーの途中に決済ポイントが現れる。
この仕組の大枠は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安値ライン")
※設定でオンオフと価格を調整できる
トレイリングストップなし。
ビットコインFX(bitFlyer)
トレイリングストップあり
PFとSRが僅かに上昇
補足:スクリーンショット時にif(high >= trail_high_and_low)
の条件のイコールを設定しわすれていた。
こちらを書き換えたところPF,SRはもう少しよくなった
尚、ここをif(high > trail_high_and_low)
としてしまうと、ロング中high
を超えた足でexit
が発注されないため利確ラインが僅かに変化する。
トレイリングストップを入れれば必ず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。
このコードは一つ前の足を参考にクローズするので
【Pine】strategy.exitでトレイリングストップ【Trading View】
こちらで解説したexit
内部の不具合を回避できているはずだ。
これで(私が見落としているバグがなければ)正しいバックテスト結果が得られる。
パっと思いつくもので2つの課題が残っている
2020/07/31更新:
完全にTVのバージョンアップを失念していた。
以前はできなかったのだがストラテジから直接アラートが打てるようTV側内部のバージョンアップがされているので記事を打ち消した。
ただしalertcondition関数自体はstrategyの中で使えないのである程度自由度は制限されている。
ストラテジーアラートの詳細は次を参照
このコードはstrategy
のentry
, exit
, cancel
を利用している。
これをTrading Viewのアラートに変換してメールなどで知らせてくれるコードにするにはどうしたらいいだろうか。
はむとれ利用者はよく知っていると思うがstrategy
系のコードは直接アラートに設定できない。
さらに自前で擬似的なエントリーとクローズのコードを実装する必要がある。
特にexit
のstop
を使っている場合は「どこでstop
したのか」を正確に把握する必要があるため1段コーディングレベルがあがる。
こちらも時間があれば取り組んでみたいが、正直私も逆指値を含むコードのアラート化は慣れていないので頭が混乱する。
既存のストラテジに対して気軽にトレイリングストップを埋め込めるコード整理もやっておきたい。
ちょっと変数周りが複雑なのでじっくり考えればもうすこしなんとかなるかもしれない。
可能であればこの記事は続きを書いていきたい。
単純にエントリータイミングだけでなく「利確 / 損切り」にもロジックが存在し、色々研究しなければいけない。
投資の難しさは無限大である。