FX・シストレ Python プログラミング

【Python】GMOコインでビットコインを自動取引するプログラムを作成してみた

この記事は約14分で読めます。

 

 

こんにちはミナピピンです。今回はPythonで「GMOコイン」でビットコインを自動取引するプログラムを作成していきたいと思います。

 

GMOコインのAPIドキュメント:https://api.coin.z.com/docs/

 

CryptowatchのAPI レートリミットは一定時間で一定回数以内という制限ではなくCPU処理時間によって制限されます。CPU処理時間とはサーバーがAPIに対するレスポンスを返すのに利用したCPUの処理時間です。

 

get_btcprice()で使用しているCryptowatchのAPIは何種類かあり、実行するAPIによってサーバーでの処理の重さが異なります。Cryptowatchのレートリミットは1時間でサーバーが返事を返すのにかかるCPUの処理時間の合計が8秒を超えた場合に発生します。なので無料版のAPIを叩く時は迂闊にデータの多いリクエストは送らないように注意しましょう。

 

ブログの乗せるコードはとりあえずこんな感じ。ここからprint文を消してメール処理とかdb処理とかして使うと良いと思います。あと関数内で重複して処理があるのでクラスとかで共通化できます。時間がないのでおいおいちゃんとした解説記事を書きます。

 

import numpy as np
import pandas as pd
import time
from datetime import datetime
import talib
import requests
import json
import hmac
import hashlib



#GMOコインのAPI鍵
api_key = '自分のAPI鍵'
secret = '自分のAPI秘密鍵'


