# PyAlgoTrade
#
# Copyright 2011-2018 Gabriel Martin Becedillas Ruiz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
.. moduleauthor:: Gabriel Martin Becedillas Ruiz <gabriel.becedillas@gmail.com>
"""
import abc
import six
from pyalgotrade import dispatchprio
class Event(object):
def __init__(self):
# 待处理的事件
self.__handlers = []
# 缓存中的事件
self.__deferred = []
# 是否放出的状态
self.__emitting = 0
def __subscribeImpl(self, handler):
# 如果当前不是要放出的状态
assert not self.__emitting
# 如果这个事件没有在待处理的事件列表中
if handler not in self.__handlers:
# 添加这个事件到事件列表
self.__handlers.append(handler)
def __unsubscribeImpl(self, handler):
# 如果当前不是要放出的状态
assert not self.__emitting
# 从事件列表中删除
self.__handlers.remove(handler)
def __applyChanges(self):
# 如果当前不是要放出的状态
assert not self.__emitting
# 对缓存中的时间进行处理,先遍历需要处理的事件
for action, param in self.__deferred:
action(param)
# 处理完后,缓存中的事件变为0
self.__deferred = []
def subscribe(self, handler):
# 如果当前是要放出的状态
if self.__emitting:
# 把需要处理的函数名和参数放到缓存当中去
self.__deferred.append((self.__subscribeImpl, handler))
# 另外如果当前不是要放出的状态
elif handler not in self.__handlers:
self.__subscribeImpl(handler)
def unsubscribe(self, handler):
# 取消订阅
# 如果当前的状态是放出
if self.__emitting:
self.__deferred.append((self.__unsubscribeImpl, handler))
# 如果不是
else:
self.__unsubscribeImpl(handler)
def emit(self, *args, **kwargs):
# 完整运行一个事件?
# 试运行
try:
# 当前的状态变为发射、放出
self.__emitting += 1
# 循环处理每个handler
for handler in self.__handlers:
handler(*args, **kwargs)
# 最终运行
finally:
# 当前的状态变为非发射或者放出的状态
self.__emitting -= 1
# 如果是非发射或者放出的状态
if not self.__emitting:
# 做出来相应的改变
self.__applyChanges()
@six.add_metaclass(abc.ABCMeta)
class Subject(object):
def __init__(self):
# dispatchprio.LAST=None
self.__dispatchPrio = dispatchprio.LAST
# This may raise.
@abc.abstractmethod
def start(self):
pass
# This should not raise.
@abc.abstractmethod
def stop(self):
raise NotImplementedError()
# This should not raise.
@abc.abstractmethod
def join(self):
raise NotImplementedError()
# Return True if there are not more events to dispatch.
@abc.abstractmethod
def eof(self):
raise NotImplementedError()
# Dispatch events. If True is returned, it means that at least one event was dispatched.
@abc.abstractmethod
def dispatch(self):
raise NotImplementedError()
@abc.abstractmethod
def peekDateTime(self):
# Return the datetime for the next event.
# This is needed to properly synchronize non-realtime subjects.
# Return None since this is a realtime subject.
raise NotImplementedError()
def getDispatchPriority(self):
# Returns a priority used to sort subjects within the dispatch queue.
# The return value should never change once this subject is added to the dispatcher.
return self.__dispatchPrio
def setDispatchPriority(self, dispatchPrio):
self.__dispatchPrio = dispatchPrio
def onDispatcherRegistered(self, dispatcher):
# Called when the subject is registered with a dispatcher.
pass