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

dev.soo·2020년 10월 25일
0

Coinone

목록 보기
3/3

스케쥴러를 사용하여 2초에 8건의 주문이 일어나도록 하였다.

주문은 os.system 모듈을 사용하여 API 로 전송되고, API 에서 해당 주문을 파악하여 거래가 일어나고 유저의 자산과 현금이 업데이트 되게 하였다.

import schedule
import time
import random
import datetime
import faker

import os
import django
import sys

import bcrypt
import jwt

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

from django.db.models       import Q, Prefetch, Sum

from product.models import Product
from order.models   import Order, Transaction, Time_Unit, Report
from user.models    import User, Asset
from wallstreet.settings    import SECRET_KEY, ALGORITHM

def round_four(num):
    return float(round(num, 4))

def round_four(num):
    return float(round(num, 4))

suns_prices = [2355, 2405, 2492, 2542, 2560, 2600, 2610, 2650, 2700, 2750, 2750, 2780, 2800, 2800, 2830, 2850, 2855, 2890, 2905, 2922, 2940, 2958, 2972, 3000, 3008, 3020, 3050, 3050, 3070, 3100, 3100, 3105, 3150, 3155, 3190, 3200, 3240, 3247, 3250, 3290, 3297, 3300, 3340, 3350, 3350, 3375, 3390, 3400, 3400, 3410, 3450, 3470, 3475, 3500, 3600, 3650, 4000, 4200, 4322, 4500]
btcs_prices = [21900, 21950, 22000, 22100, 22300, 22500, 22750, 22900, 23000, 23150, 23200, 23300, 23500, 23400, 23470, 23500, 23690, 23800, 23960, 24000, 24050, 24100, 24500, 24200, 24320, 34460, 24700,24735, 24800, 24900, 25000, 25050, 25100, 25200, 25350, 25500, 25600, 25700, 26000, 26050, 26500, 26550, 26900, 26950, 27000, 27050, 27200, 27400, 27450, 27500, 27500, 27600, 27600, 27700, 27800, 28000, 28000, 28050, 28050, 28090, 28100, 28200, 28300, 28350, 28410, 28500, 28600, 28650, 28800, 29000, 29050, 29400]

class Scheduler():
    def make_order(self, coin):
        fake = faker.Faker()

        users = User.objects.all().select_related('bank_account').select_related('bank_account').prefetch_related('order_set')
        user = random.choice(users)
        access_token = jwt.encode({'user_id': user.id}, SECRET_KEY, ALGORITHM).decode('utf-8')
        
        ordered_time = datetime.datetime.now()

        #sell 파는거 파란색 
        # 랜덤시간 생성
        product = Product.objects.prefetch_related('transaction_set', 'asset_set', 'order_set').get(full_name=coin)
        product_id = product.id
        if product.asset_set.filter(user_id=user.id).exists():
            coin_in_asset = product.asset_set.get(user_id=user.id).product_quantity
            coin_other_orders = product.order_set.filter(status=1, \
                                                    user_id=user.id, 
                                                    buy_or_sell=True, 
                                                    product_id=product_id
                                                    ).aggregate(Sum('quantity')).get('quantity__sum') # 유저가 동일 상품 판다고 내놓은 거래들의 수량 합
            last_buy_order_price = round_four(product.order_set.filter(buy_or_sell=False).latest('ordered_at').price)

            if not coin_other_orders:
                coin_other_orders = 1
                available_coin_to_sell = coin_in_asset-coin_other_orders       
                if available_coin_to_sell > 2:
                    if coin=='썬쓰':
                        fake_price_sell = random.choice(suns_prices)
                        fake_quantity_sell = fake.random_int(
                            1, round(available_coin_to_sell)
                            ) 
                    else:
                        fake_price_sell = random.choice(btcs_prices)
                        fake_quantity_sell = fake.random_int(
                            1, round(available_coin_to_sell)
                            ) 

                    os.system(f'http POST localhost:8000/orders/sell Authorization:{access_token} user_id={user.id} product_id={product_id} quantity={fake_quantity_sell} price={fake_price_sell}')

        #buy 빨간색 
         # 유저가 사겠다고 줄 선 다른 거래들 양*가격 총 합
        other_orders_of_user_sum  = sum([order.price*order.quantity for order in user.order_set.filter(buy_or_sell=False, status=1)])
        last_sell_order_price = round_four(product.order_set.filter(buy_or_sell=True).latest('ordered_at').price)

        available_money = float(user.bank_account.balance - other_orders_of_user_sum)
        if available_money:
            if coin=='썬쓰':
                fake_price_buy = random.choice(suns_prices)
                if available_money//fake_price_buy > 2:
                    fake_quantity_buy = (available_money//fake_price_buy) * fake.random_int(50,80) / 10000000
                    os.system(f'http POST localhost:8000/orders/buy Authorization:{access_token} product_id={product_id} quantity={fake_quantity_buy} price={fake_price_buy}')
            else:
                fake_price_buy = random.choice(btcs_prices)
                if available_money//fake_price_buy//10000 > 2:
                    fake_quantity_buy = (
                        fake.random_int(1, available_money//fake_price_buy//10000) ###
                        )
                    os.system(f'http POST localhost:8000/orders/buy Authorization:{access_token} product_id={product_id} quantity={fake_quantity_buy} price={fake_price_buy}')
#--------------
    def scheule_a_job(self, type="Secs", interval=2):

        if (type == "Secs"):
            schedule.every(interval).seconds.do(self.make_order, coin='썬쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='방탄코인쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='썬쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='방탄코인쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='썬쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='썬쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='방탄코인쓰')
            schedule.every(interval).seconds.do(self.make_order, coin='방탄코인쓰')


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

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

거래를 일으킬 때 주의할 점은

매도의 경우

  • 랜덤한 User 가 해당 코인을 가지고 있지, 가지고 있다면 몇 개 가지고 있는지 파악
  • 유저가 가지고 있는 코인보다 적은 수량을 판매

매수의 경우

  • 랜덤한 User 가 현재 보유한 자산을 파악함
  • 해당 유저의 미체결 매수 주문의 가격과 수량을 파악하여 신규 매수주문을 걸 때 사용가능한 현금이 얼마 있는지 파악함
  • 위에서 계산한 돈(총알)로 몇 개의 코인을 살 수 있는지 계산함
  • 구매가능한 수량보다 적은 수량을 랜덤하게 보내줌

이것들을 모두 로직으로 구현했는데, 가격 자체도 이전 매수/매도 주문을 참고하여 위아래 10%정도 높거나 낮게 랜덤으로 설정하였더니 랜덤임에도 불구하고 떡락과 떡상이 반복돠었다. 가격이 마이너스가 되는 경우에 대한 함수를 또 작성하고 싶지 않아서(살려줘...) 결국은 가능한 가격대를 설정해서 랜덤으로 뽑게 했더니 거래도 충분히 일어나고, 미체결 주문도 충분히 쌓이게 되었다.

하드코딩한 부분이 많지만 발표 전날 밤 급하게 짠 코드치고 잘 작동해서 만족스럽다.

0개의 댓글