def build_position(ticker,side, amount, exe_type, price='', loss_rate=''):
    timestamp = '{0}000'.format(int(time.mktime(datetime.now().timetuple())))
    method    = 'POST'
    endPoint  = 'https://api.coin.z.com/private'
    path      = '/v1/order'
    reqBody = {
        "symbol": ticker,
        "side": side,
        "executionType": exe_type,
        "timeInForce": "FAK",
        "price": price,
        "losscutPrice": loss_rate,
        "size": amount
    }
    text = timestamp + method + path + json.dumps(reqBody)
    sign = hmac.new(bytes(secret.encode('ascii')), bytes(text.encode('ascii')), hashlib.sha256).hexdigest()
    headers = {
        "API-KEY": api_key,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
    res = requests.post(endPoint + path, headers=headers, data=json.dumps(reqBody))
    return res.json()


def get_position():
    timestamp = '{0}000'.format(int(time.mktime(datetime.now().timetuple())))
    method    = 'GET'
    endPoint  = 'https://api.coin.z.com/private'
    path      = '/v1/openPositions'

    text = timestamp + method + path
    sign = hmac.new(bytes(secret.encode('ascii')), bytes(text.encode('ascii')), hashlib.sha256).hexdigest()
    parameters = {
        "symbol": "BTC_JPY",
        "page": 1,
        "count": 100
    }

    headers = {
        "API-KEY": api_key,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
    res = requests.get(endPoint + path, headers=headers, params=parameters)
    return res.json()


def close_position(ticker, side, amount, exe_type, position_id):
    timestamp = '{0}000'.format(int(time.mktime(datetime.now().timetuple())))
    method    = 'POST'
    endPoint  = 'https://api.coin.z.com/private'
    path      = '/v1/closeOrder'
    reqBody = {
        "symbol": ticker,
        "side": side,
        "executionType": exe_type,
        "timeInForce": "",
        "price": "",
        "settlePosition": [
            {
                "positionId": position_id,
                "size": amount
            }
        ]
    }
    text = timestamp + method + path + json.dumps(reqBody)
    sign = hmac.new(bytes(secret.encode('ascii')), bytes(text.encode('ascii')), hashlib.sha256).hexdigest()
    headers = {
        "API-KEY": api_key,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
    res = requests.post(endPoint + path, headers=headers, data=json.dumps(reqBody))
    return res.json()


def exe_position(side,position):
    if side == 'BUY':
        close_side = 'SELL'
    elif side == 'SELL':
        close_side = 'BUY'
    for i in position:
        if i['side']=='BUY':
            close_res = close_position(i['symbol'], close_side, i['size'], 'MARKET',i['positionId'])
            if close_res['status'] ==0:
                print('買い注文を決済しました')
            else:
                print(close_res)
        elif i['side']=='SELL':
            close_res = close_position(i['symbol'], close_side, i['size'], 'MARKET',i['positionId'])
            if close_res['status'] ==0:
                print('売り注文を決済しました')
            else:
                print(close_res)

def exe_all_position():
    position = get_position()
    if position['data'] == {}:
        print('ポジションはありません')
    else:
        for i in position['data']['list']:
            if i['side']=='BUY':
                close_res = close_position(i['symbol'], 'SELL', i['size'], 'MARKET',i['positionId'])
                if close_res['status'] ==0:
                    print(datetime.now(), '注文を決済(sell)しました')
                else:
                    print(close_res)
            elif i['side']=='SELL':
                close_res = close_position(i['symbol'], 'BUY', i['size'], 'MARKET',i['positionId'])
                if close_res['status'] ==0:
                    print(datetime.now(), '注文を決済(buy)しました')
                else:
                    print(close_res)

def get_btcprice():
    url = 'https://api.cryptowat.ch/markets/bitflyer/btcjpy/ohlc?periods=300&after=' + str(int(time.time()-10800)) 
    r = requests.get(url)
    r2 = json.loads(r.text)
    pricedata = []
    for data in r2['result']['300']:
        dt = datetime.fromtimestamp(data[0])
        price = data[4]
        vol = data[5]
        pricedata.append([dt, price, vol])
    return pd.DataFrame(pricedata, columns=['date','price','vol'])
    
    

def order_process(side):
  
    if side == 'BUY':
        result = build_position(ticker,side, amount, exe_type, price='', loss_rate='')
        print('ビットコインを' + str(get_position()['data']['list'][0]['price']) + '円でロングしました')
    elif side == 'SELL':
        result = build_position(ticker,side, amount, exe_type, price='', loss_rate='')
        print('ビットコインを' + str(get_position()['data']['list'][0]['price']) + '円でショートしました')
    else:
        pass


def algorithmic_trade():
    if momentam[-1] > 0 and macd[2][-1] > 0:
        order_process('BUY')
    elif momentam[-1] < 0 and macd[2][-1] < 0 and trend[2][-1] < 0 and vol_trend.iloc[-1] < 0:
        order_process('SELL')
    else:
        order_process('no')
        print('シグナル無反応',momentam[-1],macd[2][-1])


def get_balance():
    timestamp = '{0}000'.format(int(time.mktime(datetime.now().timetuple())))
    method    = 'GET'
    endPoint  = 'https://api.coin.z.com/private'
    path      = '/v1/account/margin'

    text = timestamp + method + path
    sign = hmac.new(bytes(secret.encode('ascii')), bytes(text.encode('ascii')), hashlib.sha256).hexdigest()

    headers = {
        "API-KEY": api_key,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }

    res = requests.get(endPoint + path, headers=headers)
    return res.json()



# ーーーーーーーーーーーーーーーbot本体の処理ーーーーーーーーーーーーーーーーーーーーー#
while True:
    # 残高を取得する
    ticker = "BTC_JPY"
    exe_type = 'MARKET'

    # ポジションを決済する
    exe_all_position()
    time.sleep(3)
    after_balances = int(get_balance()['data']['availableAmount'])
    profit_loss = after_balances - 50000
    if profit_loss > 0:
        print('現在の残高は' + str(after_balances) + '円です')
    elif profit_loss <= 0:
        print('現在の残高は' + str(after_balances) + '円です')
    time.sleep(3)

    # 価格取得&シグナル算出 botを走らせる前準備(テクニカル指標はグローバル変数)
    bitcoin_price = get_btcprice()['price']
    today_price = bitcoin_price[35]
    print('現在のビットコイン価格は' + str(today_price) + '円です')
    # 残高とBTC価格から注文量を計算する
    amount = round(after_balances / today_price * 2, 2)
    numpyprice = np.array([float(x) for x in bitcoin_price])

    # macdの短期トレンドを計算する
    macd = talib.MACD(numpyprice, fastperiod=5, slowperiod=25, signalperiod=3)
    momentam = talib.MOM(numpyprice, timeperiod=6)

    # macdの長期トレンドを計算する
    trend = talib.MACD(numpyprice, fastperiod=9,
                       slowperiod=10, signalperiod=10)

    # 出来高のトレンドを計算する
    df = get_btcprice()['vol']
    vol_trend = df.rolling(window=5).mean() - df.rolling(window=25).mean()

    # 指定したシグナルに従って取引する
    algorithmic_trade()
    print('-------------------------------------------')
    time.sleep(300)

 

関連記事:【Python】ビットコインの高頻度価格データ(5分足)をGMOコインのAPIでスクレイピングする

 


プログラミング・スクレイピングツール作成の相談を受け付けています!

クラウドワークス・ココナラ・MENTAなどでPython・SQL・GASなどのプログラミングに関する相談やツール作成などを承っております!

過去の案件事例:

  • Twitter・インスタグラムの自動化ツール作成
  • ウェブサイトのスクレイピングサポート
  • ダッシュボード・サイト作成
  • データエンジニア転職相談

これまでの案件例を見る

キャリア相談もお気軽に!文系学部卒からエンジニア・データサイエンティストへの転職経験をもとに、未経験者がどう進むべきかのアドバイスを提供します。


スポンサーリンク
/* プログラミング速報関連記事一覧表示 */
ミナピピンの研究室

コメント

タイトルとURLをコピーしました