{
  "$defs": {
    "BandSpec": {
      "additionalProperties": false,
      "description": "Band specification for technical indicators.\n\nIMPORTANT: 'length' is in BARS, not days. Effective lookback horizon =\ntf \u00d7 length (e.g., 720 bars \u00d7 1h \u2248 30 days, 24 bars \u00d7 1h \u2248 1 day).\nMaximum length is 400 bars.",
      "properties": {
        "anchor": {
          "anyOf": [
            {
              "enum": [
                "session",
                "week",
                "month"
              ],
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Anchor point for AVWAP-based bands (session/week/month supported)",
          "title": "Anchor"
        },
        "band": {
          "enum": [
            "bollinger",
            "keltner",
            "donchian",
            "vwap_band"
          ],
          "title": "Band",
          "type": "string"
        },
        "length": {
          "description": "Number of BARS for lookback. Must be >=1 for bollinger/keltner/donchian; vwap_band is anchor-driven and accepts 0.",
          "maximum": 400,
          "minimum": 0,
          "title": "Length",
          "type": "integer"
        },
        "mult": {
          "default": 2.0,
          "description": "Standard deviation multiplier",
          "maximum": 5.0,
          "minimum": 0.1,
          "title": "Mult",
          "type": "number"
        }
      },
      "required": [
        "band",
        "length"
      ],
      "title": "BandSpec",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Level (while-X-holds) band event: price is currently inside or outside a band.\n\nComplements ``BandEdgeCondition`` which fires on edge events\n(touch / cross_in / cross_out). This primitive fires on every bar the\nlevel condition holds, which is the natural shape for gating (e.g.,\n\"while price is outside upper band, suppress entries\") without needing\nmanual reentry / state composition.\n\nOps:\n  - ``inside``: price is strictly between lower and upper band\n    (lower < close < upper).\n  - ``outside_above``: close > upper band.\n  - ``outside_below``: close < lower band.\n  - ``outside``: close > upper band OR close < lower band.\n\nSupported band kinds: bollinger, keltner, donchian.\n\nFor edge/onset semantics (firing once when price crosses the band edge), use\n``BandEdgeCondition`` with ``event='cross_in'`` or ``'cross_out'``, or\n``BandReentryCondition``.",
  "properties": {
    "band": {
      "$ref": "#/$defs/BandSpec"
    },
    "op": {
      "enum": [
        "inside",
        "outside_above",
        "outside_below",
        "outside"
      ],
      "title": "Op",
      "type": "string"
    },
    "type": {
      "const": "band_level",
      "default": "band_level",
      "title": "Type",
      "type": "string"
    }
  },
  "required": [
    "band",
    "op"
  ],
  "title": "BandLevelCondition",
  "type": "object"
}
