Using an indicator in a live strategy¶
The strategy on Using an indicator in a backtest runs live without changing a line. Only how you start it changes:
from lumibot.brokers import Alpaca
from lumibot.traders import Trader
from lumibot.example_indicators.indicator_strategy import CustomIndicatorStrategy
broker = Alpaca({"API_KEY": "<your-key>", "API_SECRET": "<your-secret>", "PAPER": True})
strategy = CustomIndicatorStrategy(broker=broker, parameters={"symbol": "SPY", "length": 20})
trader = Trader()
trader.add_strategy(strategy)
trader.run_all()
Any broker LumiBot supports works (see Trading Brokers Supported by LumiBot). Start with a paper account.
What happens live¶
self.indicators.get(...)reads the bars the data source has at that moment and updates the indicator with any new closed bars.Values are for closed bars, so a signal does not flicker while a bar is still forming. For live values of a forming bar, use the streaming pattern on Stream an indicator live from a crypto exchange.
Running indicators outside a strategy¶
IndicatorRunner runs indicators with any
LumiBot data source, for scripts, notebooks or a chart server:
from lumibot.indicators import IndicatorRunner
runner = IndicatorRunner(data_source, asset, timestep="minute")
rsi = runner.add("rsi", length=14)
snapshot = runner.load_history(500) # history, all closed
values = runner.on_bar(bar, closed=False) # live tick
values = runner.on_bar(bar, closed=True) # bar closed
How indicators run (the execution hook)¶
By default an indicator runs in the same Python process as your strategy.
You never need to change that. A program that runs indicators written by
other people (for example a chart server) may want them to run somewhere
else, such as a separate process. It registers an
IndicatorExecutor:
from lumibot.indicators import IndicatorExecutor, use_indicator_executor
class MyExecutor(IndicatorExecutor):
name = "my-executor"
def prepare(self, indicator):
# Return an object with the indicator's update/reset/describe
# methods. Returning the indicator itself keeps it in-process.
return indicator
with use_indicator_executor(MyExecutor()):
runner.add("rsi", length=14)
IndicatorRunner and self.indicators.get hand every new indicator to
the active executor. IndicatorRunner(..., executor=...) sets one for a
single runner. Indicator authors change nothing. LumiBot’s tests run
indicators in a child process this way and check the numbers match an
in-process run exactly.
- class lumibot.indicators.IndicatorExecutor¶
Decides where an indicator instance runs. Subclass and override
prepare().- close() None¶
Release anything the executor holds (processes, connections).
- prepare(indicator)¶
Return the object callers will use for
indicator.Called once per indicator instance, before any bar is processed. The default returns
indicatoritself (in-process).
- lumibot.indicators.set_indicator_executor(executor: IndicatorExecutor | None) IndicatorExecutor¶
Use
executorfor indicator instances created from now on.Nonerestores the in-process default. Returns the previous executor so it can be put back. Instances created earlier keep the executor they were prepared with. The setting is process-wide.
- lumibot.indicators.use_indicator_executor(executor: IndicatorExecutor | None)¶
Temporarily use
executor; the previous one is restored on exit, including when an error is raised.