無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

OANDA fx Trade API を使って、リアルタイムな為替レートを取得してみる

今さらですが、OANDA Japan から FXトレードAPI が提供されているのを発見。

www.oanda.jp

  • レート情報の取得から、取引、建玉情報の取得などのFX 取引に必要なAPI一式が提供されています。
  • 初期費用、月額利用料金は無料。ただし、口座残高が25万円以上必要です。
  • 本物の口座を使うLive環境のほか、デモ口座のアカウントで使える Practice、アカウントなしで試せるSandbox環境も提供。
  • REST APIの他、Java/FIX版のAPIも有り。


機能もかなり充実してます。本格的なトレードアプリも作れるんじゃないかな。

  • REST APIだけど、ストリーミングでのレートデータ配信に対応
    • Transfer-Encoding: chunked で配信する仕組みで、ポーリングなしでリアルタイムなレートデータを取得できます。
  • OAuth 2.0での認証に対応
    • サードパーティのサービスに、アカウント/パスワードを渡すことなくREST APIへのアクセストークンを安全に渡すことが可能。
    • なので、クラウド型のWebサービスも作ったりしやすいかと。
    • ただし、APIから取得した情報の再配信は禁止されているのでご注意。
  • すべてのGET APIが ETag に対応しているなど、細かいところの完成度も高い。

ということで、Rubyを使ってREST APIにアクセスし、リアルタイムな為替レートを取得してみるサンプルを書いてみました。(といっても、公開されているアクセスライブラリのサンプルを動かしてみただけですが・・・)

アクセスライブラリのインストール

RubyだとREST APIのアクセスライブラリが公開されているので、これを利用します。 gemでインストール。

$ gem install oanda_api

デモ口座のアカウントを使って、現在価格を得るサンプルコードです。 「<アクセストークン>」のところには、OANDAのサイトから取得したアクセストークンを指定します。取得方法はこちら。

require 'oanda_api'

client = OandaAPI::Client::TokenClient.new(:practice, <アクセストークン>)

prices = client.prices(instruments: ['EUR_USD','USD_JPY']).get
prices.each do |p|
  puts "#{p.instrument} #{p.ask} #{p.bid} #{p.time}"
end

実行結果です。

$ retrieve_price.rb
EUR_USD 1.1201 1.11994 2015-05-11 00:22:16 UTC
USD_JPY 119.744 119.728 2015-05-11 00:21:43 UTC

せっかくなので、ストリーミングAPIでリアルタイムなレート情報の取得もやってみます。

require 'oanda_api'

access_token =  <アクセストークン>

# アカウントのIDが必要なので取得しておく。
client = OandaAPI::Client::TokenClient.new(:practice, access_token )
account =  client.accounts.get.first

# ストリーミングAPI用のクライアントを別途作成し、実行
streaming_client = OandaAPI::Streaming::Client.new(:practice, access_token )
prices = streaming_client.prices(account_id: account.account_id, instruments: ["USD_JPY"])
prices.stream do |p|
  # ※無限ループするので Ctrl+Cで停止すること。
  puts "#{p.instrument} #{p.ask} #{p.bid} #{p.time}"
end 

実行してみます。放置するとずっと更新を続けるので、Ctrl+Cで停止すること。

$ ruby retrieve_price_uses_streaming_api.rb
USD_JPY 119.747 119.743 2015-05-11 00:37:52 UTC
USD_JPY 119.748 119.744 2015-05-11 00:38:12 UTC
USD_JPY 119.749 119.745 2015-05-11 00:38:12 UTC
USD_JPY 119.75 119.746 2015-05-11 00:38:12 UTC
...

Jiji2のバックエンドもこれに移行かな

Jiji2絶賛開発中ですが、

unageanu.hatenablog.com

github.com

バックエンドは OANDA fx trade API に変更かな、と考えています。 旧バージョンと同じくスクレイピングを使う方向で考えていましたが、次のようなリスクはどうしても残るので。

  • (アクセス頻度はもちろん抑えるにしても)やはり証券会社のサービスに多少は負荷がかかるので、利用禁止になる可能性がある。
  • サイトの仕様変更で突然動作しなくなるリスクがある。

