OANDA APIで注文、決済

スポンサーリンク
スポンサーリンク

注文

接続までの箇所は、接続ページとほぼ同じですが、import oandapyV20.endpoints.orders as ordersをインポートして使用します。

注文の種類

注文の種類は以下のように多彩ですが、内容について多分あっていると思いますが検証していません。

設定値(type意味内容
MARKET成行注文
LIMIT指値注文
STOP逆指値注文
MARKET_IF_TOUCHEDマーケット・イフ・タッチ注文成行に近い注文で、マーケットより低いレートで買い注文、もしくは高いレートで売り注文を行う方法です。要はスリッページで悪い方に行かないという意味だと思います。
TAKE_PROFITテイクプロフィット注文利益額の範囲を事前に決めてそのレートに達した時点で自動的に決済する方法です。
STOP_LOSSストップロス注文損失額の範囲を事前に決めてそのレートに達した時点で自動的に決済する方法です。
TRAILING_STOP_LOSSトレーリングストップロス注文マーケットに合わせてストップロス注文を自動的に修正する方法です。
FIXED_PRICE固定価格注文OCO注文のことかもしれません。OANDA JAPANにはOCO注文ができると記載されています。
OCO注文は、2つ同時に注文を出し、どちらか決まったら残った方をキャンセルするという方法です。

以下にドキュメンがありますので、合わせて確認していただくといいと思います。

Order

成行注文

# パラメーター
data = {
  "order": {
    "instrument": "USD_JPY",
    "units": 1000,
    "type": "MARKET",
    "positionFill": "DEFAULT"
  }
}

# API経由で成行注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

成行注文では以下のパラメーターの設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • type:注文方法:成行はMARKET
  • positionFill:両建ての指定:通常はDEFAULT
    • DEFAULT
      • 両建不可アカウントの場合:REDUCE_FIRST
      • 両建可能アカウントの場合:OPEN_ONLY
    • OPEN_ONLY:新規のみ
    • REDUCE_ONLY:決済のみ
    • REDUCE_FIRST:決済を優先

システム例

以下は、より実践に近い形のシステムで、ポイントは注文した際にOANDA側にキャンセルされた際のアクションも作ってあります。例えば、証拠金が足りないなどの事態で一方的にキャンセルされたりします。

# APIのPythonラッパーをインポート
from oandapyV20 import API
import oandapyV20.endpoints.orders as orders

import settings

# OANDA API アクセストークンと口座ID
accountID       = settings.ACCOUNT_ID
access_token    = settings.ACCESS_TOKEN

# APIに接続
api = API(environment="practice", access_token=access_token)

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
trade_type = "MARKET"
# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "positionFill": "DEFAULT"
  }
}

# 注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)
# print(json.dumps(res.response, indent=2))

