Skip to content

backtest 전략을 실제 투자에 적용하기 #2

사이드 프로젝트 링크 : https://www.github.com/fromitive/backtest

고려해야할 사항 (계속)

이번엔 매수를 하는 API를 어떻게 구현할지 고민해본다.

요구사항
1. top 5 거래량은 어떻게 추출할 것인지 (완료)
2. 매수를 하는 API는 어떻게 구현 하는지
3. 매수 할 때의 금액은 어떻게 계산할 것인지
4. 매수 플래그는 어떻게 세팅할 것인지
5. 주문은 했으나, 구매에 성공했는지 안했는지 어떻게 확인할 수 있는지
6. 매수한 코인의 수익율은 어떻게 실시간으로 계산하는지
7. 매수한 코인의 매도에 실패 했을 때, 어떻게 주문을 취소하고 재 매도할 수 있는지

bithumb api - 매수 및 매도

빗썸 API 가이드를 따르자면 구매 및 판매를 할 때, api 키secret 키가 필요하다고 한다.

파이썬 예제 코드는 빗썸 API 가이드에서 가져왔으며, 천천히 분석한다.

매수 및 매도
import requests

url = "https://api.bithumb.com/trade/place"

headers = {
    "accept": "application/json",
    "content-type": "application/x-www-form-urlencoded",
    "Api-Key": "사용자 Access Key",
    "Api-Nonce": "현재시각(ms)",
    "Api-Sign": "상세 가이드 참고"
}

response = requests.post(url, headers=headers)

print(response.text)

5 번째 줄headers변수에 사용자 API를 세팅하고, POST 메소드를 이용해 호출하는 것 으로 분석된다.

10 번째 줄에서 상세 가이드에 나와 있는대로 API를 세팅하면, API를 사용할 수 있을 것이다.

bithumb api - private api 상세 가이드

인증 헤더 만들기에서 API 헤더를 만드는 내용이 첨부되어 있으며

파이썬 예제코드가 있어서 바로 실행해 보았다. 아래는 빗썸에서 제공하고 있는 파이썬 예제 코드이다

인증 헤더 구현.py
import time
import math
import base64
import hmac, hashlib
import urllib.parse
import requests

class XCoinAPI:
    api_url = "https://api.bithumb.com";
    api_key = "";
    api_secret = "";

    def __init__(self, api_key, api_secret):
        self.api_key = api_key;
        self.api_secret = api_secret;

    def body_callback(self, buf):
        self.contents = buf;

    def microtime(self, get_as_float = False):
        if get_as_float:
            return time.time()
        else:
            return '%f %d' % math.modf(time.time())

    def usecTime(self) :
        mt = self.microtime(False)
        mt_array = mt.split(" ")[:2];
        return mt_array[1] + mt_array[0][2:5];

    def xcoinApiCall(self, endpoint, rgParams):
        # 1. Api-Sign and Api-Nonce information generation.
        # 2. Request related information from the Bithumb API server.
        #
        # - nonce: it is an arbitrary number that may only be used once.
        # - api_sign: API signature information created in various combinations values.

        endpoint_item_array = {
            "endpoint" : endpoint
        }

        uri_array = dict(endpoint_item_array, **rgParams) # Concatenate the two arrays.

        str_data = urllib.parse.urlencode(uri_array)

        nonce = self.usecTime()

        data = endpoint + chr(0) + str_data + chr(0) + nonce
        utf8_data = data.encode('utf-8')

        key = self.api_secret
        utf8_key = key.encode('utf-8')

        h = hmac.new(bytes(utf8_key), utf8_data, hashlib.sha512)
        hex_output = h.hexdigest()
        utf8_hex_output = hex_output.encode('utf-8')

        api_sign = base64.b64encode(utf8_hex_output)
        utf8_api_sign = api_sign.decode('utf-8')

        headers = {
            "Accept": "application/json",
            "Content-Type": "application/x-www-form-urlencoded",
            "Api-Key": self.api_key,
            "Api-Nonce": nonce,
            "Api-Sign": utf8_api_sign
        }

        url = self.api_url + endpoint

        r = requests.post(url, headers=headers, data=rgParams)
        return r.json()

아래의 코드로 위의 예제코드를 실행해 보았다.

주의사항

해당 코드의 api_keysecret_key는 실제 API키가 아니며, 테스트를 하기 위해서는 bithumb 홈페이지 내 API 관리 메뉴에서 발급이 필요하다.

인증 API 예제.py
if __name__ == '__main__':
    bithumb = XCoinAPI('api_key','secret_key')
    print(bithumb2.xcoinApiCall('/info/balance',{'currency':'BTC'}))

하지만 결과는 아래와 같이 나온다.