アプリ開発者としては、特定の証券会社にロックオンしてしまうのは避けたいところではあるので、このようなAPIを提供してくれる証券会社がもっと増えてくるといいな。(クリック証券、何でやめたんや・・・。)

追記(2015-12-01)

OANDA FX trade APIを利用した、無料のFXシステムトレードフレームワーク「Jiji」をリリースしました!

jiji2.unageanu.net

使ってみて、ご意見など頂けるとうれしいです。

JavaScript Dateのタイムゾーン指定できない問題とその対策

JavaScriptのDate型では、タイムゾーンを外部から指定できない

  • JavaScriptのDate型は、タイムゾーンの情報を持ってはいますが、APIで外から変更することはできません。
    • getTimezoneOffset() はあるけど、setTimezoneOffset(timezone) はありません。
    • getTimezoneOffset() の値は実行環境のタイムゾーンになります。

  • getHours()やgetMinutes()はローカルのタイムゾーンにおける時刻表現を返すので、実行環境によって結果が異なり、問題になる場合があります。
    • Dateを表示用の文字列に変換する処理のテストを書いていたら、CI環境(CircleCI)で動かしたときに結果が違ってエラーに。
    • 変換APIの仕様としては、「実行環境に合わせた時刻表現を返す」のが期待の動作なので、動きとしては間違っていないのですが、テストでは困る・・
    • CI環境のタイムゾーンを変更する道もあるけど、タイムゾーンの設定によって影響が出る範囲を把握するためにテストケースはいろいろな環境で動かすようにした方がいいかな、ということで、環境はいじらない方向で対策を検討。
const date = new Date( '2015-05-10T12:00:00.000Z' );
expect( date.getHours() ).toEqual(21); 
// ローカルタイムゾーンがJSTの場合は動作するが、他の環境では違う結果になる。

対策

以下のようにしてみました。

  • Dateの代わりに、 date-with-offset を使う。
    • Dateにタイムゾーン指定機能を追加したライブラリ。DateのAPIと互換性があるのでそのまま置き換えられます。
  • DateWithOffsetをnewするときに、static変数からタイムゾーンを読み込んで使う。
    • static変数で指定されていればそちら、指定がなければローカルのタイムゾーンを使います。
    • これにより、ローカルタイムゾーンの影響を受けるテストの実行時にのみ、指定したタイムゾーンでテストを実行きるようになります。
    • 指定がない場合は普通のDateと同じ動きになるので、プロダクション環境では「実行環境に合わせた時刻表現を返す」動作となります。

具体的にはこんなユーティリティを作成。

import DateWithOffset from "date-with-offset"

const defaultTimezoneOffset = new Date().getTimezoneOffset()*-1;

export default class Dates {

  static date(iso8601String) {
    return new DateWithOffset(
      iso8601String, this.getTimezoneOffset() );
  }

  static getTimezoneOffset() {
    return this.timezoneOffset != null
        ? this.timezoneOffset
        : defaultTimezoneOffset;
  }
  static setTimezoneOffset(timezoneOffset) {
    this.timezoneOffset = timezoneOffset;
  }
  static resetTimezoneOffset() {
    this.timezoneOffset = null;
  }
}

ローカルタイムゾーンに依存するテストが動作するところは、以下のようにすることで、どの環境でも同じ結果が返るようになります。

beforeEach( ()=> Dates.setTimezoneOffset(540) );
afterEach(  ()=> Dates.resetTimezoneOffset() );

it("ローカルタイムゾーンに依存するテスト", () => {
  // このテスト内では、ローカルタイムゾーンがJSTになる。
  expect( Dates.date("2015-05-10T12:00:00.000Z").getHours() ).toEqual(21);
});

jiji2の画面スケッチを3つほど。

追記(2015-12-01):

FXシステムトレードフレームワーク「Jiji」、リリースしました!

jiji2.unageanu.net

使ってみて、ご意見など頂けるとうれしいです。



jiji2の画面スケッチを少し作ったので、公開します。

  • ホーム画面、ナビを開いたところ、チャートの3つ。
  • 表示するデータや機能をざっくりと並べてみました。
  • アイコンなど、細かいデザインの詰めはまだです。