if res.response.get('orderFillTransaction') is not None:
    tickets = res.response['orderFillTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))
    
elif res.response.get('orderCreateTransaction') is not None:
    tickets = res.response['orderCreateTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))


else:
    tickets = res.response['orderCancelTransaction']
    reason = tickets['reason']
    tradeID = tickets["id"]
    
    print("Error(reason):{} orderID:{}".format(reason, tradeID))


# orderID:23379 price:107.417 units:1000
以下のように管理画面に反映されています。

オーターと注文確定で別々のチケットがあります。
orderIDは決済する時に必要ですのでシステムに保持しましょう。

両建てについて(positionFill

OANDAはコースによって、両建てが可能になっていますが、現在APIでは両建てできません

仕様は両建てをするかしないかを強制的に決めることができます。しかし、基本的にはこちらの意図で実行すればいいので、"positionFill": "DEFAULT"で良いと思います。

パラメーター一覧
OPEN_ONLY新規ポジションのみ。両建する。
REDUCE_FIRSTポジションがあれば決済し、ない場合は新規ポジションを作成する。
REDUCE_ONLYポジションがあれば決済する。ない場合でも新規ポジションは作成しない。
DEFAULT両建が可能な場合は”OPEN_ONLY”、両建が不可の場合は”REDUCE_FIRST”になる。

指値注文

# パラメーター
data = {
  "order": {
    "instrument": "USD_JPY",
    "units": 1000,
    "type": "LIMIT",
    "price": 107.15,
    "positionFill": "DEFAULT"
  }
}

# API経由で指値注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

指値注文では、パラメーターに以下の設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • price価格:指値の価格です。
  • type:注文方法:指値はLIMIT
  • timeInForce:注文の期限:詳細は下記にて。任意。
  • positionFill:両建ての指定:通常はDEFAULT

私のシストレでは指値注文という考えがほとんどないのでここでは簡単に説明します。

システム例

# APIのPythonラッパーをインポート
from oandapyV20 import API
import oandapyV20.endpoints.orders as orders

import settings

# OANDA API アクセストークンと口座ID
accountID       = settings.ACCOUNT_ID
access_token    = settings.ACCESS_TOKEN

# APIに接続
api = API(environment="practice", access_token=access_token)

# -----------------------------------------------------------------------
# 設定情報
currency = "EUR_JPY"
units = 1000
price = 116.4
trade_type = "LIMIT"
# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "positionFill": "DEFAULT"
  }
}

# 注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)
print(json.dumps(res.response, indent=2))


if res.response.get('orderFillTransaction') is not None:
    tickets = res.response['orderFillTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))
    
elif res.response.get('orderCreateTransaction') is not None:
    tickets = res.response['orderCreateTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))


else:
    tickets = res.response['orderCancelTransaction']
    reason = tickets['reason']
    tradeID = tickets["id"]
    
    print("Error(reason):{} orderID:{}".format(reason, tradeID))


# orderID:23383 price:116.400 units:1000

以下のように管理画面の「注文中」のタブ内に反映されています。

注文の期限(timeInForce

指値注文では注文の期限を任意に指定することができますが、これもシステム側で基本的には判断すればいいかと考えています。省略した時のデフォルト値はGTCの無期限になります。

GTC無期限(OANDA JAPANのサイトには100 日間とあるのでどちらかだと思います。
GTD指定されて日時まで
GFD当日のニューヨーク時間の17時まで
FOK注文数量の全てが約定しない場合、全ての注文をキャンセルする?
IOC注文数量の全てが約定しない場合、全ての注文を約定させる?

ちょっと私の英語力では下の2つがちょっと不明です。。。以下のドキュメントを参照してください。

Order

その他にも以下のようにパラメーターを追加するとストップロスの設定ができるなど多彩な注文方法がありますが、ここでは省略します。

"stopLossOnFill": {
  "timeInForce": "GTC",
  "price": "1.22"
},

逆指値注文

data = {
  "order": {
    "instrument": "USD_JPY",
    "units": 1000,
    "type": "STOP",
    "price": 107.15,
    "positionFill": "DEFAULT"
  }
}

# API経由で逆指値注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

逆指値注文では、パラメーターに以下の設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • price価格:指値の価格です。
  • type:注文方法:逆指値はSTOP
  • timeInForce:注文の期限:任意
  • positionFill:両建ての指定:通常はDEFAULT

システム例

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
price = 108.650
trade_type = "STOP"

# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "positionFill": "DEFAULT"
  }
}

# API経由で逆指値注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)
print(json.dumps(res.response, indent=2))

# {
#   "orderCreateTransaction": {
#     "type": "STOP_ORDER",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "price": "108.650",
#     "timeInForce": "GTC",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT",
#     "positionFill": "DEFAULT",
#     "reason": "CLIENT_ORDER",
#     "id": "23754",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23754",
#     "requestID": "42715683966828197",
#     "time": "2020-07-09T07:01:24.081859570Z"
#   },
#   "relatedTransactionIDs": [
#     "23754"
#   ],
#   "lastTransactionID": "23754"
# }

IFD注文(イフダン)

新規注文と同時に決済注文を出す方法です。
以下の例では指値の新規注文になっていますが、成り行きでも新規注文と同時に決済注文を出すことができます。

# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "takeProfitOnFill":{
        "timeInForce": "GTC",
        "price": 108.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

IFD注文(イフダン)では、パラメーターに以下の設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • price価格:指値の価格です。
  • type:注文方法:指値はLIMIT
  • takeProfitOnFill:テイクプロフィット注文
    • timeInForce:注文の期限
    • price価格:利確させる指値の価格です。
  • timeInForce:注文の期限:任意
  • positionFill:両建ての指定:通常はDEFAULT

システム例

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
price = 106.650
trade_type = "LIMIT"


# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "takeProfitOnFill":{
        "timeInForce": "GTC",
        "price": 108.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)
print(json.dumps(res.response, indent=2))

# {
#   "orderCreateTransaction": {
#     "type": "LIMIT_ORDER",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "price": "106.650",
#     "timeInForce": "GTC",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT",
#     "positionFill": "DEFAULT",
#     "takeProfitOnFill": {
#       "price": "108.650",
#       "timeInForce": "GTC"
#     },
#     "reason": "CLIENT_ORDER",
#     "id": "23755",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23755",
#     "requestID": "78744482726534211",
#     "time": "2020-07-09T07:08:19.671568047Z"
#   },
#   "relatedTransactionIDs": [
#     "23755"
#   ],
#   "lastTransactionID": "23755"
# }

新規+損切注文(ストップロス)

新規注文と同時に損切注文(ストップロス)を出す方法です。
以下の例では指値の新規注文になっていますが、成り行きでも新規注文と同時に決済注文を出すことができます。

# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "stopLossOnFill":{
        "timeInForce": "GTC",
        "price": 105.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

IFD注文(イフダン)では、パラメーターに以下の設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • price価格:指値の価格です。
  • type:注文方法:指値はLIMIT
  • stopLossOnFill:ストップロス注文
    • timeInForce:注文の期限
    • price価格:損切りさせる指値の価格です。
  • timeInForce:注文の期限:任意
  • positionFill:両建ての指定:通常はDEFAULT

システム例

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
price = 106.650
trade_type = "LIMIT"

# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "stopLossOnFill":{
        "timeInForce": "GTC",
        "price": 105.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)
print(json.dumps(res.response, indent=2))

# {
#   "orderCreateTransaction": {
#     "type": "LIMIT_ORDER",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "price": "106.650",
#     "timeInForce": "GTC",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT",
#     "positionFill": "DEFAULT",
#     "stopLossOnFill": {
#       "price": "105.650",
#       "timeInForce": "GTC"
#     },
#     "reason": "CLIENT_ORDER",
#     "id": "23756",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23756",
#     "requestID": "78744486213978801",
#     "time": "2020-07-09T07:22:11.490303981Z"
#   },
#   "relatedTransactionIDs": [
#     "23756"
#   ],
#   "lastTransactionID": "23756"
# }

IFO注文

IFO注文は、新規注文と同時に決済注文と損切注文(ストップロス)を出す方法です。
以下の例では指値の新規注文になっていますが、成り行きでも新規注文と同時に決済注文を出すことができます。

# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "takeProfitOnFill":{
        "timeInForce": "GTC",
        "price": 108.650
    },      
    "stopLossOnFill":{
        "timeInForce": "GTC",
        "price": 105.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

IFO注文では、パラメーターに以下の設定が必要です。

  • instrument:通貨ペア:USD_JPYなど
  • units:数量:1枚から注文できます。マイナスにすると売りになります。
  • price価格:指値の価格です。
  • type:注文方法:指値はLIMIT
  • takeProfitOnFill:テイクプロフィット注文
    • timeInForce:注文の期限
    • price価格:利確させる指値の価格です。
  • stopLossOnFill:ストップロス注文
    • timeInForce:注文の期限
    • price価格:損切りさせる指値の価格です。
  • timeInForce:注文の期限:任意
  • positionFill:両建ての指定:通常はDEFAULT

システム例

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
price = 106.650
trade_type = "LIMIT"

# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "takeProfitOnFill":{
        "timeInForce": "GTC",
        "price": 108.650
    },      
    "stopLossOnFill":{
        "timeInForce": "GTC",
        "price": 105.650
    },
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderCreate(accountID, data=data)
api.request(res)

