OANDA APIを使った注文の出し方について色々調べてみた!

 ※ 本記事は広告・プロモーションを含みます。
OANDA API

このページでは実際にAPIを叩いて動作を確認していきましょう!
サンプルコードをいくつか載せておきます。

OANDA APIを使った注文の出し方について色々調べてみた!

 ①: ~口座開設編~
 ②: ~実際にAPIで注文を出してみる編~   ← 今ここ

注文のAPI仕様

OANDAの注文API仕様についてはOANDA’s REST-V20のページにまとめられていますが、今回は実戦で役に立ちそうなAPIのみに絞って紹介していこうと思います。

注文で使用するAPIは主に以下の3種類の操作となります。

  • 注文操作系API ⇒ 主に新規注文で使用
  • トレード操作系API ⇒ 各取引に対する決済注文で使用
  • ポジション操作系API ⇒ 各ポジションに対する決済注文で使用

注文操作系のAPI

注文操作系のAPIは主に新規注文で使用されます。

“主に”と書いたのには理由があって、一応注文操作系のAPIでも決済注文は出せます。

しかし、後で紹介するトレード操作系ポジション操作系のAPIでも決済注文が出せるため、注文操作系のAPIは新規注文のみで使用していこうと考えています。

注文操作系のAPIの一覧はoandapyV20.endpoints.ordersにまとめられていますが、その中でも実戦で使用頻度が高そうなものを以下にピックアップしましたので紹介していこうと思います。

API用途
OrderCreate(accountID, data)注文を作成する
OrderDetails(accountID, orderID)注文の詳細情報を取得する
OrdersPending(accountID)未約定の全注文リストを取得する
OrderCancel(accountID, orderID)未約定の注文をキャンセルする

OrderCreate(accountID, data)

新規注文を作成します。

引数のdataに与えるパラメータによって様々な種類の注文を出すことができます。

  • instrument: 通貨ペアを指定
  • units: 取引数量と買い/売りを指定
    • +(プラス)の数値だと買い注文
    • -(マイナス)の数値だと売り注文
  • type: 注文の種類を指定
    • MARKET: 成行注文
    • LIMIT: 指値注文(ポジション・オープン用)
    • STOP: 逆指値注文(ポジション・オープン用)
    • MARKET_IF_TOUCHED: MIT注文
    • TAKE_PROFIT: 利益確定注文[指値注文](ポジション・クローズ用)
    • STOP_LOSS: ストップ注文[逆指値注文](ポジション・クローズ用)
    • TRAILING_STOP_LOSS: トレイリング・ストップ・リミット注文(ポジション・クローズ用)
    • FIXED_PRICE: ※不明

<Example 01:成行注文①>

import json
from oandapyV20.endpoints.orders import OrderCreate
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ========== ex_maket01 ==========
# 注文方法:成行
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# ================================
data = {
    "order": {
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "MARKET",
        "positionFill": "DEFAULT"
    }
}

api = API(access_token=access_token , environment=environment )
ep = OrderCreate(accountID=account_id, data=data)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "orderCreateTransaction": {
    "type": "MARKET_ORDER",
    "instrument": "USD_JPY",
    "units": "10000",
    "timeInForce": "FOK",
    "positionFill": "DEFAULT",
    "reason": "CLIENT_ORDER",
    "id": "206",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "206",
    "requestID": "24652091288072165",
    "time": "2020-02-24T13:01:20.873733113Z"
  },
  "orderFillTransaction": {
    "type": "ORDER_FILL",
    "orderID": "206",
    "instrument": "USD_JPY",
    "units": "10000",
    "requestedUnits": "10000",
    "price": "111.348",
    "pl": "0.0000",
    "financing": "0.0000",
    "commission": "0.0000",
    "accountBalance": "3000892.2842",
    "gainQuoteHomeConversionFactor": "1",
    "lossQuoteHomeConversionFactor": "1",
    "guaranteedExecutionFee": "0.0000",
    "halfSpreadCost": "20.0000",
    "fullVWAP": "111.348",
    "reason": "MARKET_ORDER",
    "tradeOpened": {
      "price": "111.348",
      "tradeID": "207",
      "units": "10000",
      "guaranteedExecutionFee": "0.0000",
      "halfSpreadCost": "20.0000",
      "initialMarginRequired": "44538.4000"
    },
    "fullPrice": {
      "closeoutBid": "111.340",
      "closeoutAsk": "111.352",
      "timestamp": "2020-02-24T13:01:20.447002900Z",
      "bids": [
        {
          "price": "111.344",
          "liquidity": "250000"
        }
      ],
      "asks": [
        {
          "price": "111.348",
          "liquidity": "250000"
        }
      ]
    },
    "id": "207",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "206",
    "requestID": "24652091288072165",
    "time": "2020-02-24T13:01:20.873733113Z"
  },
  "relatedTransactionIDs": [
    "206",
    "207"
  ],
  "lastTransactionID": "207"
}

他にもいくつかの注文例を載せておきます。

<Example 02:成行注文②>

