Problem Description
Solution
Yes, it is possible to update parameters in a live trading bot without restarting it. You can achieve this by implementing the on_command event handler in your algorithm.
This method allows your algorithm to receive external data payloads (commands) sent via the QuantConnect API. You can parse this data to dynamically modify variables such as stop-loss percentages, target weights, or lookback periods.
Implementation Details
To handle dynamic parameter updates:
- Define
on_command: Add this method to your algorithm class. - Parse the Data: The
dataargument contains the payload sent from the external source. It is often best to send a JSON string so you can easily parse key-value pairs. - Update Variables: Assign the new values to your class variables (e.g.,
self.variable). - Return True: Return
Trueto signal to the LEAN engine that the command was processed successfully.
Code Example
The following algorithm demonstrates a strategy that starts with a specific profit target. It includes an on_command handler that listens for a JSON string (e.g., {"target": 0.05}) to update that target dynamically.
from AlgorithmImports import *
import json
class DynamicParameterAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_cash(100000)
# 1. Define the parameter you want to change dynamically
self.profit_target = 0.02 # Default 2%
self.symbol = self.add_equity("SPY", Resolution.MINUTE).symbol
self.set_benchmark(self.symbol)
def on_data(self, data: Slice):
if not self.portfolio.invested:
self.set_holdings(self.symbol, 1)
self.debug(f"Purchased. Current Target: {self.profit_target}")
# Logic using the dynamic parameter
# If unrealized profit > target, liquidate
pnl_percent = self.portfolio[self.symbol].unrealized_profit_percent
if pnl_percent > self.profit_target:
self.liquidate(self.symbol)
self.debug(f"Target hit ({self.profit_target}). Liquidating.")
def on_command(self, data):
"""
Event handler for receiving external commands.
Expected data format: A JSON string, e.g., '{"target": 0.05}'
"""
try:
# Log the raw command data
self.log(f"Command received: {data}")
# Attempt to parse the data as JSON
# Note: Depending on how the command is sent, 'data' might be a
# Command object or a string. We cast to str to be safe before parsing.
payload = json.loads(str(data))
# Check if the specific parameter key exists
if "target" in payload:
new_target = float(payload["target"])
old_target = self.profit_target
# Update the parameter
self.profit_target = new_target
self.debug(f"Parameter Updated: Profit Target changed from {old_target} to {self.profit_target}")
return True
except Exception as e:
self.error(f"Failed to process command: {e}")
return False
return True
How to Send the Command
Once this code is deployed live, you send the command using the QuantConnect REST API (specifically the commands endpoint) or through the IDE's "Results" tab if supported for your project type.
The payload you send would look like this string:
{"target": 0.05}
Q&A
Q: Does on_command work in backtesting?
A: No, the on_command event handler is designed for live trading environments where external interaction is required. In backtesting, you should use Scheduled Events or logic within on_data to simulate parameter changes if necessary.
Q: What happens if I don't return True in on_command?
A: Returning True indicates to the LEAN engine that the command was successfully handled. If you return False or nothing, the system may log that the command was not processed, though your code logic inside the function will still execute.
Q: Can I use this to liquidate my portfolio manually?
A: Yes. You can send a command like {"action": "liquidate"} and write logic inside on_command to call self.liquidate() when that specific key is detected.
Q: Is there a limit to how often I can send commands?
A: While there is no strict hard limit in the algorithm code, the QuantConnect API has rate limits. Additionally, frequent parameter changes might lead to unstable strategy behavior or "curve fitting" in a live environment.