Pythonで仮想通貨の移動平均線とボリンジャーバンド取得④ BTCトレード動作プログラム

zaifを使った、ビットコインのトレードプログラムです。ただし、プラスになったりマイナスになったりしてます。何%の利益が~とか言ってみたいですよ。
zaifのAPIコールは、エラーになることが結構あるため、APIコールを複数回繰り返す処理をいれています。
また、zaifは手数料がマイナスであるため、トレードプログラムでプラマイゼロであっても、ボーナスがもらえてプラスになったりします。

作ったのでコードを載せていますが、参考程度としておくのがよろしいかと思います。

スポンサードリンク

動作環境

NCU(4コア)に、ESXiを導入した仮想サーバーを持っているため、windows7 Starter(2仮想CPU) をインストールして常時稼働させています。Starterには、リモートディスクトップのサーバ機能が無いため、高速リモートディスクトップ「Yule」を使っています。
python 3.6.4 は、Anaconda version 5.1.0 で導入しています。

スポンサードリンク

購入判断

ボリンジャーバンド(σ*2)の低偏差より低ければ、購入申請します。

利確判断

ボリンジャーバンド(σ2 or σ1)の高偏差より高くなれば、利確申請します。

損切り判断

購入した価格から0.3%程度損益になれば、損切り申請します。

コード

注意
コードを記載していますが、使用する場合は自己責任でお願いします。

key.jsonの書式は前回の記事を参照してください。

Pythonで仮想通貨の移動平均線とボリンジャーバンド取得② 公開API動作プログラム
# coding=utf-8

import json
import time
import pprint
import codecs
import slackweb
import numpy as np
import datetime
from zaifapi import ZaifPublicApi
from zaifapi import ZaifTradeApi
from decimal import (Decimal)
from logger import error_logger
from logger import trade_logger

with codecs.open('config/key.json', 'r', 'utf-8') as f:
    API_data = json.load(f)

WEBHOOK_URL = API_data["slack_webhook_url"]
slack = slackweb.Slack(WEBHOOK_URL)

API_KEY = API_data["zaif_key"]
API_SECRET = API_data["zaif_secret"]
COIN_NAME = 'btc'
COIN_PAIR = 'btc_jpy'
EXCHANGE = 'Zaif:'

trade_log = trade_logger.TradeLogger('zaif', COIN_NAME)
error_log = error_logger.ErrorLogger('error')

PERIOD1 = 8  # 短期平均線
PERIOD2 = 36  # 平均線&ボリンジャーバンドの間隔数
LOOP_TIME = 15  # 市場価格取得間隔の秒数
CANCEL_LOOP_MAX = 4  # キャンセルするまでのループ回数 4x15=60秒
TRADE_HOLD_MAX = 12  # トレード直後に売買しないようにする回数 4x15=60秒

last_price = []  # 市場価格
cancel_flag = False  # キャンセル処理をするかのフラグ
cancel_loop_count = 0  # キャンセルまでのカウント
trade_hold_count = 0  # トレード後の売買処理しないカウント

low_borin1 = 0  # x1低ボリンジャーバンド
low_borin2 = 0  # x2低ボリンジャーバンド
moving_avg1 = 89999999  # 移動平均
moving_avg2 = 89999999  # 移動平均
sigma = 0  # 標準偏差
moving_avg1_pre = 0  # 一つ前の移動平均
moving_avg2_pre = 0  # 一つ前の移動平均
high_borin1 = 89999999  # x1高ボリンジャーバンド
high_borin2 = 89999999  # x2高ボリンジャーバンド

bid_amount = 0.0  # 買い取引量
ask_amount = 0.0  # 売り取引量

funds_jpy = 0  # 注文余力日本円
funds_coin = 0.0  # 注文余力コイン
start_funds_jpy = 0  # プログラム開始時の日本円

