프로젝트/암호화폐 투자 프로그램 제작

[코인 자동투자 봇 제작기 7] 가격 데이터, 기술적 지표 계산하기(1)

woghd 2024. 12. 18. 07:37
728x90

이제 가격 데이터를 받아오고, 기술적 지표를 계산하는 코드를 짜보자.

여기부터는 chat GPT의 도움을 좀 받아보도록 하겠다.

Chat GPT 신기능 - 프로젝트

챗 지피티 유료 버전 사용자라면, 사이드바에 프로젝트 라는 기능이 추가되어 있을 것이다.

이 기능을 활용하면 프로젝트 단위별로 여러 개의 채팅방을 묶어서 관리할 수 있고, 프로젝트와 관련된 파일들을 추가해두고 채팅을 할 수도 있다. 다만 사진 파일 외의 다른 파일을 넣으면 GPT O1은 활용할 수 없다는 점이 큰 단점이지만, 그럼에도 쓸만하다.

위 사진과 같이 만들어서 활용할 수 있다.

우선 지금은 이게 중요한 게 아니니, 나중에 따로 소개하도록 하고 지금은 프로젝트에 집중하도록 하겠다.


1. API 객체 생성

전에 설정한 API를 활용하기 위해서는, API 객체를 만들어야 한다. Binance api는 어떻게 활용하는지 우선 chat gpt에게 물어보자.

Binance api를 python에서 활용하고자 합니다. 사용법을 초보자도 쉽게 알아볼 수 있도록 정리해 주세요.

작성한 프롬포트이다.


아래는 GPT의 답변이다.


1 Binance 라이브러리 설정

아래 코드를 통해 API를 설정합니다.

from binance.client import Client

api_key = "YOUR_API_KEY"       # 발급받은 API 키
api_secret = "YOUR_SECRET_KEY" # 발급받은 Secret 키

client = Client(api_key, api_secret)  # Binance 클라이언트 생성

2 Public API: 시장 데이터 조회

현재 가격 조회

price = client.get_symbol_ticker(symbol="BTCUSDT")
print("BTC 가격:", price["price"])

캔들스틱 데이터 조회 (예: 1시간 단위 데이터)

candles = client.get_klines(symbol="BTCUSDT", interval=Client.KLINE_INTERVAL_1HOUR)

# 출력: 시간, 오픈, 하이, 로우, 클로즈 가격
for candle in candles[:5]:
    print(f"Time: {candle[0]}, Open: {candle[1]}, High: {candle[2]}, Low: {candle[3]}, Close: {candle[4]}")

3 Private API: 계정 정보 및 거래

계정 정보 조회

account_info = client.get_account()
print(account_info)

잔액 조회

balance = client.get_asset_balance(asset="USDT")
print("USDT 잔액:", balance["free"])

주문 실행

주의: 실수로 거래하지 않도록 주의하세요.

시장가 매수 주문:

order = client.order_market_buy(symbol="BTCUSDT", quantity=0.001)
print(order)

시장가 매도 주문:

order = client.order_market_sell(symbol="BTCUSDT", quantity=0.001)
print(order)

4. 기타 유용한 기능

거래 내역 조회

trades = client.get_my_trades(symbol="BTCUSDT")
for trade in trades:
    print(trade)

최근 거래 내역 조회 (Public API)

recent_trades = client.get_recent_trades(symbol="BTCUSDT")
for trade in recent_trades[:5]:
    print(trade)

이제 여기서 필요한 내용들을 추려서 data_control.py 파일에 적용하도록 하자.

main.py , data_control.py 코드 개발

우선 새로운 기능 브랜치를 만들어야 한다. 명령어는 전에도 설명했으니 생략.

그리고 binance api를 활용하기 위한 라이브러리를 다운로드받자.

pip install python-binance

그 뒤에, config 객체를 먼저 호출해서 access key와 secret key를 받아와서 객체를 만들어내면 된다.

main 코드의 입장에서 개발해나가면서 data_control 코드를 함께 수정하겠다. 개발 흐름에 따라 이어져가는 글이니 헷갈려도 어쩔 수 없다...

from binance.client import Client

from config import Config

def main():
    print("투자 프로그램을 시작합니다.")

    # Config에서 환경변수 및 고정변수 불러오기
    config = Config()
    client = Client(config.binance_access_key, config.binance_secret_key)

이런식으로 config = Config() 코드를 통해 객체를 한번 만들어 두면, Config 클래스 안에 들어있는 함수나 변수에 대해 자유롭게 접근할 수 있다.
이제 데이터를 불러오는 함수를 작성해보자.

현재 가격 조회

def get_current_price(self,client):
    print("현재 가격을 불러옵니다...")
    price = client.get_symbol_ticker(symbol="BTCUSDT")
    return price["price"]

gpt의 답변을 바탕으로 작성했다.
client를 쓰는 함수는 신경쓰지 않아도 되지만,
symbol 부분을 보니 입력을 "BTCUSDT"와 같이 붙여서 받는걸 볼 수 있다.
환경변수에는 USDT-BTC 형태로 저장해 뒀으니, 이 변수를 받아서 재가공한 후 입력을 넣어줘야 한다.
우선 위 함수의 경우는 symbol도 입력을 받는걸로 바꿔두자.

