backtest 전략을 실제 투자에 적용하기 #2
고려해야할 사항 (계속)
이번엔 매수를 하는 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 예제.pyif __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_data를 rgParams만 넣고 수정한 후 실행하면 잘 나오는 것을 확인할 수 있다.
| 수정 된 예제 코드.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을 분석해 볼 것이다.