zaif apiとpythonの勉強。売り買い・コメント・価格帯を指定して、合致する注文をすべてキャンセルする

python3でzaif apiを使ってなんやかやしています。

いろいろやろうとした結果、こういうのほしい……ほしくない?ってなったんですけど見つからなかったものを作りました。

(たぶん探すのが下手)

(zaif api 注文 キャンセル pythonとかで見つからなかった)

注文のキャンセル

テスト的に出した注文を手作業で取り消すのがだるすぎたので一括で削除できるようにえんやこらしました。
要らんライブラリとか呼んでる気がします。

from datetime import datetime
import sys
import time
from zaifapi import *
from decimal import (Decimal)
import logging
from pprint import pprint

FILE_ID='cancel'

########################################
# ログ関連
########################################
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(message)s')

handler = logging.StreamHandler()
handler.setFormatter(formatter)
handler.setLevel(logging.INFO)

fileHandler = logging.FileHandler('./log/'+FILE_ID+".log")
fileHandler.setFormatter(formatter)

logger.addHandler(handler)
logger.addHandler(fileHandler)

def function_message():
    print('python cancel.py [action=checkall/checkbid/checkask/all/bid/ask] [comment=*] [currency_pair=btc_jpy]')
    print('check action is print instead of cancel.')
    print('comment=* is target all orders.')

def namuamidabutsu():
    print('何かの間違いでプログラムを止めたい人のための入力猶予タイム')
    for i in range(5):
        print(str(5 - i) + ' ...')
        time.sleep(1)

def help():
    print("custom_cancel_orders(action='checkall', comment='*', currency_pair='btc_jpy', min_limit=0, max_limit=sys.maxsize)")
    print("cancel order(s) are...")
    print("action = order's action")
    print("comment = order's comment")
    print("currency_pair = order's currency_pair")
    print("min_limit <= order's price <= max_limit")

########################################
# ZAIFAPI
########################################
zaif_keys_json = open('config/zaifkeys.json', 'r')
zaif_keys = json.load(zaif_keys_json)
KEY = zaif_keys["key"]
SECRET = zaif_keys["secret"]
zaif = ZaifPublicApi()
trade = ZaifTradeApi(KEY, SECRET)

def custom_cancel_orders(action='checkall', comment='*', currency_pair='btc_jpy', min_limit=0, max_limit=sys.maxsize):
    # actionのチェック check~~はキャンセル注文を出さず、キャンセル対象の注文を表示する
    checkFlag = False
    if (action in ['checkall', 'checkbid', 'checkask', 'all', 'bid', 'ask']):
        if (action in ['checkall', 'checkbid', 'checkask']):
            checkFlag = True
            action = action[5:]
    else:
        function_message()
        return

    # 現在有効な注文の取得
    while True:
        try:
            active_orders = trade.active_orders(currency_pair=currency_pair)
            break
        except Exception as ex:
            logger.debug(ex)
            print('502か何かが出たっぽいので5秒後に再実行')
            time.sleep(5)

    print('<<< cancel target(s) >>>')

    # active_ordersのループ
    # forするとidが取れるのでチェックする
    cancel_order_ids = []
    for order_id in active_orders:
        order = active_orders[order_id]

        # 通貨ペアが一致すること
        if (currency_pair == order['currency_pair']):
            # 注文タイプが一致すること
            if (action in ['all', order['action']]):
                # コメントが一致すること
                if (comment in ['*', order['comment']]):
                    # 価格がリミット値に含まれること
                    if (min_limit <= order['price'] and order['price'] <= max_limit):
                        print(order)
                        cancel_order_ids.append(order_id)

    print('<<< cancel ids >>>')
    print(cancel_order_ids)

    if len(cancel_order_ids) == 0:
        return

    if not checkFlag:
        namuamidabutsu()

    # キャンセル注文を実施する
    if not checkFlag:
        print('<<< cancel now! cancel now! >>>')
        namuamidabutsu()

        for cancel_order_id in cancel_order_ids:
            while True:
                try:
                    trade.cancel_order(order_id=int(cancel_order_id), currency_pair=currency_pair)
                    break
                except Exception as ex:
                    logger.debug(ex)
                    logger.info('キャンセル失敗につき5秒後に再実行')
                    time.sleep(5)
            print(".cancel_order(order_id=%s, currency_pair='%s')" % (cancel_order_id, currency_pair))
            time.sleep(1)

if __name__=='__main__':
    args = sys.argv

    if len(args) == 1:
        custom_cancel_orders()
        function_message()
    elif len(args) == 2:
        custom_cancel_orders(action=args[1])
    elif len(args) == 3:
        custom_cancel_orders(action=args[1], comment=args[2])
    elif len(args) == 4:
        custom_cancel_orders(action=args[1], comment=args[2], currency_pair=args[3])
    else:
        function_message()

使い方

コマンドライン

呼び方はこんな感じ。

python zaif_custom_cancel.py [action] [comment] [currency_pair]

パラメータを指定した場合、一致する注文をキャンセル対象とします。
パラメータを指定しない場合はすべての注文を表示して、キャンセルはしません。

キャンセルする場合は、action に all / bid / ask のいずれかを指定する必要があります。

サンプル

python zaif_custom_cancel.py
# すべてのbtc_jpy注文を表示

python zaif_custom_cancel.py all
# すべてのbtc_jpy注文をキャンセル

python zaif_custom_cancel.py checkbid
# すべてのbtc_jpy買い注文を表示

python zaif_custom_cancel.py ask hoge
# すべてのbtc_jpy売り注文のうち、コメントに"hoge"とあるものをキャンセル

注意点

  • action
    checkをつける(checkallとか)とキャンセル注文を省略して実行します。
    その条件に含まれる注文を確認できます。
    check部分を削って再度実行すると、表示された注文がキャンセルされます。

  • comment
    リミット設定によって発生した注文にはコメントがつかないので注意が必要です。

ライブラリ

python上で、import zaif_custom_cancel as cancelとかそんな感じで呼べます。

ライブラリから起動すると、キャンセルする注文の価格帯を指定できます。

import zaif_custom_cancel as cancel

cancel.custom_cancel_orders()
# すべての注文を表示

cancel.custom_cancel_orders(min_limit=500000, max_limit=700000)
# 500000円〜700000円の間のすべての注文を表示

cancel.custom_cancel_orders('checkask', min_limit=500000)
# 500000円以上のすべての売り注文を表示

cancel.custom_cancel_orders('bid','hoge', max_limit=800000)
# 800000円以下でコメントが"hoge"のすべての買い注文をキャンセル

ヘルプ

cancel.help()とかすると一応ヘルプ的なものが表示されます。

まとめ

というわけでキャンセル注文を出しやすくしてみました。
一通り動きは確認してますがバグあったらごめんなさい。
当プログラムを利用したことで不利益がうんたんうんたん(呪文)

動きを確認するために今度は自動で注文を複数出すみたいな処理を書き始めたわけですが、キリねーなこれって思いました。

exceptであらゆる例外を掴むというクソ仕様なので気軽に無限ループすると思います。
お気をつけください。

あとcloud9からgithubにpushしたいですね。

gitの話。
普通にgitは使えるので、あとはあれですね。
apiのキーを.gitignoreに指定しておけばいけそうです。

流石に調べないと怖いのでそのうちやろうと思います。
資料はいくらでもありそうですし。

コメント