フィードバックとかいただけるとうれしいです。

ホーム

アプリ起動直後に表示する画面。

f:id:unageanu:20150428134409p:plain

  • 損益状況、エージェントからの通知を、ファーストビューでさっと確認。
  • ミニチャートで、現在のレートと直近の値動きを確認できる。
    • 「取引」ボタンから、取引を行うことも可能。
  • ミニチャートの下には、建玉一覧、バックテスト一覧のサマリを表示。
  • 各カードをタップすると、詳細が見える
    • 例) ミニチャートをタップすると、チャート画面に移動して詳しいチャートが確認できるイメージ

ナビ

ナビを開いたところ。

f:id:unageanu:20150428134522p:plain

  • バックテスト一覧やエージェントエディタなどの機能は、ナビからアクセスする。

チャート

ローソク足チャート。

f:id:unageanu:20150428134556p:plain

  • レートの動きと、エージェントが出力したグラフ(移動平均, RSI ..etc..)を表示。
    • 移動平均はチャートと重ねて表示。RSIはレートの下の部分に別枠で表示。
    • 通貨ペア、集計期間(10分足,1時間足 ,,et,,)は、上部のメニューから変更できる。
  • レートの下部には、売り買いした建玉の情報も表示。
    • 値動きに対して、売り買いのタイミングが妥当かどうか確認できる。
    • 緑が買、赤が売。●のタイミンクでエントリーして、〇で決済したことを示す。
  • 値動き/現在価格をみながら、右下の「+」ボタンから、売り買いもできる。
  • 下のスライダーで、表示する期間を変更できる。
    • チャート部分を左右にドラッグしてもOK

作っていく過程で変わるところも多々あるとは思いますが、とりあえずはこれをゴールに実装進めます。 他の画面の絵も作っておきたいところだけど、現状の3枚で「ほんまこれ実装できんの」感が半端ない・・・。絵に描いた餅にならないよう、実装も並行して進める方がいいかなと思ってます。まずはチャートかな。

Cordova + React.js + Material UI で、 Material Design な Android アプリのプロトタイプを作ってみた

Cordova のお試しということで、 Cordova + React.js + Material UI で Material Design な Android アプリのサンプルを作ってみました。

  • HTML+CSS+JavaScript でネイティブアプリが作れるCordova ですが、やはり遅いという話をよく耳にするので、実際どうなのか確認してみるのが目的。
    • 使えそうなら、フロントはJavaScriptで書いて、せめてモデル層だけでも共通化したい。
  • UIは Material Designにしたいので、 Material UI フレームワークを使ってみました。
  • React Nativeも気になるところですが、Android版はまだらしいのでとりあえずスルー。Macも持ってないし。

プロトタイプの機能

f:id:unageanu:20150404202246p:plain

  • メイン画面には、Action Bar と Card を表示。
    • Cardは以下の3種類を用意。
      • テキストを流し込んだもの
      • 画像を張り付けたもの
      • 簡単なグラフを描画したキャンバスを張り付けたもの
    • 少しスクロールするよう、複数個貼り付けています。
  • Action Bar の左上のボタンをタップすると、Navigation Drawerが表示される。
    • メニュー選択時の処理は実装していないので、表示だけです。
  • パネルをタップすると、パネルが回転するアニメーションが走る
    • CSS transitionのパフォーマンスも見てみたいので。

コードと実行手順

コードは こちら で公開しています。 Node.js とAndroidのビルドツール一式(JDK, Android SDK, Ant) をインストールして、以下のコマンドを実行すれば動かせるはずです。

$ git clone https://github.com/unageanu/sandbox.git
$ cd sandbox/cordova/sample-app
$ npm install
$ npm run-script init
$ npm run-script build
$ npm run-script run-browser # ブラウザで実行
$ npm run-script run-android # Android(実機)で実行

所感

ややもっさり感はあるものの、シンプルなアプリであれば十分使えそう。

  • 画面のスクロールや、LeftNavi表示時のアニメーションは少しもたつく。
  • transition を使ったアニメーションは速い。
  • レンダリングも、特に汚いといったことはなさそう。
  • 起動は5~6秒といったところ。スプラッシュスクリーンを出しておけば大丈夫なレベルかな。

