예제 #1
0
class QSM(Process, Dictable):
    def __init__(self, name: str, msg_list: list = None):
        super().__init__()
        self.is_exitting = False
        self.name = name

        self.mappings = {}
        self.setup_states()

        self.msg_list = msg_list if msg_list is not None else []
        if 'all' not in self.msg_list:
            self.msg_list.append('all')

        self.setup_msg_mappings(self.msg_list)

        self.handler = MessageHandler(self.name, self.msg_list)  # Because otherwise we can't join from 'final'
        self.states = Queue()
        self.append_state('init')

    @property
    def dict(self) -> dict:
        print('Converting qsm to dict')
        d = {'name': self.name,
             'msg_list': self.msg_list,
             'handler': self.handler.dict}
        return d

    @staticmethod
    def from_dict(d: dict) -> object:
        sm = QSM(d['name'], d['msg_list'])
        sm.handler = MessageHandler.from_dict(d['handler'])
        sm.append_state('init')
        return sm

    def join(self, timeout: Optional[float] = -1) -> None:
        self.append_state('exit')
        super().join(timeout=timeout)
        self.handler.join()

    def run(self) -> None:
        # sys.stdin = self.cclient
        while not self.is_exitting:
            try:
                s = self.states.get_nowait()
                # print('Going to {}'.format(s['state']))
                if s['payload'] is not None:
                    self.mappings[s['state']](s['payload'])
                else:
                    self.mappings[s['state']]()
            except Empty as _:
                self.mappings['idle']()

    def setup_msg_mappings(self, msg_list: list):
        """Sets up the self.msg_map dictionary, mapping message titles to state names,
        by default, appends '_msg' to msg_list entries"""
        for m in msg_list:
            # print('Setting up message state for {} to {}'.format(m, eval('self.' + m + '_msg')))
            self.mappings[m] = eval('self.' + m + '_msg')

    def all_msg(self, msg: Message):
        if msg.msg == 'save':
            self.handler.send(Message('json_update', self.name, {'dtype': str(type(self).__name__),
                                                                 'package': inspect.getmodulename(
                                                                     inspect.getfile(self.__class__)),
                                                                 'path': str(inspect.getfile(self.__class__)),
                                                                 'data': self.dict}))

    def setup_states(self):
        """Sets up the self.mappings dictionary, mapping state names to state methods,
        by default 'init', 'idle', 'exit', and 'final' states are set up."""
        self.mappings['init'] = self.initial_state
        self.mappings['idle'] = self.idle_state
        self.mappings['exit'] = self.exit_state
        self.mappings['final'] = self.final_state

    def append_state(self, state: str, payload: object = None):
        try:
            # print('Appending {}'.format(state))
            self.states.put_nowait({'state': state, 'payload': payload})
        except Full as _:
            print('{} state queue is full, skipping {}'.format(self.name, state))

    def append_states(self, states: list, payloads: list = None):
        for i, s in enumerate(states):
            p = payloads[i] if payloads is not None else None
            self.append_state(s, p)

    def initial_state(self):
        """This is the first state to execute, always"""
        pass

    def idle_state(self):
        """This is the state the is triggered when the state machine has nowhere to go to."""
        m = self.handler.receive(block=False)
        if m is not None:
            print('Received message {}'.format(m))
            self.append_state(m.title, m)

    def exit_state(self):
        """This stateis triggered when the qsm should exit, enqueues the 'final' state"""
        # print('Exitting')
        self.append_state('final')

    def final_state(self):
        """This is the final state to execute, always"""
        self.is_exitting = True
예제 #2
0
        time.sleep(self.interval)


class MarketTimer(Timer):
    """A Normal Timer class that automatically pauses during after hours."""
    def idle_state(self):
        dow = dt.datetime.now().isoweekday()
        hour = dt.datetime.now().hour
        minute = dt.datetime.now().minute
        # print('The date is {} @ {}:{}'.format(dow, hour, minute))
        if not self.paused and ((dow == 6 or dow == 7) or
                                ((hour >= 16 or hour < 9) or (hour == 9 and minute < 30))):
            print('Pausing Timer')
            self.paused = True
        elif self.paused and ((dow != 6 and dow != 7) and ((9 < hour < 16) or (hour == 9 and minute >= 30))):
            print('Unpausing Timer')
            self.paused = False
        super().idle_state()


if __name__ == "__main__":
    from tradebot.messaging.message import MessageHandler

    t = Timer('timer1')
    h = MessageHandler('timer_rx', ['timer'])
    t.start()

    while True:
        if h.receive() is not None:
            print('Timer triggered')