# ========== ex_maket02 ==========
# 注文方法:成行
# 取引通貨:USD/JPY
# 売買:売
# 数量:10000
# ================================
data = {
    "order": {
        "instrument": "USD_JPY",
        "units": -10000,
        "type": "MARKET",
        "positionFill": "DEFAULT"
    }
}

<Example 03:成行注文③(+ OCO注文)>

以下のように記述することで、新規と同時にOCO注文を出すこともできます。

# ========== ex_maket03 ==========
# 注文方法:成行(OCO注文)
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# 利確指値:150.00円(GTC)
# 損切逆指値:100.00円(GTC)
# ================================
data = {
    "order": {
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "MARKET",
        "positionFill": "DEFAULT",
        "takeProfitOnFill": {
            "timeInForce": "GTC",
            "price": 150.000
        },
        "stopLossOnFill": {
            "timeInForce": "GTC",
            "price": 80.000
        },
    }
}

<Example 04:指値注文①>

# ========== ex_limit01 ==========
# 注文方法:指値
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# ================================
data = {
    "order": {
        "price": 100.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "LIMIT",
        "positionFill": "DEFAULT"
    }
}

<Example 05:指値注文②>

# ========== ex_limit02 ==========
# 注文方法:指値
# 価格指定:100.000円
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:売
# 数量:10000
# ================================
data = {
    "order": {
        "price": 100.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": -10000,
        "type": "LIMIT",
        "positionFill": "DEFAULT"
    }
}

<Example 06:指値注文③(+ OCO注文)>

# ========== ex_limit03 ==========
# 注文方法:指値(OCO)
# 価格指定:100.000円
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# 利確指値:150.00円(GTC)
# 損切逆指値:100.00円(GTC)
# ================================
data = {
    "order": {
        "price": 100.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "LIMIT",
        "positionFill": "DEFAULT",
        "takeProfitOnFill": {
            "timeInForce": "GTC",
            "price": 150.000
        },
        "stopLossOnFill": {
            "timeInForce": "GTC",
            "price": 80.000
        },
    }
}

<Example 07:逆指値注文①>

# ========== ex_stop01 ==========
# 注文方法:逆指値
# 価格指定:130.000円
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# ===============================
data = {
    "order": {
        "price": 130.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "STOP",
        "positionFill": "DEFAULT"
    }
}

<Example 08:逆指値注文②>

# ========== ex_stop02 ==========
# 注文方法:逆指値
# 価格指定:130.000円
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:売
# 数量:10000
# ================================
data = {
    "order": {
        "price": 130.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": -10000,
        "type": "STOP",
        "positionFill": "DEFAULT"
    }
}

<Example 09:逆指値注文③(+ OCO注文)>

# ========== ex_stop03 ==========
# 注文方法:逆指値(OCO)
# 価格指定:130.000円
# 有効期間:キャンセルされるまで有効(GTC)
# 取引通貨:USD/JPY
# 売買:買
# 数量:10000
# 利確指値:150.00円(GTC)
# 損切逆指値:100.00円(GTC)
# ================================
data = {
    "order": {
        "price": 130.000,
        "timeInForce": "GTC",
        "instrument": "USD_JPY",
        "units": 10000,
        "type": "STOP",
        "positionFill": "DEFAULT",
        "takeProfitOnFill": {
            "timeInForce": "GTC",
            "price": 150.000
        },
        "stopLossOnFill": {
            "timeInForce": "GTC",
            "price": 100.000
        },
    }
}

OrderDetails(accountID, orderID)

引数に渡されたオーダーIDの注文情報の詳細を取得します。

レスポンスの“state”より、以下のような注文状態を知ることができます。

  • PENDING: 注文が未約定の状態
  • TRIGGERED: 注文が執行中の状態(通常、約定処理は短時間で行われるため、本ステータスが長時間表示されることはない。)
  • FILLED: 注文が約定済みの状態
  • CANCELLED: 注文がキャンセルされた状態

コンピュータ上でシストレ運用する場合、作成した注文が約定したかどうかを判別するには、このAPIを使用する必要がありそうです。

<Example>

import json
from oandapyV20.endpoints.orders import OrderDetails
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# オーダーを作成しておくこと
# -----------------------------
order_id = 192  # 作成したオーダーIDを指定

api = API(access_token=access_token, environment=environment)
ep = OrderDetails(accountID=account_id, orderID=order_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "order": {
    "id": "192",
    "createTime": "2020-02-21T12:34:03.881872950Z",
    "type": "LIMIT",
    "instrument": "USD_JPY",
    "units": "1",
    "timeInForce": "GTD",
    "price": "100.000",
    "gtdTime": "2020-02-28T12:34:01.000000000Z",
    "triggerCondition": "DEFAULT",
    "partialFill": "DEFAULT_FILL",
    "positionFill": "DEFAULT",
    "state": "PENDING"
  },
  "lastTransactionID": "199"
}

OrdersPending(accountID)

未約定の状態の全注文を取得します。

シストレ運用する場合、注文ステータスはシストレ運用サーバー側で管理しようと思っているので、このAPIの使用頻度は高くなさそうです。

<Example>