確認は手持ちの端末(Xperia Z)で行いました。2年前の端末なので、これで使えれば最近の端末でも大丈夫でしょう。さすがにゲームとかは厳しそうですが、とりあえず、jiji2で必要な機能なら十分実用に耐えるのではないかと。

unageanu.hatenablog.com

unageanu.hatenablog.com

jiji2の画面一覧(案)をまとめてみた

追記(2015-12-01):

FXシステムトレードフレームワーク「Jiji」、リリースしました!

jiji2.unageanu.net

使ってみて、ご意見など頂けるとうれしいです。



検討段階ですが、jiji2の画面と機能概要をざっくりとまとめてみました。

f:id:unageanu:20150331103430p:plain

  • 基本的な機能は、PCとスマホで同じに。
    • レスポンシブにして、PCでもスマホでも大体同じ機能が使えるようにしたい。
      • エージェントの作成・編集はPCがメイン。一応スマホでもできるようにしておく。
      • バックテストの実行や分析も同じ。
    • ↑は、スマホで見た場合の画面+機能案。
      • PCだと画面が広いので、一覧と詳細は同じ画面にしたりはするかも。

  • メイン画面は、「ホーム」「バックテスト」「エージェント」「設定」の4つ
    • これらをナビで切り替えながら使う形。

旧バージョンとの違いは次の2つ。

  • ホーム画面を新設。

    • 最初に表示されるビュー。
    • ダッシュボート的な感じで、資産状況などが最初の一画面でざっくり把握できるようにする。
    • ダッシュボートのパネルをタップすると、詳細を確認できる。

  • プライスボード && 価格一覧からの裁量取引もできるようにする

    • 通貨ペアごとの現在価格を一覧表示するプライスボードを追加。
    • ここから、成行での取引もできるようにする。
      • 「指標のPush通知で裁量トレード」を行うときに使う。
      • 通知からシームレスに取引できるようにするのが狙いなので、指値/逆指値/OCOでの取引はサポートしない。 (やりたい場合は証券会社が提供しているツールで。)

エージェントを作る → バックテストで検証 → 運用 あたりの画面フローは旧バージョンと同じでいいかな。

ユースケース

1.完全自動でのシステムトレード

  1. エージェントエディタからエージェントを作る。

    • PCからの作成がメイン(画面が広くてキーボードが使えるので)
    • ひな形のエージェントがあり、コピペして編集する形で簡単にロジックを組める。
    • 移動平均線など主要な指標も組み込みのライブラリとし提供されていて、簡単に組み込める。

  2. エージェントができたら、バックテストで検証。

    • 期間を指定して、本番と同様のデータ(tick)で動作を確認できる。
    • テストが完了したら、収益や勝率、プロフィトァクターなどがレポートされ、成績を評価できる。
    • 取引や約定のタイミングがチャート上に表示され、タイミングが妥当だったか確認できる。
    • 移動平均線など、エージェントが使用した指標をチャート上に出力して確認できる。

  3. 満足な結果が出たら、実際に運用してみる。

    • デモ取引での利用に対応しているので、まずはデモ取引口座で気軽にお試しできる。
    • 約定や決済は、随時スマホにPush通知される。
    • 通知をタップするとjijiが起動し、ホーム画面から現在の損益やチャート、ポジジョン一覧を確認できる。

2.指標のPush通知で裁量トレード

  1. エージェントプログラムがレートを監視。
  2. 移動平均線のゴールデンクロスなど、取引のチャンスが来たら、通知がスマホに届く。
  3. 通知をタップすると、アプリが起動。
    • ホーム画面で、チャートと現在価格をチェック。
  4. 価格を確認し、取引するか判断。OKならプライスボードから取引を実行する。
  5. 取引が成立したら、ポジション一覧に反映される。
    • 以降の損益推移はここから確認できる。
    • 決済も可能。

