diff --git a/hbotrc/__init__.py b/hbotrc/__init__.py deleted file mode 100644 index c2daf65..0000000 --- a/hbotrc/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -__version__ = "0.1.0" -__author__ = "Konstantinos Panayiotou" -__maintainer__ = "Konstantinos Panayiotou" - -from .listener import BotListener -from .commands import BotCommands -from .external_events import BotEventEmitter -from .msgs import ExternalEvent diff --git a/hbotrc/commands.py b/hbotrc/commands.py deleted file mode 100644 index a3606f2..0000000 --- a/hbotrc/commands.py +++ /dev/null @@ -1,191 +0,0 @@ -from commlib.node import Node -from commlib.transports.mqtt import ConnectionParameters - -from .msgs import * -from .spec import TopicSpecs - - -class BotCommands(Node): - def __init__(self, - bot_id: str, - host: str = 'localhost', - port: int = 1883, - username: str = '', - password: str = '', - namespace: str = 'hbot', - **kwargs - ): - self._bot_id = bot_id - self._ns = namespace - - topic_prefix = TopicSpecs.PREFIX.format( - namespace=self._ns, - instance_id=self._bot_id - ) - self._start_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.START}' - self._stop_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.STOP}' - self._import_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.IMPORT}' - self._config_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.CONFIG}' - self._status_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.STATUS}' - self._history_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.HISTORY}' - self._balance_limit_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.BALANCE_LIMIT}' - self._balance_paper_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.BALANCE_PAPER}' - self._command_shortcut_uri = f'{topic_prefix}{TopicSpecs.COMMANDS.COMMAND_SHORTCUT}' - - conn_params = ConnectionParameters( - host=host, - port=int(port), - username=username, - password=password - ) - - super().__init__( - node_name=f'{self._ns}.{self._bot_id}', - connection_params=conn_params, - heartbeats=False, - debug=True, - **kwargs - ) - self._init_clients() - self.run() - - def _init_clients(self): - self._start_cmd = self.create_rpc_client( - msg_type=StartCommandMessage, - rpc_name=self._start_uri - ) - # print(f'[*] Created RPC client for start command @ {self._start_uri}') - self._stop_cmd = self.create_rpc_client( - msg_type=StopCommandMessage, - rpc_name=self._stop_uri - ) - # print(f'[*] Created RPC client for stop command @ {self._stop_uri}') - self._import_cmd = self.create_rpc_client( - msg_type=ImportCommandMessage, - rpc_name=self._import_uri - ) - # print(f'[*] Created RPC client for import command @ {self._import_uri}') - self._config_cmd = self.create_rpc_client( - msg_type=ConfigCommandMessage, - rpc_name=self._config_uri - ) - # print(f'[*] Created RPC client for config command @ {self._config_uri}') - self._status_cmd = self.create_rpc_client( - msg_type=StatusCommandMessage, - rpc_name=self._status_uri - ) - # print(f'[*] Created RPC client for status command @ {self._status_uri}') - self._history_cmd = self.create_rpc_client( - msg_type=HistoryCommandMessage, - rpc_name=self._history_uri - ) - # print(f'[*] Created RPC client for history command @ {self._history_uri}') - self._balance_limit_cmd = self.create_rpc_client( - msg_type=BalanceLimitCommandMessage, - rpc_name=self._balance_limit_uri - ) - # print(f'[*] Created RPC client for balance limit command @ {self._balance_limit_uri}') - self._balance_paper_cmd = self.create_rpc_client( - msg_type=BalancePaperCommandMessage, - rpc_name=self._balance_paper_uri - ) - # print(f'[*] Created RPC client for balance limit command @ {self._balance_limit_uri}') - self._command_shortcut_cmd = self.create_rpc_client( - msg_type=CommandShortcutMessage, - rpc_name=self._command_shortcut_uri - ) - # print(f'[*] Created RPC client for command shortcuts @ {self._command_shortcut_uri}') - - def start(self, - log_level: str = None, - script: str = None, - async_backend: bool = False - ): - resp = self._start_cmd.call( - StartCommandMessage.Request( - log_level=log_level, - script=script, - async_backend=async_backend - ) - ) - return resp - - def stop(self, - skip_order_cancellation: bool = False, - async_backend: bool = False - ): - resp = self._stop_cmd.call( - StopCommandMessage.Request( - skip_order_cancellation=skip_order_cancellation, - async_backend=async_backend - ) - ) - return resp - - def import_strategy(self, - strategy: str, - ): - resp = self._import_cmd.call( - ImportCommandMessage.Request(strategy=strategy) - ) - return resp - - def config(self, - params: List[Tuple[str, Any]], - ): - resp = self._config_cmd.call( - ConfigCommandMessage.Request(params=params) - ) - return resp - - def status(self, - async_backend: bool = False - ): - resp = self._status_cmd.call( - StatusCommandMessage.Request(async_backend=async_backend) - ) - return resp - - def history(self, - async_backend: bool = False - ): - resp = self._history_cmd.call( - HistoryCommandMessage.Request(async_backend=async_backend) - ) - return resp - - def balance_limit(self, - exchange: str, - asset: str, - amount: float - ): - resp = self._balance_limit_cmd.call( - BalanceLimitCommandMessage.Request( - exchange=exchange, - asset=asset, - amount=amount - ) - ) - return resp - - def balance_paper(self, - asset: str, - amount: float - ): - resp = self._balance_paper_cmd.call( - BalancePaperCommandMessage.Request( - asset=asset, - amount=amount - ) - ) - return resp - - def shortcut(self, - params=List[List[Any]] - ): - resp = self._command_shortcut_uri.call( - CommandShortcutMessage.Request( - params=params - ) - ) - return resp diff --git a/hbotrc/external_events.py b/hbotrc/external_events.py deleted file mode 100644 index bc4fe9a..0000000 --- a/hbotrc/external_events.py +++ /dev/null @@ -1,64 +0,0 @@ -import asyncio -from commlib.node import Node -from commlib.transports.mqtt import ConnectionParameters -from typing import Any, List, Optional, Tuple, Callable -from pydantic import BaseModel - -from .msgs import ExternalEvent -from .spec import TopicSpecs, CommandTopicSpecs - - -class BotEventEmitter(Node): - def __init__(self, - bot_id: str, - host: str = 'localhost', - port: int = 1883, - username: str = '', - password: str = '', - namespace: str = 'hbot', - **kwargs - ): - self._bot_id = bot_id - self._ns = namespace - self._pub = None - - _prefix = TopicSpecs.PREFIX.format( - namespace=self._ns, - instance_id=self._bot_id - ) - self._uri_prefix = f'{_prefix}{TopicSpecs.EXTERNAL_EVENTS[:-1]}' - - conn_params = ConnectionParameters( - host=host, - port=int(port), - username=username, - password=password - ) - - super().__init__( - node_name=f'{self._ns}.{self._bot_id}', - connection_params=conn_params, - heartbeats=False, - debug=True, - **kwargs - ) - self._init_publisher() - self.run() - - def _event_name_to_uri(self, event_name: str) -> str: - uri = f'{self._uri_prefix}{event_name}' - return uri - - def _init_publisher(self): - self._pub = self.create_mpublisher() - self._pub.run() - - def _publish_event(self, event: ExternalEvent): - _uri = self._event_name_to_uri(event.name.replace('.', '/')) - _data = event.dict() - # Remove name property from message. Only used on client - _data.pop('name') - self._pub.publish(_data, _uri) - - def send(self, event: ExternalEvent): - self._publish_event(event) diff --git a/hbotrc/listener.py b/hbotrc/listener.py deleted file mode 100644 index b0aaf50..0000000 --- a/hbotrc/listener.py +++ /dev/null @@ -1,106 +0,0 @@ -import asyncio -from commlib.node import Node -from commlib.transports.mqtt import ConnectionParameters -from typing import Any, List, Optional, Tuple, Callable - -from .msgs import * -from .spec import TopicSpecs, CommandTopicSpecs - - -class BotListener(Node): - def __init__(self, - host: str = 'localhost', - port: int = 1883, - username: str = '', - password: str = '', - bot_id: str = 'bot1', - namespace: str = 'hbot', - notifications: bool = True, - events: bool = True, - logs: bool = True, - on_notification: Optional[Callable] = None, - on_event: Optional[Callable] = None, - on_log: Optional[Callable] = None, - on_hb: Optional[Callable] = None, - **kwargs - ): - self._notifications = notifications - self._events = events - self._logs = logs - self._bot_id = bot_id - self._ns = namespace - - if on_notification is not None: - self._on_notification = on_notification - if on_event is not None: - self._on_event = on_event - if on_log is not None: - self._on_log = on_log - if on_hb is not None: - self._on_hb = on_hb - - topic_prefix = TopicSpecs.PREFIX.format( - namespace=self._ns, - instance_id=self._bot_id - ) - self._hb_topic = f'{topic_prefix}{TopicSpecs.HEARTBEATS}' - self._notify_topic = f'{topic_prefix}{TopicSpecs.NOTIFICATIONS}' - self._events_topic = f'{topic_prefix}{TopicSpecs.MARKET_EVENTS}' - self._logs_topic = f'{topic_prefix}{TopicSpecs.LOGS}' - - conn_params = ConnectionParameters( - host=host, - port=int(port), - username=username, - password=password - ) - - super().__init__( - node_name=f'{self._ns}.{self._bot_id}', - connection_params=conn_params, - heartbeats=False, - debug=True, - **kwargs - ) - - def _init_endpoints(self): - if self._notifications: - self.notify_sub = self.create_subscriber(msg_type=NotifyMessage, - topic=self._notify_topic, - on_message=self._on_notification) - print(f'[*] Subscribed to NOTIFY topic: {self._notify_topic}') - if self._events: - self.events_sub = self.create_subscriber(msg_type=EventMessage, - topic=self._events_topic, - on_message=self._on_event) - print(f'[*] Subscribed to EVENT topic: {self._events_topic}') - if self._logs: - self.logs_sub = self.create_subscriber(msg_type=LogMessage, - topic=self._logs_topic, - on_message=self._on_log) - print(f'[*] Subscribed to LOG topic: {self._logs_topic}') - self.hb_sub = self.create_subscriber(msg_type=HeartbeatMessage, - topic=self._hb_topic, - on_message=self._on_hb) - print(f'[*] Subscribed to HEARTBEAT topic: {self._hb_topic}') - - def _on_notification(self, msg): - print(f'[NOTIFICATION] - {msg}') - - def _on_event(self, msg): - print(f'[EVENT] - {msg}') - - def _on_log(self, msg): - print(f'[LOG] - {msg}') - - def _on_hb(self, msg): - print(f'[HEARTBEAT] - {msg}') - - def start(self): - self._init_endpoints() - self.run() - - async def run_forever(self): - self.start() - while True: - await asyncio.sleep(0.01) diff --git a/hbotrc/msgs.py b/hbotrc/msgs.py deleted file mode 100644 index bcb18b3..0000000 --- a/hbotrc/msgs.py +++ /dev/null @@ -1,139 +0,0 @@ -from typing import Any, List, Optional, Tuple, Dict -from commlib.msg import PubSubMessage, RPCMessage, HeartbeatMessage -from pydantic import root_validator, validator -import datetime - - -class BROKER_STATUS_CODE: - ERROR: int = 400 - SUCCESS: int = 200 - - -class NotifyMessage(PubSubMessage): - seq: Optional[int] = 0 - timestamp: Optional[int] = -1 - msg: Optional[str] = '' - - -class EventMessage(PubSubMessage): - timestamp: Optional[int] = -1 - type: Optional[str] = 'Unknown' - data: Optional[Dict[str, Any]] = {} - - -class LogMessage(PubSubMessage): - timestamp: Optional[float] = 0.0 - msg: Optional[str] = '' - level_no: Optional[int] = 0 - level_name: Optional[str] = '' - logger_name: Optional[str] = '' - - -class StartCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - log_level: Optional[str] = None - script: Optional[str] = None - is_quickstart: Optional[bool] = False - async_backend: Optional[bool] = False - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - - -class StopCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - skip_order_cancellation: Optional[bool] = False - async_backend: Optional[bool] = False - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - - -class ConfigCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - params: Optional[List[Tuple[str, Any]]] = [] - - class Response(RPCMessage.Response): - changes: Optional[List[Tuple[str, Any]]] = [] - config: Optional[Dict[str, Any]] = {} - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - - -class CommandShortcutMessage(RPCMessage): - class Request(RPCMessage.Request): - params: Optional[List[List[Any]]] = [] - - class Response(RPCMessage.Response): - success: Optional[List[bool]] = [] - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - - -class ImportCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - strategy: str - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - - -class StatusCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - async_backend: Optional[bool] = True - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - data: Optional[Any] = '' - - -class HistoryCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - days: Optional[float] = 0 - verbose: Optional[bool] = False - precision: Optional[int] = None - async_backend: Optional[bool] = True - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - trades: Optional[List[Any]] = [] - - -class BalanceLimitCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - exchange: str - asset: str - amount: float - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - data: Optional[str] = '' - - -class BalancePaperCommandMessage(RPCMessage): - class Request(RPCMessage.Request): - asset: str - amount: float - - class Response(RPCMessage.Response): - status: Optional[int] = BROKER_STATUS_CODE.SUCCESS - msg: Optional[str] = '' - data: Optional[str] = '' - - -class ExternalEvent(PubSubMessage): - name: str - timestamp: Optional[int] = -1 - sequence: Optional[int] = 0 - type: Optional[str] = 'eevent' - data: Optional[Dict[str, Any]] = {} - - @validator('timestamp', pre=True, always=True) - def set_ts_now(cls, v): - return v or datetime.now().timestamp() diff --git a/hbotrc/spec.py b/hbotrc/spec.py deleted file mode 100644 index b96dff3..0000000 --- a/hbotrc/spec.py +++ /dev/null @@ -1,21 +0,0 @@ - -class CommandTopicSpecs: - START: str = '/start' - STOP: str = '/stop' - CONFIG: str = '/config' - IMPORT: str = '/import' - STATUS: str = '/status' - HISTORY: str = '/history' - BALANCE_LIMIT: str = '/balance/limit' - BALANCE_PAPER: str = '/balance/paper' - COMMAND_SHORTCUT: str = '/command_shortcuts' - - -class TopicSpecs: - PREFIX: str = '{namespace}/{instance_id}' - COMMANDS: CommandTopicSpecs = CommandTopicSpecs() - LOGS: str = '/log' - MARKET_EVENTS: str = '/events' - NOTIFICATIONS: str = '/notify' - HEARTBEATS: str = '/hb' - EXTERNAL_EVENTS: str = '/external/event/*'