Skip to main content
Glama
pineforge-4pass

PineForge-Codegen

Sweep strategy parameters

backtest_pine_grid
Destructive

Sweep PineScript strategy parameters across input and override grids, compiling once and ranking each combination by net PnL, win rate, drawdown, or trade count.

Instructions

Use when the user wants to optimize, sweep, tune, or compare PineScript parameter values (e.g. 'try fast length 8/12/19', 'find the best commission/qty settings') rather than test a single configuration — for one fixed configuration use backtest_pine. Run a parameter sweep: transpile the Pine source ONCE (locally, in-container), then compile (g++) and backtest that C++ against the OHLCV CSV once per combination in the cartesian product of inputs × overrides grids. Returns a ranked list of {inputs, overrides, summary, elapsed_seconds} entries sorted by sort_by descending, plus the top entry under best. Cap: max_combinations (default 64). Takes the same symbol / market / syminfo as backtest_pine and applies the instrument to every combination (the result's instrument shows it). The lot size is TradingView's own reading for the symbol, from a measured table shipped with this server (Binance's LOT_SIZE.stepSize only for a symbol TradingView does not list; TradingView's usual 0.001 for a listing newer than the table); the tick size and currencies come from Binance's public exchangeInfo (or from the sidecar next to a CSV fetched by fetch_binance_ohlcv). syminfo goes over all of it. Set concurrency > 1 to run backtests in parallel — each docker container has its own startup overhead, so 2-4 is usually plenty.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
imageNoDocker image override. Defaults to ghcr.io/pineforge-4pass/pineforge-engine:latest.
inputsNoGrid of input.*() names → list of values to sweep. Example: {"Fast Length": [8, 12, 19], "Slow Length": [21, 26, 39]}
marketNo'spot' (default; a warning says when it is assumed) or 'usdt_perp'; the Binance market `symbol` is looked up in. A CSV fetched by fetch_binance_ohlcv for the same symbol keeps the market it was fetched for.
sourceYesPineScript v6 source.
symbolNoBinance symbol the CSV holds, e.g. 'BTCUSDT'. The lot size is TradingView's own reading for the symbol, from a measured table shipped with this server (Binance's LOT_SIZE.stepSize only for a symbol TradingView does not list; TradingView's usual 0.001 for a listing newer than the table); the tick size and currencies come from Binance's public exchangeInfo (or from the sidecar next to a CSV fetched by fetch_binance_ohlcv). TradingView's reading differs from Binance's step for most symbols (USDT-M BTCUSDT is 0.000001 on TradingView, 0.001 on Binance), so order quantities are floored as on TradingView; 0.001 is what TradingView reads for 90.6% of Binance spot symbols and 97.5% of USDT-M ones, and a lot size that is Binance's or that usual 0.001 comes with a warning. Without an instrument the engine can book sub-lot margin-call rows TradingView does not. A CSV written by fetch_binance_ohlcv needs neither `symbol` nor `syminfo`: the instrument is recorded next to it (<csv>.instrument.json) and used. If nothing can be resolved the run still goes ahead without a lot grid and says so in `warnings` and applied_runtime.syminfo.
runtimeNoEngine runtime args applied to every combo in the sweep. Same shape as backtest_pine.runtime — input_tf / script_tf / bar_magnifier / magnifier_samples / magnifier_dist. Currently fixed across the grid (not swept); add to the grid axes through future versions if you need to vary them.
sort_byNosummary.* field to rank by, descending. Default net_pnl.
syminfoNoThe instrument's own values, for a CSV of any other instrument; they win over what `symbol` or the CSV's sidecar gives. Applied to the engine: qty_step (the lot grid) and mincontract, mintick, pointvalue, type, currency, basecurrency. Without a qty_step (or mincontract) the lot grid stays off and the result carries a warning; without a mintick the engine's 0.01 applies. ticker, tickerid, timezone and session are not applied (engine defaults).
overridesNoGrid of strategy(...) header overrides → list of values, one axis per key. Example: {"default_qty_value": [1, 5], "commission_value": [0.04]}. Call list_engine_params for the full catalog with types and enum values.
concurrencyNoParallel backtests. Default 1.
report_pathNoWhere to write the full sweep JSON IF it is too large to return inline. Oversized sweeps are offloaded here and the tool returns the best + top-ranked combinations + report_path; read the file for all combinations. Defaults to pineforge-grid-<timestamp>.json in the working dir.
fixed_inputsNoInputs applied to every combo (overridden by per-combo `inputs` keys).
include_tradesNoInclude the per-trade list in each result. Default false (saves tokens).
ohlcv_csv_pathYesPath to OHLCV CSV (same format as backtest_pine).
fixed_overridesNoOverrides applied to every combo (overridden by per-combo `overrides` keys).
max_combinationsNoHard cap on combinations. Default 64.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changedv0.9.36
    • addedInput schema / properties / market
      Added value: +{
      +  "description": "'spot' (default; a warning says when it is assumed) or 'usdt_perp'; the Binance market `symbol` is looked up in. A CSV fetched by fetch_binance_ohlcv for the same symbol keeps the market it was fetched for.",
      +  "enum": [
      +    "spot",
      +    "usdt_perp"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / symbol
      Added value: +{
      +  "description": "Binance symbol the CSV holds, e.g. 'BTCUSDT'. The lot size is TradingView's own reading for the symbol, from a measured table shipped with this server (Binance's LOT_SIZE.stepSize only for a symbol TradingView does not list; TradingView's usual 0.001 for a listing newer than the table); the tick size and currencies come from Binance's public exchangeInfo (or from the sidecar next to a CSV fetched by fetch_binance_ohlcv). TradingView's reading differs from Binance's step for most symbols (USDT-M BTCUSDT is 0.000001 on TradingView, 0.001 on Binance), so order quantities are floored as on TradingView; 0.001 is what TradingView reads for 90.6% of Binance spot symbols and 97.5% of USDT-M ones, and a lot size that is Binance's or that usual 0.001 comes with a warning. Without an instrument the engine can book sub-lot margin-call rows TradingView does not. A CSV written by fetch_binance_ohlcv needs neither `symbol` nor `syminfo`: the instrument is recorded next to it (<csv>.instrument.json) and used. If nothing can be resolved the run still goes ahead without a lot grid and says so in `warnings` and applied_runtime.syminfo.",
      +  "maxLength": 40,
      +  "minLength": 2,
      +  "type": "string"
      +}
    • addedInput schema / properties / syminfo
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The instrument's own values, for a CSV of any other instrument; they win over what `symbol` or the CSV's sidecar gives. Applied to the engine: qty_step (the lot grid) and mincontract, mintick, pointvalue, type, currency, basecurrency. Without a qty_step (or mincontract) the lot grid stays off and the result carries a warning; without a mintick the engine's 0.01 applies. ticker, tickerid, timezone and session are not applied (engine defaults).",
      +  "properties": {
      +    "basecurrency": {
      +      "description": "syminfo.basecurrency, e.g. 'BTC'.",
      +      "maxLength": 64,
      +      "minLength": 1,
      +      "pattern": "^[\\x20-\\x7e]+$",
      +      "type": "string"
      +    },
      +    "currency": {
      +      "description": "syminfo.currency, e.g. 'USDT'.",
      +      "maxLength": 64,
      +      "minLength": 1,
      +      "pattern": "^[\\x20-\\x7e]+$",
      +      "type": "string"
      +    },
      +    "mincontract": {
      +      "description": "syminfo.mincontract: the smallest tradable quantity step (TradingView reports the lot size here). Defaults to qty_step when only that is given.",
      +      "maximum": 1000000000000,
      +      "minimum": 1e-12,
      +      "type": "number"
      +    },
      +    "mintick": {
      +      "description": "Price tick size (syminfo.mintick). Fills round to it. Engine default 0.01.",
      +      "maximum": 1000000000000,
      +      "minimum": 1e-12,
      +      "type": "number"
      +    },
      +    "pointvalue": {
      +      "description": "Money per price point per contract (syminfo.pointvalue). Engine default 1.",
      +      "maximum": 1000000000000,
      +      "minimum": 1e-12,
      +      "type": "number"
      +    },
      +    "qty_step": {
      +      "description": "Lot size in base units: order quantities are floored to a multiple of it. This is what removes sub-lot rows. Defaults to mincontract when only that is given.",
      +      "maximum": 1000000000000,
      +      "minimum": 1e-12,
      +      "type": "number"
      +    },
      +    "type": {
      +      "description": "syminfo.type, e.g. 'crypto', 'forex', 'stock'.",
      +      "maxLength": 64,
      +      "minLength": 1,
      +      "pattern": "^[\\x20-\\x7e]+$",
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
  2. Changed4 schema fields changedv0.9.30
    • removedInput schema / properties / fixed_inputs / additionalProperties / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "boolean"
      -  }
      -]
    • addedInput schema / properties / fixed_inputs / additionalProperties / type
      Added value: +[
      +  "string",
      +  "number",
      +  "boolean"
      +]
    • removedInput schema / properties / inputs / additionalProperties / items / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "boolean"
      -  }
      -]
    • addedInput schema / properties / inputs / additionalProperties / items / type
      Added value: +[
      +  "string",
      +  "number",
      +  "boolean"
      +]
  3. Changed1 schema field changedv0.9.0
    • addedInput schema / properties / report_path
      Added value: +{
      +  "description": "Where to write the full sweep JSON IF it is too large to return inline. Oversized sweeps are offloaded here and the tool returns the best + top-ranked combinations + report_path; read the file for all combinations. Defaults to pineforge-grid-<timestamp>.json in the working dir.",
      +  "type": "string"
      +}
  4. First observedv0.8.4

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive/non-idempotent/open-world, so the bar is lower; the description still adds real context beyond them: transpiles Pine once, compiles C++ and backtests per combination, spawns docker containers with per-container startup overhead, applies a hard max_combinations cap, and offloads oversized sweeps to report_path. It never explains why the tool is flagged destructive (arbitrary container execution) or what failure modes look like, which keeps it off a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the when-to-use clause and then the mechanics, so the most decision-relevant content comes first. However, the instrument/lot-size passage (TradingView vs Binance step, 90.6%/97.5% statistics) is verbose and duplicates the schema's symbol description, costing it a point on economy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter, nested-object tool with no output schema, the description covers the return shape (ranked {inputs, overrides, summary, elapsed_seconds} plus best), the sort_by ordering, the report_path offload path, and the instrument-resolution behavior. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description clarifies the grid semantics (cartesian product of inputs x overrides, instrument applied to every combination) and the max_combinations default, but the long lot-size/instrument paragraph is largely verbatim duplication of the `symbol` schema description rather than added meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific operation (run a parameter sweep over PineScript inputs/overrides) and explicitly contrasts itself with the sibling backtest_pine for single-configuration runs. An agent can distinguish it from every other sibling without reading either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Opens with an explicit trigger ('when the user wants to optimize, sweep, tune, or compare...'), names the exclusion ('rather than test a single configuration'), and routes to the alternative ('for one fixed configuration use backtest_pine'). Also gives operational guidance (concurrency 2-4 is usually plenty) and points to list_engine_params via the schema for the override catalog.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.