3.ロスカットをシステム化して徹底

  1. チャートやレートを見ながら、裁量で取引する。
    • エージェントでチャート上にグラフを描くことができるので、移動平均など好みの指標をみながらタイミングを判断できる。
    • jijiのプライスボードから発注する他、使い慣れた証券会社のツールを使っても取引できる。
    • 他のツールで行った取引も、jijiに反映され、管理できる。
  2. エージェントのポジションを監視。プログラムされたルールに従って、 一定の損失となった時点で自動で決済される。
  3. 決済が行われると、結果がスマホに通知される。
  4. 通知をタップすると、ポジションの詳細な情報(損益、通貨ペア、約定日時、決済日時 ..etc..)を確認できる。

4.承認制システムトレード

  1. エージェント追加時に、「承認制にする」をチェックすると、承認制モードになる。
    • 実運用のほか、バックテストでも同様に選べて試せる。
  2. 承認制エージェントが取引を行うと、スマホにPush通知が届く。
  3. 通知を確認して、OKなら「承認」を実行。
  4. 承認を受けて、エージェントが取引を実行する。

5. トレンドにあわせて、複数のシステムを用意して切り替え

  1. 上昇トレンド・ボックスなどのトレンドごとに、エージェントの成績を確認しておく。
    • バックテストを利用して把握しておく。成績はレポートで残しておける。
  2. 取引するエージェントのほかに、トレンドの変化をチェックするエージェントも作る。
    • 取引は行わず、好みの指標を監視してトレンドの変化を追う。
    • 変化があったら、通知のみ行う。
  3. 取引用エージェントとトレンドチェックエージェントの両方を実行。
    • トレンドチェックエージェントからの通知をチェックしてエージェントを切り替えて運用する。
    • 運用するエージェントの切り替えも、スマホからリアルタイムにできる。

設定値管理ライブラリ Figaroを使う

FigaroRubyアプリ用のシンプルな設定値管理ライブラリ です。

github.com

  • 設定ファイル(YAML)の値を読み込んで、アプリから参照できるようにします。
    • 設定ファイルは1つ。その中に、環境(development,production,test)ごとの設定も書く形。
  • アクセス時のインターフェイスに ENV を使うのが特徴。
    • ENV を 拡張し、設定ファイルから読み込んだ値も ENV['HOGE'] で参照できるようにしてくれます。
    • なので、環境変数で設定値を管理するやり方と親和性が高い。
      Heroku環境では、このやり方が主流になっているようです。

同様の機能を提供するライブラリに、 Dotenv もあります。違いはざっくり以下の3つ。

違い Figaro Dotenv
設定ファイルの形式 YAML 独自のKey-Value形式
環境ごとの設定の切り分け 1つのYAMLの中に書く形 ファイルを別ける
Rails Railsでの利用にフォーカス Rails環境もサポート


設定ファイルはYAMLのほうがいいかな・・・、と思ってFigaroにしました。参照使えるしね。ただし、Rails向けに作られているところがあるので、非Rails環境で使うには一工夫必要です。

使い方

インストール:

$ gem install figaro

設定ファイル( ./config/application.yml )を用意ます。

# デフォルトの設定
KEY1: 'key1'
KEY2: 'key2-default'
# ERBで処理されるので、rubyコードも利用可
ERB : <%= 'abc' * 3 %>

# 特定環境での設定
test:
  KEY2: 'key2-test'

development:
  KEY2: 'key2-development'
  • ルートに、キーと値を書きます。
  • test や development のようなエントリーを用意して、特定環境下でのみ有効な設定を記載できます。
    • 値の優先順位は、以下の通りです。
      • 1.環境変数の値
      • 2.特定環境下向けの設定
      • 3.デフォルトの設定
  • ERBで処理されるので、rubyコードも書けます。

設定ファイルを使うサンプルです。

require 'figaro'

class Application < Figaro::Application
  private

  # 設定ファイルのパス。 ./config/application.yml から読み込む
  def default_path
    File.join( File.dirname(__FILE__), 'config', 'application.yml')
  end
  # 環境(development,test..)の取得先。環境変数RACK_ENVを使う
  def default_environment
    ENV['RACK_ENV']
  end
end

Figaro.adapter = Application
Figaro.load

puts ENV['KEY1']
puts ENV['KEY2']
puts ENV['ERB_VALUE']
  • Figaro::Application を継承した Application を用意して、設定ファイルのパスと環境の取得先を指定します。
  • あとは、 Figaro.load すれば ENV で値を参照できるようになります。