실행 결과
(env) ubuntu@ubuntu:~/coding-interview$ python bithumb_api.py 
{'status': '5100', 'message': 'Bad Request.(Auth Data)'}

가이드 대로 했는데 왜 5100에러가 나타나는 건가.. 라고 하는 순간 가이드 를 보면 아래와 같이 Api-Sign을 설정하는 것을 확인할 수 있었다.

Api-Sign : End Point + Request Parameter + Api-Nonce + 사용자 Secret Key를 조합하여 인코딩한 값

하지만 예제 코드에는 endpoint를 두번 감싼다.

예제 코드2.py
import time
import math
import base64
import hmac, hashlib
import urllib.parse
import requests

class XCoinAPI:
    api_url = "https://api.bithumb.com";
    api_key = "";
    api_secret = "";

    # ...(중략)...

    def xcoinApiCall(self, endpoint, rgParams):
        # 1. Api-Sign and Api-Nonce information generation.
        # 2. Request related information from the Bithumb API server.
        #
        # - nonce: it is an arbitrary number that may only be used once.
        # - api_sign: API signature information created in various combinations values.

        endpoint_item_array = {
            "endpoint" : endpoint
        }

        uri_array = dict(endpoint_item_array, **rgParams) # Concatenate the two arrays.

        str_data = urllib.parse.urlencode(uri_array)

        nonce = self.usecTime()
        # str_data에 endpoint 파라미터가 들어가게 된다.
        data = endpoint + chr(0) + str_data + chr(0) + nonce
        utf8_data = data.encode('utf-8')

        key = self.api_secret
        utf8_key = key.encode('utf-8')

        h = hmac.new(bytes(utf8_key), utf8_data, hashlib.sha512)
        hex_output = h.hexdigest()
        utf8_hex_output = hex_output.encode('utf-8')

        api_sign = base64.b64encode(utf8_hex_output)
        utf8_api_sign = api_sign.decode('utf-8')

        headers = {
            "Accept": "application/json",
            "Content-Type": "application/x-www-form-urlencoded",
            "Api-Key": self.api_key,
            "Api-Nonce": nonce,
            "Api-Sign": utf8_api_sign
        }

        url = self.api_url + endpoint

        r = requests.post(url, headers=headers, data=rgParams)
        return r.json()

따라서, 중복인 endpoint 값을 제거하고 str_datargParams만 넣고 수정한 후 실행하면 잘 나오는 것을 확인할 수 있다.

수정 된 예제 코드.py
import time
import math
import base64
import hmac, hashlib
import urllib.parse
import requests

class XCoinAPI:
    api_url = "https://api.bithumb.com";
    api_key = "";
    api_secret = "";

    # ...(중략)...

    def xcoinApiCall(self, endpoint, rgParams):
        # 1. Api-Sign and Api-Nonce information generation.
        # 2. Request related information from the Bithumb API server.
        #
        # - nonce: it is an arbitrary number that may only be used once.
        # - api_sign: API signature information created in various combinations values.

        str_data = urllib.parse.urlencode(rgParams) 

        nonce = self.usecTime()
        # str_data에 endpoint 파라미터가 들어가게 된다.
        data = endpoint + chr(0) + str_data + chr(0) + nonce
        utf8_data = data.encode('utf-8')

        key = self.api_secret
        utf8_key = key.encode('utf-8')

        h = hmac.new(bytes(utf8_key), utf8_data, hashlib.sha512)
        hex_output = h.hexdigest()
        utf8_hex_output = hex_output.encode('utf-8')

        api_sign = base64.b64encode(utf8_hex_output)
        utf8_api_sign = api_sign.decode('utf-8')

        headers = {
            "Accept": "application/json",
            "Content-Type": "application/x-www-form-urlencoded",
            "Api-Key": self.api_key,
            "Api-Nonce": nonce,
            "Api-Sign": utf8_api_sign
        }

        url = self.api_url + endpoint

        r = requests.post(url, headers=headers, data=rgParams)
        return r.json()

if __name__ == '__main__':
    bithumb = XCoinAPI('api_key','secret_key')
    print(bithumb2.xcoinApiCall('/info/balance',{'currency':'BTC'}))
실행 결과
(env) ubuntu@ubuntu:~/coding-interview$ python bithumb_api.py 
{'status': '0000', 'data': {'total_krw': '현금', 'in_use_krw': '현금', 'available_krw': '현금', 'total_btc': '비트코인', 'in_use_btc': '비트코인', 'available_btc': '비트코인', 'xcoin_last_btc': '비트코인'}}

다음은?

다음 내용은 API 구현 찾느라 시간이 지체되었다. 문서의 오류는 pybithumb과 비교하였으며, 본격적으로 pybithumb을 분석해 볼 것이다.


Comments