[코인원] 코인원 사이트 클론 프로젝트 후기 - 2

dev.soo·2020년 10월 18일
0

Coinone

목록 보기
2/3

기억하고 싶은 코드

import schedule
import time
import random
import datetime

import os
import django
import sys

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wallstreet.settings")
django.setup()

from django.db.models       import Q, Prefetch

from product.models import Product
from order.models   import Order, Transaction, Time_Unit, Report

class Scheduler():
    def report_maker(self, coin):
        time_unit_id            = Time_Unit.objects.get(name=1).id
        product                 = Product.objects.prefetch_related('transaction_set').get(full_name=coin)

        now                     = datetime.datetime.now() 
        time                    = now - datetime.timedelta(0, 60) 
        report_start_time       = datetime.datetime(time.year, time.month, time.day, time.hour, time.minute)
        report_end_time         = report_start_time + datetime.timedelta(0, 60) 

        last_closing_price      = product.transaction_set.filter(traded_at__lt=report_start_time).latest('traded_at').price
        transactions_to_report  = product.transaction_set.filter(
                                    traded_at__gte  =report_start_time,
                                    traded_at__lt   =report_end_time, 
                                ).order_by('traded_at')

        if len(transactions_to_report)==0:
            Report.objects.create(
            product_id          = product.id,
            time_unit_id        = time_unit_id, 
            opening_price       = last_closing_price,
            closing_price       = last_closing_price,
            high_price          = last_closing_price,
            low_price           = last_closing_price,
            transaction_volume  = 0,
            reported_time       = report_start_time,
            )

        else:
            transaction_price_list      = [trade.price for trade in transactions_to_report]
            transaction_quantity_list   = [trade.quantity for trade in transactions_to_report]

            Report.objects.create(
                product_id          = product.id,
                time_unit_id        = time_unit_id, 
                opening_price       = last_closing_price,
                closing_price       = transactions_to_report.last().price,
                high_price          = max(transaction_price_list), 
                low_price           = min(transaction_price_list), 
                transaction_volume  = sum(transaction_quantity_list),
                reported_time       = report_start_time,
                )
        print(report_start_time, coin)

    def scheule_a_job(self, type="Mins", interval=1):

        if (type == "Mins"):
            schedule.every(interval).minutes.do(self.report_maker, coin='썬쓰')
            schedule.every(interval).minutes.do(self.report_maker, coin='방탄코인쓰')

        while True:
            schedule.run_pending()
            time.sleep(1)

if __name__ == "__main__":
    run = Scheduler()
    run.scheule_a_job()

스케쥴러를 사용해서 1분동안 직전 1분동안 일어났던 거래들을 모두 불러와 시가/종가/고가/저가/거래량 등을 계산한다.
1분동안 거래가 일어나지 않은 경우에는 그 전에 일어난 마지막 거래로부터 시가를 가져오고, 거래량을 0으로 처리해준다.
이렇게 쌓이게 된 1분 간격의 히스토리를 프론트에 전달해주면, 프론트는 하이차트 라이브러리를 이용해 예쁘게 시각화해서 보여주게 된다.
근데 내가 가격을 너무 들쑥날쑥하게 만들었더니 하하하ㅏ.. 떡락과 떡상이 반복하는 못난이 차트가 되어버려서 나중에 데이터를 다 수정해 주엇다 ㅠㅠ

스케쥴러 사용이 처음이라 그냥 인터넷에서 우선 배껴온 코드인데, 처음에는 함수로 작성했다가 나중에는 클래스로 바꾸었다.

모든 시간에 대한 거래 히스토리가 있어야 차트가 예쁘게 나오기 때문에, 이전에 빼먹은 레포트들을 한 번에 만들어 주는 함수도 구현하였다. 이번에는 재귀함수를 사용했다..!!

def make_report(coin, report_start_time):
    report_start_time = report_start_time
    report_end_time = report_start_time + datetime.timedelta(0,60)

    if not Report.objects.filter(product=coin, reported_time=report_start_time).exists():
        transactions_to_report = Transaction.objects.filter(
                traded_at__gte = report_start_time,
                traded_at__lt  = report_end_time, 
                product        = coin,
            ).order_by('traded_at')

        time_unit_id            = Time_Unit.objects.get(name=1).id

        last_closing_price = Transaction.objects.filter(traded_at__lt=report_start_time).latest('traded_at').price

        if len(transactions_to_report)==0:
            Report.objects.create(
            product_id          = coin.id,
            time_unit_id        = time_unit_id, 
            opening_price       = decimal.Decimal(last_closing_price),
            closing_price       = decimal.Decimal(last_closing_price),
            high_price          = decimal.Decimal(last_closing_price),
            low_price           = decimal.Decimal(last_closing_price),
            transaction_volume  = decimal.Decimal(0),
            reported_time       = report_start_time,
            )

        else:
            transaction_price_list      = [trade.price for trade in transactions_to_report]
            transaction_quantity_list   = [trade.quantity for trade in transactions_to_report]

            Report.objects.create(
                product_id          = coin.id,
                time_unit_id        = time_unit_id, 
                opening_price       = decimal.Decimal(last_closing_price),
                closing_price       = decimal.Decimal(transactions_to_report.last().price),
                high_price          = decimal.Decimal(max(transaction_price_list)), 
                low_price           = decimal.Decimal(min(transaction_price_list)), 
                transaction_volume  = decimal.Decimal(sum(transaction_quantity_list)),
                reported_time       = report_start_time,
                )

    if report_end_time <= datetime.datetime.now():
        make_report(coin=coin, report_start_time=report_end_time)

for name in ['방탄코인쓰', '썬쓰']:
    coin = Product.objects.get(full_name=name)

    first_trade_time = Transaction.objects.filter(product=coin).earliest('traded_at').traded_at
    first_reported_time = datetime.datetime(
                            first_trade_time.year, 
                            first_trade_time.month, 
                            first_trade_time.day, 
                            first_trade_time.hour, 
                            first_trade_time.minute)
    make_report(coin=coin, report_start_time=first_reported_time)

지금이 12:34:19 라면, 12:33:00 부터 12:34:00이 되기 직전까지 일어난 거래들을 가져와야 했다. 이를 위해서 datetime.datetime, datetime.timedelta 를 사용했고, 만약 그 시간에 대한 거래 히스토리가 이미 만들어져 있다면 건너뛰기를 해주었다.

프론트에게 예쁜 자료를 넘겨줘야 한다는 집념으로 이런 변태스러운 함수를 만드는 지경에 이르게 되었다. 심지어 API 로는 호출되지도 않는 함수였다 하하..
사실 이 함수는 데이터 구축용이라 한 번밖에 쓸 일이 없기 때문에 리팩토링따위 하지 않았다.
난 그치만 변태니까, 리팩토링 하고나서 이런 함수들은 어떻게 유닛 테스트를 하는지 알아 볼 작정이다 (그떄 이어서 작성예정).

0개의 댓글