2020-06-28

【Pine】strategy.orderとstrategy.entryのオプション「oca_nameとoca_type」【Trading View】

オプション解説第三回目は「oca_name」「oca_type」について解説する。

Article Image

本日はoca

strategy.entrystrategy.orderのオプションに関する解説の第3回目である。

オプションは以下の中から

strategy.order(id, long, qty, limit, stop, oca_name, oca_type, comment, when)
  • oca_name
  • oca_type

に絞って解説していく

ocaって?

OCA(One-Cancels-All)注文というものがあるらしい。私はPine Script以外では使ったことがない。

OCA(One-Cancels-All)注文 | インタラクティブ・ブローカーズ証券株式会社

一つ約定すると他に出しておいた指値注文をキャンセルするグループを作る。

前準備

これまでの記事通りサンプルとしてわかりやすいようにバーに数字を与えている。

コードは次

bar_no = 0
if(bar_index > 21699)
    bar_no := bar_index - 21699
    l = label.new(bar_index,na,text=tostring(bar_no),color=color.blue, textcolor=color.white,style=label.style_labeldown,yloc=yloc.abovebar)

最初の数字は適当に私の方で調整しただけであり、各ユーザーは無視すること。

image-20200625214525219

こんな感じでラベルがつく。これは以前からやっているのでおなじみのコードである。

oca_nameoca_type

別々の注文一度グループにすると考えれば良い。

別々の注文なのでIDが違う注文だ。

まずocaを設定しない例として3つロングしてみる。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000)
    strategy.order("LONG 2", strategy.long,limit=1000000)
    strategy.order("LONG 3", strategy.long,limit=995000)

結果は

image-20200627134004779

3回約定するコードである。

次で解説するがoca_nameoca_typeはセットで使うと覚えておく。

タイプ:strategy.oca.cancel

さっそくocaを追加する。

  • oca_name"A"
  • oca_typestrategy.oca.cancel

にする。

コードは先程のorder3行にocaを追加。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, oca_name="A" ,oca_type=strategy.oca.cancel)
    strategy.order("LONG 2", strategy.long,limit=1000000, oca_name="A" ,oca_type=strategy.oca.cancel)
    strategy.order("LONG 3", strategy.long,limit=995000, oca_name="A" ,oca_type=strategy.oca.cancel)

すると...

image-20200627134339406

最初の一個目以外はの注文はキャンセルされた。

つまり?

oca_nameによって同じ名前がつけられたものを「グループ」として扱い

oca_typeによってそれらのグループに属する発注同士がどういう風に干渉するのかを指定する。

つまり初めにグループの一つが約定した時点で

oca_typeに設定されたstrategy.oca.cancelが発動し残りの指値はキャンセルされたわけだ。

これがcancel

strategy.oca.reduce

今度はreduceを見てみよう。基本的にはこの2つを覚えておけば良い。

これは発注の数量を抑えるコードで、発注数qtyとセットで使う。

次のコードを用意した。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)

1つ目の発注からqtyが順に1, 2, 5としてstrategy.oca.reduceしている。

さて、どうなる。

image-20200627135303106

分かる人には分かると思う。

左から順に実際の発注数が1, 1, 3となっている。

何が起こったのか。

最大発注数を定めている

設定は1, 2, 5。実際に発注されたのは1, 1, 3

これは「最大の発注数」を設定しているのである。

つまり始めは0ポジションからスタートで

  • 0ポジションからqty=1まで発注して良いので +1
  • 1の指値を持った状態からqty=2まで発注して良いので +1発注して合計が2(qtyの値)
  • 2の指値を持った状態でqty=5まで発注して良いので+3発注して合計が5(qtyの値)

ちょっと難しいが理解してしまえば単純だ。

実験:最後のqty=5qty=1にかえたらどうなる?

次のコードはどうだろうか。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 3", strategy.long,limit=995000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce) //ここのqtyを変えた

結果は

image-20200627135849879

