| name | backtest |
| description | Scaffold and create a new backtest plugin strategy for the B3 data pipeline. Use when the user asks to create a new strategy, backtest, or trading signal. |
| argument-hint | <describe the strategy> |
| disable-model-invocation | true |
Backtest Strategy Builder
Build a new backtest strategy from the description below and write it to disk.
Input
$ARGUMENTS
Defaults (apply unless the description overrides)
- Mode: Plugin strategy (extends
StrategyBase, auto-registered for UI)
- File:
backtests/strategies/<snake_case_name>.py
- Rebalance: Monthly (
ME)
- Universe filters: ADTV >= 1M BRL, raw close >= 1.0 BRL, no glitch rows
- Portfolio: Equal weight, top 10% of valid universe
Framework Reference
Key imports for plugin strategy
import numpy as np
import pandas as pd
from backtests.core.strategy_base import (
StrategyBase, ParameterSpec,
COMMON_START_DATE, COMMON_END_DATE, COMMON_INITIAL_CAPITAL,
COMMON_TAX_RATE, COMMON_SLIPPAGE, COMMON_MIN_ADTV,
COMMON_REBALANCE_FREQ, COMMON_MONTHLY_SALES_EXEMPTION,
)
shared_data keys
shared_data["ret"]
shared_data["log_ret"]
shared_data["px"]
shared_data["raw_close"]
shared_data["adtv"]
shared_data["has_glitch"]
shared_data["adj_close"]
shared_data["close_px"]
shared_data["ibov_ret"]
shared_data["ibov_px"]
shared_data["cdi_monthly"]
shared_data["cdi_daily"]
shared_data["is_easing"]
shared_data["ibov_calm"]
shared_data["ibov_uptrend"]
shared_data["ibov_above"]
shared_data["above_ma200"]
shared_data["dist_ma200"]
shared_data["ma200_m"]
shared_data["mf_composite"]
shared_data["vol_5m"]
shared_data["atr_m"]
shared_data["autocorr_20d"]
shared_data["autocorr_60d"]
shared_data["high_low_range_20d"]
shared_data["rolling_vol_20d_daily"]
shared_data["rolling_vol_60d_daily"]
ParameterSpec constants
COMMON_START_DATE
COMMON_END_DATE
COMMON_INITIAL_CAPITAL
COMMON_TAX_RATE
COMMON_SLIPPAGE
COMMON_MIN_ADTV
COMMON_REBALANCE_FREQ
COMMON_MONTHLY_SALES_EXEMPTION
ParameterSpec constructor
ParameterSpec(name, label, type, default, min_value=None, max_value=None, step=None, choices=None)
Plugin strategy template
class <ClassName>Strategy(StrategyBase):
@property
def name(self) -> str:
return "<ShortName>"
@property
def description(self) -> str:
return "<One-sentence description.>"
def get_parameter_specs(self) -> list[ParameterSpec]:
return [
COMMON_START_DATE, COMMON_END_DATE, COMMON_INITIAL_CAPITAL,
COMMON_TAX_RATE, COMMON_SLIPPAGE, COMMON_MIN_ADTV,
COMMON_REBALANCE_FREQ, COMMON_MONTHLY_SALES_EXEMPTION,
]
def generate_signals(self, shared_data: dict, params: dict) -> tuple[pd.DataFrame, pd.DataFrame]:
ret = shared_data["ret"]
adtv = shared_data["adtv"]
raw_close = shared_data["raw_close"]
has_glitch = shared_data["has_glitch"]
tw = pd.DataFrame(0.0, index=ret.index, columns=ret.columns)
for i in range(<lookback> + 1, len(ret)):
sig_row = <signal>.iloc[i - 1]
adtv_row = adtv.iloc[i - 1]
raw_close_row = raw_close.iloc[i - 1]
has_glitch_row = has_glitch.iloc[i - 1]
valid_mask = (adtv_row >= params["min_adtv"]) & (raw_close_row >= 1.0) & (has_glitch_row == 0)
valid = sig_row[valid_mask].dropna()
if valid.empty:
continue
n = max(5, int(len(valid) * params["top_pct"]))
selected = valid.nlargest(n).index.tolist()
w = 1.0 / len(selected)
for t in selected:
tw.iloc[i, tw.columns.get_loc(t)] = w
return ret, tw
Signal patterns by type
- Momentum:
signal = ret.rolling(lookback).sum() → nlargest (top performers)
- Mean Reversion:
signal = -ret.rolling(lookback).sum() → nlargest (biggest losers)
- Low Volatility:
signal = -ret.rolling(lookback).std() → nlargest (lowest vol)
- Regime-based: gate the selection on
shared_data["is_easing"].iloc[i-1] or similar; return empty weights when regime is off
- Multifactor: rank each signal 0–1 with
.rank(pct=True), combine: signal = w1 * rank1 + w2 * rank2
Instructions
- Read
$ARGUMENTS and infer: strategy name, signal logic, any non-default parameters or portfolio construction rules.
- Generate the complete plugin strategy file following the template above. Fill in all signal logic — no TODOs left.
- Write the file to
backtests/strategies/<snake_case_name>.py using the Write tool.
- Report: file path created, class name, and a one-line summary of the signal logic.
The strategy is auto-discovered by StrategyRegistry — no registration step needed.