Zaif取引APIで取引履歴をエクセル出力(取得件数・通貨ペア指定可)

#はじめに

前回、Zaif取引APIを使用して取引履歴のエクセル出力を行った。

前回記事：[Zaif取引APIで取引履歴をエクセル出力]
(https://qiita.com/natsume_410/items/774d4804c389b6242084)


今回、前回のプログラムに主に下記のような改良を加えた。
・API_KEY及びSECRETをオンコーディングからコンフィグファイル(zaif_keys.json)での管理に変更
・trade_history関数のパラメータcount及びcurrency_pairと、sleep時間をオンコーディングからコンフィグファイル(trade_params.json)での管理に変更





##１．取得件数・通貨ペア指定可能版
###①コード

```Python:zaif_trade_kai.py
from zaifapi import ZaifPublicApi
from zaifapi import ZaifTradeApi
from datetime import *
from decimal import Decimal as dec
import openpyxl as px
import time
import json

# Zaif API
zaif_keys_json = open('config/zaif_keys.json', 'r')
zaif_keys = json.load(zaif_keys_json)
trade_params_json = open('config/trade_params.json', 'r')
trade_params = json.load(trade_params_json)

KEY = zaif_keys["key"]
SECRET = zaif_keys["secret"]
zaif_public = ZaifPublicApi()
zaif_trade = ZaifTradeApi(KEY,SECRET)

# エクセルカラム変換関数(1⇒A…27⇒AA)
def num2char(num):
    quotient, remainder = divmod(num, 26)
    chars = ''
    if quotient > 0:
        chars = chr(quotient + 64)
    if remainder > 0:
        chars = chars + chr(remainder + 64)
    return chars

# 開始時刻
start_time = datetime.today()
print("開始時刻：" + str(start_time))

# トレード回数設定
# "all"指定で全件
# 回数指定(例："500")で1通貨ペアごとに指定の件数
# 指定なし("")で1通貨ペアごとに1000件(デフォルト)
if trade_params["count"] == "all":
    account_info = zaif_trade.get_info()
    trade_count = account_info["trade_count"]
    time.sleep(int(trade_params["sleep_time"]))
elif trade_params["count"] == "":
    trade_count = 1000
else:
    trade_count = int(trade_params["count"])
print("取引回数=" + str(trade_count))

# 通貨ペア設定
# "all"指定で全通貨ペア
# ペア指定(例："btc_jpy,xem_btc")で指定ペア
# 指定なし("")でデフォルト("btc_jpy,mona_jpy,mona_btc,xem_jpy,xem_btc")
currency_list = []
if trade_params["currency_pair"] == "all":
    pairs_list = zaif_public.currency_pairs('all')
    for p in range(len(pairs_list)):
        currency_list.append(pairs_list[p]["currency_pair"])
elif trade_params["currency_pair"] == "":
    currency_list = ['btc_jpy', 'mona_jpy', 'mona_btc', 'xem_jpy', 'xem_btc']
else:
    currency_list = trade_params["currency_pair"].split(',')

print_pairs = ','.join(currency_list)
print("通貨ペア=" + str(print_pairs))

#トレード履歴取得
trade_list = {}
for c in range(len(currency_list)):
    currency = currency_list[c]
    if trade_count != 0:
        temp_list = zaif_trade.trade_history(count = trade_count, currency_pair = currency)
        time.sleep(int(trade_params["sleep_time"]))
    if trade_params["count"] == "all": #取引件数分取得したら終了。全通貨指定時の処理速度向上のため
       trade_count = trade_count - len(temp_list)
    if trade_count < 0: #自動取引等により実行中に取引回数が変動した場合の考慮
        trade_count = 0
    if len(temp_list) != 0:
        trade_list.update(temp_list)

# エクセルファイル作成
wb = px.Workbook()  # 新規ファイルの作成
ws = wb.active      # 現在選択中のシートを取得
ws.title = "list"   # シートをリネーム

# ヘッダー書き込み
header1 = ['項番','注文id','通貨ペア','b/a','数量','単位','価格','単位',
           '手数料','単位','b/a','ボーナス','取引日時','コメント']

for i in range(14):
    cell = num2char(i + 1) + "1"
    ws[cell].value = header1[i]
    i += 1

#トレード数分繰り返し
def list_loop(trade_list):
    for j, trade_key in enumerate(trade_list):
        #単位付与
        unit = trade_list[trade_key]['currency_pair'].split('_')
        #'bonus'がNoneだった場合0に置換
        trade_list[trade_key]['bonus'] = str(trade_list[trade_key]['bonus']).replace('None', '0')
        #項番(インデックス+ 1)・キー(注文id)・キーに紐付くVale(注文の中身)
        list = [(j + 1),                                                              #項番     (int)
                int(trade_key),                                                       #注文id   (str)
                trade_list[trade_key]['currency_pair'],                               #通貨ペア (str)
                trade_list[trade_key]['action'],                                      #bid/ask  (str)
                dec(str(dec(trade_list[trade_key]['amount']))[0:10]),   unit[0],      #数量     (float)
                dec(str(dec(trade_list[trade_key]['price']))[0:10]),    unit[1],      #価格     (float)
                dec(str(dec(trade_list[trade_key]['fee_amount']))[0:8]),unit[0],      #手数料   (float)
                trade_list[trade_key]['your_action'],                                 #bid/ask  (str)
                dec(str(trade_list[trade_key]['bonus'])),                             #-手数料  (float/NoneType)
                str(datetime.fromtimestamp(int(trade_list[trade_key]['timestamp']))), #取引日時 (UNIX_TIMESTAMP)
                trade_list[trade_key]['comment']]

        # トレード履歴書き込み
        for k in range(14):
            cell = num2char(k + 1) + str(j + 2)
            ws[cell].value = list[k]

list_loop(trade_list)

# ファイル保存
wb.save("trade_list.xlsx")
print("トレード履歴(trade_list.xlsx)を出力しました")
# 終了時刻
end_time = datetime.today()
print("終了時刻：" + str(end_time))
proc_time = end_time - start_time
print("経過時間" + str(proc_time))
```



###②コンフィグ
####(1)配置
［］・・・フォルダ
[bit]
　|- zaif_trade_kai.py
　|- trade_list.xlsx ←zaif_trade_kai.pyと同じフォルダに出力されます
　|- [config]
　　　　|- zaif_keys.json
　　　　|- trade_params.json

参考：[初心者が一攫千金を目指してBitcoin自動取引botを作るよ！ その３【ローカルBot】](https://qiita.com/speedkingg/items/7f122e1fd90558c531f4#_reference-0bb3193d4b94894ec497)
keyとsecretをconfigで管理

####(2)設定値(デフォルト)

```json:zaif_keys.json
{
  "key"    : "取引所のAPI_KEY",
  "secret" : "取引所のAPI_SECRET"
}
```

```json:trade_params.json
{
  "count"         : "",
  "currency_pair" : "",
  "sleep_time"    : "30"
}
```

####(3)パラメータの説明(trade_params.json)
1.count(取得件数)

| 設定値       | 説明                             |
|:-----------------|:----------------------------|
| ""               |デフォルト(1000件)|
| "all"            |全件取得(get_ingfo関数で取得した取引回数)。 |
| "数値"            |指定の数値(例："500"を設定で、1通貨ペアにつき500件取得)。|


2.currency_pair(通貨ペア)

| 設定値       | 説明                |
|:-----------------|:------------------|
| ""               |デフォルト(btc_jpy,mona_jpy,mona_btc,xem_jpy,xem_btc)|
| "all"            |currency_pairs関数で取得した全通貨ペア(※)。非推奨。 |
| "通貨ペア"        |複数指定可(例："xem_btc,bch_jpy,fscc_btc")|

※ 通貨ペア一覧
1月17日時点で下記28ペア。

|通貨ペア一覧|　　　| 　　　| 　　　| 　　　|
|:-------|:-------|:-------|:-------|:-------|
|xem_btc	|zaif_jpy	|cicc_jpy	|eth_jpy	|zaif_btc|
|bch_jpy	|mona_jpy	|pepecash_jpy	|mona_btc	|cicc_btc|
|fscc_btc	|btc_jpy	|pepecash_btc	|sjcx_btc	|ncxc_jpy|
|sjcx_jpy	|jpyz_jpy	|xem_jpy	|xcp_btc	|bitcrystals_btc|
|bitcrystals_jpy|eth_btc	|erc20.cms_jpy	|mosaic.cms_jpy	
|xcp_jpy	|bch_btc	|ncxc_btc	|fscc_jpy	

"all" 指定は取引していない通貨に対してもtrade_history関数を無駄に実行するようになっており非常に時間がかかるため、非推奨。フリーズ等してしまった場合でも責任は取りかねますのでご注意下さい><;


3.sleep_time(スリープ秒数)

| 設定値       | 説明                             |
|:-----------------|:----------------------------|
| "数値"            |取引API(get_info,trade_history)をcallした後のsleep秒数。|

スリープ短すぎるとAPI制限のエラーになるので、少なくとも30秒程度はスリープ入れておいた方がよいと思われる(10秒、20秒で試すとエラーになった)。

参考：[Zaif api document v1.1.1 ドキュメント » Q&A » エラーメッセージ一覧](http://techbureau-api-document.readthedocs.io/ja/latest/faq/2_error_message.html)
上記ドキュメントによると、取引履歴・入出金履歴については最大60秒程度制限されるようなので、30秒でもエラーになるかもしれない。



###③出力内容
####(1)デフォルト設定
以下の設定で実行

```json:trade_params.json
{
  "count"         : "",
  "currency_pair" : "",
  "sleep_time"    : "30"
}
```

・コンソール
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/8f3a6761-0038-4b31-ab36-26d56baaa4a6.png)

・エクセル
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/9d4b047a-8e72-b436-f83c-0116da479c25.png)



####(2)全通貨ペア全件取得
以下の設定で実行

```json:trade_params.json
{
  "count"         : "all",
  "currency_pair" : "all",
  "sleep_time"    : "30"
}
```

・コンソール
通貨ペアが長いので、サクラエディタの設定で右端で折り返してます。
Sleep30秒で全28通貨ペア分繰り返すと9分以上かかる…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/d2fb4c79-3609-b454-4270-890d8dedfba2.png)

