본문 바로가기
파이썬으로 웹 App 작성하기/파이썬으로 Upbit 자동거래하기

파이썬만 사용해서 커스텀 코인 트레이더 웹사이트 만들기 - 2 : 기본 UI

by Slate_Knowledge 2023. 5. 25.
728x90

모의투자 시스템 링크(구글 인증을 통해서 모의투자 자동 가입 가능)(찝찝하면 https://temp-mail.org/ 과 같은 임시 메일 서비스를 이용해 가입후 초기 1회 인증하면 이후 해당 아이디로 로그인 가능)

데모 :

시리즈 이전 발행글 :  2023.04.06 - [파이썬으로 웹 App 작성하기/파이썬으로 Upbit 자동거래하기] - Anvil과 파이썬 Upbit API로 커스텀 코인 트레이더 어플 만들기 - 0 : 준비단계 (환경 설정, 분봉차트)

2023.04.17 - [파이썬으로 웹 App 작성하기/파이썬으로 Upbit 자동거래하기] - Anvil과 파이썬 Upbit API로 커스텀 코인 트레이더 어플 만들기 - 1 : 기본 API

 

Anvil과 파이썬 Upbit API로 커스텀 코인 트레이더 어플 만들기 - 1 : 기본 API

이전 포스팅 : 2023.04.06 - [파이썬으로 웹 App 작성하기/파이썬으로 Upbit 자동거래하기] - Anvil과 파이썬 Upbit API로 커스텀 코인 트레이더 어플 만들기 - 0 : 준비단계 (환경 설정, 분봉차트) Anvil과 파

doodlrudco.tistory.com

 

User Interface

커스텀 트레이더 어플을 만들기 위해 지난 포스팅까지 설치 및 기본적인 거래 기능을 담당하는 API들을 준비해왔다. 그러나, 현재 상태에서는 사용자가 사거나 팔기 위해서 일일히 get_chart, buy_coin 이라든지 sell_coin 등의 정의된 API 함수들을 호출해야하고 이렇게 되면 너무나 불편한 나머지 트레이딩 어플리케이션이라고 부르기도 민망할 것이다. 따라서, 본 포스팅에서는 어떻게 보면 트레이딩 어플리케이션의 가장 중요한 부분이라고도 할 수 있는 UI, 즉 User Interface를 구축하기로 한다.

모의투자 시스템

실제 거래 API와 연동하는 것은 UI의 측면에서 최종적으로 필요한 것이긴 하지만, 완성이 되기 전 시험 단계에서는 예상치 못한 에러 등으로 인해서 거래 transaction들이 원하지 않는 방향으로 진행될 수도 있고 보안상으로도 그리 안전하지는 못하다. 따라서, 본 포스팅을 진행하면서는 일종의 모의투자 시스템을 구현하는걸 1차적인 목표로 잡는다.

1. 프로젝트 생성 및 로그인 페이지

UI 빌드를 위해 이전 anvil 게시글(2023.05.09 - [파이썬으로 웹 App 작성하기] - Anvil 로 웹 앱 만들어서 배포하기 (기능편) - <2> Timer 로 주기적 Background 작업 생성하기)에서와 같이 빈 프로젝트 하나를 시작하고 프로젝트 이름을 클릭해서  "모의투자UI" 라고 이름을 바꿔주자.

새 프로젝트 시작 및 이름 바꾸기.

2. 기능별 Form(페이지) 만들어주기

맨 처음 프로젝트를 시작하면, 메인 UI인 Form1 파일 하나만 있는것을 볼 수 있는데, 본 포스팅 시리즈에서는 이 메인 UI 는 로그인 기능으로만 남겨두고, 각 기능별 페이지 Form을 아래와 같이 추가해주자

기능별 별도 Form 생성하기

일단 Chart 기능과 Trade 기능탭을 만들었다.

3. Chart 탭

가장 먼저 차트 탭을 채워주자. 차트 탭은 Timer를 이용해서 사용자가 선택한 시장에 대해 실시간 candle chart를 보여주는 기능을 수행한다. 이전 Anvil 기능편 Timer 포스팅을 참고해서 아래와 같이 완성해준다.

2023.05.09 - [파이썬으로 웹 App 작성하기] - Anvil 로 웹 앱 만들어서 배포하기 (기능편) - <2> Timer 로 주기적 Background 작업 생성하기

 

Anvil 로 웹 앱 만들어서 배포하기 (기능편) - <2> Timer 로 주기적 Background 작업 생성하기

TL;DR : 완성본 체험 링크 (아래 과정만 따라하면 누구나 동일하게 작성 및 배포가 가능하다!) 웹 앱에는 종종 주기적으로 실행해야하는 기능들이 생기는데, 예를 들어서 현재 작업 진행 상태를 자

doodlrudco.tistory.com

차트 UI 컴포넌트
이전 게시글에서 복붙해온 차트 코드

4. Trade 탭

Trade 탭은 기본적으로 Upbit 트레이딩 화면에서 제공하는 기능들을 제공하는걸 초기 목표로 잡는다.

업비트 거래소 UI

여기서 눈여겨 볼 정보들은, 호가차트, 매수, 매도, 간편주문, 거래내역 창 정도가 되겠다. 본 포스팅에서는, UI의 틀을 잡고 모의 트레이딩이 가능한 수준으로 뼈대를 잡는것이 목적이므로, 완벽하게까지는 아니더라도 기본적인 호가차트와 매수, 매도 기능을 구현해보도록 하자.

Trade 탭 레이아웃

위에서 복붙한 차트 엘리먼트 아래로 상기 그림과 같이 outlined_card 엘리먼트를 2개 추가해준 다음, 각각 이름을 self.orderbook(호가차트)과 self.tradetab(매수매도)로 변경하여 레이아웃을 잡아준다. 이 다음 self.orderbook 및 self.tradetab을 이 화면에서 직접 디자인하는 방법도 있지만, 매수/매도간 이동의 구현을 위해 추가적으로 Form을 만들어서 이를 import 하는 방식을 사용하겠다.

5. 거래호가차트 & 매수/매도 간 이동

기본적인 레이아웃을 잡았으니, 호가를 디스플레이하는 기능과 위에서 간략히 언급한 매수/매도 탭 간 이동을 구현하고 마치도록 한다.

먼저, Trade Form 밑에 Orderbook, Buy, Sell 의 빈 Form 들을 새로 생성해주자.

거래호가차트, 매수, 매도 탭 레이아웃 파일 생성

Orderbook Form

이때, Orderbook Form은 아래와 같이 Spacer, Plot, Text 를 사용해서 구성한다.(Main.Trade.Orderbook에서 수정할것)

거래호가차트 Form 파일로 이동
거래호가차트 레이아웃 및 변수명

이렇게 구성한 다음, 이걸 호가차트처럼 보이게 하기 위해서, plot_1에는 오른쪽에서 왼쪽으로 뻗어나가는 파란색 매도 호가 bar_chart를, plot_2에는 왼쪽에서 오른쪽으로 뻗어나가는 붉은색 매수 호가 bar_chart를, self.label_1에는 "현재가" 라는 텍스트와 self.label_2에는 현재거래가(KRW)를 표시하도록 코드를 작성해보자.

제일 먼저, 현재 거래가와 호가차트를 가져오는 코드는 Upbit API를 이용했을 때 아래와 같이 작성할 수 있다.

def get_current_price(self, market=None):
    if market is None:
    	market = self.market
    url = f"https://api.upbit.com/v1/ticker?markets={market}"
    headers = {"accept": "application/json"}
    res = http.request(url=url, method='GET', headers =headers)
    data = json.loads(res.get_bytes().decode('utf-8'))
    return data[0]['trade_price']

def get_orderbook(self, market=None):
    if market is None:
    	market = self.market
    url = f"https://api.upbit.com/v1/orderbook?markets={market}"
    headers = {"accept": "application/json"}
    res = http.request(url=url, method='GET', headers =headers)
    data = json.loads(res.get_bytes().decode('utf-8'))
    return data[0]

이때 get_current_price의 리턴값은 현재 거래가(KRW) 정보를 담은 숫자이고, get_orderbook의 리턴값은 매수, 매도 호가를 현재 거래가에서 가까운 순서대로 묶어서 반환하는 list of dict 이다. 따라서 현재가의 경우 반환된 텍스트를 self.label_2.text에 직접 할당해주면 설정이 끝나는 단순한 작업이 되고, 나머지 호가의 경우 아래와 같이 bar chart를 그려줘야한다.

def plot_orderbook(self, orderbook):
    units = orderbook['orderbook_units'][:5]
    asks = [(o['ask_price'], o['ask_size']) for o in units] # 매수 호가 리스트 분리
    bids = [(o['bid_price'], o['bid_size']) for o in units] # 매도 호가 리스트 분리

    self.plot_1.data = [
        go.Bar(
        x=[a[1] for a in asks],
        y=[str(a[0]) for a in asks],
        orientation='h', 
        marker=dict(color='rgba(0,100,255,0.6)')
        )
    ]
    # orientation = 'h' --> 수평방향 bar chart
    # marker --> 마커의 color를 'rgba(0,100,255,0.6)'으로 설정해서 푸른 차트 생성
    
    self.plot_1.layout.margin = dict(l=20, r=80, t=20, b=20) # 고정 마진으로 가시성 증대
    
    self.plot_1.layout.yaxis.autotypenumbers = 'strict' # 숫자를 38.9M 이 아닌 38900000 으로 표기
    self.plot_1.layout.yaxis.side = 'right' # 호가 레이블이 오른쪽에 있도록 변경
    
    self.plot_1.layout.xaxis.type = 'log' # 거래량을 로그 스케일로 표시
    self.plot_1.layout.xaxis.autorange='reversed' # 오른쪽에서 왼쪽으로 뻗어나가는 바 차트
    

    self.plot_2.data = [
        go.Bar(
        y=[str(b[0]) for b in bids],
        x=[b[1] for b in bids],
        orientation='h',
        marker=dict(color='rgba(255,0,0,0.6)')
        )
    ]
    self.plot_2.layout.margin = dict(l=80, r=20, t=20, b=20)
    self.plot_2.layout.yaxis.autotypenumbers = 'strict'
    self.plot_2.layout.xaxis.type = 'log'
    self.plot_2.layout.yaxis.autorange='reversed' # 매도 호가의 경우 리스트의 순서가 뒤집혀있으므로 다시 뒤집어줌

이렇게 하면 timer를 부착한 최종 예시에서 아래와 같은 호가차트를 볼 수 있다.

업데이트 되는 호가 및 거래량 차트(예시는 웨이브 코인)

이렇게 Orderbook Form을 완성했으면 아래와 같이 M.Trade Form에서 self.orderbook 카드에 Orderbook Form을 끌어다가 배치해준다

Buy/Sell Form

M.Trade Form에서 self.tradetab 카드는 Upbit UI를 참고하여 현재 주문가능액(매도가능수량), 매수(매도)가격, 주문수량, 주문 총액을 나타내는 텍스트칸과 초기화, 매수(매도)버튼으로 이루어진 Buy(Sell) 폼들과 이들 사이를 왔다갔다 할 수 있는 보라색 버튼으로 이루어져있다.

 제일 먼저 Main.Trade 폼에서 아래와 같이 보라색 버튼을 매수, 매도 버튼으로 추가해주고 그 아래 들어갈 Buy/Sell Form 들을 완성시켜보자

매수/매도 창 레이아웃

위와 같은 구성을 M.Trade.Buy Form 안에 구성하면 다음과 같은 레이아웃이 만들어진다.

매수 창 Form

이와 비슷하게 매도 창도 구성한 다음 해결해야하는 문제는 매수와 매도 버튼을 눌렀을 때 해당하는 Form이 아래에 뜨도록 하는 것인데, 이는 이전 포스팅에서도 언급했던 Tab화 기법을 이용해서 해결한다.

2023.05.23 - [파이썬으로 웹 App 작성하기] - Anvil 로 웹 앱 만들어서 배포하기 (기능편) - <3> UI에 주제별 탭(Tab) 만들기

 

Anvil 로 웹 앱 만들어서 배포하기 (기능편) - <3> UI에 주제별 탭(Tab) 만들기

웹 서비스를 만들거나 사용하다 보면, 한 UI Page 내부에 여러가지 기능을 넣어야 할 때가 있다. 그러나 한정된 페이지 공간 안에 이런저런 기능 및 요소들을 욱여넣다보면 스크롤이 너무나 길어

doodlrudco.tistory.com

Main.Trade Form의 코드에서 매수(self.outlined_button_1)와 매도(self.outlined_button_2) 버튼의 click 합수를 위 이전 게시물을 참고하여 아래와 같이 바꿔준다.

먼저 __init__에 다음과 같이 buy 와 sell 클래스를 Form에서부터 import 하여 객체로 선언해준다. 그리고 아까 정해두 self.tradetab 카드에 self.buytab을 컴포넌트로 추가해준다.

... 기타 import 들
from .Buy import Buy
from .Sell import Sell

class Trade(TradeTemplate):
    def __init__(self, **properties):
        # Set Form properties and Data Bindings.
        ...
        
        self.buytab = Buy()
        self.selltab = Sell()
        self.tradetab.add_component(self.buytab)

그 다음 버튼들에 대해서도

    ... Trade 클래스 코드들
    
    def outlined_button_1_click(self, **event_args):
        """This method is called when the button is clicked"""
        self.selltab.remove_from_parent()
        self.tradetab.add_component(self.buytab)

    def outlined_button_2_click(self, **event_args):
        """This method is called when the button is clicked"""
        self.buytab.remove_from_parent()
        self.tradetab.add_component(self.selltab)

매수(매도) 버튼을 클릭할때마다 매도(매수) 컴포넌트를 제거하고 매수(매도) 객체를 컴포넌트로 추가하게 만들면 아래의 예시와 같이 매수와 매도 탭을 성공적으로 구현할 수 있다.

완성된 UI

이렇게 완성된 UI를 바탕으로 백엔드 기능들을 추가함으로써 이후 포스팅 시리즈를 이어나갈 예정이다.

UI 완성본은 다음 링크를 따라가면 공개되어 있다.

https://jaunty-piercing-trash.anvil.app

728x90
반응형

댓글