diff --git a/README.md b/README.md index 91b53c5c..5629fa17 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ A locally-focused workflow (local development, local execution) with the CLI may - [`lean build`](#lean-build) - [`lean cloud backtest`](#lean-cloud-backtest) - [`lean cloud live`](#lean-cloud-live) +- [`lean cloud live command`](#lean-cloud-live-command) - [`lean cloud live deploy`](#lean-cloud-live-deploy) - [`lean cloud live liquidate`](#lean-cloud-live-liquidate) - [`lean cloud live stop`](#lean-cloud-live-stop) @@ -101,6 +102,7 @@ A locally-focused workflow (local development, local execution) with the CLI may - [`lean live`](#lean-live) - [`lean live add-security`](#lean-live-add-security) - [`lean live cancel-order`](#lean-live-cancel-order) +- [`lean live command`](#lean-live-command) - [`lean live deploy`](#lean-live-deploy) - [`lean live liquidate`](#lean-live-liquidate) - [`lean live stop`](#lean-live-stop) @@ -303,11 +305,30 @@ Options: --help Show this message and exit. Commands: + command Send a command to a running cloud live trading project. deploy Start live trading for a project in the cloud. liquidate Stops live trading and liquidates existing positions for a certain project. stop Stops live trading for a certain project without liquidating existing positions. ``` +### `lean cloud live command` + +Send a command to a running cloud live trading project. + +``` +Usage: lean cloud live command [OPTIONS] PROJECT + + Send a command to a running cloud live trading project. + +Options: + --data TEXT The command to send, 'str' representation of a 'dict' e.g. "{ \"target\": \"BTCUSD\", + \"$type\":\"MyCommand\" }" + --verbose Enable debug logging + --help Show this message and exit. +``` + +_See code: [lean/commands/cloud/live/command.py](lean/commands/cloud/live/command.py)_ + ### `lean cloud live deploy` Start live trading for a project in the cloud. @@ -1165,6 +1186,7 @@ Options: Commands: add-security Represents a command to add a security to the algorithm. cancel-order Represents a command to cancel a specific order by id. + command Send a command to a local running live trading project. deploy Start live trading a project locally using Docker. liquidate Liquidate the given symbol from the latest deployment of the given project. stop Stop an already running local live trading project. @@ -1216,6 +1238,25 @@ Options: _See code: [lean/commands/live/cancel_order.py](lean/commands/live/cancel_order.py)_ +### `lean live command` + +Send a command to a local running live trading project. + +``` +Usage: lean live command [OPTIONS] PROJECT + + Send a command to a local running live trading project. + +Options: + --data TEXT The command to send, 'str' representation of a 'dict' e.g. "{ \"target\": \"BTCUSD\", + \"$type\":\"MyCommand\" }" + --lean-config FILE The Lean configuration file that should be used (defaults to the nearest lean.json) + --verbose Enable debug logging + --help Show this message and exit. +``` + +_See code: [lean/commands/live/command.py](lean/commands/live/command.py)_ + ### `lean live deploy` Start live trading a project locally using Docker. diff --git a/lean/commands/cloud/live/__init__.py b/lean/commands/cloud/live/__init__.py index 4a21f122..697bab85 100644 --- a/lean/commands/cloud/live/__init__.py +++ b/lean/commands/cloud/live/__init__.py @@ -14,9 +14,11 @@ from lean.commands.cloud.live.live import live from lean.commands.cloud.live.deploy import deploy from lean.commands.cloud.live.stop import stop +from lean.commands.cloud.live.command import command from lean.commands.cloud.live.liquidate import liquidate live.add_command(deploy) live.add_command(stop) -live.add_command(liquidate) \ No newline at end of file +live.add_command(command) +live.add_command(liquidate) diff --git a/lean/commands/cloud/live/command.py b/lean/commands/cloud/live/command.py new file mode 100644 index 00000000..aff1c26d --- /dev/null +++ b/lean/commands/cloud/live/command.py @@ -0,0 +1,41 @@ +# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. +# Lean CLI v1.0. Copyright 2021 QuantConnect Corporation. +# +# 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. + + +from lean.container import container +from click import command, argument, option +from lean.click import LeanCommand + + +@command(cls=LeanCommand) +@argument("project", type=str) +@option("--data", type=str, help="The command to send, 'str' representation of a 'dict' e.g. " + "\"{ \\\"target\\\": \\\"BTCUSD\\\", \\\"$type\\\":\\\"MyCommand\\\" }\"") +def command(project: str, data: str) -> None: + """ + Send a command to a running cloud live trading project. + """ + data = eval(data) + + logger = container.logger + api_client = container.api_client + + cloud_project_manager = container.cloud_project_manager + cloud_project = cloud_project_manager.get_cloud_project(project, False) + logger.info(f"cloud.live.command(): sending command.") + response = api_client.live.command_create(cloud_project.projectId, data) + if response.success: + logger.info(f"cloud.live.command(): command executed successfully.") + else: + raise Exception("cloud.live.command(): Failed: to execute the command successfully.") + diff --git a/lean/commands/live/__init__.py b/lean/commands/live/__init__.py index c2f6dc72..1d3cc401 100644 --- a/lean/commands/live/__init__.py +++ b/lean/commands/live/__init__.py @@ -14,6 +14,7 @@ from lean.commands.live.live import live from lean.commands.live.deploy import deploy from lean.commands.live.stop import stop +from lean.commands.live.command import command from lean.commands.live.liquidate import liquidate from lean.commands.live.submit_order import submit_order from lean.commands.live.cancel_order import cancel_order @@ -22,8 +23,9 @@ live.add_command(deploy) live.add_command(stop) +live.add_command(command) live.add_command(liquidate) live.add_command(submit_order) live.add_command(cancel_order) live.add_command(add_security) -live.add_command(update_order) \ No newline at end of file +live.add_command(update_order) diff --git a/lean/commands/live/command.py b/lean/commands/live/command.py new file mode 100644 index 00000000..e0da2e42 --- /dev/null +++ b/lean/commands/live/command.py @@ -0,0 +1,37 @@ +# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. +# Lean CLI v1.0. Copyright 2021 QuantConnect Corporation. +# +# 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. + + +from pathlib import Path +from click import command, argument, option +from lean.click import LeanCommand, PathParameter +from lean.commands.live.live import get_result, send_command + + +@command(cls=LeanCommand, requires_lean_config=True, requires_docker=True) +@argument("project", type=PathParameter(exists=True, file_okay=True, dir_okay=True)) +@option("--data", type=str, help="The command to send, 'str' representation of a 'dict' e.g. " + "\"{ \\\"target\\\": \\\"BTCUSD\\\", \\\"$type\\\":\\\"MyCommand\\\" }\"") +def command(project: Path, + data: str) -> None: + """ + Send a command to a local running live trading project. + """ + data = eval(data) + if "id" not in data: + from uuid import uuid4 + data["id"] = uuid4().hex + + docker_container_name = send_command(project, data) + get_result(data["id"], docker_container_name) + diff --git a/lean/components/api/live_client.py b/lean/components/api/live_client.py index 39e2460a..8dbc862e 100644 --- a/lean/components/api/live_client.py +++ b/lean/components/api/live_client.py @@ -123,3 +123,15 @@ def liquidate_and_stop(self, project_id: int) -> QCRestResponse: "projectId": project_id }) return QCRestResponse(**data) + + def command_create(self, project_id: int, command: dict) -> QCRestResponse: + """Sends a command to a live trading deployment + + :param project_id: the id of the project + :param command: the command to send + """ + data = self._api.post("live/commands/create", { + "projectId": project_id, + "command": command + }) + return QCRestResponse(**data)