import json
from oandapyV20.endpoints.orders import OrdersPending
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# 保留中となるオーダーを作成しておくこと
# -----------------------------

api = API(access_token=access_token, environment=environment)
ep = OrdersPending(accountID=account_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "orders": [
    {
      "id": "193",
      "createTime": "2020-02-21T13:14:53.578393158Z",
      "type": "LIMIT",
      "instrument": "EUR_JPY",
      "units": "1",
      "timeInForce": "GTD",
      "price": "100.000",
      "gtdTime": "2020-02-28T13:14:46.000000000Z",
      "triggerCondition": "DEFAULT",
      "partialFill": "DEFAULT_FILL",
      "positionFill": "DEFAULT",
      "state": "PENDING"
    },
    {
      "id": "192",
      "createTime": "2020-02-21T12:34:03.881872950Z",
      "type": "LIMIT",
      "instrument": "USD_JPY",
      "units": "1",
      "timeInForce": "GTD",
      "price": "100.000",
      "gtdTime": "2020-02-28T12:34:01.000000000Z",
      "triggerCondition": "DEFAULT",
      "partialFill": "DEFAULT_FILL",
      "positionFill": "DEFAULT",
      "state": "PENDING"
    }
  ],
  "lastTransactionID": "199"
}

OrderCancel(accountID, orderID)

引数に渡されたオーダーIDの注文をキャンセルします。

<Example>

import json
from oandapyV20.endpoints.orders import OrderDetails, OrderCancel
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# 保留中となるオーダーを作成しておくこと
# -----------------------------

order_id = 192  # 作成したオーダーIDを指定

api = API(access_token=access_token, environment=environment)

