send_order_exit.py
import urllib.request
import urllib.error
import json
import pprint
import settings
import variables
import sys
class SendOrderExitBase:
def __init__(self):
self.obj = {'Password': settings.password,
'Symbol': settings.symbol,
'Exchange': settings.exchange,
'SecurityType': 1,
'Side': settings.opposite_side,
'CashMargin': 3,
'MarginTradeType': settings.margin_trade_type,
'DelivType': settings.closing_deliv_type,
'AccountType': settings.account_type,
'Qty': variables.exitQty,
'ClosePositions': variables.closePositions,
'Price': 0,
'ExpireDay': 0,
'FrontOrderType': 10}
def send_order(self):
json_data = json.dumps(self.obj).encode('utf-8')
url = 'http://localhost:' + settings.port + '/kabusapi/sendorder'
req = urllib.request.Request(url, json_data, method='POST')
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-KEY', variables.token)
try:
print('###send_order_exit')
with urllib.request.urlopen(req) as res:
print(res.status, res.reason)
for header in res.getheaders():
print(header)
print()
content = json.loads(res.read())
pprint.pprint(content)
return
except urllib.error.HTTPError as e:
print(e)
content = json.loads(e.read())
pprint.pprint(content)
# 決済内容に誤りがあります はポジション取得遅延のせいなので無視
if content['Code'] == 8:
return
except Exception as e:
print(e)
sys.exit()
class MarketSendOrderExit(SendOrderExitBase):
def __init__(self):
super().__init__()
def send_order_market(self):
print('###send_order_market')
self.obj["FrontOrderType"] = 10
self.obj["Price"] = 0
super().send_order()
class IOCLimitSendOrderExit(SendOrderExitBase):
def __init__(self):
super().__init__()
def send_order_ioc_limit(self, price):
print('###send_order_ioc_limit')
self.obj["FrontOrderType"] = 27
self.obj["Price"] = price
super().send_order()
def send_order_market():
temp_class = MarketSendOrderExit()
temp_class.send_order_market()
def send_order_ioc_limit(price):
temp_class = IOCLimitSendOrderExit()
temp_class.send_order_ioc_limit(price)
継承を使って、成行注文とIOC指値注文を共通化しています。
分かりにくい人は、別々のモジュールにしても全く問題ありません。
IOC注文は決済同期APIではない
ここでポイントとなるのは、49行目からの以下の部分です。
except urllib.error.HTTPError as e:
print(e)
content = json.loads(e.read())
pprint.pprint(content)
# 決済内容に誤りがあります はポジション取得遅延のせいなので無視
if content['Code'] == 8:
return
なぜこの”Code” = 8 のエラーを無視しなければならないかというと、IOC注文といえども決済同期ではないため、
- IOC注文
- 残高照会
- 残高が残っていたので次のIOC注文
とする処理の場合、以下の2パターンでエラーになることがあるのです。
- 2の段階で、1の注文がまだ発注中で約定/約定失敗が決まっていないため残高情報が古い
- 3の段階でも、1の注文がまだ発注中で2重発注になる
いずれの場合も”Code” = 8のエラーとなるため、それを無視します。
なんのためのIOC注文なのか…
IOC注文は、即時決済注文(immediate or kill)と呼ばれ、通常の成行や指値注文のように約定するまで注文が滞留することはなく、即時に決済できない場合は自動的にキャンセルされる という定義のものです。
この注文のなにがいいかというと、HFTなどのプログラム超高速取引において、いちいち約定状態を確認したりキャンセルしたりする必要がない ということが1つにあるんですね。
プログラムをすこしかじっている人なら分かると思いますが、通常の同期APIと、非同期APIで結果をポーリングしなければならないものとでは、プログラムの処理速度も複雑さも全く違います。同期APIのほうが格段に速いですし、プロクラムもシンプルです。
私は、IOC注文は同期APIかと思っていたのですが、東京証券取引所のIOC注文はキャンセルまでの時間が短いだけの非同期APIなのです。
東京証券取引所は、2010年にシステムを大更改し、「アローヘッド」という新システムをリリースしました。
その売りの1つが、「海外の取引所に負けない処理性能を実現し、HFTなどの超高速取引に対応する」ということでした。
しかし、その結果、IOC注文が同期APIとなってないとは…
高速で取引できても、プログラム側でそれが即時に検知できないと次の処理に移ることができず、HFT対応としての効果はほとんどなくなってしまうと思つたのですが…
この仕様はにわかには信じられなかったので、auカブコム証券と、日本取引所グループの両方に問い合わせたので、間違いないようです。
auカブコム証券に問い合わせした内容
日本取引所グループにメールで問い合わせた内容
・IOC注文を受け付けた場合、弊社の売買システムは2種類の通知を行います。
・最初の通知は注文受付通知と呼ばれるもので、「弊社システムがIOC注文を受け付けた」ことだけを示すものです。確かにこちらの通知だけをもって約定した・していないを判断することは出来ません。
・ただしその後、約定通知(約定した)もしくは失効通知(約定しなかった)のいずれかが必ず送信されますので、それらを用いることで、IOC注文の結果を判断することが可能です。
・最初の通知から約定/失効通知が送信されるまでの時間は、ほとんどの場合1秒もかかりませんので、ほぼ即時といって差し支えないスピードでご判断いただけるとは思います。
「ほとんどの場合1秒もかからない」って1秒以上かかることもあるんでか。HFTは普通ミリ秒単位で取引するんですけど…
「約定通知(約定した)もしくは失効通知(約定しなかった)のいずれかが必ず送信され」って、いうのが証券会社までで、kabuステーションAPIではそれを通知してくれるAPIはいまのところないようです。githubで要望を出してみますか…期待薄ですけど。
コメント