코인 자동 매매 프로그램 만들기 [1] – chatGPT, 업비트, 비트코인, 페이스북 llama3.1, AI 투자 자동화 <- 링크

[1] 편에서 chatGPT 혹은 페이스북의 llama 3.1 무료 AI 모델에게 차트 정보를 주고 코인을 살지 말지에 대한 판단을 맞기고 그 판단을 믿고 python 코드로 비트코인을 사고 파는 것을 구현하였다.

[2] 편에서는 우리가 만든 파이썬 프로그램이 자동으로 일정 시간마다 실행되도록 하고, discord 를 활용하여 우리가 보고 싶은 코인, 프로그램 관련 정보를 볼 수 있고 알림을 받을 수 있도록 대시보드를 만들겠다.

1. python 코드 일정 시간마다 자동 실행

1.1. bat 파일 만들기

bat 파일을 만든다. txt 파일을 만들고 확장자를 .bat 으로 바꾸어도 된다.
bat 파일은 어디에다 만들지는 자유이다.

image 48

위와 같이 bat 파일을 만들어서 위 사진의 형식을 참고하여 그 안에 실행하고 싶은 코드들을 넣으면 된다.

anaconda 가상환경을 사용하고 있다면 위 사진처럼 하면 되고 그렇지 않다면 마지막 2줄의 코드만 넣으면 된다.

1.3. 작업 스케줄러 이용해서 자동 실행되게 만들기

윈도우 검색에 작업 스케줄러를 검색하여 들어간다.

image 40
image 41
image 42

새로운 작업을 만들 때 일반과 트리거 옵션에서는 위 사진처럼 하면 되고 본인의 의도에 맞게 작업 반복 간격을 설정해 주면 된다.

image 44
image 45

마지막 동작 옵션에서가 중요하다
“동작” 옵션을 들어가서 새로 만들기를 누르고 위 사진처럼
“찾아보기”를 통해 이전에 만들었던 .bat 파일을 선택하면 된다.

image 47

위 사진처럼 우리가 원하는 시간에 원하는 파이썬 코드가 실행되게 된다.

2. 디스코드로 메세지 보내고 알림 받기

2.1. discord 설치 및 웹후크 생성

discord 를 생성하여 채널을 만들자

image 36

만들었다면 채널의 설정에서

image 37

서버 설정 -> 앱 -> 연동 -> 웹후크 를 클릭하자

image 38

클릭하면 새 웹후크를 클릭한 뒤 생성된 웹후크를 클릭하면 “웹후크 URL 복사” 칸을 볼수 있다. 해당 URL 을 복사하자

image 51

2.2. 디스코드로 메세지 보내기

해당 URL 을 이용하여 디스코드에 메세지를 보낼 수 있다.

이제 아래 코드와 같이 discord 로 메세지를 보낼 수 있다.

def send_message(self, msg, embed_image_url=None):
        """Send a message to Discord"""
        now = datetime.datetime.now()
        message = {
            "content": f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] {str(msg)}",
        }
        if embed_image_url:
            message["embeds"] = [{"image": {"url": embed_image_url}}]
        
        requests.post(webhook, json=message)

2.3. 디스코드로 그래프 그려서 보내고 알림으로 그래프 받기

아래 코드를 통해서 우리는 discord 의 원하는 데이터를 담은 그래프를 보내고 우리가 이를 확인 할 수 있게 할 수 있다.

import requests

    def generate_chart_url(self, data):
        """Generate chart image URL using QuickChart API"""
        chart_data = {
            "type": "line",
            "data": {
                "labels": data.index.strftime('%H:%M').tolist(),
                "datasets": [
                    {
                        "label": "Close Price",
                        "data": data['close'].tolist(),
                        "borderColor": "rgb(75, 192, 192)",
                        "fill": False
                    },
                ],
            },
            "options": {
                "title": {"display": True, "text": "Bitcoin Close Price"},
                "scales": {
                    "xAxes": [{"scaleLabel": {"display": True, "labelString": "Time"}}],
                    "yAxes": [{"scaleLabel": {"display": True, "labelString": "Price (KRW)"}}],
                },
            },
        }
        
        encoded_chart = requests.utils.quote(json.dumps(chart_data))
        return f"https://quickchart.io/chart?c={encoded_chart}"

3. 최종 결과 및 전체 코드

image 50

위 사진과 같이 여러가지 정보들을 확인할 수 있다.

전체코드


from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)
from langchain_ollama import OllamaLLM
from langchain_core.output_parsers import StrOutputParser
import os
from dotenv import load_dotenv
import pyupbit
import json
import requests
import datetime
import time



# Load environment variables
load_dotenv()
access = os.getenv("UPBIT_ACCESS_KEY")
secret = os.getenv("UPBIT_SECRET_KEY")
webhook= os. getenv("DISCORD_WEBHOOK_URL")

INPUT_MONEY = 100000

system_template = """
You are an expert in Bitcoin investing. Based on the provided chart data, determine whether to buy, sell, or hold.
ONLY respond in JSON format with keys "decision" and "reason". No additional explanations, just JSON.

You MUST choose one of the following three options for "decision": "buy", "sell", or "hold".
Do not use any other words or formats.

Format Example:
{{"decision": "buy", "reason": "some technical reason"}}
{{"decision": "sell", "reason": "some technical reason"}}
{{"decision": "hold", "reason": "some technical reason"}}
"""