def get_current_price(self,client,symbol):
    print("현재 가격을 불러옵니다...")
    price = client.get_symbol_ticker(symbol)
    current_price = price["price"]
    return current_price

이제 입력은 client, symbol이 되고, 출력은 current_price가 된다.


과거 가격 조회

과거 가격 조회는 data 라는 하나의 함수로 만들어뒀다.

    def data(self,client):
        print("데이터를 불러옵니다...")

        print("기술적 지표를 데이터에 추가합니다.")

        print("데이터 로드 완료!")

여기에도 마찬가지로 input을 수정해야 한다.
입력은 client, symbol, timeframe, data(업데이트 시) 정도가 있겠고, 출력은 data가 된다.


candles = client.get_klines(symbol="BTCUSDT", interval=Client.KLINE_INTERVAL_1HOUR)

캔들 데이터는 위와 같이 불러올 수 있다고 한다.
타임프레임은 5분봉을 기준으로 매매할 것이고, 보조 타임프레임으로 1분봉과 1시간봉을 활용할 것이다.

def data(self,client,symbol,timeframe):
    limit = 100
    if timeframe == "1MINUTE":
        candles = client.get_klines(symbol=symbol, interval=client.KLINE_INTERVAL_1MINUTE, limit=limit)
    elif timeframe == "5MINUTE":
        candles = client.get_klines(symbol=symbol, interval=client.KLINE_INTERVAL_5MINUTE, limit=limit)
    elif timeframe == "1HOUR":
        candles = client.get_klines(symbol=symbol, interval=client.KLINE_INTERVAL_1HOUR, limit=limit)
    else:
        raise ValueError("Invalid timeframe. Please use '1MINUTE', '5MINUTE', or '1HOUR'.")

    # 새로운 데이터를 DataFrame으로 변환

    data = pd.DataFrame(candles, columns=[
        "Open Time", "Open", "High", "Low", "Close", "Volume",
        "Close Time", "Quote Asset Volume", "Number of Trades",
        "Taker Buy Base Asset Volume", "Taker Buy Quote Asset Volume", "Ignore"
    ])
    data["Open Time"] = pd.to_datetime(data["Open Time"], unit='ms')  # 시간 변환

    print("기술적 지표를 데이터에 추가합니다.")

    return data

위와 같이 코드를 작성했다. 하나씩 뜯어보면,

  1. timeframe 변수가 1분인지, 5분인지, 1시간인지에 따라 데이터를 불러온다. 만약 타임프레임이 지정되지 않았다면 오류를 반환한다.
  2. 불러온 데이터를 판다스의 데이터프레임형태로 변환한다. 나와있는 정보들을 어떻게 활용할 것인지는 조금 더 살펴보도록 하자.
  3. 시간 자료형으로 open time을 변환한다.
  4. 데이터를 반환한다.

이제 data를 불러오는 코드를 작성했으니, main.py 파일로 넘어가서 해당 부분에 대한 로직을 추가해주자.

from binance.client import Client

from config import Config
from data_control import Data_Control

def main():
    print("투자 프로그램을 시작합니다.")
    
    # Config에서 환경변수 및 고정변수 불러오기
    config = Config()
    ticker_list = config.coin_tickers.split(" ")
    client = Client(config.binance_access_key, config.binance_secret_key)
    data_control = Data_Control()

    # 초기 자산 조회 - notifier.py

    # 반복문 시작
    while True:
        try:
            print("매수/매도 판단을 시작합니다.")
            for i in ticker_list:
            # 현재 가격 조회

            # 가격데이터 업데이트
                i.split("-")
                symbol = i[1]+i[0]
                data_1m = data_control.data(client,symbol,"1MINUTE")
                data_5m = data_control.data(client,symbol,"5MINUTE")
                data_1h = data_control.data(client,symbol,"1HOUR")

            # 매수/매도 판단

            # 주문 진행

        except Exception as e:
            print(f"메인 루프 오류: {e}")
            # notifier.py를 통해 error 로그 전송

여기서는 몇가지 추가적인 로직이 들어갔다. 

  1. 데이터를 업데이트하는 형식이 아니라 매번 새로운 데이터를 불러오는 방식으로 변경했으므로 초기 데이터 불러오기 부분을 삭제했다.
  2. 우리가 coin_tickers에서 몇개의 코인을 지정받을 지 모르니 우선 split 함수를 통해 분리하였다.
  3. 반복문을 통해 티커 개수만큼 구매판단을 하도록 했다.
  4. 그 후 symbol 형식을 맞추기 위해 하이픈(-)을 기준으로 다시 분리하여 문자열을 생성하도록 했다.
    (split 함수가 어디어디 쓰였는지 확인하면 금방 알 수 있는 로직이다.)
  5. 그 후에는 data_control 클래스 호출하고, data 함수 호출해서 데이터 구하기...

이정도로 작성하고, 다음 글에서는 기술적 지표를 추가하겠다.

 
 
728x90