【アーカイブ】投資自動化のために鞘取りシステムをつくる
システム概要
端的に言うと投資を自動化するシステム。
鞘取りというのは複数の銘柄の動きの差で利ザヤを狙う手法で、例えば日経225指数に連動する銘柄とTOPIX指数に連動する銘柄に対して買いと売りを出しておいて、2つの銘柄の価格離れると儲かって、2つの銘柄の価格が近づくと損をするという形にする。
日経225指数とTOPIX指数はどちらも日本株の価格から作られる指数なので、極端に離れた動きはしないことが期待されている。
今回は指数に連動するETF商品での鞘取りを狙う。
対象とするのは、カブコムで手数料無料のETF。
※ 手数料が無料なだけで、信用取引にはほんの少しだけコストがかかります
手数料無料なので短期売買し放題。
開発手順
モデリング
脳内で済ますか、何かしらUMLみたいなので書き出すか、オレオレモデリングで済ますかは未定
出来れば全部ここに残したいので、オレオレモデリングにしちゃうかも
モデリング → コーディング を徹底したい
開発
新規注文
戦略管理
注文管理
約定確認
ポジション管理
返済注文
戦略管理
注文管理
どんなモデリングをするかを考える
シナリオを書いてそこからモデリングしていくのは変わらないけど、何を意識するかを先にはっきりさせておく。
かなり不純な動機であることは把握してるけど、ディレクトリ構成を変えたくないから構成に意味を持たせる。
ディレクトリ構成が先にあって、そこに明確な責務を持たせて何をモデル化するかを意識する。
とはいえ、Clean Architectureとかを意識して作ったディレクトリ構成やから、ある程度責務の分離をしやすい形にはなってるはず。
エンティティ: domain/entity
実体があったりなかったり
とりあえず一意に定まるものに使う = 固有名詞
固有名詞の反対は普通名詞
普通名詞がヒト、固有名詞がツチナガ(僕のこと
リポジトリ: domain/repository
永続化を責務としてる
永続化自体はrepositoryではなく、もっと外のinfraで行なう
interfaceで永続化に必要な関数の定義をして、実装はinfra、DIでドメイン層にいれる
つまりビジネスロジックの外側にあるものとのやり取りになる
利便性のために永続化と関係ないものをrepositoryに置くこともある
例えば現在時刻はサービスの中にあるとテストがしんどくなるから外に永続化されてる体にしたい
サービス: domain/service
エンティティの振る舞い
エンティティにはデータをやり取りするアクターもやり取りされるデータも入っているから、サービス間の依存は発生するかもやけどできるだけ発生させない
とにかく再利用可能なものにする
ユースケース: usecase
ドメイン層のやりくりで課題を解決するレイヤー
解決したい問題はここに出ることになる
システムの大まかな動きを書いた時の動きはここに表現されて、大まかな動きで書ききれない細かいのがサービスに出てくるはず
たぶん再利用しない
シナリオ
基本的に誰が何をどうするかというのを書く。
「誰が」とか「何を」は基本的に登場人物になって、entityになる。
ただ、システムの外側にあるものはentityにならないものもある。
「どうするか」についてはserviceになる。システムの外側に起こすアクションはrepositoryになる。
ある程度の「どうするか」の塊がユースケースになって、シナリオの文脈的な塊になる。
ってことで、以下シナリオ本文
ユーザは戦略を作ることができる。戦略にはエントリーの条件とエグジットの条件があって、それにしたがって新規の注文や決済の注文が行われるので、ユーザは各条件まで設定する必要がある。戦略にはエントリーとエグジットの条件以外にも、どの銘柄を売買するのかや、2つの銘柄の価格の差をどのように計算するのかなどが設定できる。
システムは登録された戦略に従ってエントリーを行なう。
鞘取りなので注文はセットで行なわれ、片方の注文は買い建て、もう片方の注文は売り建てとなる。
システムによってエントリーが行なわれた場合、定期的にエントリーの注文が約定しているかを確認し、約定していたら約定情報を永続化したうえで、ポジション情報を作成する。
保有中のポジションはエントリーした際の戦略で設定されているエグジットの条件によって決済注文が行われる。
買い建てのポジションは売りで決済注文をだし、売り建てのポジションは買いで決済注文をだす。
決済注文が約定すると、管理しているポジション情報の保有中の情報を更新する。
注文やポジションは証券会社が管理していいて、システムは証券会社に注文を出したり情報提供を依頼したりする。
売買は営業日の営業時間中にしか行なえない。
エントリーやエグジットの判断として、4本値を取得して行う。基本的には2つの銘柄の同じタイミングの終値を比較して使うことになる。
登場人物とできること
ユーザ: 利用者
できることはなし
サービスとしては戦略の追加や注文の確認ができるけど、バックエンドの開発ではUIが提供されないので何もできない
戦略: どういった条件で売買するかをまとめたもの
できることはなし
システムは戦略情報を見て売買の判断を行なう
注文: ポジションをとること。基本的に買い注文と売り注文は同時に行われる
できることはなし
どんな注文を行なうか、注文がどんな状態かを持っている
約定の情報や、状態の履歴も持つ
注文セット: 同時に行われる注文をセットにしたもの
できることはなし
買い注文と売り注文の情報を同時に持つ
他にもエントリー・エグジットや、いつ注文したのか、注文セットとしての状態を持っている
銘柄: 売買する商品。今回はETF
できることはなし
売買の対象で、銘柄ごとに呼び値や注文単位が違う。差の計算時には注文単位が重要になる
4本値: ある期間の最初の価格と最後の価格、一番高い価格と一番安い価格の4つ(始値、終値、高値、安値)をまとめたもの
できることはなし
約定: 注文が成立すること
できることはなし
ポジション: 売買した銘柄のうち、保有中の株式のこと。信用の場合は売り建てもある。建玉とも。
できることはなし
証券会社: 市場に注文を出したりしてくれる会社。一般的に個人は証券会社に口座を作り、その口座の金を使って売買を行う
市場に対して注文を出したり、市場の板の情報を見たりできる
またユーザの口座の管理も行っていて、口座から出される注文や保有しているポジションなどに関して管理している
システムは証券会社とのやり取りを行ない、システムと市場は直接は繋がらない
証券会社はシステムだったりユーザが管理できるものではない
口座: 証券口座。銀行の口座と同じ、お金を入れたり出したりすることができる。銀行との送金なども可能。注文はユーザではなく口座に紐づく
できることはない
ってことで、動作があるのはシステム、ユーザ、証券会社だけ。
それ以外はすべてデータ。
外からのインプット、外へのアウトプット以外はすべてシステムのユースケースで実現する。
ユースケースの中で再利用可能なものがサービスとしてドメインの中に出てくる。
シナリオと登場人物の書き出しまではいつもやってること。
この粒度のモデリングを作るだけなら負荷は小さいけど、実装に落とし込むのが難しい状態だと思う。
ドメイン理解が進んでればこれだけで十分実装できるんやとおもうけど。
https://gyazo.com/5485d71be5fe4ed3cb6517d40d48cdc8
動作の名前はとりあえずおいといて、どういった情報が行き来するかをまとめたのが上の絵
scrapboxのお絵描きでかいたけど、undoがないからついらいなー
この絵には描けてないけど、ユーザと証券会社の間での動作もあるけど、
それはシステムからすると関与しない範囲やから描いてない
これがシステムと外部とのお話の俯瞰図になるんかなー
あ、システムの中には、ソフトウェアとかDBとか通信とかそういうの全部入ってます。
余談やけど、ここでモデリングは何が必要なのかを考えをまとめてみた
ってことで、システムが行なうアウトプットからユースケースを遡りながらどんな動きをするかをまとめてみようと思う。
ここでいうアウトプットは、他の動作可能な登場人物に取ってのインプットを作ることであって、
動作の起点がシステムか他の登場人物かは関係ない。
ユースケース
上の絵で何かしらのやり取りをしている動作に名前を付けていく。
この名前をユースケースととりあえず呼ぶ。本来の意味とはちょっと違うかも。
ユーザが起点となる動作
戦略情報の登録 ※とりあえずはシステムに直接登録するためUIはなし
口座情報の登録 ※とりあえずはシステムに直接登録するためUIはなし
システムが起点となる動作
営業日情報の取得
銘柄情報の取得
4本値情報の取得
ユーザの注文の登録
ユーザの注文一覧の取得
ユーザの約定一覧の取得(≒ポジション一覧の取得)
システムが起点となる動作
なし
どんなデータがやり取りされるかはまだ分からんけど、とりあえずこんなことするんやなーってのがぼんやりと洗い出せたと思う。
あとは前提条件でも付け足しておこうかなー。
ユーザが起点となる動作
戦略情報の登録 ※とりあえずはシステムに直接登録するためUIはなし
口座情報の登録 ※とりあえずはシステムに直接登録するためUIはなし
システムが起点となる動作
営業日情報の取得
銘柄情報の取得
4本値情報の取得
ユーザの注文の登録
ユーザ起点の「戦略情報の登録」
ユーザ起点の「口座情報の登録」
ユーザの注文一覧の取得
ユーザ起点の「口座情報の登録」
ユーザの約定一覧の取得(≒ポジション一覧の取得)
ユーザ起点の「口座情報の登録」
システムが起点となる動作
なし
とりあえずシステムと外部との動作はこんな感じか。
あとは外部からは見えないシステム内部で完結する動作。
ここでは詳細まではみないで、大雑把な括りで出してしまう。
エントリー
営業日情報の取得
銘柄情報の取得
4本値情報の取得
ユーザの注文の登録
エグジット
営業日情報の取得
銘柄情報の取得
4本値情報の取得
ユーザの注文の登録
約定確認
ユーザの注文一覧の取得
ユーザの約定一覧の取得(≒ポジション一覧の取得)
この3つがこのシステムの持ってるユースケースになる!
UIがあったらControllerがあって、そっからどんなレスポンスを返したいのかでユースケースが増えるけど、
今はバックエンドだけを対象にしてるからUIがない。ってことで、ユースケースが少ない!!!
一応各ユースケースで外部と行なうことを書いた。
システム内部でどんな情報を持つのかが分からないからあんまり動くところがイメージできへんし、
毎回APIでとるんか?!みたいな気になるけど、そういうのは今のところ度外視。
ここまででユースケースと、証券会社リポジトリに必要な処理が出せたと思います。
と思ったけど、サービスとユーザの認証があるわ!!
でも今ここでだすことでもないか。この辺がモデリングよくわからんところ。
ユースケースの中身
ユースケースは出せたから、こっからユースケースの中身をみていこうと思うけど、
その前に各ユースケースに期待するものを出しておく。
エントリー
戦略からポジションを取るべき状態かを確認し、取るべき状態ならポジションを取るための注文を出す
エグジット
戦略からポジションを返済すべき状態かを確認し、返済すべき状態ならポジションを返済するための注文を出す
約定確認
未約定状態の注文が約定状態になっているかを確認し、約定状態になっていたら注文とポジションの状態を更新する
エントリーの約定なら手元にポジション情報を作成
エグジットの約定なら手元のポジション情報を更新
システムが一通り動いた後って手元に何も残らないんですよねー
注文出して、ポジション取って、返済して、手元空っぽ。って感じ。だから分かりにくいけど、
各ユースケースに期待されるお仕事がはっきりしているならそれを実装することに集中できると思う。
ってことで、お仕事を達成するための中身について考えていく。
にしても、こっからが難しいなーって感じる。ここまでは雰囲気で書けばいいからプレッシャーはないけど、
こっからは実装に影響が出るから雰囲気で書けばいいやが許されないからつらい。
いや、なんとか雰囲気で書いていいような作りにすればいいんか。
ってことで、お仕事が達成できたときから遡って中身を書いていってみる。
エントリー
エントリーのお仕事はポジションをとるための新規注文を出すこと。
売り建てもするので、信用売買を前提に、注文時にどんなデータが必要かを確認しておく。
認証のための口座情報
銘柄コード
市場
ETFが対象なので東証で固定
信用取引区分
制度、一般(長期)、一般(短期)
命令種別
エントリー固定
売買方向
買い、売り
注文有効期限
場中の成行注文しかしないので当日のみ
注文数量
執行条件
成行で固定
上記以外にも指定する必要のある項目はあるけど、重要でないので割愛
例えば注文価格とかもあるけど、成行注文しかしないのであれば関係ない
上記の各項目について、どこから情報を得るかをまとめる。
table:エントリー情報ソース
認証のための口座情報 ユーザが登録した口座情報
銘柄コード 戦略で指定された銘柄
信用取引区分 証券会社の銘柄情報に含まれている
売買方向 戦略で指定された方向。安い方を買うか、安い方を売るか
注文有効期限 当日の年月日
注文数量 戦略で指定された数と2つの銘柄取引単位から計算した数。
取引単位が同じならその等倍なので、戦略で指定された数 x 取引単位
市場 東証で固定
命令種別 エントリーで固定
執行条件 成行で固定
固定のものを下に集めて、上が変動するものにした。
データソースはシステムが保持してる口座情報と戦略情報。あと証券会社から得る銘柄情報。
少しまとめると、
エントリーでは口座情報と戦略情報をシステム内から取ってくる処理が必要で、証券会社から銘柄情報を取ってくる処理が必要。
口座情報では認証のために使うキーが必要
戦略では下記が必要
口座情報を特定するためのキー
売買する銘柄の銘柄コード
売買方向
注文数量
銘柄情報では下記が必要
銘柄コード
取引単位
信用取引区分
って感じ。
ちょっとデータのモデルとサービスが出来てきてる感じがする。
今回のシステムは鞘取りなので、2つの銘柄を同時に売買する必要がある。
ってことを考えると、エントリーは2つ同時に行なわれることになる。
ということは、戦略が持ってる情報が少し変わる。
戦略
口座情報を特定するためのキー
売買する銘柄の銘柄コード1
売買する銘柄の銘柄コード2
安い方の銘柄の売買方向(高い方の銘柄は反対方向の売買をする)
取引単位の多い方の注文数量
足の長さ(5分足や10分足など)
これでエントリーの注文を出すのに必要な情報がわかった。
やっばー。考えてること一個ずつ書いていくとめっちゃ書いてるのに全然進まへん。
注文を出すことはできそうなので、次に注文を出していいかの判断をする処理について考える。
大きく見れば戦略で指定されている方法で注文を出すべきかを判断することになるんやけど、戦略についてどんなものなのかが分からないとイメージがつかみにくいと思う。
ってことで、移動平均のゴールデンクロスでエントリーする戦略を例に進めてみる。
ゴールデンクロスはチャート上に描画された2本の線のうち、よく動く方の線があまり動かない方の線の下から上に抜けることをいう。
移動平均線はN日間の単純平均で考える。
移動平均のゴールデンクロスルール
よく動くほうの線(= 短期線)の期間
あまり動かない方の線(= 長期戦)の期間
データとしてはこんな感じ。
ということで、戦略をみて、判断のためのルールを取り出して、そのルールにしたがって判断するという流れになる。
戦略からエントリーのルールを取り出す
エントリーのルールにしたがって判断する
移動平均のゴールデンクロスの場合
2つの銘柄の4本値を取ってきて、その差を計算したうえで、短期と長期の期間分の移動平均値を作る
一番後ろ(直近)が短期<長期なら条件を満たさない
直近が短期>長期で、1本前が短期<長期なら条件を満たす
直近が短期>長期で、1本前が短期=長期ならもう1本前を見て判断する
もう1本前が短期<長期なら条件を満たす
判断の結果注文を出して良ければ注文を出す処理を行う
自然と2つの銘柄の差を計算してるけど、これは鞘取りシステムで、2つの銘柄の価格が離れていってるかを見るために差をつかってる
ここまでのことをまとめると。
口座情報
認証のために使うキーが必要
戦略
口座情報を特定するためのキー
売買する銘柄の銘柄コード
売買方向
注文数量
足の長さ(5分足や10分足など)
エントリールール
移動平均のゴールデンクロスの場合のルール詳細
短期の期間
長期の期間
銘柄情報
銘柄コード
取引単位
信用取引区分
あー、忘れてたけど、注文を出したなら出した注文の情報も手元に置いとかなあかんなー。
注文
どの口座で出された注文かを特定するためのキー
どの戦略で出された注文かを特定するためのキー
注文コード(証券会社が発行した注文を一意に特定するためのコード
銘柄コード
命令種別(エントリー or エグジット)
信用取引区分
売買方向
注文有効期限
注文数量
注文日時
基本的には証券会社に出したときの注文の情報と、他のデータと紐づけるための情報を持ってる。
んで、注文は2つセットで行なわれるから、
注文セット
買い注文
売り注文
ってなる。
この形にできるなら、2つの注文で共通の部分は注文セットに出してしまえる。
注文セット
どの口座で出された注文かを特定するためのキー
どの戦略で出された注文かを特定するためのキー
命令種別(エントリー or エグジット)
買い注文
注文コード(証券会社が発行した注文を一意に特定するためのコード
銘柄コード
信用取引区分
売買方向
注文有効期限
注文数量
注文日時
売り注文
注文コード(証券会社が発行した注文を一意に特定するためのコード
銘柄コード
信用取引区分
売買方向
注文有効期限
注文数量
注文日時
約定確認とかの話になってくると、注文の状態とかも管理しなあかんくなるけど、まだそこまで進んでないから一旦こんな感じで。
ここまで書いてて思ったけど、データをまとめる画面と処理をまとめる画面を用意して、両方に同時に書き込んでいかなつらいなー。
あとはどんな戦略をとってくるかと、いつエントリーが動くかをはっきりさせておく。
取引日でなければ何もせずに終了
取引時間内でなければ何もせずに終了
今の時間に確定する足で売買判断を行なう戦略の取得
これでエントリーの処理は流れるようになったんじゃないですかね
取引日でなければ何もせずに終了
取引時間内でなければ何もせずに終了
今の時間に確定する足で売買判断を行なう戦略の取得
戦略からエントリーのルールを取り出す
エントリーのルールにしたがって判断する
移動平均のゴールデンクロスの場合
2つの銘柄の4本値を取ってきて、その差を計算したうえで、短期と長期の期間分の移動平均値を作る
一番後ろ(直近)が短期<長期なら条件を満たさない
直近が短期>長期で、1本前が短期<長期なら条件を満たす
直近が短期>長期で、1本前が短期=長期ならもう1本前を見て判断する
もう1本前が短期<長期なら条件を満たす
判断の結果注文を出して良ければ注文を出す処理を行う
注文結果を保存
ここまで進めたけど、データモデリングから見直したい。
この記事はアーカイブしてしまって、書きなおそう。
更新履歴