OANDA(つーかFIX API)で自動売買プログラム作成が大変
前回↓から約1年(!)、とりあえずFIX APIでレート取得が出来ました。
いやー、牛歩もいいところですね。
まぁ、実際のとろこはほとんど放置状態だったんですが。
たまにOANDAのドキュメント読んでFIX APIわかんねーって悶ていただけ…
しかし!
さるGWに一念発起しまして、OANDAのFIX APIを使っての自動売買プログラム作成を再開しました!
GWなら取引時間内での検証も出来ますしね。
これ結構重要で、放置の理由にFIX APIわからんということもあったのですが、むしろFXは平日しかレートが動いていないということの方が放置の原因だったり。
株も同じですが平日しか取引していないのはやっぱりやりづらいですね。
まぁ、株は平日の日中のみに対して、FXは平日であれば24時間取引しているので気合があればなんとかなるんですが…
僕にはその気合は無かった…
それはさておき、GWにわりとガッツリ取り組んでから約二ヶ月、とりあえずレート取得のみですが一週間連続で安定稼動させることが出来ました。
前回同様、なかなか分かりづらい点が有ったので、そのことも含めてやったことを書き残そうかと思います。
先に作った物の概要。
# 実行例 $ java -jar \ -Dpassword=$PASS \ -Daccount=$ACCOUNT \ -Dsymbols=USD/JPY,EUR/JPY \ fix-prototype-1.5-SNAPSHOT.jar
- 標準出力にレート
USD/JPY Mon May 29 09:22:23 JST 2017 111.239 0.008 USD/JPY Mon May 29 09:22:23 JST 2017 111.24 0.008 EUR/JPY Mon May 29 09:22:23 JST 2017 124.264 0.013 USD/JPY Mon May 29 09:22:23 JST 2017 111.242 0.008 USD/JPY Mon May 29 09:22:23 JST 2017 111.242 0.008
- 標準エラー出力にアプリケーションログ
6 12, 2017 4:55:02 午前 com.example.FixApplication onMessage 重大: Notes on market data entry: Halted 6 13, 2017 9:32:02 午前 quickfix.Session disconnect 情報: [FIX.4.4:hogehoge->OANDA/RATES:testusr1-Session1] Disconnecting: Encountered END_OF_STREAM 6 13, 2017 9:32:03 午前 quickfix.mina.initiator.IoSessionInitiator$ConnectTask resetIoConnector 情報: [FIX.4.4:hogehoge->OANDA/RATES:testusr1-Session1] - reset IoConnector
以上。
ではでは、以下について記していこうと思います。
- OANDAサンプル付属のcfg
- DataDictionary
- StartTimeとEndTime
- その他
- Tips
- JMX
- FileLogPath
- cfgのシステムProperty展開機能
OANDAサンプル付属のcfg
OANDAにFIX APIの設定をしてもらう際、サンプルのJavaアプリケーションを貰えます。
そのサンプルには、FIXにおける設定ファイルに相当するcfgファイルが含まれており、そのcfgファイルに自身のアカウントとパスワードを記述することによってサンプルJavaアプリケーションを動作させることができます。
(詳細は前回記事を参照)
このcfgを自作のFIXアプリケーションでそのまま利用するとハマります…
UseDataDictionary
OANDAのサンプルFIXアプリケーション付属のcfgではUseDataDictionary=N
が指定されています。
にも関わらず、DataDictionary=FIX42.xml
が指定されています。
UseDataDictionary=N
だと意味がないはずなんですが…
それはさておき、QuickFIX/Jのドキュメントを読む感じではこの指定方法だとrepeating groupsが作用せずにうまく値が取得できないはずです。
実際、自分が作成したFIXアプリケーションではこの指定方法でrepeating groupsがうまく作用せずに値が取れない状況になり、随分とハマりました。
具体的にどうなるかというと、例えば↓のFIXメッセージはとある時点でのUSD/JPYのbitとofferですが、
8=FIX.4.4 9=211 35=W 34=4 49=OANDA 50=RATES 52=20170620-09:09:19.900 56=account-id 55=USD/JPY 262=1497949759660 268=2 269=0 270=111.612 271=3000000 272=20170620 273=09:09:17 269=1 270=111.62 271=3000000 272=20170620 273=09:09:17 10=165 (読みやすいように整形)
repeating groupsが効いていない状態では、bitの値しか取れません…
だがしかし、OANDAのサンプルFIXアプリケーションはうまく動作しているようです。
OANDAサンプルもQuickFIX/Jを使っているっぽいのですが…
謎です…
/(^o^)\
それはさておき、UseDataDictionary=Y
にしなければならないということはわかったのですが、
DataDictionaryどこでゲットすんの?
ってなります。
これはわりとすぐに解決してQuickFIX/Jのリポジトリを漁ったら発見しました。
後は簡単。
src/main/resources/
に発見したDataDictionaryファイル(FIX44.xml
)を置いておけばmaven-resources-plugin
がbuild時に良しなにやってくれます。
これでrepeating groupsが作用して、先ほどの例でのbitしか取れない問題が解決してbitとofferの値がきちんと取れるようになります。
めでたしめでたし。
と思いきや、続きがあります。
ふと、OANDAのサンプルFIXアプリケーションはどうなっているんだろう、と思い立って漁ってみたらquickfixj-all-1.4.0-oanda.jar
なる意味深なjarを読み込んで実行していることを発見。
jarの中身を見てみると、ありましたFIX44.xml
。
QuickFIX/Jリポジトリにあるものと比べてみると結構diffがあり、ざっと見た感じquickfixj-all-1.4.0-oanda.jar
にあったDataDictionaryのほうが良さそうだったのでこっちを使うことにしました。
我ながらよく気がついたなぁと思います(ドヤァァ
めでたしめでたし。
余談ですが、OANDAのサンプルFIXアプリケーションはやっぱりツッコミどころ満載だと思います。
実行可能jarが配置されているにもかかわらず、その中身らしきclassファイルが別途、置かれています。
何のために?
StartTimeとEndTime
自作のFIXアプリケーションを何日か連続稼働していると、必ず1日1回、決まった時間にセッションを貼り直している(再起動している)ログに気が付きました。
なんでだろなーっと思ってドキュメントを調べているとOANDAサンプルのcfgの指定方法だとdailyなアプリケーションの設定になっていることがわかりました。
その設定値が表題のStartTimeとEndTimeです。
この2つの設定のみだとアプリケーションはdailyでセッションを貼り直します。
歴史的経緯でしょうか。
少なくとも現在のOANDAは月曜朝のオープンから土曜朝のクローズまでダウンタイム無しで稼働しているようなのでweeklyの設定に変更しました。
これは簡単でStartDayとEndDayを追加して何曜日の何時オープンで何曜日の何時にクローズかを指定するだけです。
具体的には↓な感じ。
StartDay=sun StartTime=19:55:00 EndDay=fri EndTime=21:05:00
念のため、ゆとりを持たせて5分ずつ前後に挟んでいます。
が、運用実績的に1分もいらないかなぁという感想です。
めでたしめでたし。
その他
FIXプロトコルにもVersionがいくつかあるようで、OANDAのサンプルFIXアプリケーションでは4.2が指定されていたのですが、ドキュメントを読む限り4.4の方が勝手が良さそうなので4.4に変更しました。
ちなみに、前述の通り、OANDAのサンプルFIXアプリケーションには4.4のDataDictionaryが含まれています。
なして4.2指定なの…
Tips
いやー、いろいろとハマったのは辛かったんですが、そのかいあってか調べている過程でいろいろな機能を発見できました。
その中から使えるなーと思った機能は自作のFIXアプリケーションに取り込んでいます。
せっかくなので、それらを紹介しようと思います。
JMX
Javaあるあるのアレです。JConsoleとかでつなぐ奴。
これを有効化するといろいろと便利になる奴です。(問われる語彙力w
QuickFIX/JがJmxExporter
クラスを用意してくれているので有効化はとっても簡単。
new JmxExporter().register(initiator);
これだけ。
そーすると何が嬉しいかというと、いろいろとあるんですが、おおきく以下の2つがあります。
- (ヒープの利用状況などの)メトリクスの可視化
- ログレベルの動的変更
それぞれについて記載します。
メトリクスの可視化
24時間365日とまでいかなくても、5日間連続稼動させると気になることがあります。
JMX + JConsoleを使うと簡単にメトリクスを見れるので便利です。
5日間連続稼動を何回か繰り返し運用してみた感じだと大体↓な傾向が見れました。
ヒープ使用率やGCの時間などを監視&通知までできるとベストですが、ただでさえ牛歩なのでいったんはこれで満足としましょう(諦め大事
ただ、0.5秒のGCはなんとかしたいなぁ…
G1GCとか検証したいとは思います。
ログレベルの動的変更
アプリケーション起動時のログレベルはinfoです。
つーかロギングの設定を何もしていないのでデフォルトの動作なんですがw
まぁ、それはゆくゆくやるとして、 JConsoleを使うとアプリケーション起動後、つまり動作中に動的にログレベルを変更できます。
やり方は簡単で、JConsleのMBeansタブ→左のBeans一覧からjava.util.logging
→Logging→Operations→setLoggerLevel(p1,p2)
のp1にクラス名(例:com.example.FixApplication
)、p2にログレベルを入れて実行するだけ。
ちなみにですが、QuickFIX/J関連も同様の手順でいろいろできます。
リセットとかHeartBeat送信とか。
FileLogPath
cfgの設定にFileLogPathという項目があります。
こいつにパスを指定するだけでイベントと送受信FIXメッセージを指定したパスにロギングしてくれます。
例えば、↓をcfgに記述すると、
[LOGGING] FileLogPath=log/
↓なログファイルが生成されます。
$ tail -n5 log/FIX.4.4-hoge0011-OANDA_RATES-testusr2-Session1.event.log 20170625-09:20:25: Session FIX.4.4:hoge0011->OANDA/RATES:testusr2-Session1 schedule is daily, 00:00:00-UTC - 00:00:00-UTC 20170625-09:20:25: Created session: FIX.4.4:hoge0011->OANDA/RATES:testusr2-Session1 20170625-09:20:27: Initiated logon request 20170625-09:20:28: Logon contains ResetSeqNumFlag=Y, resetting sequence numbers to 1 20170625-09:20:28: Received logon
$ tail -n5 log/FIX.4.4-hoge0011-OANDA_RATES-testusr2-Session1.messages.log | tr "^A" " " 8=FIX.4.4 9=421 35=B 34=2 49=OANDA 50=RATES 52=20170625-09:20:28.497 56=hoge0011 33=4 58=version: 2.4.21 (fxTrade rates server 03 [3,130] 1498382428 163.49.210.211) 58=notice: Market Data Request now supports new MarketDepth and MDUpdateType settings 58=notice: halted pairs are now marked QuoteCondition=B Text=Halted 58=notice: please include the complete server version string in all support requests 148=OANDA FIX Server Information 10=213 8=FIX.4.4 9=158 35=V 34=2 49=hoge0011 52=20170625-09:20:28.553 56=OANDA 57=RATES 262=1498382428547 263=1 264=1 265=1 146=3 55=USD/JPY 55=EUR/JPY 55=EUR/USD 267=2 269=0 269=1 10=206 8=FIX.4.4 9=243 35=W 34=3 49=OANDA 50=RATES 52=20170625-09:20:28.801 56=hoge0011 55=USD/JPY 262=1498382428547 268=2 269=0 270=111.258 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 269=1 270=111.34 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 10=231 8=FIX.4.4 9=244 35=W 34=4 49=OANDA 50=RATES 52=20170625-09:20:28.801 56=hoge0011 55=EUR/USD 262=1498382428547 268=2 269=0 270=1.11922 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 269=1 270=1.11953 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 10=026 8=FIX.4.4 9=244 35=W 34=5 49=OANDA 50=RATES 52=20170625-09:20:28.801 56=hoge0011 55=EUR/JPY 262=1498382428547 268=2 269=0 270=124.515 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 269=1 270=124.606 271=3000000 272=20170623 273=20:59:59 276=B 58=Halted 10=035
とくにmessages.log
はAcceptanceテスト用の入力データ(↓な感じらしい)に使えそうです。
I8=FIX.4.2␁35=A␁34=1␁49=TW␁52=<time>␁56=ISLD␁98=0␁108=30␁ E8=FIX.4.2␁9=57␁35=A␁34=1␁49=ISLD␁52=00000000-00:00:00␁56=TW␁98=0␁108=30␁10=0␁
ただし、全てのFIXメッセージをロギングするのでディスクを大量消費する点と、ログインパスワードもロギングされちゃうので扱いに注意です><
cfgのシステムProperty展開機能
cfgに↓のように記述するとJavaのシステムPropertyを展開することができます。
SenderCompID=${account}
# アカウントIDをhoge0011にして実行 $ java -jar -Daccount=hoge0011 fix-prototype-1.5-SNAPSHOT.jar
これ、とっても便利です。
なのにドキュメントに書いていないですorz
QuickFIX/Jのコード読んでいて違和感を感じて、デバッガでステップ実行してやっと気が付きました。
ドキュメントェ
これまた、我ながらよく気がついたなぁと思います(ドヤァァ
まとめ
ふぅ。疲れた。
FIXつらたん。
編集後記
上記以外にもMarketDataRequestでの値の取得方法がいまいちわからずGithubを検索したりと牛歩要因がほんとに多いなと思いました。
果たして完成する日は来るのか…
自動売買の道のりは長いンゴねぇ…
今後、特にやりたいことリストです。
- Acceptance(受け入れ)テストの導入
- 単体テストもまだですが…
- これができると取引時間外の土日での開発が捗る(はず)
- order(売買)実装
- 何をトリガーとして売買するかが悩みどころ
- とりあえず、単純に移動平均線に触れたことをトリガーにする
ちなみにですが、OANDAのルールがわりと大きく変更されています。
FIX使うにはプロコース必須になって、スプレッドが0.8銭になったり。