last_trade_func = ''  # 取引機能
last_trade_order_id = 0  # 最後に取引したID
last_trade_size = 0.0  # 最後に取引したサイズ
last_trade_price = 0  # 最後に取引した価格
last_trade_price_pre = 0  # 一つ前の取引した価格(キャンセルした時用)
last_trade_type = 0  # 0:購入、1:利確1、2:利確2、3:損切り
asset_info = False

message_func = ''  # トレードログ用
message_trade = ''  # トレードログ用
message_size = 0  # トレードログ用
message_price = 0.0  # トレードログ用

date_time = datetime.datetime.now()  # print用表示タイム
current_price = 0  # 一時的に保管する市場価格

END_FLAG = False  # プログラムの終了タイム
end_datetime = datetime.datetime.now()  # 終了タイム
END_HOUR = 17  # 終了時
END_MINUTE = 0  # 終了分

call_count = 0  # API呼び出し繰り返し回数
CALL_MAX = 3  # APIコール連続回数
call_success = False


def check_results(trade_result):
    global last_trade_order_id, cancel_loop_count, cancel_flag
    if trade_result['order_id'] != 0:
        last_trade_order_id = trade_result['order_id']
        cancel_flag = True
        cancel_loop_count = 0
    else:
        print('■ 取引が完了しました。')
        # slack.notify(text='取引完了')
        last_trade_order_id = 0