from tradebot.messaging.qsm import QSM
from tradebot.messaging.message import Message


class TimerRelay(QSM):
    def __init__(self, name: str, target_msg: Message):
        super().__init__(name, ['timer'])
        self.target = target_msg

    def timer_msg(self, msg: Message):
        print('Relay {} triggered'.format(self.name))
        self.handler.send(self.target)


if __name__ == '__main__':
    from tradebot.controllers.timer import Timer
    from tradebot.messaging.message import MessageHandler

    t = Timer('timer1', 1)
    tr = TimerRelay('relay', Message('something'))
    rx = MessageHandler('receiver', ['something'])

    tr.start()
    t.start()

    while True:
        if rx.receive() is not None:
            print('Relay fired')
예제 #4
0
class CLITest(unittest.TestCase):
    def setUp(self) -> None:
        self.handler = MessageHandler('test_handler', ['trade_request', 'monitor_config', 'vault_request'])

    def tearDown(self) -> None:
        self.handler.join()
        cli.cli_handler = None

    def test_add(self):
        parse_command('add stock AAPL shares=10; add stock AAPL 1 3.0; add stock AAPL shares=10 price=4.50')
        msg = self.handler.receive()

        self.assertEqual(msg.title, 'vault_request', 'Add command should produce vault_request message')
        self.assertEqual(msg.msg, 'add_stock', 'Add command should produce an add_stock message')
        self.assertTrue(msg.payload == ManagedStock('AAPL', shares=10, last_price=-1))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == ManagedStock('AAPL', shares=1, last_price=3))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == ManagedStock('AAPL', shares=10, last_price=4.5))

    def test_remove(self):
        parse_command('remove stock 123; remove stock 123 10')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'vault_request', 'Remove command should produce vault_request message')
        self.assertEqual(msg.msg, 'remove_stock', 'Remove command should produce a remove_stock message')

        self.assertTrue(msg.payload == ManagedStock('None', table_id=123, shares=-1))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == ManagedStock('None', table_id=123, shares=10))

    def test_list(self):
        parse_command('list; list acronym AAPL')

        # msg = self.handler.receive()
        # self.assertEqual(msg.title, 'vault_request', 'List command should produce vault_request message')
        # self.assertEqual(msg.msg, 'get_stock_names', 'List command should produce a get_stock_names message')

    def test_limit(self):
        parse_command('add limit 123; add limit 123 % 1.05 0.95; add limit 123 0.95 0.85')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'monitor_config', 'List command should produce monitor_config message')
        self.assertEqual(msg.msg, 'limit', 'List command should produce a limit message')

        self.assertTrue(msg.payload == LimitDescriptor(123))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == LimitDescriptor(123))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == LimitDescriptor(123, upper=0.95, lower=0.85))

    def test_buy(self):
        parse_command('buy AAPL; buy AAPL 10; buy AAPL 10 3.75')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'trade_request', 'Buy command should produce a trade_request message')
        self.assertEqual(msg.msg, 'buy', 'Buy command should produce a buy message')

        self.assertTrue(msg.payload == ManagedStock('AAPL', last_price=-1))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == ManagedStock('AAPL', shares=10, last_price=-1))

        msg = self.handler.receive()
        self.assertTrue(msg.payload == ManagedStock('AAPL', shares=10, last_price=3.75))

    def test_sell(self):
        parse_command('sell 123; sell 123 10')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'trade_request', 'Sell command should produce a trade_request message')
        self.assertEqual(msg.msg, 'sell', 'Sell command should produce a sell message')

        self.assertEqual(msg.payload['id'], 123)
        self.assertEqual(msg.payload['shares'], -1)

        msg = self.handler.receive()
        self.assertEqual(msg.payload['id'], 123)
        self.assertEqual(msg.payload['shares'], 10)

    def test_update(self):
        parse_command('update')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'monitor_config', 'Update command should produce a monitor_config message')
        self.assertEqual(msg.msg, 'update', 'Update command should produce an update message')

    def test_export(self):
        parse_command('export')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'all', 'Export command should produce a global message')
        self.assertEqual(msg.msg, 'save', 'Export command should produce an save message')

    def test_import(self):
        parse_command('import')

        msg = self.handler.receive()
        self.assertEqual(msg.title, 'all', 'Import command should produce a global message')
        self.assertEqual(msg.msg, 'load', 'Import command should produce an load message')