첫 번째 커밋
This commit is contained in:
277
cron.py
Normal file
277
cron.py
Normal file
@@ -0,0 +1,277 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
from tzlocal import get_localzone
|
||||
|
||||
import logging
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from datetime import datetime
|
||||
from db import DB
|
||||
|
||||
from trader import Trader
|
||||
from bot import Bot
|
||||
|
||||
'''
|
||||
- (매시간 단위)Base 테이블의 새 데이터 추가시 테이블 생성(종목-거래소)
|
||||
- (매일 단위) 거래소-종목 거래량 미달 시 해당 종목 포지션 청산 후 테이블 삭제
|
||||
- (매분 단위)종목-거래소별 Tinker 정보 저장(1분, 1시간, 1일) => 1분만 할지 다시 고민
|
||||
- (매시간 단위) 시간봉 데이터 저장 및 분석 클래스에 전달
|
||||
- (매일 단위) 일봉 데이터 저장 및 분석 클래스에 전달
|
||||
|
||||
* 잡 단위는 함수
|
||||
|
||||
- 크론 테이블에 데이터 등록
|
||||
=> 업비트-비트코인 아이템 테이블에 분, 시간, 일을 구분하는 컬럼을 추가하여, 봉별 시간을 유지.
|
||||
=> 업비트-비트코인 아이템 테이블에 2개의 used 컬럼을 추가하여, 해당 데이터가 머신러닝, 보조지표에 활용 되었는 지 식별
|
||||
=> 거래소-종목 아이템이 추가 될때 크론 테이블에 추가(3개가 한 세트로 분마다, 시간마다, 일 마다)
|
||||
|
||||
- 크론 테이블 데이터 로드 후 스케쥴러에 등록
|
||||
|
||||
* 작업 목록 생성 -> 등록 -> 작업 목록 실행
|
||||
- 다음 작업 스케쥴러 라이브러리 연동 후 데이터 저장 프로세스 구현하기
|
||||
'''
|
||||
|
||||
# base path
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + '/collectors'
|
||||
|
||||
# time array for curl data
|
||||
columns = ['hour', 'day'] # 분봉, 시간봉, 일봉
|
||||
added_job = ['bot', 'trader']
|
||||
|
||||
|
||||
class Cron:
|
||||
mode = 'Test'
|
||||
# mode = 'Service'
|
||||
|
||||
exchange_instance_list = {}
|
||||
|
||||
def __init__(self):
|
||||
# init variables
|
||||
self.db = DB()
|
||||
|
||||
# set logger
|
||||
# self._set_logger_for_cron()
|
||||
logging.basicConfig()
|
||||
|
||||
# set base data
|
||||
self.f_list = self.db.select_base_table()
|
||||
|
||||
# def _set_logger_for_cron(self):
|
||||
# logging.basicConfig()
|
||||
|
||||
def start(self):
|
||||
print('For %s Working. ' % self.mode)
|
||||
|
||||
if self.mode != 'Test':
|
||||
# 배치 프로세스를 위한 인스턴스 저장
|
||||
self.save_exchange_instances_2_cron()
|
||||
|
||||
# 배치 목록 생성
|
||||
self.save_batch_job_list()
|
||||
|
||||
# 배치 목록 실행
|
||||
self.excute_batch_job_list()
|
||||
|
||||
else:
|
||||
self.save_exchange_instances_2_cron()
|
||||
|
||||
self.save_batch_job_list() # DB에 배치 목록 없을 시 주석 해제
|
||||
|
||||
# 거래 종목 생성 및 데이터 저장 로직
|
||||
self.test_excute_batch_job_list()
|
||||
|
||||
# 거래소 거래 기준 업데이트 => 외부에서 호출 => 크론에 잡 추가 예정
|
||||
def update_exchange_standard_options(self):
|
||||
for e in self.f_list:
|
||||
obj = self.exchange_instance_list[e['exchange_name']]
|
||||
obj.update_exchange_standard_options()
|
||||
|
||||
def save_exchange_instances_2_cron(self):
|
||||
# for finance, exchange in self.f_list.items() : # dynamically create an exchange instance
|
||||
for f_item in self.f_list: # dynamically create an exchange instance
|
||||
finance = f_item['finance_name']
|
||||
exchange = f_item['exchange_name']
|
||||
|
||||
# add dynamically path to os.path
|
||||
if not BASE_DIR + '/' + finance in sys.path:
|
||||
sys.path.append(BASE_DIR + '/' + finance)
|
||||
|
||||
module = importlib.import_module('c_' + exchange)
|
||||
|
||||
self.exchange_instance_list.update({
|
||||
exchange: getattr(module, str(exchange).capitalize())()
|
||||
})
|
||||
|
||||
self.exchange_instance_list[exchange].finance = finance # set finance name
|
||||
self.exchange_instance_list[exchange].db = self.db # set db object
|
||||
|
||||
# 잡 리스트를 디비에 등록하기(시간, 일 세트)
|
||||
def save_batch_job_list(self, job_type='price'):
|
||||
# 거래소별 잡 등록
|
||||
for f_item in self.f_list:
|
||||
finance = f_item['finance_name']
|
||||
exchange = f_item['exchange_name']
|
||||
trade_type = f_item['trade_type']
|
||||
|
||||
# 거래소 정보 로드
|
||||
e_info = self.db.select_row_data_from_exchange(exchange)
|
||||
|
||||
# 거래소 종목 로드
|
||||
items = self.db.select_items_data_from_tb_items_by_exchange_id(e_info['id'])
|
||||
|
||||
# 아이템별 잡 디비= 저장
|
||||
for i in items:
|
||||
# 상태값 준비-시작의 아이템만 잡 리스트 추가
|
||||
if i['status'] == 'ready' or i['status'] == 'started':
|
||||
self.db.insert_job_data_to_cron(finance, exchange, job_type, i['name'], columns, 1, trade_type)
|
||||
|
||||
# 크론 잡 등록
|
||||
def _add_job_to_sched(self, job_info):
|
||||
# custum job
|
||||
if job_info == 'bot':
|
||||
self.sched.add_job(self.excute_outer_obj, 'interval', minutes=60, id='bot', args=[job_info])
|
||||
elif job_info == 'trader':
|
||||
self.sched.add_job(self.excute_outer_obj, 'interval', minutes=10, id='trader', args=[job_info])
|
||||
# curl job
|
||||
else:
|
||||
self.add(self.save_candel_data, 'cron', job_info['time_unit'], job_info['job'], job_info)
|
||||
|
||||
# self.add(self.save_candel_data, 'cron', job_info['time_unit'], job_info['job'], job_info)
|
||||
# self.save_candel_data(job_info) # for test
|
||||
# self.sched.add_job(job, 'cron', second='5', id="test_10") # 매 지정 일-시간 실행(매일)
|
||||
# self.sched.add_job(job, 'cron', minute="01", second='5', id="test_10") # 매 지정 시간 실행(매 시간)
|
||||
# self.sched.add_job(job, 'cron', hour="9", minute="01", second='5', id="test_10") # 매 지정 초 실행(매 분)
|
||||
# self.sched.add_job(self.save_candel_data, 'interval', seconds=3, id=job_info['job'], args=[job_info], replace_existing=True) # 초 마다 실행
|
||||
|
||||
def excute_outer_obj(self, obj_name):
|
||||
o = importlib.import_module(obj_name)
|
||||
c = getattr(o, obj_name.capitalize())()
|
||||
c.run()
|
||||
|
||||
del o, c
|
||||
|
||||
def test_excute_batch_job_list(self):
|
||||
print('function called : test_excute_batch_job_list()')
|
||||
job_list = self.db.select_job_list()
|
||||
|
||||
for job in job_list:
|
||||
# print('this job :', job)
|
||||
self.save_candel_data(job)
|
||||
|
||||
def excute_batch_job_list(self): # 디비에서 잡 리스트 가져온 뒤 크론 등록
|
||||
# 스케쥴러 실행
|
||||
# self.sched = BackgroundScheduler({'apscheduler.timezone': 'UTC'})
|
||||
# self.sched = BackgroundScheduler({'apscheduler.timezone': get_localzone()})
|
||||
self.sched = BackgroundScheduler({'apscheduler.timezone': 'Asia/Seoul'})
|
||||
|
||||
# reset job list
|
||||
self.sched.remove_all_jobs()
|
||||
|
||||
# added jobs
|
||||
if self.mode == 'Service':
|
||||
for job in added_job:
|
||||
# continue # for test
|
||||
self._add_job_to_sched(job)
|
||||
|
||||
# curl data job
|
||||
job_list = self.db.select_job_list()
|
||||
|
||||
for job in job_list:
|
||||
self._add_job_to_sched(job)
|
||||
|
||||
self.sched.start()
|
||||
|
||||
# 스케쥴러 전체 잡 리스트 출력
|
||||
self.sched.print_jobs()
|
||||
|
||||
def _convert_slash_string_to_array(self, str):
|
||||
return str.split('/')
|
||||
|
||||
# 봉데이터 저장
|
||||
def save_candel_data(self, job_info):
|
||||
job = self._convert_slash_string_to_array(job_info['job'])
|
||||
obj = self.exchange_instance_list[job[1]]
|
||||
|
||||
print('now job :', job, datetime.now())
|
||||
|
||||
# 종목별 day 테이블 생성 => 종목 당 min-day 테이블 두개 운영
|
||||
if 'min' in job_info['time_unit']:
|
||||
obj.save_current_min_data(job[2])
|
||||
elif 'hour' in job_info['time_unit']:
|
||||
obj.save_current_hour_data(job[2])
|
||||
elif 'day' in job_info['time_unit']:
|
||||
obj.save_current_day_data(job[2])
|
||||
|
||||
# 정적 시간 스케쥴 등록
|
||||
def add(self, func, job_type, time_type, id, data, day_of_week=0, day=1):
|
||||
job = self._convert_slash_string_to_array(data['job'])
|
||||
obj = self.exchange_instance_list[job[1]]
|
||||
|
||||
hour = 9
|
||||
# hour = obj.get_based_time_from_data(data)
|
||||
sec = str(random.randrange(2, 57))
|
||||
min = str(1)
|
||||
# min = str(random.randrange(2, 10))
|
||||
|
||||
''' https://apscheduler.readthedocs.io/en/3.0/modules/triggers/cron.html#module-apscheduler.triggers.cron
|
||||
year (int|str) – 4-digit year
|
||||
month (int|str) – month (1-12)
|
||||
day (int|str) – day of the (1-31)
|
||||
week (int|str) – ISO week (1-53)
|
||||
day_of_week (int|str) – number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun)
|
||||
hour (int|str) – hour (0-23)
|
||||
minute (int|str) – minute (0-59)
|
||||
second (int|str) – second (0-59)
|
||||
start_date (datetime|str) – earliest possible date/time to trigger on (inclusive)
|
||||
end_date (datetime|str) – latest possible date/time to trigger on (inclusive)
|
||||
timezone (datetime.tzinfo|str) – time zone to use for the date/time calculations (defaults to scheduler timezone)
|
||||
kst : 한국 기준 시간 9시 마감
|
||||
utc : 세계 공용 기준 시간 0시 마감
|
||||
'''
|
||||
|
||||
if 'min' in time_type: # 매분
|
||||
self.sched.add_job(func, job_type, second=sec, id=id, args=[data], replace_existing=True)
|
||||
|
||||
elif 'hour' in time_type: # 매시
|
||||
# self.sched.add_job(func, job_type, minute=10, second=sec, id=id, args=[data], replace_existing=True)
|
||||
self.sched.add_job(func, job_type, minute=min, second=sec, id=id, args=[data], replace_existing=True)
|
||||
|
||||
elif 'day' in time_type: # 매일
|
||||
self.sched.add_job(func, job_type, hour=hour, minute=min, second=sec, id=id, args=[data],
|
||||
replace_existing=True)
|
||||
|
||||
elif 'day_of_week' in time_type: # 요일 마다
|
||||
self.sched.add_job(func, job_type, day_of_week=day_of_week, hour=hour, minute=min, second=sec, id=id,
|
||||
args=[data], replace_existing=True)
|
||||
|
||||
elif 'month' in time_type: # 매달-일 마다
|
||||
self.sched.add_job(func, job_type, day=day, hour=hour, minute=min, second=sec, id=id, args=[data],
|
||||
replace_existing=True)
|
||||
|
||||
def remove_job(self, id):
|
||||
self.sched.remove_job(id)
|
||||
|
||||
def get_job(self, id):
|
||||
return self.sched.get_job(id)
|
||||
|
||||
def update_job(self, job_id, jobstore=None, trigger=None, **trigger_args):
|
||||
'''
|
||||
reschedule_job(job_id, jobstore=None, trigger=None, **trigger_args)
|
||||
Constructs a new trigger for a job and updates its next run time.
|
||||
Extra keyword arguments are passed directly to the trigger’s constructor.
|
||||
|
||||
Parameters
|
||||
job_id (str|unicode) – the identifier of the job
|
||||
jobstore (str|unicode) – alias of the job store that contains the job
|
||||
trigger – alias of the trigger type or a trigger instance
|
||||
Return Job
|
||||
the relevant job instance
|
||||
'''
|
||||
return self.sched.reschedule_job(job_id, jobstore, trigger, trigger_args)
|
||||
|
||||
def remove_all_jobs(self):
|
||||
self.sched.remove_all_jobs()
|
||||
Reference in New Issue
Block a user