実行してみます。 まずは素で実行。デフォルトの設定が使われます。

$ ruby test.rb 
key1
key2-default
abcabcabc

RACK_ENVを指定すると、特定環境用の設定がアクティブになります。

$ RACK_ENV=test ruby test.rb                                                                                                       
key1
key2-test
abcabcabc
$ RACK_ENV=development ruby test.rb 
key1
key2-development
abcabcabc

さらに、環境変数で値を上書きすることも可能です。

$ KEY1=foo KEY2=var RACK_ENV=test ruby test.rb                                                                                     
WARNING: Skipping key "KEY1". Already set in ENV.
WARNING: Skipping key "KEY2". Already set in ENV.
foo
var
abcabcabc

警告出ますけど。

Code Climate + Circle CI でRubyプロジェクトのコードカバレッジを計測する手順

Code Climate + Circle CI でRubyプロジェクトのコードカバレッジを計測する手順です。 試したのはCircle CIですが、テストが実行できる環境であればTravis CIやJenkinsでも同じ仕組みでできるはず。

概要

  1. テストに SimpleCov を仕込み、コードカバレッジを計測
  2. SimpleCov のレポーターに codeclimate-test-reporter を追加して、結果を Code Climate に送信
    Code Climateカバレッジが集計されるようになります。

  3. あとは、Circle CIなりTravis CIなりでテストを実行すればOK

簡単ですね。

1.テストに SimpleCov を仕込んでカバレッジを計測する

SimpleCov をbundlerでインストールします。

Gemfileに以下を追加して、

gem 'simplecov', :require => false, :group => :test

インストール。

$ bundle install

テストの先頭に、SimpleCovの設定を行うコードを追加します。

require 'simplecov'

# カバレッジレポートの出力先を指定
# Circle CIで実行する場合は、ビルド成果物置き場に、
# ローカルで実行する場合は、 ./build/coverage に作成します。
dir = File.join(ENV['CIRCLE_ARTIFACTS'] || 'build', 'coverage')
SimpleCov.coverage_dir(dir)

SimpleCov.start do
  # /vendor/,/spec/ を集計対象から除外
  add_filter '/vendor/'
  add_filter '/spec/'
end

テストを実行すれば、 ./build/coverage/index.html にカバレッジレポートが作成されるはず。

2. SimpleCov に codeclimate-test-reporter を追加する

Gemfileに一行追加して、bundler でインストール

gem 'codeclimate-test-reporter', :require => false, :group => :test
$ bundle install

SimpleCov の設定部分を以下のように変更。レポーターを追加します。

require 'simplecov'
require 'codeclimate-test-reporter'   # ★追加

dir = File.join(ENV['CIRCLE_ARTIFACTS'] || 'build', 'coverage')
SimpleCov.coverage_dir(dir)

SimpleCov.start do
  add_filter '/vendor/'
  add_filter '/spec/'

  # ★追加
  formatter SimpleCov::Formatter::MultiFormatter[
    SimpleCov::Formatter::HTMLFormatter,
    CodeClimate::TestReporter::Formatter
  ]
end

3. Circle CIに 環境変数を追加

最後に、環境変数 CODECLIMATE_REPO_TOKEN を設定します。 これをしないと、レポーターを追加しても 結果の送信はされません。

まず、CODECLIMATE_REPO_TOKEN の値を Code Climate の Settings ページから取得します。(プロジェクトごとに異なります。)

f:id:unageanu:20150322144620p:plain

Circle CIのページの右上にある、Project Settingsをクリック。

f:id:unageanu:20150322144617p:plain

Enviroment variables に移動し、

f:id:unageanu:20150322144618p:plain

CODECLIMATE_REPO_TOKEN を設定します。

f:id:unageanu:20150322144619p:plain

あとは、Circle CIでテストを実行すると、Code Climate のページでコードカバレッジが見られるようになるはず。

f:id:unageanu:20150322144621p:plain

参考: バッジを貼る

Code Climate の Settings ページに各種形式のURLがあるので、コピペして貼り付ければOK

f:id:unageanu:20150322144622p:plain