最後の行はqty=1。この時点でポジションは2なので3番目のロングはキャンセルされた。

注意点としてはあくまでキャンセルであって、逆にショートしてポジションを削ってqtyに合わせるということはない。

いつ使う?

戦略の中でポジション管理を行うコードなので、私はここまで戦略を練ったことがないが

strategy.order関数を使っていてピラミッディングがロングとショートで可変数になる設計の場合の最大値を設定するには有用に思う。

例えばマーチンゲール投資法で初期ロットをダイアログで変更できるストラテジ等だろうか・・・他にアイデアが無くて申し訳ない。

reduceは一括発注がオススメ

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
    strategy.order("LONG 3", strategy.long,limit=995000, qty=3, oca_name="A" ,oca_type=strategy.oca.reduce)

想定内のロット数を維持したい場合はこのように一度に発注を出す時に使うこと。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 2)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 3)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)

この用に使うのはかなり詳しい理解が必要なのでおすすめしない。

ここが完璧なら最上級ストラテジストになるのではないかと思う。

一つだけ覚えておくとするならばstrategy.oca.reduce現在のポジションではなく、現在溜まっている「指値のロット数」に対して差し引きを行う物だ。

ここまで

ここまで理解できれば良い。

というかこのコードを使いこなしている人はいるのだろうか。

私は単にBLOGネタのためだけにやっている。

それでもやりたい人向け

一応説明する。

プログラミングオタクであれば挑戦してみてほしい。

バーを分けてreduceを発注するとポジションが難しくなる

このコードがなぜ難しいのか。

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 2)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 3)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)

あれ?違いがわからない。

結果を見てみよう。

image-20200627150042917

こういうことになる。よく見ると発注している数字が想定していたものと違う。

順を追って説明する。

さらに一行増やしてこうしてみよう

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 2)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 3)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 4)
    strategy.order("LONG 4", strategy.long,limit=992800,  qty=10, oca_name="A" ,oca_type=strategy.oca.reduce) //追加

最後に10ロットを追加した。

image-20200627151239668

最後が7になった。もうなにがなんだか。

最初に必要な理解

reduceは現在溜まっている指値注文(つまり未約定)の総ロットに対して差し引きされるという点を覚えておく。

もう一つ、指値発注は対象のバーのCLOSEが確定した時点で行われるということ。これは以前も解説した。

では、いってみよう。

1の足

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)

これは問題ない。普通に1ロットが指値で積まれる。

2の足

if (bar_no == 2)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)

image-20200627151632306

まず1の足で既に1の発注が出ている。

それから前述したとおり

strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.reduce)

この発注が発射されるのは2の足のCLOSEが確定した直後である。

ということは、2の足が確定した直後にこの発注が出る瞬間に「溜まっている指値のロット総数」はいくらだろうか。

0である。これは分かるだろうか。

バーの中で約定しているので、CLOSE時に溜まっている発注は0である。

もう一度言う。2の足の中で1の足で出した発注が解決されているので、指値発注は残っていない。

つまり2が確定した時点で出される発注は

qtyに設定されている2から0を引いて2である。

LONG 2というIDで2の指値が入った。

3の足

image-20200627151958908

3の足では溜まっていた指値は刺さらなかった。

3の足に仕掛けられた指値コードは

if (bar_no == 3)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)

溜まっている指値ロットは2であると述べた。

つまりここのcloseで発注される数量は

qtyに設定されている5 から 溜まっていた2 を引いて実際に指値に入るロットは3(IDはLONG 3) となる

4の足

コード

if (bar_no == 4)
    strategy.order("LONG 4", strategy.long,limit=992800,  qty=10, oca_name="A" ,oca_type=strategy.oca.reduce)

image-20200627152155995

まず、ここではLONG 2と書いてある指値が刺さった。つまり2の足で出した2ロットの指値だ。

さて、この足がcloseしようとしている。残っている指値はなんだろうか。

3の足で出した3のロットがまだ指値として残っている。

そしてこのcloseが処理された直後に4のオーダーが実行される。