print(json.dumps(res.response, indent=2))
# {
#   "orderCreateTransaction": {
#     "type": "LIMIT_ORDER",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "price": "106.650",
#     "timeInForce": "GTC",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT",
#     "positionFill": "DEFAULT",
#     "takeProfitOnFill": {
#       "price": "108.650",
#       "timeInForce": "GTC"
#     },
#     "stopLossOnFill": {
#       "price": "105.650",
#       "timeInForce": "GTC"
#     },
#     "reason": "CLIENT_ORDER",
#     "id": "23757",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23757",
#     "requestID": "78744486952589873",
#     "time": "2020-07-09T07:25:07.407429349Z"
#   },
#   "relatedTransactionIDs": [
#     "23757"
#   ],
#   "lastTransactionID": "23757"
# }

注文情報を取得

注文の一覧を取得

res = orders.OrderList(accountID)
api.request(res)

orders.OrderListaccountIDを渡すだけです。

不具合なのか、私が悪いのか、50件しか取得できません。注意してください。

システム例

import json

res = orders.OrderList(accountID)
api.request(res)

print(json.dumps(res.response, indent=2))

{
#   "orders": [
#     {
#       "id": "23744",
#       "createTime": "2020-07-09T04:56:32.171986413Z",
#       "type": "LIMIT",
#       "instrument": "USD_JPY",
#       "units": "1000",
#       "timeInForce": "GTC",
#       "price": "106.650",
#       "triggerCondition": "DEFAULT",
#       "partialFill": "DEFAULT_FILL",
#       "positionFill": "DEFAULT",
#       "state": "PENDING"
#     }
#   ],
#   "lastTransactionID": "23744"
# }

ペンディングの注文一覧を取得

res = orders.OrdersPending(accountID)
api.request(res)

orders.OrdersPendingaccountIDを渡すだけです。
orders.OrderListとの大きな違いは以下の通りです。

  • 全ての注文を取得できる。orders.OrderListはなぜか50件しか取得できない。
  • orders.OrderClientExtensionsでオーダーに設定したクライアント拡張機能の値を取得できる。

システム例

res = orders.OrdersPending(accountID)
api.request(res)

print(json.dumps(res.response, indent=2))

# {
#   "orders": [
#     {
#       "id": "23744",
#       "createTime": "2020-07-09T04:56:32.171986413Z",
#       "type": "LIMIT",
#       "instrument": "USD_JPY",
#       "units": "1000",
#       "timeInForce": "GTC",
#       "price": "106.650",
#       "triggerCondition": "DEFAULT",
#       "partialFill": "DEFAULT_FILL",
#       "positionFill": "DEFAULT",
#       "state": "PENDING"
#     }
#   ],
#   "lastTransactionID": "23744"
# }

注文の詳細を取得

res = orders.OrderDetails(accountID, orderID)
api.request(res)

orders.OrderDetailsaccountIDorderIDを渡すだけです。

trans.TransactionDetailsとの大きな違いは以下の通りです。

  • reasonを取得できない。
  • typeの値から_ORDERが排除され、TAKE_PROFIT_ORDERTAKE_PROFITとなる。
  • orders.OrderClientExtensionsでオーダーに設定したクライアント拡張機能の値を取得できる。

システム例

orderID = 23744

res = orders.OrderDetails(accountID, orderID)
api.request(res)

print(json.dumps(res.response, indent=2))
# {
#   "order": {
#     "id": "23744",
#     "createTime": "2020-07-09T04:56:32.171986413Z",
#     "type": "LIMIT",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "timeInForce": "GTC",
#     "price": "106.650",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT_FILL",
#     "positionFill": "DEFAULT",
#     "state": "PENDING"
#   },
#   "lastTransactionID": "23744"
# }

注文情報にコメントなどを保存(クライアント拡張機能

data = {
  "clientExtensions": {
    "comment": "hogehoge",
    "id": "12345"
  }
}

res = orders.OrderClientExtensions(accountID, 93571, data=data)
api.request(res)

orders.OrderClientExtensionsを使用して、自身で構築したシステムのIDやコメントなどを注文情報に保存(埋め込む)ことができます。

新規注文時のパラメーターにclientExtensionsを入れてもエラーになります。

保存(埋め込む)した情報は、orders.OrderDetailsclientExtensionsModifyで取得できます。

保存した情報は、trans.TransactionDetailsでは取得できないので注意しましょう。

また、新規注文に情報を埋め込んでも、指値注文の約定したオーダーや建玉の決済情報などに引き継がれません。それぞれに同じように情報を保存してあげる必要があります。

システム例

# オーダー詳細を取得

orderID = 93571

res = orders.OrderDetails(accountID=accountID, orderID=orderID)
api.request(res)
res.response

# {'order': {'id': '93571',
#   'createTime': '2020-10-16T14:26:01.947194844Z',
#   'type': 'TAKE_PROFIT',
#   'tradeID': '93570',
#   'price': '1.17282',
#   'timeInForce': 'GTC',
#   'triggerCondition': 'DEFAULT',
#   'state': 'PENDING'},
#  'lastTransactionID': '93622'}

# オーダーに情報を埋め込む
data = {
  "clientExtensions": {
    "comment": "hogehoge",
    "id": "12345"
  }
}

res = orders.OrderClientExtensions(accountID, orderID, data=data)
api.request(res)
res.response

# {'orderClientExtensionsModifyTransaction': {'id': '93623',
#   'accountID': '',
#   'userID':,
#   'batchID': '93623',
#   'requestID': '78781092515906722',
#   'time': '2020-10-18T07:42:33.990702202Z',
#   'type': 'ORDER_CLIENT_EXTENSIONS_MODIFY',
#   'orderID': '93571',
#   'clientExtensionsModify': {'id': '12345', 'comment': 'hogehoge'}},
#  'relatedTransactionIDs': ['93623'],
#  'lastTransactionID': '93623'}

# もう一度、オーダー詳細を取得する
res = orders.OrderDetails(accountID=accountID, orderID=orderID)
api.request(res)
res.response

# {'order': {'id': '93571',
#   'createTime': '2020-10-16T14:26:01.947194844Z',
#   'type': 'TAKE_PROFIT',
#   'tradeID': '93570',
#   'price': '1.17282',
#   'timeInForce': 'GTC',
#   'triggerCondition': 'DEFAULT',
#   'state': 'PENDING',
#   'clientExtensions': {'id': '12345', 'comment': 'hogehoge'}},
#  'lastTransactionID': '93623'}

注文のキャンセル

res = orders.OrderCancel(accountID, orderID=12345)
api.request(res)

orders.OrderCancelを使用します。パラメーターの設定がほとんどなく、以下のみとなります。

  • orderID:注文ID:取り消したい注文IDです。上記の指値注文などで取得したIDを利用します。

システム例

# APIのPythonラッパーをインポート
from oandapyV20 import API
import oandapyV20.endpoints.orders as orders

import settings

# OANDA API アクセストークンと口座ID
accountID       = settings.ACCOUNT_ID
access_token    = settings.ACCESS_TOKEN

# APIに接続
api = API(environment="practice", access_token=access_token)

# -----------------------------------------------------------------------
# 設定情報
orderID = 23388
# -----------------------------------------------------------------------

# 注文を実行
res = orders.OrderCancel(accountID, orderID=orderID)
api.request(res)
print(json.dumps(res.response, indent=2))

if res.response.get('orderFillTransaction') is not None:
    tickets = res.response['orderFillTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))
    
elif res.response.get('orderCreateTransaction') is not None:
    tickets = res.response['orderCreateTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))


else:
    tickets = res.response['orderCancelTransaction']
    reason = tickets['reason']
    tradeID = tickets["id"]
    
    print("Error(reason):{} orderID:{}".format(reason, tradeID))


# Error(reason):CLIENT_REQUEST orderID:23389

以下のように管理画面の「取引履歴」のタブ内に反映されています。

全注文のキャンセル

OANDA JAPANでは全ての注文を一括でキャンセルする方法は用意されていません。

注文一覧をループさせて個別にキャンセルするしかないです。

システム例

res = orders.OrdersPending(accountID)
api.request(res)

# print(json.dumps(res.response, indent=2))
for details in res.response["orders"]:
    print(details["id"])

    # API経由でキャンセルを実行
    resCancel = orders.OrderCancel(accountID, orderID=details["id"])
    api.request(resCancel)
    print(json.dumps(resCancel.response, indent=2))

# 23764
# {
#   "orderCancelTransaction": {
#     "type": "ORDER_CANCEL",
#     "orderID": "23764",
#     "reason": "CLIENT_REQUEST",
#     "id": "23767",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23767",
#     "requestID": "60730099324088721",
#     "time": "2020-07-09T08:08:21.561599571Z"
#   },
#   "relatedTransactionIDs": [
#     "23767"
#   ],
#   "lastTransactionID": "23767"
# }
# 23758
# {
#   "orderCancelTransaction": {
#     "type": "ORDER_CANCEL",
#     "orderID": "23758",
#     "reason": "CLIENT_REQUEST",
#     "id": "23768",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23768",
#     "requestID": "60730099324089179",
#     "time": "2020-07-09T08:08:21.747747953Z"
#   },
#   "relatedTransactionIDs": [
#     "23768"
#   ],
#   "lastTransactionID": "23768"
# }

注文の修正(置き換え)

OANDA JAPANのAPIでは、注文の修正という処理はなく、キャンセルと同時に新規注文を作成し、注文を置き換えるという仕組みになっています。

# 設定情報
orderID = 12345

# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderReplace(accountID, orderID=orderID, data=data)
api.request(res)

orders.OrderReplaceaccountIDorderIDdataを渡すだけです。dataは注文と同じ仕様です。

システム例

# 設定情報
orderID = 23762

res = orders.OrderDetails(accountID, orderID)
api.request(res)

print(json.dumps(res.response, indent=2))
# {
#   "order": {
#     "id": "23762",
#     "createTime": "2020-07-09T07:38:32.773382397Z",
#     "replacesOrderID": "23760",
#     "type": "LIMIT",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "timeInForce": "GTC",
#     "price": "106.650",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT_FILL",
#     "positionFill": "DEFAULT",
#     "state": "PENDING"
#   },
#   "lastTransactionID": "23762"
# }

# -----------------------------------------------------------------------
# 設定情報
currency = "USD_JPY"
units = 1000
price = 105.650
trade_type = "LIMIT"
# -----------------------------------------------------------------------
# パラメーター
data = {
  "order": {
    "instrument": currency,
    "units": units,
    "type": trade_type,
    "price": price,
    "positionFill": "DEFAULT"
  }
}

# API経由で注文を実行
res = orders.OrderReplace(accountID, orderID=orderID, data=data)
api.request(res)

print(json.dumps(res.response, indent=2))
# {
#   "orderCancelTransaction": {
#     "type": "ORDER_CANCEL",
#     "orderID": "23762",
#     "replacedByOrderID": "23764",
#     "reason": "CLIENT_REQUEST_REPLACED",
#     "id": "23763",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23763",
#     "requestID": "78744490410668207",
#     "time": "2020-07-09T07:38:51.529364612Z"
#   },
#   "orderCreateTransaction": {
#     "type": "LIMIT_ORDER",
#     "instrument": "USD_JPY",
#     "units": "1000",
#     "price": "105.650",
#     "timeInForce": "GTC",
#     "triggerCondition": "DEFAULT",
#     "partialFill": "DEFAULT",
#     "positionFill": "DEFAULT",
#     "reason": "REPLACEMENT",
#     "replacesOrderID": "23762",
#     "id": "23764",
#     "accountID": "",
#     "userID": ,
#     "batchID": "23763",
#     "requestID": "78744490410668207",
#     "time": "2020-07-09T07:38:51.529364612Z"
#   },
#   "relatedTransactionIDs": [
#     "23763",
#     "23764"
#   ],
#   "lastTransactionID": "23764"
# }

決済

建玉別の決済(注文に基づく決済)

注文とほぼ同じですが、import oandapyV20.endpoints.trades as traderをインポートして使用します。

# 設定情報
data = {
    "units": "1000"
}

# 決済を実行
res = trades.TradeClose(accountID=accountID, tradeID=23413, data=data)
api.request(res)

設定は以下だけです。

  • tradeID:注文ID:決済したい注文IDです。
  • data
    • units:数量:決済したい数量。同じ建玉の全ての数量の場合はNoneと指定してもいいです。

ポイント

  • 数量は売りでも買いでも自然数(マイナス指定しない)です。そして文字列に変換しないとエラーになります。
  • 決済後に、単体取引の損益(tickets["pl"])と口座の証拠金情報(tickets["accountBalance"])も一緒に取得できます。

システム例

# APIのPythonラッパーをインポート
from oandapyV20 import API
import oandapyV20.endpoints.trades as trades

import settings

# OANDA API アクセストークンと口座ID
accountID       = settings.ACCOUNT_ID
access_token    = settings.ACCESS_TOKEN

# APIへ接続
api = API(environment="practice", access_token=access_token)

# -----------------------------------------------------------------------
# 設定情報
orderID = 23413
units = 1000
# -----------------------------------------------------------------------
# パラメーター
if units is None:
    data = None
else:
    data = {
        "units": str(units)
    }

# 決済を実行
res = trades.TradeClose(accountID=accountID, tradeID=orderID, data=data)
api.request(res)
print(json.dumps(res.response, indent=2))

if res.response.get('orderFillTransaction') is not None:
    tickets = res.response['orderFillTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    pl              = float(tickets["pl"])
    accountBalance  = int(float(tickets["accountBalance"]))

    print ('orderID:{} price:{} units:{} pl:{} accountBalance:{}'.format(tradeID, price, units, pl, accountBalance))
    
elif res.response.get('orderCreateTransaction') is not None:
    tickets = res.response['orderCreateTransaction']
    tradeID = tickets["id"]
    price   = tickets["price"]
    units   = tickets["units"]

    print ('orderID:{} price:{} units:{}'.format(tradeID, price, units))

else:
    tickets = res.response['orderCancelTransaction']
    reason = tickets['reason']
    tradeID = tickets["id"]
    
    print("Error(reason):{} orderID:{}".format(reason, tradeID))


# orderID:23395 price:107.455 units:-1000 pl:3.0 accountBalance:3102174

以下のように管理画面の「取引履歴」のタブ内に反映されています。

通貨別の決済(全ての同一通貨の建玉を決済)

同一通貨で全ての建玉を決済するにはpositions.PositionCloseを使用します。

# 設定情報
currency = "USD_JPY"
data = {"longUnits":"ALL"}

# 決済を実行
res = positions.PositionClose(accountID=accountID, instrument=currency, data=data)
api.request(res)

設定は以下のとおりです。

  • instrument:通貨のシンボル:通貨を指定します。
  • data
    • longUnits:買い建玉:ALLとします。
    • shortUnits:売り建玉:ALLとします。

 

コメント

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