【保存版】Pythonを使ったOANDA API v1で知っておきたい10の基本操作
日本国内でPythonでFX API取引を行う決定版「OANDA API v1」。Pythonを使ってAPI経由でレート取得や注文、ポジション管理など基本操作をまとめました。
こんばんは、新米データサイエンティスト(@algon_fx)です。先日はLSTMを使ったFX予測のチュートリアルを公開したのですが、思った以上に反響を頂いて嬉しい限りです。
さて、LSTM関連でお問い合わせを頂くことが多いのですが、次に多いのがOANDAのAPIの使い方や質問です。(参考:私の機械学習&FXトレード環境)
本記事ではこれからPythonを使ってFX取引に挑もうと考えている方に向けて、OANDA API v1の使うまでの手順やレートの取得、基本的な発注方法などをまとめます。
- 1. そもそもなぜOANDAなのか?
- 2. すぐOANDA API v1の利用可能?
- 3. OANDA API v1とv20について
- 4. 概要と必要環境
- 5. 基本操作その1 APIキーと口座番号を別管理
- 6. 基本操作その2 現在のレート取得
- 7. 基本操作その3 APIの日付の変換
- 8. 基本操作その4 過去レートを取得
- 9. 基本操作その5 口座情報へアクセス
- 10. 基本操作その6 API経由で注文してみよう
- 11. 基本操作その7 トレードの管理
- 12. 基本操作その8 ポジションを管理しよう
- 13. 基本操作その9 取引履歴を管理しよう
- 14. 基本操作その10 レートのストリーミング
- 15. まとめと次の課題
そもそもなぜOANDAなのか?
まず前提としてですが、現時点で日本国内でFX APIを公開している会社は、私が知っている限りで3社しかありません(OANDA証券、日産証券、YJFXのみ)。過去にクリック証券もFX APIを提供していたのですが、こちらはとうの昔に終了しています。
APIが使える3社を比べるとOANDAは…
すぐOANDA API v1の利用可能?
はい、デモ口座であれば即時利用が可能です。申し込み後にWEB管理画面からAPIキーの取得が可能で、すぐに利用はできます。
ただ…これから真剣にAPIでトレードを行うのであれば同時にプロコースも口座開設することを強くお勧めします。デモ口座とライブ口座の2つを使いこなすのが一番賢いです。
理由は明確で…現金を使わないデモでは真剣にトレードしないからです。デモ口座は大きなメリットがあり、新しいロジックを書いた時や、少し不安がある動作のコードを試すときなどは必ずデモで確認を行います。
ただ、やはり現金での取引ではないので、トレードに勝ちたいと言うマインドがどうしても薄れます。Pythonでコード書いて注文を出したりする部分に自己満してしまい、そもそもトレードに勝つ為のコードの改善などが疎かになります(実体験ですw)
とりあえずデモ口座ですぐにAPIは使えるようになります。同時並行でプロコースのお申し込みをしておけば、少なくとも数日間も掛からずに本番口座でのAPI取引も可能です。私みたいに数週間もデモで取引して時間を無駄にする前に・・・デモとライブを両方最初から揃えた方が絶対に良いです!
またOANDAのプロコースのAPIは本番でも1通貨単位で取引が可能です。そうです。1通貨です(笑)慣れるまでの初期段階でも通貨単位を最低限に抑えることができるのもOANDA APIの大きなメリットです。
→ デモ口座開設(即時APIキー発行可能)
→ プロコース開設(APIキー取得まで数日必要)
OANDA API v1とv20について
OANDAのAPIですがv1(バージョン1)とv20(バージョン2)の2種類があります。日本で使えるのはOANDA API v1のみです。
ただ日本以外の国ではAPI v1ですが2018年5月に終わっており、現在はOANDA API v20のみの利用が可能な状態です。
機能的にはAPI v1もv20も大きな違いは無いのですが、海外では当然ながらv20が主流で使われています。それに伴い私が参加しているフォーラムやコミニティでは全員がv20を使っており…それらを私が実装するのにいちいちv1へ書き直す必要があるのです。非常に面倒です。
日本でもv20への切り替えが早々に行われるだろうと期待を胸に…OANDAへ聞いたのですが…現状日本ではv20への切り替えは予定されていないとのことでした。。ってことで、当面は日本国内でAPI経由でトレードするにはOANDA API v1に依存することになりそうです。
前置きが長くなりましたが、次のセクションから実際にOANDA APIの基本操作を一緒にPythonを使ってやってみましょう。
概要と必要環境
このチュートリアルの概要と実行環境をまとめました。一緒にAPIを動かしてみたい方は、まずはこちらの環境を揃えましょう。自分のPCに環境作るのが面倒な方は、Google Colabで代替も可能です。
動作環境&ライブラリ
・Python 3.6(Python2だと動きません)
・Jupyter(PythonのIDE的な)
・oandapy(OANDA APIのPythonラッパー)
・pandas(データフレームを扱うライブラリ)
・pytz(日付を処理するライブラリ)
必要なもの
・OANDA 口座番号(2〜3日で取得可能)
・OANDA APIキー(口座開設後は即時取得可能)
→ こちらから取得可能
チュートリアルでやる事&やらない事
・安全なAPI接続のための設定(configparser)
・現在レートの取得と確認
・APIの日付の変換
・過去レートを取得
・オーダー発注(成行・指値・逆指値・IFD)
・ポジション確認
・レートのストリーミング
下記の内容は含まれません。
・自動売買のストラクチャ構築
・自動売買のロジック&オーダー
あくまでOANDA APIの基本的な操作方法のみです。FXの自動売買のロジックを勉強する記事ではありませんのでご注意ください。
基本操作その1 APIキーと口座番号を別管理
まず一番に覚えるべき操作がこれかと思います。FXは実際のお金が動く世界なわけで、それを全て動かせるAPIキーと口座番号は安全に管理する必要があります。
コードに直接APIキーなどの重要な情報を記載するのは少し怖いです。そこで、最低限の対策としてPythonの configparser を利用します。
configparserでは必要な設定を別ファイルで管理して、設定した事項を読み取る便利な機能です。まずは設定ファイルを作成してあげましょう。各自のパソコンに「 config_v1.txt 」を新規作成しましょう。
下記はダミーですが、各自のAPIキー(api_key)と口座番号(acount_id)を記入しましょう。
1 2 3 4 5 6 |
# config_v1.txtの内容 [oanda] account_id = XXXXXXX api_key = abc123abc123abc123abc123abc123abc123-abc123abc123abc123abc123abc123abc123 |
では実際にPythonで読み込みましょう。
1 2 3 4 5 6 7 8 9 10 |
# API接続設定のファイルを読み込む import configparser # 設定 config = configparser.ConfigParser() config.read('./config/config_v1.txt') # パスの指定が必要です account_id = config['oanda']['account_id'] api_key = config['oanda']['api_key'] |
config.readの箇所ですが、私はconfig_v1.txtをconfigというフォルダー内で管理しています。こちらは設定ファイルを保存した先のディレクトリ指定が必要なのでご注意ください。
基本操作その2 現在のレート取得
実際にAPIに接続をしてレートを取得して見ましょう。まずは必要なライブラリを読み込みます。
1 2 3 4 5 6 7 8 |
# 必要なライブラリの読み込み import pandas as pd import oandapy import datetime from datetime import datetime, timedelta import pytz |
APIへ接続して見ましょう。デモ口座で動かしている方はenvironmentを”practice”と変更する必要があります。
1 2 3 4 5 |
# APIへ接続 oanda = oandapy.API(environment="live", access_token=api_key) |
特にエラーがでなければAPIへの接続完了です。現在のドル円のレートを取得してみます。
1 2 3 4 |
# ドル円の現在のレートを取得 res = oanda.get_prices(instruments="USD_JPY") |
こちらですがdict型です。
1 2 3 4 5 6 7 |
# データ型を確認 type(res) -- 出力 dict |
中身も覗いて見ましょう。
1 2 3 4 5 6 7 8 9 10 |
# 中身を確認 print(res) -- 出力 {'prices': [{'ask': 112.422, 'bid': 112.418, 'instrument': 'USD_JPY', 'time': '2018-07-16T06:25:12.840439Z'}]} |
ドル円のask(売値)とbid(買値)が入っています。time(時間)ですが、現在の時刻となります。ただ注意が必要なのが、こちらの時間はISO8601形式となっています。日本時間に変換させてあげる必要があります。(時間については後ほど処理を行います)
次は複数通貨ペアの現在のレートを取得してみましょう。
1 2 3 4 |
# 複数通貨ペアを取得 res_mlt = oanda.get_prices(instruments="USD_JPY,EUR_JPY,GBP_JPY") |
ドル円、ユーロ円、ボンド円のレートを取得しました。中身を確認してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 中身を確認 res_mlt -- 出力 {'prices': [{'ask': 112.476, 'bid': 112.472, 'instrument': 'USD_JPY', 'time': '2018-07-16T04:08:30.060961Z'}, {'ask': 131.417, 'bid': 131.404, 'instrument': 'EUR_JPY', 'time': '2018-07-16T04:08:43.309302Z'}, {'ask': 148.904, 'bid': 148.88, 'instrument': 'GBP_JPY', 'time': '2018-07-16T04:09:00.318481Z'}]} |
辞書型ですので、個別の情報にアクセスするには下記のように書きます。
1 2 3 4 5 6 7 8 9 10 |
# ドル円のみ表示 print(res_mlt['prices'][0]) -- 出力 {'ask': 112.441, 'bid': 112.437, 'instrument': 'USD_JPY', 'time': '2018-07-16T06:33:05.989229Z'} |
基本操作その3 APIの日付の変換
先ほどAPI経由で取得したレートを確認しましたが、日付がISO8601形式となっていました。他のAPIをいじったことがある方であれば馴染みがあるかも知れませんが、多くのAPIが採用している時間の形式です。
LSTMでFX予測の記事でも行いましたが、APIから取得したデータは全てISO形式となっていますので、日本の時間&フォーマットの変更が必要です。
まずは日本時間へ変換をしてあげましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 文字列 -> datetime def iso_to_jp(iso): date = None try: date = datetime.strptime(iso, '%Y-%m-%dT%H:%M:%S.%fZ') date = pytz.utc.localize(date).astimezone(pytz.timezone("Asia/Tokyo")) except ValueError: try: date = datetime.strptime(iso, '%Y-%m-%dT%H:%M:%S.%f%z') date = date.astimezone(pytz.timezone("Asia/Tokyo")) except ValueError: pass return date |
先ほど取得したレートで確認してみます。APIから取得した生データの時間は下記のような値でした。
1 2 3 4 5 6 7 |
# APIから取得した生データ res_mlt['prices'][0]['time'] -- 出力 '2018-07-16T06:33:05.989229Z' |
こちらを日本時間へ変更してあげましょう。
1 2 3 4 5 6 7 |
# 日本時間へ変換 iso_to_jp(res_mlt['prices'][0]['time']) -- 出力 datetime.datetime(2018, 7, 16, 15, 33, 5, 989229, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>) |
これではdatetime形式で少し見辛いですので、さらに表示用の文字列として変換してあげましょう。
1 2 3 4 5 6 7 |
# datetime -> 表示用文字列 def date_to_str(date): if date is None: return '' return date.strftime('%Y/%m/%d %H:%M:%S') |
1 2 3 4 5 6 |
date_to_str(iso_to_jp(res_mlt['prices'][0]['time'])) -- 出力 '2018/07/16 15:33:05' |
これで見やすくなりましたね。余談ですが、pandasにはISO形式をdatatime形式へ一発で変換してくれる to_datetime() という関数があります。
ただ注意が必要なのが、APIから取得したデータを日本時間へ直してあげる必要があります。ISOからdatetime形式へ変換はされますが、日本時間ではないので注意しましょう。(最初のころ、私はまさにこれでハマりました・・・)
基本操作その4 過去レートを取得
現時点のレートの取得、APIのデータの構造がある程度解ってきたと思います。次は過去のレートをAPI経由で取得してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 過去レートをAPI経由で取得 res_hist = oanda.get_history(instrument="USD_JPY") # 最初の2レコードを確認 res_hist['candles'][0:2] -- 出力 [{'closeAsk': 112.521, 'closeBid': 112.507, 'complete': True, 'highAsk': 112.524, 'highBid': 112.511, 'lowAsk': 112.518, 'lowBid': 112.505, 'openAsk': 112.524, 'openBid': 112.511, 'time': '2018-07-16T01:49:00.000000Z', 'volume': 4}, {'closeAsk': 112.519, 'closeBid': 112.505, 'complete': True, 'highAsk': 112.523, 'highBid': 112.51, 'lowAsk': 112.519, 'lowBid': 112.505, 'openAsk': 112.523, 'openBid': 112.51, 'time': '2018-07-16T01:49:05.000000Z', 'volume': 3}] |
辞書型では扱いづらいので、Pandasのデータフレーム形式へ変換してあげましょう。
1 2 3 4 5 6 7 |
# 過去レートをデータフレーム形式へ res_hist_df = pd.DataFrame(res_hist['candles']) # 最初の5行を表示 res_hist_df.head() |
get_history()ですがデフォルトは5秒足(S5)となっています。パラメータとしてgranularityを指定することで、異なる期間のレートを取得できます。試しに1分足(M1)で取得してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 1分足に変更してレートを取得してみる res_hist_1m = oanda.get_history(instrument="USD_JPY", granularity="M1") # データフレーム形式へ変換 res_hist_1m = pd.DataFrame(res_hist_1m['candles']) # 日付をISOから変換 res_hist_1m['time'] = res_hist_1m['time'].apply(lambda x: iso_to_jp(x)) res_hist_1m['time'] = res_hist_1m['time'].apply(lambda x: date_to_str(x)) # 最初の5行を確認してみよう res_hist_1m.head() |
timeを見て頂くと判りますが1分足になっているのが確認できます。(ちゃんと日本時間へ変換しています)
過去レートの取得でもう一つ覚えておくべきなのが取得件数です。デフォルトでは500件取得可能です。こちらはcountを指定することで、最大5000件まで一度のリクエストで取得が可能です。
1 2 3 4 5 6 7 |
# デフォルトは500件 - 確認してみよう res_hist_1m.shape -- 出力 (500, 11) |
先ほど取得した1分足のレートですが500行となっています。ではcountを指定して最大件数の5000件を一度に取得してみましょう。
1 2 3 4 5 6 7 8 9 10 |
# 最大で5000件まで一度に取得可能 res_hist_1m_5000 = oanda.get_history(instrument="USD_JPY", granularity="M1", count="5000") # データフレームへ変換 res_hist_1m_5000 = pd.DataFrame(res_hist_1m_5000['candles']) # サイズを確認 res_hist_1m_5000.shape |
1 2 3 4 |
-- 出力 (5000, 11) |
ご覧の通り5000件取れています。
基本操作その5 口座情報へアクセス
API経由でFX取引を行う際に、定期的に口座情報へのアクセスが必要となります。例えばプログラム上で口座残高が必要になったりする際にです。(口座残高が一定を下回ったら〇〇は注文しないなどのロジック)
ではOANDA API v1で口座情報を引き出してみましょう。まずは基本的な口座情報から。dict型で口座番号や口座の主要通貨が取れます。
1 2 3 4 5 6 7 8 9 10 11 |
# 口座の基本情報 res_acct = oanda.get_accounts() res_acct -- 出力 {'accounts': [{'accountCurrency': 'JPY', 'accountId': XXXXXXX, #ダミーに変換しています 'accountName': 'Primary', 'marginRate': 0.04}]} |
口座の基本情報はあまり役に立ちませんが、詳細情報はもう少し実践的な口座情報が含まれます。ではAPIから取得してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 口座の詳細情報 res_acct_detail = oanda.get_account(account_id) res_acct_detail -- 出力 {'accountCurrency': 'JPY', 'accountId': XXXXXXX, #ダミーに変換しています 'accountName': 'Primary', 'balance': 3131111.3397, 'marginAvail': 3131111.3397, 'marginRate': 0.04, 'marginUsed': 0, 'openOrders': 1, 'openTrades': 0, 'realizedPl': 127661.7464, 'unrealizedPl': 0} |
特に重要なのがbalance(口座残高)とrealizedPl(実現損益)です。また上の状態は全てポジションを決済したあとですので0とありますが、unrealizedPl(評価損益)も重要です。
基本操作その6 API経由で注文してみよう
次はAPIを使って実際に注文を出してみましょう。前述しましたがOANDA API v1は1通貨単位で注文が可能です。実はこれは非常にメリットが高く、とりあえず不安な時は通貨単位を最小限に落として現金でテスト出来ます。
まずは成行注文を出してみましょう。下記は「ドル円」の「売り」で「1万通貨単位」の成行注文(type = market)です。
1 2 3 4 5 6 7 8 9 10 11 |
# 成行注文 order_1 = oanda.create_order(account_id, instrument = "USD_JPY", units=10000, side="sell", type="market") # 確認 print(order_1) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- 出力 {'instrument': 'USD_JPY', 'price': 112.52, 'time': '2018-07-17T11:02:07.000000Z', 'tradeOpened': {'id': 11040041524, 'side': 'sell', 'stopLoss': 0, 'takeProfit': 0, 'trailingStop': 0, 'units': 10000}, 'tradeReduced': {}, 'tradesClosed': []} |
簡単に注文が可能ですね。念のためOANDAのWEB管理画面で注文が通っているか確認してみましょう。
ご覧の通り112.520でドル円の売り注文が1万通貨通っているのが確認できます。少し混乱しやすいですが、API上ではIDとありますが、これは管理画面上では「チケット番号」と表記されます。
次は指値注文(type = limit)をしてみましょう。指値にはトレードの有効期限のパラメータが必須となります。まずは適当に現在の時刻から+1日を有効期限として作ってあげます。
1 2 3 4 5 |
trade_expire = datetime.now() + timedelta(days=1) trade_expire = trade_expire.isoformat("T") + "Z" trade_expire |
1 2 3 4 |
-- 出力 '2018-07-18T20:08:55.571983Z' |
では指値注文を出してみましょう。create_orderのパラメータ「type」に「limit」と指定することで指値注文が可能です。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 指値注文 limit_order = oanda.create_order(account_id, instrument = "USD_JPY", units = 100, price = 112.800, side = "buy", expiry = trade_expire, type="limit") limit_order |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- 出力 {'instrument': 'USD_JPY', 'orderOpened': {'expiry': '2018-07-18T20:08:55.000000Z', 'id': 11040043129, 'lowerBound': 0, 'side': 'buy', 'stopLoss': 0, 'takeProfit': 0, 'trailingStop': 0, 'units': 100, 'upperBound': 0}, 'price': 112.8, 'time': '2018-07-17T11:10:43.000000Z'} |
では同様に逆指値(type = stop)も出してみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
# 指値注文 stop_order = oanda.create_order(account_id, instrument = "USD_JPY", units = 100, price = 112.800, side = "buy", expiry = trade_expire, type="stop") stop_order |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- 出力 {'instrument': 'USD_JPY', 'orderOpened': {'expiry': '2018-07-18T20:08:55.000000Z', 'id': 11040043743, 'lowerBound': 0, 'side': 'buy', 'stopLoss': 0, 'takeProfit': 0, 'trailingStop': 0, 'units': 100, 'upperBound': 0}, 'price': 112.8, 'time': '2018-07-17T11:14:18.000000Z'} |
またOANDA APIには少し変わった注文タイプがあります。それが「type = marketIfTouched」です。これは指定したレートに相場が達した時に「成行注文」が出されます。
加えてAPIで注文する際に覚えておくべき重要な3つのパラメータが下記です。
・takeProfit = 利益確定レート
・stopLoss = 損切りレート
・trailingStop = トレールストップのpip
では試しに成行注文で「takeProfit」と「stopLoss」を指定して発注してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 成行注文(利確レート = 112.900 / 損切りレート = 112.200 order_mk = oanda.create_order(account_id, instrument = "USD_JPY", units=10000, side="buy", takeProfit = 112.900, stopLoss = 112.200, type="market") order_mk |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- 出力 {'instrument': 'USD_JPY', 'price': 112.533, 'time': '2018-07-17T11:25:14.000000Z', 'tradeOpened': {'id': 11040047586, 'side': 'buy', 'stopLoss': 112.2, 'takeProfit': 112.9, 'trailingStop': 0, 'units': 10000}, 'tradeReduced': {}, 'tradesClosed': []} |
ご覧の通り管理画面で確認しても損切りと利確のレートが注文として通っています。実際にPythonを使ってAPI経由でトレードをするときは、私は必ず損切り&利確を指定します。
基本操作その7 トレードの管理
次は発注した注文(トレード)の管理をAPI経由で行いましょう。まずは、オープンオーダー(注文中)を取得してみましょう。
1 2 3 4 5 |
# オープントレードを取得 open_orders = oanda.get_orders(account_id) open_orders |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- 出力 {'orders': [{'expiry': '2018-07-18T20:08:55.000000Z', 'id': 11040043743, 'instrument': 'USD_JPY', 'lowerBound': 0, 'price': 112.8, 'side': 'buy', 'stopLoss': 0, 'takeProfit': 0, 'time': '2018-07-17T11:14:18.000000Z', 'trailingStop': 0, 'type': 'stop', 'units': 100, 'upperBound': 0}]} |
オープンオーダーとは「取引中」、つまり取引が執行されていない注文です。現在、私の口座には1件しか入っていませんが、get_orders()ではオープンオーダー全てを取得できます。
上記の出力を見ればわかりますが、こちらはドル円の買いの逆指値注文@112.800円@100通貨です。まだ執行されていませんので、API経由で注文を変更することも可能です。
1 2 3 4 |
# オープンオーダーを変更 oanda.modify_order(account_id, order_id=11040043743, price=112.700, units=10000) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- 出力 {'expiry': '2018-07-18T20:08:55.000000Z', 'id': 11040043743, 'instrument': 'USD_JPY', 'lowerBound': 0, 'price': 112.7, 'side': 'buy', 'stopLoss': 0, 'takeProfit': 0, 'time': '2018-07-17T11:49:56.000000Z', 'trailingStop': 0, 'type': 'stop', 'units': 10000, 'upperBound': 0} |
modify_order()により逆指値のレートを112.700円へ、さらに通貨単位を1万通貨へ変更しました。実際のトレードでは、状況に応じてプログラムでオープンオーダーを細かく調整していくことなどが有り得ますので覚えておくと便利です。
続いて取引中のオーダーを取得しましょう。私の口座には現在3件の「取引中」があります。こちらをAPIから取得して、Pandasのデータフレームに入れて出力してみましょう。
1 2 3 4 5 6 |
# トレードの情報を取得 trades = oanda.get_trades(account_id) trades = pd.DataFrame(trades['trades']) trades.head() |
1 2 3 4 5 6 7 |
-- 出力 id instrument price side stopLoss takeProfit time trailingAmount trailingStop units 0 11040047586 USD_JPY 112.533 buy 112.2 112.9 2018-07-17T11:25:14.000000Z 0 0 10000 1 11040047485 USD_JPY 112.533 buy 112.2 112.9 2018-07-17T11:25:01.000000Z 0 0 10000 2 11040043130 USD_JPY 112.512 buy 0.0 0.0 2018-07-17T11:10:43.000000Z 0 0 100 |
複雑なロジックや複数通貨に渡って取引をしていると「取引中」のオーダーが増えてきます。このようにシステム内でトレードの詳細を常に管理しておく必要が出てくるわけです。
基本操作その8 ポジションを管理しよう
先ほど確認したのは「トレード(注文)」の管理でしたが、次はポジションです。違いはトレードはあくまで注文ですので、幾らで何をどのような条件で注文したかの情報です。
対してポジションは今の相場に対して、どのトレードがどのくらい利益/損益を出しているの?を主に確認するものです。では、早速やってみましょう。
まずは口座全体のポジションを取得しましょう。
1 2 3 4 5 |
# 口座のポジションを取得 positions = oanda.get_positions(account_id) positions |
1 2 3 4 5 6 7 |
-- 出力 {'positions': [{'avgPrice': 112.533, 'instrument': 'USD_JPY', 'side': 'buy', 'units': 10100}]} |
私の現在の口座はドル円しか注文していませんが、複数通貨の場合、全てのポジションが表示されます。avgPriceは保有しているポジションの平均レートです。
では全てのドル円のポジションを一括で決済してみましょう。
1 2 3 4 5 |
# ポジションの手仕舞い close_pos = oanda.close_position(account_id, instrument="USD_JPY") close_pos |
1 2 3 4 5 6 7 |
-- 出力 {'ids': [11040047485, 11040057332, 11040047586, 11040057333], 'instrument': 'USD_JPY', 'price': 112.621, 'totalUnits': 10100} |
全て保持していたドル円のポジションが一括で決済されます。大雑把な処理ですので、あまり使う場面が少ないのでは?と最初は思っていたのですが、実はこれ意外と便利です。
基本操作その9 取引履歴を管理しよう
これは非常に重要なAPI操作です。口座の取引履歴をAPIから取得する方法ですが、プログラムでトレードをする際は特に重要になります。
では実際に取引履歴を取得してみましょう。
1 2 3 4 5 6 7 8 9 10 |
# 取引履歴を取得 tran_hist = oanda.get_transaction_history(account_id) # データフレームへ変換 tran_hist = pd.DataFrame(tran_hist['transactions']) # 確認 tran_hist[0:1] |
1 2 3 4 5 |
-- 出力 accountBalance accountId expiry id instrument interest orderId pl price reason side stopLossPrice takeProfitPrice time tradeId tradeOpened tradeReduced type units 0 3132744.4 XXXXXXX NaN 11040057333 USD_JPY 1.3028 NaN 880.0 112.621 NaN sell NaN NaN 2018-07-17T12:02:39.000000Z 1.104005e+10 NaN NaN TRADE_CLOSE 10000.0 |
このようにトレードの詳細履歴の取得が可能です。get_transaction_history()ですがデフォルトで最新の50件のレコードを取得可能です。パラメータにcountを指定することで、最大500件まで取得が可能です。
当然ですが個別にIDを指定することで、トレードの詳細情報を取得するのも簡単です。やってみましょう。
1 2 3 4 5 |
# 取引詳細 tran_detail = oanda.get_transaction(account_id, transaction_id=11040057333) tran_detail |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- 出力 {'accountBalance': 3132744.4, 'accountId': XXXXXXX, 'id': 11040057333, 'instrument': 'USD_JPY', 'interest': 1.3028, 'pl': 880, 'price': 112.621, 'side': 'sell', 'time': '2018-07-17T12:02:39.000000Z', 'tradeId': 11040047586, 'type': 'TRADE_CLOSE', 'units': 10000} |
次はいよいよAPI基本操作の最後です!
基本操作その10 レートのストリーミング
最後になりましたが、これまた基本かつとても重要なAPI操作です。機械学習では過去レートを大量に取得して、こねくりまわしてモデルに訓練して・・と言った流れが基本です。
モデルを訓練しては、テストをして評価をしながら精度を上げていき・・・さぁいよいよ本番で運用してみよう!という段階で必要なのがレートのストリーミングです。
ストリーミングですが、実際に使うときはもっと色々なことを考えながら操作しなくてはいけませんが、とりあえず基本操作ですので、まずはレートをシンプルにストリーミングしてみましょう。
まずはクラスを作ります。count=10とあるように、ストリーミングで10件単位で情報を取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class RateStreaming(oandapy.Streamer): def __init__(self, count=10, *args, **kwargs): super(RateStreaming, self).__init__(*args, **kwargs) self.count = count self.reccnt = 0 def on_success(self, data): print(data, "\n") self.reccnt += 1 if self.reccnt == self.count: self.disconnect() |
では実際にストリーミングを動かしてみましょう。
1 2 3 4 5 |
stream = RateStreaming(environment="practice", access_token=api_key) stream.rates(account_id, instruments="USD_JPY") |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
-- 出力 {'tick': {'instrument': 'USD_JPY', 'time': '2018-07-17T12:43:38.647687Z', 'bid': 112.639, 'ask': 112.643}} {'heartbeat': {'time': '2018-07-17T12:43:48.932427Z'}} {'heartbeat': {'time': '2018-07-17T12:43:51.213438Z'}} {'heartbeat': {'time': '2018-07-17T12:43:53.690221Z'}} {'heartbeat': {'time': '2018-07-17T12:43:56.213492Z'}} {'tick': {'instrument': 'USD_JPY', 'time': '2018-07-17T12:43:58.888425Z', 'bid': 112.637, 'ask': 112.641}} {'heartbeat': {'time': '2018-07-17T12:43:58.903875Z'}} {'tick': {'instrument': 'USD_JPY', 'time': '2018-07-17T12:44:00.734094Z', 'bid': 112.635, 'ask': 112.639}} {'heartbeat': {'time': '2018-07-17T12:44:01.213552Z'}} {'tick': {'instrument': 'USD_JPY', 'time': '2018-07-17T12:44:01.429852Z', 'bid': 112.632, 'ask': 112.636}} |
ご覧の通りレスポンスとしてレートのストリーミングがJSONフォーマットで戻ってきます。常に新しいレートが出た時点で出力されます。heatbeatとありますが、これはコネクションが繋がっていることを確認するために定期的に吐き出されます。(レートの変更が一定期間内とheatbeatが戻ってくる=コネクションが切れている訳ではないことが判る)
まとめと次の課題
今回の記事はOANDA API v1の知っておくべき10の基本操作をまとめました。いきなり自動売買のシステムをスクラッチで作るのは非常に手間がかかります。
まずは基本操作をしっかりと使いこなして、少しづつAPIでの操作に慣れていくことで、必要なロジックを追加しながらシステム全体を改善していくと進めやすいと思います。
今回はあくまで基本操作編でしたが、イベントの管理やポートフォリオの管理など、実際にPythonでトレードをするには、様々な実装が必要です。また機会があれば、応用編もまとめたいと思います。
以上となります!ブログ読んでいただきありがとうございます!Twitterでも色々と発信しているので、是非フォローお願いします!
【人気記事】
ディスカッション
コメント一覧
@algon_fx様
こんにちは。よろしければ、ご質問させてください。
この記事が面白く、実行してみたところ、その5の口座情報の詳細を得るところからエラーが出始め、その6では”market”が原因でエラーが出てうまくいきません。
その5の口座情報の基本情報では、account_idの表示はされますが、本来のidとは違うものが表示されています。本文中に”ダミーに変換しています”とあるので、もともとここは、違うidが表示されるのでしょうか。
何れにしても、marketでエラーが表示され、注文ができないんです。
アメリカのoandaにメールして聞いてみましたが、自分で調べてみましょう、な感じで困った状況です。
コメント、ありがとうございます。
まず前提なんですが、こちらは日本のOandaジャパンが提供しているAPIv1のチュートリアルです。アメリカを含むグローバルのOANDAではすでにV1は終了しており、v2のみ利用が可能な状況です。
その5の口座情報ですが、ご自身の口座IDが表示されるはずです。Oandaのオンラインの管理画面へログインすると「口座情報 Primary」の部分に番号が記載されていますが、そちらが表示されませんか?APIへ接続が問題なく出来た時点で、口座番号が異なることはおそらく無いとは思うのですが・・
ちなみに注文ですがmarketと記載して、どのようなエラーが発生しますか?
この記事のおかげで色々助かりました。
v20用もお待ちしております。