ということは

qty10 から 溜まっている3 を引いて 7 のロットが発注される(IDはLONG 4)

6の足と9の足

ここまで理解できれば残りは新規エントリーがないので指値を解決するだけだ。

image-20200627152623026

6の足でLONG 3が解決された(3ロット)

9の足でLONG 4が解決された(7ロット)

おまけ:strategy.oca.none

ここまでやってさらにおまけもある。strategy.oca.none

if (bar_no == 1)
    strategy.order("LONG 1", strategy.long,limit=1030000, qty=1, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 2)
    strategy.order("LONG 2", strategy.long,limit=1000000, qty=2, oca_name="A" ,oca_type=strategy.oca.none) //ここをnoneにした!
if (bar_no == 3)
    strategy.order("LONG 3", strategy.long,limit=995000,  qty=5, oca_name="A" ,oca_type=strategy.oca.reduce)
if (bar_no == 4)
    strategy.order("LONG 4", strategy.long,limit=992800,  qty=10, oca_name="A" ,oca_type=strategy.oca.reduce)

これはreducecancelも受けない発注にするオプションだ。

このようにすると

image-20200627153959820

bar_no == 32の発注が溜まっていたにもかかわらず無視されてで5がそのまま発注された。

これも細かくやれば説明できるが...そこまでやっても需要がなさそうなのであとは任せる。

更にcancelも組み合わせ始めたらプログラマー側に異次元のIQが必要になるかもしれない。

サンプルストラテジ

さて、適当に書いたがこれでいいのかわからないが...

とりあえず作ってみた

指値ばらまきストラテジ。

//@version=4
strategy("マイストラテジー", overlay=true)
price_range = input(2000, step=1000)

if(strategy.openprofit == 0)
    strategy.order("long", strategy.long)

if(strategy.openprofit < 0)
    strategy.order("short1", strategy.short,limit=close + price_range*1, qty=abs(strategy.position_size * 2), oca_name="S_group", oca_type=strategy.oca.reduce)
    strategy.order("short2", strategy.short,limit=close + price_range*2, qty=abs(strategy.position_size * 2 * 2), oca_name="S_group", oca_type=strategy.oca.reduce)
    strategy.order("short3", strategy.short,limit=close + price_range*3, qty=abs(strategy.position_size * 2 * 2 * 2), oca_name="S_group", oca_type=strategy.oca.reduce)
    strategy.order("short4", strategy.short,limit=close + price_range*4, qty=abs(strategy.position_size * 2 * 2 * 2 * 2), oca_name="S_group", oca_type=strategy.oca.reduce)
    
    strategy.order("long1", strategy.long, limit=close - price_range*1, qty=abs(strategy.position_size * 2), oca_name="L_group", oca_type=strategy.oca.reduce)
    strategy.order("long2", strategy.long, limit=close - price_range*2, qty=abs(strategy.position_size * 2 * 2), oca_name="L_group", oca_type=strategy.oca.reduce)
    strategy.order("long3", strategy.long, limit=close - price_range*3, qty=abs(strategy.position_size * 2 * 2 * 2), oca_name="L_group", oca_type=strategy.oca.reduce)
    strategy.order("long4", strategy.long, limit=close - price_range*4, qty=abs(strategy.position_size * 2 * 2 * 2 * 2), oca_name="L_group", oca_type=strategy.oca.reduce)

if(strategy.openprofit > 1)
    strategy.close_all()

1分足

image-20200627162702674

負けてる間は永遠に指値をばらまき続けるストラテジなので実際にこの通りにトレードしないように。

さいごに

reduceを使って実際にどれだけエントリーされるかを追いかけていくと結構難しい。

とはいったものの、実際にエントリーされるポジションを目視で追いかけると難しいだけで

単純に「溜まってる指値の注文量をキャップする」という意味では簡単なのかもしれない。

私は使いこなせていないが、きっと使いこなしている人もいるんだろう。



この記事をシェア


謎の技術研究部 (謎技研)