・エクセル
前回と比べて順番が変わっているのは、Pythonの配列が順不同のため。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/e7897d1a-05dc-4b4c-ac47-a8851599e329.png)


####(3)回数・通貨ペア指定
以下の設定で実行

```json:trade_params.json
{
  "count"         : "5",
  "currency_pair" : "btc_jpy,mona_btc,bch_jpy,eth_btc",
  "sleep_time"    : "30"
}
```

・コンソール
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/fa0a3ab3-66c5-c871-d3c9-8906699e2d25.png)

・エクセル
1通貨ペアにつき、5件取得。btc_jpyはたくさん取引してるが、5件のみ書き出される。出力はデフォルトだと降順。
取引回数が5回以下のペアは、あるだけ書き出される。bch_jpyのように、一度も取引がない場合は何も書き出されない。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/241c3365-f536-ac27-2efc-735940e73e78.png)





##２．未解決事項について
前回からの未解決問題について

前回記事：[Zaif取引APIで取引履歴をエクセル出力]
(https://qiita.com/natsume_410/items/774d4804c389b6242084)

###①trade_historyの戻り値'bonus'の型がNoneType
前回のzaif_tran_print.pyを改造してコメント列にbonusの型を出力するようにした。
btc_jpyではfloat型になっているが、xem_btc等、jpy以外同士の通貨ペアの場合にNoneTypeになるっぽい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228630/bfb60411-8765-ba4b-9fb3-ca06c2195c75.png)

bonusなしの場合は0を設定すればいいんじゃないかと思ってしまうのだが…
なんでこのような仕様になっているんだろう？何かメリットがある？



###②処理時間の問題
結局今回も解決できなかった…



#おわりに
全件取得する方法も全通貨ペア取得する方法ももっといい方法があるとは思うのですが…
とりあえずやりたかったことはできたので、今回はここまでにしとこうと思いますm(_ _)m