# Create the system and user message templates
system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)
user_message_prompt = HumanMessagePromptTemplate.from_template("{input}")

# Define the chat prompt template with system and user messages
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, user_message_prompt])

# Initialize the LLM model
llm = OllamaLLM(model="llama3.1:70b")

# Create the chain with prompt and output parser
chain = chat_prompt | llm | StrOutputParser()

class autoCoinBot:
    def __init__(self):
        self.send_message("AI COIN BOT 시작")

    def send_message(self, msg, embed_image_url=None):
        """Send a message to Discord"""
        now = datetime.datetime.now()
        message = {
            "content": f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] {str(msg)}",
        }
        if embed_image_url:
            message["embeds"] = [{"image": {"url": embed_image_url}}]
        
        requests.post(webhook, json=message)

    def generate_chart_url(self, data):
        """Generate chart image URL using QuickChart API"""
        chart_data = {
            "type": "line",
            "data": {
                "labels": data.index.strftime('%H:%M').tolist(),
                "datasets": [
                    {
                        "label": "Close Price",
                        "data": data['close'].tolist(),
                        "borderColor": "rgb(75, 192, 192)",
                        "fill": False
                    },
                ],
            },
            "options": {
                "title": {"display": True, "text": "Bitcoin Close Price"},
                "scales": {
                    "xAxes": [{"scaleLabel": {"display": True, "labelString": "Time"}}],
                    "yAxes": [{"scaleLabel": {"display": True, "labelString": "Price (KRW)"}}],
                },
            },
        }
        
        encoded_chart = requests.utils.quote(json.dumps(chart_data))
        return f"https://quickchart.io/chart?c={encoded_chart}"

    def ai_trading(self):
        
        
        upbit = pyupbit.Upbit(access, secret)
        
         # Retrieve Bitcoin and KRW balances
        btc_balance = upbit.get_balance("KRW-BTC")
        time.sleep(1)
        krw_balance = upbit.get_balance("KRW")
        time.sleep(1)
        current_price = pyupbit.get_current_price("KRW-BTC")
        time.sleep(1)
        
        # Calculate profit or loss based on entry price
        profit = (btc_balance+krw_balance)/INPUT_MONEY

        # Send balance and profit info to Discord
        self.send_message(f"Current BTC Balance: {btc_balance*current_price} KRW")
        self.send_message(f"Current KRW Balance: {krw_balance} KRW")
        self.send_message(f"Rate    Of  Return : {profit:.2f} %")

        # Retrieve Bitcoin chart data
        input_data = pyupbit.get_ohlcv("KRW-BTC", count=20, interval="minute5")
        # Generate chart URL
        chart_url = self.generate_chart_url(input_data)
        # Send chart image to Discord
        self.send_message("Here's the latest Bitcoin chart:", embed_image_url=chart_url)

        # Execute the chain with the input data
        result = chain.invoke({"input": input_data})

        # Format and log the result
        self.send_message("Result:")
        self.send_message(result)

        result = json.loads(result)
    
        self.send_message(f"### AI DECISION: {result['decision'].upper()} ###")
        self.send_message(f"### Reason: {result['reason']} ###")
        
        division = 3

        if result['decision'] == "buy":
            my_krw = upbit.get_balance("KRW")
            if my_krw * 0.9955 > 5000 * division:
                self.send_message("### Buy Order Executed ###")
                self.send_message(upbit.buy_market_order("KRW-BTC", upbit.get_balance("KRW") / division))
            elif my_krw * 0.9955 > 5000:
                self.send_message("### Buy Order Executed ###")
                self.send_message(upbit.buy_market_order("KRW-BTC", upbit.get_balance("KRW")))    
            else:
                self.send_message("### Buy Order Failed: Insufficient KRW (less than 5000 KRW) ###")
            
        elif result['decision'] == "sell":
            my_btc = upbit.get_balance("KRW-BTC")
            current_price = pyupbit.get_orderbook(ticker="KRW-BTC")['orderbook_units'][0]["ask_price"]
            if my_btc * current_price > 5000 * division:
                self.send_message("### Sell Order Executed ###")
                self.send_message(upbit.sell_market_order("KRW-BTC", upbit.get_balance("KRW-BTC") / division))
            elif my_btc * current_price > 5000:
                self.send_message("### Sell Order Executed ###")
                self.send_message(upbit.sell_market_order("KRW-BTC", upbit.get_balance("KRW-BTC")))
            else:
                self.send_message("### Sell Order Failed: Insufficient BTC (less than 5000 KRW worth) ###")

        elif result['decision'] == "hold":
            self.send_message(result["reason"])

def main():
    # Initialize and run the bot
    bot = autoCoinBot()
    bot.ai_trading()

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        autoCoinBot().send_message(f"Exception occurred: {e}")

2 Comments

ㅇㅇ · October 30, 2024 at 10:45 pm

부자되세요~

    KANG · October 30, 2024 at 10:48 pm

    정진하겠습니다.

Leave a Reply