Пример #1
0
# -*- coding: utf-8 -*-

from zaifapi import ZaifPublicApi  # Zaifが公開している認証情報が要らないAPIを実行するクラス
from pprint import pprint  # 表示用(jsonをきれいに表示してくれる)

if __name__ == '__main__':
    zaif = ZaifPublicApi()

    print('---last_price : 終値--')
    pprint(zaif.last_price('btc_jpy'))

    print('---ticker : ティッカー(集計情報取得)--')
    pprint(zaif.ticker('btc_jpy'))

    print('---trades : 全ての取引履歴--')
    print('取得件数:' + str(len(zaif.trades('btc_jpy'))))
    pprint(zaif.trades('btc_jpy'))

    print('---depth : 板情報--')
    print('取得件数[買い]:' + str(len(zaif.depth('btc_jpy')['asks'])))
    print('取得件数[売り]:' + str(len(zaif.depth('btc_jpy')['bids'])))
    pprint(zaif.depth('btc_jpy'))

    print('---currency_pairs : trade_history等で利用可能な通貨ペア情報--')
    pprint(zaif.currency_pairs('btc_jpy'))

    print('---currencies : deposit_history等で利用可能な通貨情報--')
    pprint(zaif.currencies('all'))
Пример #2
0
class Exporter:
    ORDER_MAP = dict(bid='買', ask='売', both='自己')
    FUTURE_MAP = {
        1: 'AirFX',
        2: '四半期6月(07-01) ',
        3: '四半期9月(10-01)',
        4: '四半期12月(01-01)',
        5: '四半期3月(04-01)',
    }

    def __init__(self, api_key: str, api_secret: str,
                 wait_interval: float,
                 limit: int,
                 cache_limit: int,
                 currencies: Optional[List[str]]):
        self.public_api = ZaifPublicApi()
        self.trade_api = ZaifTradeApi(api_key, api_secret)
        self.futures_public_api = ZaifFuturesPublicApi()
        self.futures_trade_api = ZaifLeverageTradeApi(api_key, api_secret)
        self._wait_interval = wait_interval
        self._limit = limit
        self._cache_limit = cache_limit
        if currencies:
            currencies = [x.upper() for x in currencies]
        self._currencies = currencies

    def get_history(self, fn: Callable[[dict], dict], parse_fn: Callable[[dict], Iterator[dict]],
                    **kwargs) -> Generator[dict, None, None]:
        def retry_wrapper(*_args, **_kwargs):
            while True:
                try:
                    print('.', file=sys.stderr, end='', flush=True)
                    return fn(*_args, **_kwargs)
                except ZaifApiError as e:
                    s = str(e)
                    if 'time wait restriction, please try later.' in s:
                        print('rate limit exceeded. wait and retry...', file=sys.stderr)
                        time.sleep(self._wait_interval)
                    elif 'return status code is 502' in s:
                        print('502 error. wait and retry...', file=sys.stderr)
                        time.sleep(self._wait_interval)
                    elif 'return status code is 504' in s:
                        print('504 error. wait and retry...', file=sys.stderr)
                        time.sleep(self._wait_interval)
                    else:
                        raise

        from_i = 0
        params = kwargs.copy()
        params.update(count=self._limit)
        cache = OrderedDict()
        cache_limit = self._cache_limit
        while True:
            params['from_num'] = from_i
            res = retry_wrapper(**params)
            if not len(res):
                break
            for k, v in sorted(res.items(), key=lambda _x: int(_x[0]), reverse=True):
                k = int(k)
                v['id'] = k
                # ID降順で取得できる保証がないので、
                # IDをキャッシュしてキャッシュに無いもののみ出力する。
                if k not in cache:
                    cache[k] = True
                    if len(cache) > cache_limit:
                        cache.popitem(last=False)
                    for x in parse_fn(v):
                        yield x
            from_i += len(res)

    @classmethod
    def convert_timestamp(cls, timestamp: Union[int, float], tz: pytz.timezone = JST) -> str:
        timestamp = float(timestamp)
        return pytz.UTC.localize(datetime.utcfromtimestamp(timestamp)).astimezone(tz).isoformat()

    @classmethod
    def write_csv(cls, gen: Generator[dict, None, None], file):
        writer = None
        for data in gen:
            if not writer:
                writer = csv.DictWriter(file, fieldnames=tuple(data.keys()))
                writer.writeheader()
            writer.writerow(data)

    def export_spot(self) -> Generator[dict, None, None]:
        pairs = self.public_api.currency_pairs('all')
        for pair in sorted(pairs, key=lambda x: x['name']):
            def parse(trade: dict) -> Iterator[dict]:
                """
                "182": {
                    "currency_pair": "btc_jpy",
                    "action": "bid",
                    "amount": 0.03,
                    "price": 56000,
                    "fee": 0,
                    "your_action": "ask",
                    "bonus": 1.6,
                    "timestamp": 1402018713,
                    "comment" : "demo"
                }
                """
                x = OrderedDict()
                is_taker = trade['action'] == trade['your_action']
                x['分類'] = '現物'
                x['ID'] = trade['id']
                x['日時'] = self.convert_timestamp(trade['timestamp'])
                x['通貨ペア'] = '/'.join(trade['currency_pair'].upper().split('_'))
                x['注文種別'] = self.ORDER_MAP[trade['your_action']]
                x['TAKER/MAKER'] = 'TAKER' if is_taker else 'MAKER'
                x['価格'] = trade['price']
                x['数量'] = trade['amount']
                x['手数料'] = trade['fee_amount']
                x['ボーナス'] = trade['bonus']
                x['コメント'] = trade['comment']

                results = []
                if trade['your_action'] == 'both':
                    if trade['action'] == 'bid':
                        # 買い
                        x['注文種別'] = '自己買'
                        x['TAKER/MAKER'] = 'TAKER'
                        results.append(x.copy())
                        x['注文種別'] = '自己売'
                        x['TAKER/MAKER'] = 'MAKER'
                        results.append(x.copy())
                    elif trade['action'] == 'ask':
                        # 売り
                        x['注文種別'] = '自己売'
                        x['TAKER/MAKER'] = 'TAKER'
                        results.append(x.copy())
                        x['注文種別'] = '自己買'
                        x['TAKER/MAKER'] = 'MAKER'
                        results.append(x.copy())
                    else:
                        assert False, 'unknown action: {}'.format(trade)
                else:
                    results.append(x)
                return results

            currency_pair = pair['currency_pair']
            yield from self.get_history(self.trade_api.trade_history, parse, currency_pair=currency_pair)

    def _export_margin_or_future(self, **kwargs) -> Generator[dict, None, None]:
        def parse(trade: dict) -> Iterator[dict]:
            """
            "182": {
                "group_id": 1,
                "currency_pair": "btc_jpy",
                "action": "bid",
                "leverage": 2.5,
                "price": 110005,
                "limit": 130000,
                "stop": 90000,
                "amount": 0.03,
                "fee_spent": 0,
                "timestamp": 1402018713,
                "term_end": 1404610713,
                "timestamp_closed": 1402019000,
                "deposit": 35.76 ,
                "deposit_jpy": 35.76,
                "refunded": 35.76 ,
                "refunded_jpy": 35.76,
                "swap": 0,
            }
            group_id	グループID	int
            currency_pair	通貨ペア	str
            action	bid(買い) or ask(売り)	str
            amount	数量	float
            price	価格	float
            limit	リミット価格	float
            stop	ストップ価格	float
            timestamp	発注日時	UNIX_TIMESTAMP
            term_end	注文の有効期限	UNIX_TIMESTAMP
            leverage	レバレッジ	float
            fee_spent	支払い手数料	float
            timestamp_closed	クローズ日時	UNIX_TIMESTAMP
            price_avg	建玉平均価格	float
            amount_done	建玉数	float
            close_avg	決済平均価格	float
            close_done	決済数	float
            deposit_xxx	実際にデポジットした額(xxxは通貨コード)	float
            deposit_price_xxx	デポジット時計算レート(xxxは通貨コード)	float
            refunded_xxx	実際に返却した額(xxxは通貨コード)	float
            refunded_price_xxx	実際に返却した額(xxxは通貨コード)	float
            swap	受け取ったスワップの額(AirFXのみ)	float
            guard_fee	追証ガード手数料(信用取引のみ)	float
            """
            x = OrderedDict()
            is_executed = 'amount_done' in trade
            if 'group_id' in trade:
                x['分類'] = '先物'
                x['先物グループ'] = self.FUTURE_MAP[trade['group_id']]
            else:
                x['分類'] = '信用'
            x['ID'] = trade['id']
            x['発注日時'] = self.convert_timestamp(trade['timestamp'])
            x['決済日時'] = self.convert_timestamp(trade['timestamp_closed'])
            x['通貨ペア'] = '/'.join(trade['currency_pair'].upper().split('_'))
            if is_executed:
                x['ステータス'] = '成立'
            else:
                x['ステータス'] = '取消済み(建玉不成立)'
            x['注文種別'] = self.ORDER_MAP[trade['action']]
            x['数量'] = trade['amount']
            x['価格'] = trade['price']
            x['リミット価格'] = trade.get('limit')
            x['ストップ価格'] = trade.get('stop')
            x['支払い手数料'] = trade['fee_spent']
            x['建玉平均価格'] = trade.get('price_avg')
            x['建玉数'] = trade.get('amount_done')
            x['決済平均価格'] = trade.get('close_avg')
            x['決済数'] = trade.get('close_done')
            x['スワップ'] = trade.get('swap')
            swap = trade.get('swap', 0)
            x['追証ガード手数料(信用取引のみ)'] = trade.get('guard_fee')
            guard_fee = trade.get('guard_fee', 0)
            if is_executed:
                pnl = trade['close_avg'] * trade['close_done'] - trade['price_avg'] * trade['amount_done']
                pnl = pnl if trade['action'] == 'bid' else -pnl
                pnl_with_fee_swap = pnl + swap - guard_fee - trade['fee_spent']
            else:
                pnl = None
                pnl_with_fee_swap = None
            x['ポジション損益'] = pnl
            x['ポジション損益(手数料・スワップ込み)'] = pnl_with_fee_swap
            return [x]

        yield from self.get_history(self.futures_trade_api.get_positions, parse, **kwargs)

    def export_margin(self) -> Generator[dict, None, None]:
        yield from self._export_margin_or_future(type='margin')

    def export_future(self) -> Generator[dict, None, None]:
        groups = self.futures_public_api.groups('all')
        for group_id in sorted(map(lambda x: x['id'], groups)):
            yield from self._export_margin_or_future(type='futures', group_id=group_id)

    def export_deposit(self) -> Generator[dict, None, None]:
        currencies = [x['name'] for x in self.public_api.currencies('all')]
        for currency in sorted(currencies):
            if self._currencies and (currency.upper() not in self._currencies):
                continue

            def parse(d: dict) -> Iterator[dict]:
                """
                "3816":{
                    "timestamp":1435745065,
                    "address":"12qwQ3sPJJAosodSUhSpMds4WfUPBeFEM2",
                    "amount":0.001,
                    "txid":"64dcf59523379ba282ae8cd61d2e9382c7849afe3a3802c0abb08a60067a159f",
                },
                """
                return [OrderedDict([
                    ('通貨', currency),
                    ('ID', d['id']),
                    ('日時', self.convert_timestamp(d['timestamp'])),
                    ('数量', d['amount']),
                    ('入金アドレス', d.get('address')),
                    ('トランザクション', d.get('txid')),
                ])]

            yield from self.get_history(self.trade_api.deposit_history, parse, currency=currency)

    def export_withdrawal(self) -> Generator[dict, None, None]:
        currencies = [x['name'] for x in self.public_api.currencies('all')]
        for currency in sorted(currencies):
            if self._currencies and (currency.upper() not in self._currencies):
                continue

            def parse(d: dict) -> Iterator[dict]:
                """
                "3816":{
                    "timestamp":1435745065,
                    "address":"12qwQ3sPJJAosodSUhSpMds4WfUPBeFEM2",
                    "amount":0.001,
                    "txid":"64dcf59523379ba282ae8cd61d2e9382c7849afe3a3802c0abb08a60067a159f",
                },
                """
                bank_processed_at = d.get('processed')
                if bank_processed_at:
                    bank_processed_at = self.convert_timestamp(bank_processed_at)
                return [OrderedDict([
                    ('通貨', currency),
                    ('ID', d['id']),
                    ('日時', self.convert_timestamp(d['timestamp'])),
                    ('数量', d['amount']),
                    ('手数料', d['fee']),
                    ('出金アドレス', d.get('address')),
                    ('トランザクション', d.get('txid')),
                    ('銀行名', d.get('bank_name')),
                    ('支店名', d.get('bank_branch')),
                    ('口座種別', d.get('account_type')),
                    ('口座番号', d.get('account_no')),
                    ('口座名義', d.get('account_kana')),
                    ('処理日時', bank_processed_at),
                ])]

            yield from self.get_history(self.trade_api.withdraw_history, parse, currency=currency)