새소식

💻 Programming (프로그래밍)/Python

[Python][업비트 자동매매프로그램] 5. 기능 (2)

  • -

해당 포스팅은 upbit API를 손쉽게 이용하기 위한 pyupbit 그리고 GUI 라이브러리를 위한 tkinter을 사용하였습니다.

[UPBIT] DCTSS(가상화폐 매매 서포트 프로그램)


🌳 1. mainView

mainView 전체보기

더보기
from asyncio.windows_events import NULL
import tkinter as tk
import tkinter.messagebox as msgbox
import pyupbit
from tkinter.constants import BOTH, TOP
from . import orderF1
from ..V2 import subView as W2

class View_main(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.upbit = self.__Account_Init()
        self._jobB =None
        self._jobS =None
        self._jobAuto =None
        self._Auto_Base_Price =None

        self.in_list_frame = orderF1.orderFrame(self, text="진행중인 주문") # 매매진행 리스트 프레임
        self.standby_list_frame = orderF1.orderFrame(self, text="대기중인 주문") # 매매대기 리스트 프레임
        self.func_frame = orderF1.funcFrame(self, n1 = "추가", n2 = "삭제") # 기능 프레임1(추가, 삭제)
        self.func_frame2 = orderF1.funcFrame(self, n1= "실행", n2= "실행취소") # 기능 프레임2 (실행, 실행취소버튼)
        self.func_frame3 = orderF1.funcFrame(self, n1="자동매수", n2="자동매수취소")  # 기능 프레임3 (자동매수, 자동매수취소버튼 )
        self.cur_asset_frame = orderF1.currencyFrame(self) # 주문가능한 현재자산 프레임

        # Packing
        self.in_list_frame.pack(fill="both", expand=True, padx=5, pady=5, ipady=5)
        self.standby_list_frame.pack(fill="both", expand=True, padx=5, pady=5, ipady=5)
        self.func_frame.pack(fill="both", padx=5, pady=5)
        self.func_frame2.pack(fill="both", padx=5, pady=5)
        self.func_frame3.pack(fill="both", padx=5, pady=5)
        self.cur_asset_frame.pack(fill="both", padx=5, pady=5, ipady=10, ipadx=10)

        # Function
        self.__Update_currency()
        self.func_frame.btn1.bind("<Button-1>", self.Add_Ticker) # need 보이게 하는 기능 추가
        self.func_frame.btn2.bind("<Button-1>", self.Del_Ticker)
        self.func_frame2.btn1.bind("<Button-1>", self.Check)
        self.func_frame2.btn2.bind("<Button-1>", self.Cancle)
        self.func_frame3.btn1.bind("<Button-1>", self.AutoCheck)
        self.func_frame3.btn2.bind("<Button-1>", self.AutoCancle)
    
    def __Account_Init(self):
        # access key와 secret key를 발급
        f = open("업비트 키 경로")
        lines = f.readlines()
        access = lines[0].strip()
        secret = lines[1].strip()
        f.close()
        
        # 업비트 exchange APi를 위하여 객체만듬
        upbit = pyupbit.Upbit(access, secret)
        return upbit

    def __Update_currency(self):
        cur_krw_balances = self.upbit.get_balance("KRW")
        self.cur_asset_frame.cur_asset_label.configure(text=cur_krw_balances)
        self.after(3000, self.__Update_currency)

    def Add_Ticker(self, event):
        window = tk.Toplevel(self)
        self.subMain = W2.View_main(window)
        self.subMain.pack(fill = BOTH, expand= True)
        self.subMain.okcnl_frame.btn1.bind("<Button-1>", self.Add_Confirm)

    def Del_Ticker(self, event):
        for index in reversed(self.standby_list_frame.in_list.curselection()):   # 리스트박스에 클릭한 것을 순서를 출력해주고 그것을 리버스로 반환함
            self.standby_list_frame.in_list.delete(index)

    def Add_Confirm(self, event):
        mm_txt = []
        mm_txt = [self.subMain.request_frame.cmb_type.get(), self.subMain.request_frame.cmb_amount.get(),\
            self.subMain.buy_frame.e.get(), self.subMain.sell_frame.e.get(), self.subMain.stoploss_frame.e.get()]
        self.standby_list_frame.in_list.insert(tk.END, mm_txt)

    #################
    # Check_Price -> (예약주문)매수 , Check_Price -> (현재진행중인)매도
    def Check(self, event):
        B_size = self.standby_list_frame.in_list.size()
        S_size = self.in_list_frame.in_list.size()
        if(B_size == 0 and S_size == 0):
            self.after(100, orderF1.my_Msg.info_error)
            return

        self.after(100, orderF1.my_Msg.info_start)
        self.Check_S()
        self.Check_B()

    def Cancle(self, event):
        try:
            #if func == 'B':
            if self._jobB != None:
                self.after_cancel(self._jobB)
                self.standby_list_frame.in_switch.config(bg="#FF6666")
                self._jobB = None
            
            #if func == 'S':
            if self._jobS != None:
                self.after_cancel(self._jobS)
                self.in_list_frame.in_switch.config(bg="#FF6666")
                self._jobS = None    

            self.after(100, orderF1.my_Msg.info_cnl)
        
        except:
            self.after(100, orderF1.my_Msg.info_error4)     

    def Check_B(self):
        size = self.standby_list_frame.in_list.size() # 확인해보려는 코인 개수
        coins = self.standby_list_frame.in_list.get(0, size)

        # 매수
        for i in coins:
            coin_ticker = "KRW-"+ i[0] # 코인 종류
            buy_target = float(i[2]) # 매수 목표가
            cur_price = float(pyupbit.get_current_price(coin_ticker))
            print(cur_price)
            if cur_price >= buy_target:
                # 매수 함수
                self.after(10, self.Start_Buy(i))
                return

        self.standby_list_frame.in_switch.config(bg="#66FF66")
        self._jobB = self.after(1000, self.Check_B)
    
    def Check_S(self):
        size = self.in_list_frame.in_list.size() # 확인해보려는 코인 개수
        coins = self.in_list_frame.in_list.get(0, size)

        if size > 0:
            # 매도
            for i in coins:
                coin_ticker = "KRW-"+ i[0] # 코인 종류
                sell_target = float(i[3]) # 매도 목표가
                stoploss_taget = float(i[4]) # 손절 목표가
                cur_price = float(pyupbit.get_current_price(coin_ticker))

                if cur_price >= sell_target:   # 손절
                    # 매도 함수
                    self.after(10, self.Start_Sell(i, coins.index(i)))
                    return

                if cur_price <= stoploss_taget: # 손절
                    # 매도 함수
                    self.after(10, self.Start_Sell(i, coins.index(i)))
                    return
        
        self.in_list_frame.in_switch.config(bg="#66FF66")       
        self._jobS = self.after(1000, self.Check_S)
    
    # 시장가 매수, 나중에 지정가로 바꿀 예정
    def Start_Buy(self, coin):
        coin_ticker = "KRW-"+ coin[0] # 코인 종류
        buy_percent = coin[1] # 남은 가격 매수 퍼센트

        krw_balance = self.upbit.get_balance("KRW")
        buy_percent = float(buy_percent[:-1]) / 100
        coin_balance = krw_balance * buy_percent
        coin_balance = round(coin_balance, -3)

        if(coin_balance <= 5000 or krw_balance <= 5000):
            self.after(100, orderF1.my_Msg.info_error3)
            return

        #self.upbit.buy_market_order(coin_ticker, krw_balance)
        tmp = coin + (coin_balance, round(coin_balance*float(coin[3])/float(coin[2])),\
            round(coin_balance*float(coin[4])/float(coin[2])),)
        
        self.standby_list_frame.in_list.delete(0,tk.END)
        self.in_list_frame.in_list.insert(tk.END, tmp)
        self.standby_list_frame.in_switch.config(bg="#FF6666")
        self.after(100, orderF1.my_Msg.info_buy)

    # 시장가 매도, 나중에 지정가로 바꿀 예정
    def Start_Sell(self, coin, idx):
        coin_ticker = "KRW-"+ coin[0] # 코인 종류
        coin_balance = self.upbit.get_balance(coin_ticker) # 내가 산 코인 수량
        
        self.after(100, orderF1.my_Msg.info_sell)
        self.upbit.sell_market_order(coin_ticker, coin_balance)
        self.in_list_frame.in_list.delete(idx)
        self.in_list_frame.in_switch.config(bg="#FF6666")

    ########## 
    # 자동매매
    def AutoCancle(self, event):
        try:
            #if func == 'Auto':
            if self._jobAuto != None:
                self.after_cancel(self._jobAuto)
                self._jobAuto = None
                self._Auto_Base_Price = None
            self.after(100, orderF1.my_Msg.info_auto_cnl)
        except:
            self.after(100, orderF1.my_Msg.info_error4) 


    def AutoCheck(self, event):
        tickers = pyupbit.get_tickers(fiat="KRW")

        # 시작 했을때의 가격 기준점
        if self._Auto_Base_Price == None:
            self.after(100, orderF1.my_Msg.info_auto)
            self._Auto_Base_Price = pyupbit.get_current_price(tickers)

        # 갱신되는 가격
        Cur_Dict = pyupbit.get_current_price(tickers)
        Cur_Prices = list(Cur_Dict.values())
        Cur_Tickers = list(Cur_Dict.keys())

        # 기존 가격
        Base_Prices = list(self._Auto_Base_Price.values())

        for i in range(len(Cur_Dict)):
            if  Cur_Prices[i] >= (Base_Prices[i] * 1.05):
                print(Cur_Tickers[i], ": ", Cur_Prices[i], Base_Prices[i])

                # 자동 매수
                order = orderF1.my_Msg.ask_auto_buy(Cur_Tickers[i], Cur_Prices[i]) # yes, no
                if order == 'yes':
                    # 매수
                    print(Cur_Tickers[i] + " 매수하였습니다.")
                    coin_ticker = Cur_Tickers[i]
                    krw_balance = self.upbit.get_balance("KRW")
                    krw_balance *= 0.3 # 매수 퍼센트
                    krw_balance = round(krw_balance, -3)

                    try:
                        self.upbit.buy_market_order(coin_ticker, krw_balance)
                        self.after(100, orderF1.my_Msg.info_buy)
                    except:
                        self.after(100, orderF1.my_Msg.info_error)

                    tmp = [coin_ticker[-3:], "30%", Cur_Prices[i], round(Cur_Prices[i] * 1.1, 1), round(Cur_Prices[i]*0.97, 1),"자동매매진행중"]
                    self.in_list_frame.in_list.insert(tk.END, tmp)
                    self.after(100, self.Check_S)
                    return

        self._jobAuto = self.after(1000, self.AutoCheck, event)

mainView 관련 클래스- orderF1

더보기
import tkinter as tk
import tkinter.messagebox as msgbox
# 주문 리스트 프레임
class orderFrame(tk.LabelFrame):
    def __init__(self, parent, *args, **kwargs):
        tk.LabelFrame.__init__(self, parent, *args, **kwargs)

        # 리스트의 스크롤바
        self.in_scrollbar = tk.Scrollbar(self)
        self.in_scrollbar.pack(side="right", fill="y")

        # 리스트
        self.in_list = tk.Listbox(self, selectmode="extended", height=8, yscrollcommand=self.in_scrollbar.set)
        self.in_list.pack(side="left", fill="both", expand=True, padx=5, pady=5)
        self.in_scrollbar.config(command=self.in_list.yview)

        # 캔버스 도형 : 주문 체크용
        self.in_switch = tk.Canvas(self, width= 10, height=20, bg="#FF6666")
        self.in_switch.pack(side="left",fill="y", pady=5, anchor="w")


# 기능 프레임
class funcFrame(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent)
    
        # 기능1 버튼
        self.btn1 = tk.Button(self, padx=5, pady=5, width=12, text= kwargs.get("n1"))
        self.btn1.pack(side="left")

        # 기능2 버튼
        self.btn2 = tk.Button(self, padx=5, pady=5, width=12, text= kwargs.get("n2"))
        self.btn2.pack(side="right")
         # command= self.Del_Cancle
          # command=self.mul_select
          # command = self.cnl_mul_select


# 현재 자산 프레임
class currencyFrame(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent)
        
        # krw 표시 레이블
        self.cur_asset_krw_label = tk.Label(self, text="krw")
        self.cur_asset_krw_label.pack(side="right")

        # 현재자산 레이블
        # cur_krw_balances = upbit.get_balance("KRW")
        self.cur_asset_label = tk.Label(self, width=15, anchor="e") # text=cur_krw_balances
        self.cur_asset_label.pack(side="right")

        # 주문가능 레이블
        self.cur_asset_txt_label = tk.Label(self, text="주문가능")
        self.cur_asset_txt_label.pack(side="right")

class my_Msg():
    def info_start():
        msgbox.showinfo("알림", "정상적으로 주문이 접수 되었습니다.")
    def info_error():
        msgbox.showerror("에러", "주문 오류가 발생하였습니다.")
    def info_error2():
        msgbox.showerror("에러", "주문 오류가 발생하였습니다. 빈값을 확인해주세요")
    def info_error3():
        msgbox.showinfo("알림", "잔액이 부족합니다.")
    def info_error4():
        msgbox.showerror("에러", "취소 오류가 발생하였습니다.")
    def info_buy():
        msgbox.showinfo("알림", "정상적으로 매수 완료되었습니다.")
    def info_sell():
        msgbox.showinfo("알림", "정상적으로 매도 완료되었습니다.")
    def info_cnl():
        msgbox.showinfo("알림", "정상적으로 주문이 취소되었습니다.")
    def info_auto():
        msgbox.showinfo("알림", "정상적으로 자동매매주문이 접수되었습니다.")
    def info_auto_cnl():
        msgbox.showinfo("알림", "정상적으로 자동매매주문이 취소되었습니다.")
    def ask_auto_buy(ticker, price):
        return msgbox.askquestion("자동매수알림", "매수 하시겠습니까?\n" + str(ticker) + "\n매수 가격: " + str(price))

- 실행기능

대기중인 주문에 한하여, 가격을 불러들인 후 조건이 성사가 된다면, 매수를 해주는 기능입니다. 또한 진행중인 주문에 대하여 매도 기능을 실행시켜 줍니다. 

 

Check() 함수와 연결되어 있습니다.

 

Check() : Check_B(), Check_S() 를 실행 시켜 줍니다.

Check_B() : 매수 조건을 지속적으로 확인합니다.

Check_S() : 매도 조건을 지속적으로 확인합니다.

 

Start_Buy() : 매수를 실행합니다.

Start_Sell() : 매도를 실행합니다.


- 자동 매매기능

AutoCheck(): 실행한 순간부터 가격이 5퍼 이상 급등한 코인을 매수합니다.

AutoCancle(): 자동매수를 취소합니다.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.