A plugin is a manifest (plugin.json) plus a Python entry point. It runs in a sandbox inside the engine: it may import a vetted set of modules, reach the network through urllib, and write only inside the data cache. A broken plugin never crashes the engine.
Manifest schema
text{
"id": "vix_data",
"name": "VIX Data",
"version": "1.0.0",
"author": "You",
"description": "...",
"type": "data_source | indicator | strategy_template | exporter | ui_widget",
"language": "python",
"entryPoint": "main.py",
"config": { "cache_days": { "type": "number", "default": 30, "label": "Cache TTL (days)" } },
"dependencies": [],
"tags": ["data", "vix"]
}Lifecycle: register(api)
The entry point defines register(api). The api registers what the plugin provides:
api.register_data_source(id, name, download_fn, config_schema)api.register_indicator(id, name, factory_fn, param_specs)api.register_strategy(id, name, strategy_class, param_specs)api.register_exporter(id, name, export_fn):export_fn(result), orexport_fn(result, options)to receive the options the export was asked with. It runs when an export is asked for, with every file it writes kept inside a new folder for that one export. It returns the path of the file it wrote, or a text.api.register_data_fetch(fetch_fn)runs before each backtest (see External Data)api.get_config(key, default)reads a config value: the one saved in the plugin's settings in the Plugins view, else the manifest defaultapi.log(message)appends to the plugin log shown in the Plugins view
VIX plugin walkthrough
The shipped VIX plugin is a data plugin built on the data_fetch hook.
- Config
series_id(default "VIXCLS") selects the FRED series, so the same plugin can fetch any FRED series by changing one value. - Config
cache_days(default 30) is the cache TTL in days; the plugin refetches only when the cache is older than this. data_fetch(context)downloads the FRED CSV, parses it into a date to value map, and writesvix.jsonintocontext.data_dir.- A strategy reads it with
ctx.data("vix", date).
pythondef on_market(self, ctx):
bars = ctx.bars(1)
if not bars:
return
vix = ctx.data("vix", bars[-1].ts)
if vix and vix > 30:
ctx.signal("EXIT")