if __name__ == '__main__':
    zaif_public = ZaifPublicApi()
    zaif_trade = ZaifTradeApi(API_KEY, API_SECRET)

    init_flag = False
    while not init_flag:
        try:
            last_trade_price = int(zaif_public.last_price(COIN_PAIR)["last_price"])
            trade_result = zaif_trade.get_info2()
            start_funds_jpy = trade_result['deposit']['jpy']
            if trade_result['deposit'][COIN_NAME] != 0:
                start_funds_jpy += trade_result['deposit'][COIN_NAME] * last_trade_price
        except:
            continue
        else:
            init_flag = True

    date_time = datetime.datetime.now()
    end_datetime = datetime.datetime(date_time.year, date_time.month, date_time.day, END_HOUR,
                                     END_MINUTE)
    END_FLAG = False
    if date_time > end_datetime:
        end_datetime += datetime.timedelta(days=1)
    print('END DATE TIME:', end_datetime)

    profit_count = 0
    loss_count = 0

    while True:
        message_func = ''
        message_trade = ''
        message_price = 0
        message_size = 0.0
        date_time = datetime.datetime.now()
        start_time = time.time()
        try:
            trade_result = zaif_trade.get_info2()
            funds_coin = Decimal(trade_result['funds'][COIN_NAME]).quantize(Decimal('0.0001'))
            funds_jpy = trade_result['funds']['jpy']
            current_price = int(zaif_public.last_price(COIN_PAIR)["last_price"])
            result = zaif_public.trades('btc_jpy')
            bid_amount = 0.0
            ask_amount = 0.0

            for currency in result:
                if currency['trade_type'] == 'bid':
                    bid_amount += currency['amount']
                if currency['trade_type'] == 'ask':
                    ask_amount += currency['amount']

        except:
            error_log.write()
            print("エラー:Cant get data")
            time.sleep(1)
            continue

        else:
            last_price.append(current_price)
            if len(last_price) <= PERIOD2:
                print("■ 現在の情報です", len(last_price))
                print(str(date_time))
                print("市場取引価格:" + str(last_price[-1]))
                print(COIN_NAME + "資産:" + str(funds_coin))
                print("jpy資産:" + str(funds_jpy))
                print("最終取引価格:" + str(last_trade_price))

        try:
            if len(last_price) < 2 or asset_info:
                if funds_coin < 0.0001 and last_trade_order_id == 0:
                    message_text = EXCHANGE + '現在の資産: ' + str(date_time) + '\njpy資産:' \
                                   + str(funds_jpy) + '\n' + COIN_NAME + '資産:' + str(funds_coin) \
                                   + '\nProfit:' + str(profit_count) + ' Loss:' + str(loss_count) \
                                   + '\nGain:' + str(funds_jpy - start_funds_jpy)
                else:
                    message_text = EXCHANGE + '現在の資産: ' + str(date_time) + '\njpy資産:' \
                                   + str(funds_jpy) + '\n' + COIN_NAME + '資産:' + str(funds_coin) \
                                   + '\nProfit:' + str(profit_count) + ' Loss:' + str(loss_count)
                slack.notify(text=message_text)
        except:
            error_log.write()
            print("エラー:slack call error")
        else:
            asset_info = False

        if len(last_price) > PERIOD2:
            print('■資産、平均線、ボリンジャーバンド', len(last_price))
            print(str(date_time))
            print(COIN_NAME + '資産:', str(funds_coin))
            print('jpy資産:', str(funds_jpy))
            print('市場価格:', str(current_price))
            print('平均  :', str(moving_avg2))
            print('高偏差:', str(high_borin2))
            print('低偏差:', str(low_borin2))
            print("最終取引価格:" + str(last_trade_price))
            message_func = EXCHANGE + '資産、平均、標準偏差'

        # コインを持っていて
        if (funds_coin >= 0.0001 and current_price > high_borin2
                and trade_hold_count > TRADE_HOLD_MAX):
            # 売却
            amount = funds_coin
            adjustment = 0
            if last_price[-1] > last_price[-2]:
                adjustment = 10
            elif last_price[-1] == last_price[-2]:
                adjustment = 5
            else:
                adjustment = 0

            call_count = 0
            call_success = False
            while not call_success:
                call_count += 1
                if call_count > CALL_MAX:
                    break
                try:
                    trade_result = zaif_trade.trade(currency_pair=COIN_PAIR, action="ask",
                                                    price=last_price[-1] - 5 + adjustment,
                                                    amount=amount)
                except:
                    error_log.write()
                    print("エラー:cant trade[ask_up]")
                    time.sleep(1)
                else:
                    last_trade_func = 'ask'
                    last_trade_size = amount
                    last_trade_price_pre = last_trade_price
                    last_trade_price = last_price[-1] - 5 + adjustment
                    last_trade_order_id = trade_result['order_id']
                    trade_hold_count = 0
                    asset_info = True
                    call_success = True
                    if last_trade_price_pre > last_trade_price:
                        loss_count += 1
                        last_trade_type = 3
                    else:
                        profit_count += 1
                        last_trade_type = 1
                    check_results(trade_result)

            if call_success:
                print('■ 利確1売却申請を行いました。')
                pprint.pprint(trade_result)
                print("売却注文価格:" + str(last_price[-1] - 5 + adjustment))
                print("売却注文量 :" + str(amount))
                message_func += '、利確1'
                message_trade = 'ask'
                message_price = current_price - 5 + adjustment
                message_size = amount

                try:
                    message_text = EXCHANGE + '■ 利確1売却申請: ' + str(date_time) \
                                   + '\nPrice:' + str(current_price - 5 + adjustment) \
                                   + '\nSize:' + str(amount)
                    slack.notify(text=message_text)

                except:
                    error_log.write()
                    print("エラー:Slack call error]")

        # コインを持っていて
        elif (funds_coin >= 0.0001 and current_price > high_borin1
              and last_price[-1] < last_price[-2]
              and trade_hold_count > TRADE_HOLD_MAX):
            # 売却
            amount = funds_coin
            adjustment = 0
            if last_price[-1] > last_price[-2]:
                adjustment = 10
            elif last_price[-1] == last_price[-2]:
                adjustment = 5
            else:
                adjustment = 0

            call_count = 0
            call_success = False
            while not call_success:
                call_count += 1
                if call_count > CALL_MAX:
                    break
                try:
                    trade_result = zaif_trade.trade(currency_pair=COIN_PAIR, action="ask",
                                                    price=last_price[-1] - 5 + adjustment,
                                                    amount=amount)
                except:
                    error_log.write()
                    print("エラー:cant trade[ask_up]")
                    time.sleep(1)
                else:
                    last_trade_func = 'ask'
                    last_trade_size = amount
                    last_trade_price_pre = last_trade_price
                    last_trade_price = last_price[-1] - 5 + adjustment
                    last_trade_order_id = trade_result['order_id']
                    trade_hold_count = 0
                    asset_info = True
                    call_success = True
                    if last_trade_price_pre > last_trade_price:
                        loss_count += 1
                        last_trade_type = 3
                    else:
                        profit_count += 1
                        last_trade_type = 2
                    check_results(trade_result)

            if call_success:
                print('■ 利確2売却申請を行いました。')
                pprint.pprint(trade_result)
                print("売却注文価格:" + str(last_price[-1] - 5 + adjustment))
                print("売却注文量 :" + str(amount))
                message_func += '、利確2'
                message_trade = 'ask'
                message_price = current_price - 5 + adjustment
                message_size = amount

                try:
                    message_text = EXCHANGE + '■ 利確2売却申請: ' + str(date_time) \
                                   + '\nPrice:' + str(current_price - 5 + adjustment) \
                                   + '\nSize:' + str(amount)
                    slack.notify(text=message_text)

                except:
                    error_log.write()
                    print("エラー:Slack call error]")

        # コインを持っていて
        elif (funds_coin >= 0.0001 and current_price < (last_trade_price * 0.997)
              and trade_hold_count > TRADE_HOLD_MAX):
            amount = funds_coin

            call_count = 0
            call_success = False
            while not call_success:
                call_count += 1
                if call_count > CALL_MAX:
                    break
                try:
                    # 売却
                    trade_result = zaif_trade.trade(currency_pair=COIN_PAIR, action="ask",
                                                    price=last_price[-1] - 5, amount=amount)
                except:
                    error_log.write()
                    print("エラー:cant trade[ask]")
                    time.sleep(1)
                else:
                    last_trade_func = 'ask'
                    last_trade_size = amount
                    last_trade_price_pre = last_trade_price
                    last_trade_price = last_price[-1] - 5
                    last_trade_order_id = trade_result['order_id']
                    trade_hold_count = 0
                    asset_info = True
                    call_success = True
                    if last_trade_price_pre > last_trade_price:
                        loss_count += 1
                        last_trade_type = 3
                    else:
                        profit_count += 1
                        last_trade_type = 2
                    check_results(trade_result)

            if call_success:
                print('■ 損切売却申請を行いました。')
                pprint.pprint(trade_result)
                print("売却注文価格:" + str(last_price[-1] - 5))
                print("売却注文量 :" + str(amount))
                message_func += '、損切'
                message_trade = 'ask'
                message_price = current_price - 5
                message_size = amount

                try:
                    message_text = EXCHANGE + '■ 損切売却申請: ' + str(date_time) \
                                   + '\nPrice:' + str(current_price - 5) + '\nSize:' \
                                   + str(amount)
                    slack.notify(text=message_text)
                except:
                    error_log.write()
                    print("エラー:Slack call error]")

        # コインを最小単位持っていない場合で、低偏差値より低い場合に購入
        elif (funds_coin < 0.0001 and low_borin2 >= current_price
              and trade_hold_count > TRADE_HOLD_MAX and last_trade_order_id == 0):

            amount = Decimal(funds_jpy * 0.9 / current_price).quantize(Decimal('0.0001'))

            call_count = 0
            call_success = False
            while not call_success:
                call_count += 1
                if call_count > CALL_MAX:
                    break

                try:
                    trade_result = zaif_trade.trade(currency_pair=COIN_PAIR, action="bid",
                                                    price=last_price[-1], amount=amount)

                except:
                    error_log.write()
                    print("エラー:cant trade[bid]")
                else:
                    last_trade_func = 'bid'
                    last_trade_size = amount
                    last_trade_price_pre = last_trade_price
                    last_trade_price = last_price[-1]
                    last_trade_order_id = trade_result['order_id']
                    trade_hold_count = 0
                    asset_info = True
                    call_success = True
                    last_trade_type = 0
                    check_results(trade_result)

            if call_success:
                print('■ 購入申請を行いました')
                pprint.pprint(trade_result)
                print("購入注文価格:" + str(last_price[-1]))
                print("購入注文量 :" + str(amount))
                message_func += '、購入'
                message_trade = 'bid'
                message_price = current_price
                message_size = amount

                try:
                    message_text = EXCHANGE + '■ 購入申請: ' + str(date_time) \
                                   + '\nPrice:' + str(current_price) + '\nSize:' + str(amount)
                    slack.notify(text=message_text)

                except:
                    error_log.write()
                    print("エラー:slack error")

        if cancel_flag and cancel_loop_count > CANCEL_LOOP_MAX:
            try:
                trade_info = zaif_trade.get_info2()
                if trade_info["open_orders"] > 0:
                    print("■ キャンセルしました")
                    print(zaif_trade.cancel_order(order_id=last_trade_order_id))
                    trade_hold_count = TRADE_HOLD_MAX
                    last_trade_price = last_trade_price_pre
                    message_func += '、キャンセル'
                    message_text = EXCHANGE + '■ キャンセルしました'
                    slack.notify(text=message_text)
                    asset_info = True
                    if last_trade_type == 1 or last_trade_type == 2:
                        profit_count -= 1
                    elif last_trade_type == 3:
                        loss_count -= 1
                else:
                    print("■ 約定しました。")
                    message_func += '、約定'
                    message_text = EXCHANGE + '■ 約定しました'
                    slack.notify(text=message_text)
                    asset_info = True
                last_trade_order_id = 0
            except:
                error_log.write()
                print("エラー:cant trade[info/cancel]")
            else:
                cancel_flag = False

        if len(last_price) >= PERIOD2:
            if len(last_price) != PERIOD2:
                trade_log.write(
                    func=message_func,
                    coin_asset=funds_coin,
                    jpy_asset=funds_jpy,
                    market_price=current_price,
                    order_id=last_trade_order_id,
                    trade=message_trade,
                    last_trade_price=last_trade_price,
                    price=message_price,
                    size=message_size,
                    mean_line1=moving_avg1,
                    mean_line2=moving_avg2,
                    bid_amount=bid_amount,
                    ask_amount=ask_amount,
                    sigma2=sigma)

            cancel_loop_count += 1
            trade_hold_count += 1
            moving_avg1_pre = moving_avg1
            moving_avg1 = np.average(last_price[-PERIOD1:])
            moving_avg2_pre = moving_avg2
            moving_avg2 = np.average(last_price[-PERIOD2:])
            sigma = np.std(last_price[-PERIOD2:], ddof=1)
            high_borin1 = moving_avg2 + sigma
            high_borin2 = moving_avg2 + sigma * 2
            low_borin1 = moving_avg2 - sigma
            low_borin2 = moving_avg2 - sigma * 2

        if date_time > end_datetime:
            END_FLAG = True

        if funds_coin < 0.0001 and END_FLAG and last_trade_order_id == 0:
            message_text = EXCHANGE + 'プログラム終了\n' + str(date_time) + '\njpy資産:' \
                           + str(funds_jpy) + '\n' + COIN_NAME + '資産:' + str(funds_coin) \
                           + '\nProfit:' + str(profit_count) + ' Loss:' + str(loss_count) \
                           + '\nGain:' + str(funds_jpy - start_funds_jpy)
            slack.notify(text=message_text)
            exit()

        end_time = time.time()
        elpsed_time = end_time - start_time
        if elpsed_time > LOOP_TIME:
            elpsed_time %= LOOP_TIME
            print('ake time over', str(LOOP_TIME), 'sec')

        time.sleep(LOOP_TIME - elpsed_time)

Monappy: MBDQ39VHypMQwfyR8SshuHvfPNUz321F6B

Monacoinを投げる
モナゲ(tipmona)ってなに?
そもそもMonacoinってなに?

コメントを残す

メールアドレスが公開されることはありません。