Skip to content

Commit

Permalink
Merge remote-tracking branch 'shidenggui/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeyJiao committed Jun 3, 2016
2 parents df0d3b8 + 6d415c7 commit d6c4d4d
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 69 deletions.
56 changes: 31 additions & 25 deletions easyquant/easydealutils/time.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import datetime
from datetime import timedelta
import doctest
from functools import lru_cache

import requests


@lru_cache()
def _is_holiday(day):
# 该接口可能将于 2016.7.1 过期, 请关注该主页
api = 'http://www.easybots.cn/api/holiday.php'
params = {'d': day}
rep = requests.get(api, params)
Expand All @@ -19,6 +20,33 @@ def is_holiday(now_time):
return _is_holiday(today)


def is_trade_date(now_time):
return not is_holiday(now_time)


def get_next_trade_date(now_time):
"""
:param now_time: datetime.datetime
:return:
>>> import datetime
>>> get_next_trade_date(datetime.date(2016, 5, 5))
datetime.date(2016, 5, 6)
"""
now = now_time
max_days = 365
days = 0
while 1:
days += 1
now += datetime.timedelta(days=1)
if is_trade_date(now):
if isinstance(now, datetime.date):
return now
else:
return now.date()
if days > max_days:
raise ValueError('无法确定 %s 下一个交易日' % now_time)


OPEN_TIME = (
(datetime.time(9, 15, 0), datetime.time(11, 30, 0)),
(datetime.time(13, 0, 0), datetime.time(15, 0, 0)),
Expand Down Expand Up @@ -79,27 +107,5 @@ def is_closing(now_time, start=datetime.time(14, 54, 30)):
return True
return False


# def calc_next_trade_time_delta_seconds():
# now_time = datetime.datetime.now()
# now = (now_time.hour, now_time.minute, now_time.second)
# if now < (9, 15, 0):
# next_trade_start = now_time.replace(hour=9, minute=15, second=0, microsecond=0)
# elif (12, 0, 0) < now < (13, 0, 0):
# next_trade_start = now_time.replace(hour=13, minute=0, second=0, microsecond=0)
# elif now > (15, 0, 0):
# distance_next_work_day = 1
# while True:
# target_day = now_time + timedelta(days=distance_next_work_day)
# if is_holiday(target_day.strftime('%Y%m%d')):
# distance_next_work_day += 1
# else:
# break
#
# day_delta = timedelta(days=distance_next_work_day)
# next_trade_start = (now_time + day_delta).replace(hour=9, minute=15,
# second=0, microsecond=0)
# else:
# return 0
# time_delta = next_trade_start - now_time
# return time_delta.total_seconds()
if __name__ == "__main__":
doctest.testmod()
34 changes: 25 additions & 9 deletions easyquant/push_engine/clock_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections import deque
from threading import Thread

import pandas as pd
import arrow
from dateutil import tz

Expand Down Expand Up @@ -48,16 +49,18 @@ def __hash__(self):


class ClockMomentHandler:
def __init__(self, clock_engine, clock_type, moment=None, makeup=False, call=None):
def __init__(self, clock_engine, clock_type, moment=None, is_trading_date=True, makeup=False, call=None):
"""
:param clock_type:
:param moment: datetime.time
:param is_trading_date: bool(是否只有在交易日触发)
:param makeup: 注册时,如果已经过了触发时机,是否立即触发
:return:
"""
self.clock_engine = clock_engine
self.clock_type = clock_type
self.moment = moment
self.is_trading_date = is_trading_date
self.makeup = makeup
self.call = call or (lambda: None)
self.next_time = datetime.datetime.combine(
Expand All @@ -74,12 +77,20 @@ def update_next_time(self):
:return:
"""
if self.is_active():
if self.is_trading_date:
next_date = etime.get_next_trade_date(self.clock_engine.now_dt)
else:
next_date = self.next_time.date() + datetime.timedelta(days=1)

self.next_time = datetime.datetime.combine(
self.next_time.date() + datetime.timedelta(days=1),
next_date,
self.moment
)

def is_active(self):
if self.is_trading_date and etime.is_holiday(self.clock_engine.now_dt):
# 仅在交易日触发时的判断
return False
return self.next_time <= self.clock_engine.now_dt


Expand Down Expand Up @@ -118,22 +129,22 @@ def _init_clock_handler(self):
"""

# 开盘事件
def open_():
def _open():
self.trading_state = True

self._register_moment('open', datetime.time(9, tzinfo=self.tzinfo), True, open_)
self._register_moment('open', datetime.time(9, tzinfo=self.tzinfo), makeup=True, call=_open)

# 中午休市
self._register_moment('pause', datetime.time(11, 30, tzinfo=self.tzinfo), True)
self._register_moment('pause', datetime.time(11, 30, tzinfo=self.tzinfo), makeup=True)

# 下午开盘
self._register_moment('continue', datetime.time(13, tzinfo=self.tzinfo), True)
self._register_moment('continue', datetime.time(13, tzinfo=self.tzinfo), makeup=True)

# 收盘事件
def close():
self.trading_state = False

self._register_moment('close', datetime.time(15, tzinfo=self.tzinfo), True, close)
self._register_moment('close', datetime.time(15, tzinfo=self.tzinfo), makeup=True, call=close)

# 间隔事件
for interval in (0.5, 1, 5, 15, 30, 60):
Expand Down Expand Up @@ -165,6 +176,11 @@ def now_dt(self):
return arrow.get(self.now).to(self.tzinfo)

def reset_now(self, now=None):
"""
调试用接口,请勿在生产环境使用
:param now:
:return:
"""
self.time_delta = self._delta(now)

def start(self):
Expand Down Expand Up @@ -215,9 +231,9 @@ def is_tradetime_now(self):
def register_moment(self, clock_type, moment, makeup=False):
return self._register_moment(clock_type, moment, makeup)

def _register_moment(self, clock_type, moment, makeup=False, call=None):
def _register_moment(self, clock_type, moment, is_trading_date=True, makeup=False, call=None):
handlers = list(self.clock_moment_handlers)
handler = ClockMomentHandler(self, clock_type, moment, makeup, call)
handler = ClockMomentHandler(self, clock_type, moment, is_trading_date, makeup, call)
handlers.append(handler)

# 触发事件重新排序
Expand Down
Loading

0 comments on commit d6c4d4d

Please sign in to comment.