# 保留中の注文情報を確認
print("①保留中の注文情報を確認(キャンセル前)")
ep = OrderDetails(accountID=account_id, orderID=order_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# 保留中の注文をキャンセルする
print("②保留中の注文キャンセル")
ep = OrderCancel(accountID=account_id, orderID=order_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# 保留中の注文情報を再度確認
print("③保留中の注文情報を確認(キャンセル後)")
ep = OrderDetails(accountID=account_id, orderID=order_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

①保留中の注文情報を確認(キャンセル前)
{
  "order": {
    "id": "192",
    "createTime": "2020-02-21T12:34:03.881872950Z",
    "type": "LIMIT",
    "instrument": "USD_JPY",
    "units": "1",
    "timeInForce": "GTD",
    "price": "100.000",
    "gtdTime": "2020-02-28T12:34:01.000000000Z",
    "triggerCondition": "DEFAULT",
    "partialFill": "DEFAULT_FILL",
    "positionFill": "DEFAULT",
    "state": "PENDING"
  },
  "lastTransactionID": "199"
}

②保留中の注文キャンセル
{
  "orderCancelTransaction": {
    "type": "ORDER_CANCEL",
    "orderID": "192",
    "reason": "CLIENT_REQUEST",
    "id": "200",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "200",
    "requestID": "78694860810480470",
    "time": "2020-02-23T08:48:33.276317439Z"
  },
  "relatedTransactionIDs": [
    "200"
  ],
  "lastTransactionID": "200"
}

③保留中の注文情報を確認(キャンセル後)
{
  "order": {
    "id": "192",
    "createTime": "2020-02-21T12:34:03.881872950Z",
    "type": "LIMIT",
    "instrument": "USD_JPY",
    "units": "1",
    "timeInForce": "GTD",
    "price": "100.000",
    "gtdTime": "2020-02-28T12:34:01.000000000Z",
    "triggerCondition": "DEFAULT",
    "partialFill": "DEFAULT_FILL",
    "positionFill": "DEFAULT",
    "state": "CANCELLED",
    "cancellingTransactionID": "200",
    "cancelledTime": "2020-02-23T08:48:33.276317439Z"
  },
  "lastTransactionID": "200"
}

トレード操作系のAPI

トレード操作系のAPIは決済注文で使用されます。

このAPIはトレードIDに対して処理を実行していきます。

WEB取引画面の「取引中」ウィンドウに表示されている各取引に対して操作していくイメージです。

トレード操作系のAPIの一覧はoandapyV20.endpoints.tradesにまとめられていますが、その中でも実戦で役に立ちそうなものを以下にピックアップしました。

API用途
OpenTrades(accountID)取引中の全トレード情報を取得する
TradeDetails(accountID, tradeID) 指定したトレードIDの取引情報詳細を取得する
TradeCRCDO(accountID, tradeID, data)指定したトレードIDに対して注文を作成/変更/キャンセルする
TradeClose(accountID, tradeID, data=None)指定したトレードIDの取引を決済する

OpenTrades(accountID)

取引中の全トレード情報を取得します。

シストレ運用する場合、あまり使用頻度は高くないAPIとなりそうですが、一応載せておきます。

<Example>

import json
from oandapyV20.endpoints.trades import OpenTrades
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

api = API(access_token=access_token, environment=environment)

# 取引中の全トレード情報を取得する
ep = OpenTrades(accountID=account_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "trade": {
    "id": "191",
    "instrument": "USD_JPY",
    "price": "111.810",
    "openTime": "2020-02-21T11:51:05.079680857Z",
    "initialUnits": "500",
    "initialMarginRequired": "2236.1600",
    "state": "OPEN",
    "currentUnits": "500",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800"
  },
  "lastTransactionID": "204"
}

TradeDetails(accountID, tradeID)

引数に渡されたトレードIDの取引情報の詳細を取得します。

レスポンスの“state”より、現在のステータスがわかります。

  • OPEN: 取引中状態
  • CLOSED: 取引が決済済みの状態
  • CLOSE_WHEN_TRADEABLE: 取引がトレード不可からトレード可能状態になるとすぐに、決済される状態

シストレ運用する上で、利益確定注文(TAKE_PROFIT)ストップ注文(STOP_LOSS)が約定したかどうかを判別するには、このAPIを使用する必要がありそうです。

<Example>

import json
from oandapyV20.endpoints.trades import TradeCRCDO, TradeDetails
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

trade_id = 191  # 作成したトレードIDを指定

api = API(access_token=access_token, environment=environment)

# トレード詳細を取得
ep = TradeDetails(accountID=account_id, tradeID=trade_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "trade": {
    "id": "191",
    "instrument": "USD_JPY",
    "price": "111.810",
    "openTime": "2020-02-21T11:51:05.079680857Z",
    "initialUnits": "500",
    "initialMarginRequired": "2236.1600",
    "state": "OPEN",
    "currentUnits": "500",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800"
  },
  "lastTransactionID": "200"
}

TradeCRCDO(accountID, tradeID, data)

引数に渡されたトレードIDの取引に対し、新規注文、既存注文の変更、キャンセルを実行します。

ちなみに、CRCDOCreate/Replace/Cancel Dependent Ordersの略です。

引数のdataに与えるパラメータによって注文の種類を選択できます。

<Example>

import json
from oandapyV20.endpoints.trades import TradeCRCDO, TradeDetails
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

trade_id = 191  # 作成したトレードIDを指定

api = API(access_token=access_token, environment=environment)

# トレード詳細を取得
print("①トレード情報を確認(決済注文実行前)")
ep = TradeDetails(accountID=account_id, tradeID=trade_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# ========== ex01 ==========
# 決済注文作成、変更
# ==========================
data01 = {
    "takeProfit": {
        "price": "150.000",
        "timeInForce": "GTC",
    },
    "stopLoss": {
        "price": "100.000",
        "timeInForce": "GTC",
    },
}

# トレード注文実行
print("②決済注文の実行")
ep = TradeCRCDO(accountID=account_id, tradeID=trade_id, data=data01)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# トレード詳細を取得
print("③トレード情報を確認(決済注文実行後)")
ep = TradeDetails(accountID=account_id, tradeID=trade_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# ========== ex02 ==========
# 決済注文キャンセル
# ==========================
data02 = {
    "takeProfit": None,
    "stopLoss": None,
}

# トレード注文実行
print("④決済注文のキャンセル")
ep = TradeCRCDO(accountID=account_id, tradeID=trade_id, data=data02)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# トレード詳細を取得
print("⑤トレード情報を確認(決済注文キャンセル後)")
ep = TradeDetails(accountID=account_id, tradeID=trade_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

①トレード情報を確認(決済注文実行前)
{
  "trade": {
    "id": "191",
    "instrument": "USD_JPY",
    "price": "111.810",
    "openTime": "2020-02-21T11:51:05.079680857Z",
    "initialUnits": "500",
    "initialMarginRequired": "2236.1600",
    "state": "OPEN",
    "currentUnits": "500",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800"
  },
  "lastTransactionID": "200"
}

②決済注文の実行
{
  "takeProfitOrderTransaction": {
    "type": "TAKE_PROFIT_ORDER",
    "tradeID": "191",
    "timeInForce": "GTC",
    "triggerCondition": "DEFAULT",
    "price": "150.000",
    "reason": "CLIENT_ORDER",
    "id": "201",
    "accountID": "012-012-01234567-001",
    "userID": 01234567,
    "batchID": "201",
    "requestID": "78694866524112026",
    "time": "2020-02-23T09:11:15.114384039Z"
  },
  "stopLossOrderTransaction": {
    "type": "STOP_LOSS_ORDER",
    "tradeID": "191",
    "timeInForce": "GTC",
    "triggerCondition": "DEFAULT",
    "price": "100.000",
    "reason": "CLIENT_ORDER",
    "id": "202",
    "accountID": "012-012-01234567-001",
    "userID": 01234567,
    "batchID": "201",
    "requestID": "78694866524112026",
    "time": "2020-02-23T09:11:15.114384039Z"
  },
  "relatedTransactionIDs": [
    "201",
    "202"
  ],
  "lastTransactionID": "202"
}

③トレード情報を確認(決済注文実行後)
{
  "trade": {
    "id": "191",
    "instrument": "USD_JPY",
    "price": "111.810",
    "openTime": "2020-02-21T11:51:05.079680857Z",
    "initialUnits": "500",
    "initialMarginRequired": "2236.1600",
    "state": "OPEN",
    "currentUnits": "500",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800",
    "takeProfitOrder": {
      "id": "201",
      "createTime": "2020-02-23T09:11:15.114384039Z",
      "type": "TAKE_PROFIT",
      "tradeID": "191",
      "price": "150.000",
      "timeInForce": "GTC",
      "triggerCondition": "DEFAULT",
      "state": "PENDING"
    },
    "stopLossOrder": {
      "id": "202",
      "createTime": "2020-02-23T09:11:15.114384039Z",
      "type": "STOP_LOSS",
      "tradeID": "191",
      "price": "100.000",
      "timeInForce": "GTC",
      "triggerCondition": "DEFAULT",
      "state": "PENDING"
    }
  },
  "lastTransactionID": "202"
}

④決済注文のキャンセル
{
  "takeProfitOrderCancelTransaction": {
    "type": "ORDER_CANCEL",
    "orderID": "201",
    "reason": "CLIENT_REQUEST",
    "id": "203",
    "accountID": "012-012-01234567-001",
    "userID": 01234567,
    "batchID": "203",
    "requestID": "78694866524112308",
    "time": "2020-02-23T09:11:15.473791301Z"
  },
  "stopLossOrderCancelTransaction": {
    "type": "ORDER_CANCEL",
    "orderID": "202",
    "reason": "CLIENT_REQUEST",
    "id": "204",
    "accountID": "012-012-01234567-001",
    "userID": 01234567,
    "batchID": "203",
    "requestID": "78694866524112308",
    "time": "2020-02-23T09:11:15.473791301Z"
  },
  "relatedTransactionIDs": [
    "203",
    "204"
  ],
  "lastTransactionID": "204"
}

⑤トレード情報を確認(決済注文キャンセル後)
{
  "trade": {
    "id": "191",
    "instrument": "USD_JPY",
    "price": "111.810",
    "openTime": "2020-02-21T11:51:05.079680857Z",
    "initialUnits": "500",
    "initialMarginRequired": "2236.1600",
    "state": "OPEN",
    "currentUnits": "500",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800"
  },
  "lastTransactionID": "204"
}

TradeClose(accountID, tradeID, data=None)

引数に渡されたトレードIDの取引を決済します。

引数のdataに数量を指定することで、決済数量を指定することが可能です。

data=Noneを指定した場合は全決済となります。

<Example>

import json
from oandapyV20.endpoints.trades import TradeDetails, TradeClose
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

trade_id = 207  # 作成したトレードIDを指定

api = API(access_token=access_token, environment=environment)

# トレード詳細を取得
print("①トレード詳細を取得")
ep = TradeDetails(accountID=account_id, tradeID=trade_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# ========== ex01 ==========
# トレード全決済
# ==========================
data01 = None

# ========== ex02 ==========
# トレード一部決済
# ==========================
data02 = {
    "units": "30"
}

data = data01
# data = data02

# トレード注文実行
print("②トレード決済実行")
ep = TradeClose(accountID=account_id, tradeID=trade_id, data=data)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

①トレード詳細を取得
{
  "trade": {
    "id": "207",
    "instrument": "USD_JPY",
    "price": "111.348",
    "openTime": "2020-02-24T13:01:20.873733113Z",
    "initialUnits": "10000",
    "initialMarginRequired": "44538.4000",
    "state": "OPEN",
    "currentUnits": "10000",
    "realizedPL": "0.0000",
    "financing": "0.0000",
    "dividendAdjustment": "0.0000",
    "unrealizedPL": "200.0000",
    "marginUsed": "44548.0000"
  },
  "lastTransactionID": "207"
}

②トレード決済実行
{
  "orderCreateTransaction": {
    "type": "MARKET_ORDER",
    "instrument": "USD_JPY",
    "units": "-10000",
    "timeInForce": "FOK",
    "positionFill": "REDUCE_ONLY",
    "reason": "TRADE_CLOSE",
    "tradeClose": {
      "units": "ALL",
      "tradeID": "207"
    },
    "id": "208",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "208",
    "requestID": "24652095467368001",
    "time": "2020-02-24T13:17:57.345894224Z"
  },
  "orderFillTransaction": {
    "type": "ORDER_FILL",
    "orderID": "208",
    "instrument": "USD_JPY",
    "units": "-10000",
    "requestedUnits": "-10000",
    "price": "111.368",
    "pl": "200.0000",
    "financing": "0.0000",
    "commission": "0.0000",
    "accountBalance": "3001092.2842",
    "gainQuoteHomeConversionFactor": "1",
    "lossQuoteHomeConversionFactor": "1",
    "guaranteedExecutionFee": "0.0000",
    "halfSpreadCost": "20.0000",
    "fullVWAP": "111.368",
    "reason": "MARKET_ORDER_TRADE_CLOSE",
    "tradesClosed": [
      {
        "tradeID": "207",
        "units": "-10000",
        "realizedPL": "200.0000",
        "financing": "0.0000",
        "price": "111.368",
        "guaranteedExecutionFee": "0.0000",
        "halfSpreadCost": "20.0000"
      }
    ],
    "fullPrice": {
      "closeoutBid": "111.364",
      "closeoutAsk": "111.376",
      "timestamp": "2020-02-24T13:17:53.863668569Z",
      "bids": [
        {
          "price": "111.368",
          "liquidity": "250000"
        }
      ],
      "asks": [
        {
          "price": "111.372",
          "liquidity": "250000"
        }
      ]
    },
    "id": "209",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "208",
    "requestID": "24652095467368001",
    "time": "2020-02-24T13:17:57.345894224Z"
  },
  "relatedTransactionIDs": [
    "208",
    "209"
  ],
  "lastTransactionID": "209"
}

ポジション操作系のAPI

ポジション操作系のAPIは決済注文で使用されます。

トレード操作系のAPIが特定のトレードIDに対してのみ決済注文を出せたのに対し、ポジション操作系のAPIは特定の通貨ペアや、全保有ポジションの決済等を行うことができます。

WEB取引画面の「通貨ペア」ウィンドウに表示されている各ポジションに対して操作していくイメージです。

ポジション操作系のAPIの一覧はoandapyV20.endpoints.positionsにまとめられていますが、その中でも実戦で役に立ちそうなものを以下にピックアップしました。

API用途
OpenPositions(accountID)取引中の全ポジション情報を取得する
PositionDetails(accountID, instrument)指定した通貨ペアのポジション情報詳細を取得する
PositionClose(accountID, instrument, data)指定した通貨ペアのポジションを決済する

OpenPositions(accountID)

取引中の全ポジション情報を取得します。

シストレ運用する場合、あまり使用頻度は高くないAPIとなりそうですが、一応載せておきます。

<Example>

import json
from oandapyV20.endpoints.positions import OpenPositions
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

api = API(access_token=access_token, environment=environment)

# 取引中の全ポジション情報を取得する
ep = OpenPositions(accountID=account_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "positions": [
    {
      "instrument": "USD_JPY",
      "long": {
        "units": "500",
        "averagePrice": "111.810",
        "pl": "1079.9160",
        "resettablePL": "1079.9160",
        "financing": "13.5866",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "tradeIDs": [
          "191"
        ],
        "unrealizedPL": "-151.5000"
      },
      "short": {
        "units": "0",
        "pl": "-188.7600",
        "resettablePL": "-188.7600",
        "financing": "-12.4584",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "unrealizedPL": "0.0000"
      },
      "pl": "891.1560",
      "resettablePL": "891.1560",
      "financing": "1.1282",
      "commission": "0.0000",
      "dividendAdjustment": "0.0000",
      "guaranteedExecutionFees": "0.0000",
      "unrealizedPL": "-151.5000",
      "marginUsed": "2230.9800"
    }
  ],
  "lastTransactionID": "204"
}

PositionDetails(accountID, instrument)

引数に渡された通貨ペアのポジション情報の詳細を取得します。

<Example>

import json
from oandapyV20.endpoints.positions import PositionDetails
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

instrument = "USD_JPY"

api = API(access_token=access_token, environment=environment)
ep = PositionDetails(accountID=account_id, instrument=instrument)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

{
  "position": {
    "instrument": "USD_JPY",
    "long": {
      "units": "500",
      "averagePrice": "111.810",
      "pl": "1079.9160",
      "resettablePL": "1079.9160",
      "financing": "13.5866",
      "dividendAdjustment": "0.0000",
      "guaranteedExecutionFees": "0.0000",
      "tradeIDs": [
        "191"
      ],
      "unrealizedPL": "-151.5000"
    },
    "short": {
      "units": "0",
      "pl": "-188.7600",
      "resettablePL": "-188.7600",
      "financing": "-12.4584",
      "dividendAdjustment": "0.0000",
      "guaranteedExecutionFees": "0.0000",
      "unrealizedPL": "0.0000"
    },
    "pl": "891.1560",
    "resettablePL": "891.1560",
    "financing": "1.1282",
    "commission": "0.0000",
    "dividendAdjustment": "0.0000",
    "guaranteedExecutionFees": "0.0000",
    "unrealizedPL": "-151.5000",
    "marginUsed": "2230.9800"
  },
  "lastTransactionID": "204"
}

PositionClose(accountID, instrument, data)

引数に渡された通貨ペアのポジションを決済します。

引数のdataに数量を指定することで、決済数量を指定することが可能です。

数量指定を“ALL”にした場合は全決済となります。

<Example>

import json
from oandapyV20.endpoints.positions import OpenPositions, PositionClose
from oandapyV20 import API

access_token = <your access token>
account_id = <your account id>
environment = "practice"   # デモ口座

# ----------事前準備 ----------
# ポジションを保有しておく
# -----------------------------

api = API(access_token=access_token, environment=environment)

# オープン中の全ポジション情報を取得する
print("①オープン中の全ポジション情報を取得(決済前)")
ep = OpenPositions(accountID=account_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# ポジションをクローズする
data = {
    "longUnits": "400",
    "shortUnits": "ALL"
}

print("②ポジションをクローズ")
ep = PositionClose(accountID=account_id, instrument="USD_JPY", data=data)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

# オープン中の全ポジション情報を取得する
print("③オープン中の全ポジション情報を取得(決済後)")
ep = OpenPositions(accountID=account_id)
rsp = api.request(ep)
print(json.dumps(rsp, indent=2))

<Response>

①オープン中の全ポジション情報を取得(決済前)
{
  "positions": [
    {
      "instrument": "USD_JPY",
      "long": {
        "units": "800",
        "averagePrice": "111.647",
        "pl": "1279.9160",
        "resettablePL": "1279.9160",
        "financing": "13.5866",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "tradeIDs": [
          "191",
          "213"
        ],
        "unrealizedPL": "-260.2000"
      },
      "short": {
        "units": "-1000",
        "averagePrice": "111.373",
        "pl": "-188.7600",
        "resettablePL": "-188.7600",
        "financing": "-12.4584",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "tradeIDs": [
          "211"
        ],
        "unrealizedPL": "47.0000"
      },
      "pl": "1091.1560",
      "resettablePL": "1091.1560",
      "financing": "1.1282",
      "commission": "0.0000",
      "dividendAdjustment": "0.0000",
      "guaranteedExecutionFees": "0.0000",
      "unrealizedPL": "-213.2000",
      "marginUsed": "4452.9600"
    }
  ],
  "lastTransactionID": "213"
}

②ポジションをクローズ
{
  "longOrderCreateTransaction": {
    "type": "MARKET_ORDER",
    "instrument": "USD_JPY",
    "units": "-400",
    "timeInForce": "FOK",
    "positionFill": "REDUCE_ONLY",
    "reason": "POSITION_CLOSEOUT",
    "longPositionCloseout": {
      "instrument": "USD_JPY",
      "units": "400"
    },
    "id": "214",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "214",
    "requestID": "24652099239768449",
    "time": "2020-02-24T13:32:56.578567028Z"
  },
  "longOrderFillTransaction": {
    "type": "ORDER_FILL",
    "orderID": "214",
    "instrument": "USD_JPY",
    "units": "-400",
    "requestedUnits": "-400",
    "price": "111.322",
    "pl": "-195.2000",
    "financing": "0.0000",
    "commission": "0.0000",
    "accountBalance": "3000897.0842",
    "gainQuoteHomeConversionFactor": "1",
    "lossQuoteHomeConversionFactor": "1",
    "guaranteedExecutionFee": "0.0000",
    "halfSpreadCost": "0.8000",
    "fullVWAP": "111.322",
    "reason": "MARKET_ORDER_POSITION_CLOSEOUT",
    "tradeReduced": {
      "tradeID": "191",
      "units": "-400",
      "realizedPL": "-195.2000",
      "financing": "0.0000",
      "price": "111.322",
      "guaranteedExecutionFee": "0.0000",
      "halfSpreadCost": "0.8000"
    },
    "fullPrice": {
      "closeoutBid": "111.318",
      "closeoutAsk": "111.330",
      "timestamp": "2020-02-24T13:32:55.620989647Z",
      "bids": [
        {
          "price": "111.322",
          "liquidity": "250000"
        }
      ],
      "asks": [
        {
          "price": "111.326",
          "liquidity": "250000"
        }
      ]
    },
    "id": "215",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "214",
    "requestID": "24652099239768449",
    "time": "2020-02-24T13:32:56.578567028Z"
  },
  "shortOrderCreateTransaction": {
    "type": "MARKET_ORDER",
    "instrument": "USD_JPY",
    "units": "1000",
    "timeInForce": "FOK",
    "positionFill": "REDUCE_ONLY",
    "reason": "POSITION_CLOSEOUT",
    "shortPositionCloseout": {
      "instrument": "USD_JPY",
      "units": "ALL"
    },
    "id": "216",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "214",
    "requestID": "24652099239768449",
    "time": "2020-02-24T13:32:56.578567028Z"
  },
  "shortOrderFillTransaction": {
    "type": "ORDER_FILL",
    "orderID": "216",
    "instrument": "USD_JPY",
    "units": "1000",
    "requestedUnits": "1000",
    "price": "111.326",
    "pl": "47.0000",
    "financing": "0.0000",
    "commission": "0.0000",
    "accountBalance": "3000944.0842",
    "gainQuoteHomeConversionFactor": "1",
    "lossQuoteHomeConversionFactor": "1",
    "guaranteedExecutionFee": "0.0000",
    "halfSpreadCost": "2.0000",
    "fullVWAP": "111.326",
    "reason": "MARKET_ORDER_POSITION_CLOSEOUT",
    "tradesClosed": [
      {
        "tradeID": "211",
        "units": "1000",
        "realizedPL": "47.0000",
        "financing": "0.0000",
        "price": "111.326",
        "guaranteedExecutionFee": "0.0000",
        "halfSpreadCost": "2.0000"
      }
    ],
    "fullPrice": {
      "closeoutBid": "111.318",
      "closeoutAsk": "111.330",
      "timestamp": "2020-02-24T13:32:55.620989647Z",
      "bids": [
        {
          "price": "111.322",
          "liquidity": "249600"
        }
      ],
      "asks": [
        {
          "price": "111.326",
          "liquidity": "250000"
        }
      ]
    },
    "id": "217",
    "accountID": "012-012-01234567-001",
    "userID": 12345678,
    "batchID": "214",
    "requestID": "24652099239768449",
    "time": "2020-02-24T13:32:56.578567028Z"
  },
  "relatedTransactionIDs": [
    "214",
    "215",
    "216",
    "217"
  ],
  "lastTransactionID": "217"
}

③オープン中の全ポジション情報を取得(決済後)
{
  "positions": [
    {
      "instrument": "USD_JPY",
      "long": {
        "units": "400",
        "averagePrice": "111.484",
        "pl": "1084.7160",
        "resettablePL": "1084.7160",
        "financing": "13.5866",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "tradeIDs": [
          "191",
          "213"
        ],
        "unrealizedPL": "-64.6000"
      },
      "short": {
        "units": "0",
        "pl": "-141.7600",
        "resettablePL": "-141.7600",
        "financing": "-12.4584",
        "dividendAdjustment": "0.0000",
        "guaranteedExecutionFees": "0.0000",
        "unrealizedPL": "0.0000"
      },
      "pl": "942.9560",
      "resettablePL": "942.9560",
      "financing": "1.1282",
      "commission": "0.0000",
      "dividendAdjustment": "0.0000",
      "guaranteedExecutionFees": "0.0000",
      "unrealizedPL": "-64.6000",
      "marginUsed": "1781.2000"
    }
  ],
  "lastTransactionID": "217"
}

ワンナップおまけ情報

OANDA APIでシストレ運用していく上で知っておくと便利な情報を載せておきます。

両建可能/不可能アカウントのAPI動作の違い

APIで注文を出すときに、オプションで“positionFill”の指定ができますが、実はこのオプション、両建可能/不可アカウントに深く関わってきます。

まず指定できるパラメータとその意味説明をすると、以下のようになります。

パラメータ用途
OPEN_ONLY新規ポジションを増やす用途のみで使用可
 ⇒要は両建してポジションをとる
REDUCE_FIRSTポジションを保有していた場合は優先して減少させる
新規ポジションを増やすことは可能
 ⇒要は両建しないでポジションをとる
REDUCE_ONLY保有ポジション数を減少させる用途のみで指定可能
新規ポジションを増やすことは不可
DEFAULT両建不可アカウントの場合、”REDUCE_FIRST”となり、両建可能アカウントの場合、”OPEN_ONLY”となる。

“DEFAULT”を指定した場合、アカウントの種類によって動作が異なり、両建可能または、両建不可に応じた動作となります。

しかし、ここでのポイントは両建可能アカウントでも“REDUCE_FIRST”が指定できるということです。

“REDUCE_FIRST”が指定された場合、両建可能アカウントであったとしても両建しない注文を出すことができます。

逆に、両建不可アカウントの場合に“OPEN_ONLY”を指定しても注文が強制的にキャンセルされてしまいます。

以上のことから、アカウントの作成する際は両建可能アカウントにしておいたほうが無難だと思います。

有効期間(Time in Force)

注文を出す際の引数dataに設定できるパラメータ“timeInForce”では注文の有効期間を指示することができます。

  • GTC: キャンセルされるまで有効
  • GTD: 指定された日時まで有効
  • GFD: 当日のニューヨーク時間17時まで有効
  • FOK: 注文数量の全部が即座に約定しない場合、注文数量の全部を即座に失効させる
  • IOC: 指定した価格かそれよりも有利な価格で、即時に一部あるいは全数量を約定させ、成立しなかった注文数量をキャンセルさせる

「MIT注文」と「指値注文」の違い

MIT注文(MARKET_IF_TOUCHED)指値(LIMIT)注文の違いについて調べたので紹介していきます。

MIT注文も指値注文もどちらも指定した条件を満たすと執行処理に移る点は同じ。

違いは執行処理中に条件を外れた場合の動作になります。

  • 指値注文: 執行が完了する前に条件を外れた場合、注文は停止される。
  • MIT注文: 条件から外れても注文は停止しない。その場合、成行きで注文が実行される。

本来、条件を満たすと即座に執行が完了するのですが、ロットサイズが大きい場合、執行処理に時間がかかるらしい。

よって、ロットサイズが大きい場合の注文はMIT注文も考えたほうが良いのかもしれません。

さいごに

OANDA APIの注文仕様について色々調べてみたり、実際に動かしてみて動作を確認した結果の備忘録的な感じでこの記事を書いてみました。

ネットで調べてもあまり情報が出てこなかったり、出てきても英語の情報だったりしたのでもしかしたら間違ったことを書いてしまっているかもしれません。

そのときはご指摘いただけると嬉しいです。

さいごに、今回作成したサンプル・コードはGitHubにUPしていますので、よかったら使ってみてください。

 ・github.com/takkin-takilog/python-eclipse-sample/tree/master/fx/orders

スポンサーリンク

コメント

タイトルとURLをコピーしました