{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/falpha-ai/json-schema/falpha-ai-signal-schema.json",
  "title": "signal",
  "x-generated": "2026-11-07",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/falpha-ai-openapi.json#/components/schemas/signal",
  "properties": {
    "ticker": {
      "type": "string",
      "title": "Ticker",
      "description": "Stock ticker symbol"
    },
    "date": {
      "anyOf": [
        {
          "type": "string",
          "format": "date-time"
        },
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Date"
    },
    "period": {
      "type": "string",
      "title": "Period",
      "description": "Signal horizon: 5d, 15d, or 2m"
    },
    "regime": {
      "type": "string",
      "title": "Regime",
      "description": "Market regime: neutral, bear, or bull"
    },
    "signal": {
      "type": "string",
      "title": "Signal",
      "description": "Signal: buy or sell"
    },
    "confidence": {
      "type": "number",
      "title": "Confidence",
      "description": "Confidence level"
    },
    "sentiment": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Sentiment",
      "description": "Average daily sentiment score (null when unavailable)"
    },
    "quality": {
      "anyOf": [
        {
          "$ref": "#/$defs/quality_metrics"
        },
        {
          "type": "null"
        }
      ],
      "description": "Signal quality metrics. Null unless include_quality=true is requested."
    },
    "drivers": {
      "anyOf": [
        {
          "items": {
            "$ref": "#/$defs/driver"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "title": "Drivers",
      "description": "Top attribution drivers (which factors moved the signal). Null unless include_drivers=true is requested."
    },
    "drivers_flat": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "title": "Drivers Flat",
      "description": "True when the model output did not move over the week, so there are no drivers (drivers is null). False when the model output moved (drivers can still be empty if every move is solver noise). Null when unknown or drivers were not requested."
    },
    "drivers_note": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Drivers Note",
      "description": "Why drivers is empty when drivers_flat is true: 'Model output unchanged over the week; no drivers'. Otherwise null."
    }
  },
  "type": "object",
  "required": [
    "ticker",
    "period",
    "regime",
    "signal",
    "confidence"
  ],
  "$defs": {
    "driver": {
      "properties": {
        "name": {
          "type": "string",
          "title": "Name",
          "description": "Human-readable factor name, e.g. Price, Sentiment, Volume, Credit Ratings"
        },
        "weight_pct": {
          "type": "number",
          "title": "Weight Pct",
          "description": "Share of total signal attribution (0-100)"
        },
        "direction": {
          "type": "string",
          "title": "Direction",
          "description": "Which way this factor pushes the signal: buy or sell"
        }
      },
      "type": "object",
      "required": [
        "name",
        "weight_pct",
        "direction"
      ],
      "title": "driver",
      "description": "One attribution driver: which factor moved the signal, and how much."
    },
    "quality_metrics": {
      "properties": {
        "sharpe_ratio": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Sharpe Ratio",
          "description": "Risk-adjusted measure of the signal's recent strength (a Sharpe-ratio proxy). Higher is better; can be negative."
        },
        "sortino_ratio": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Sortino Ratio",
          "description": "Downside-risk-adjusted counterpart to the Sharpe ratio."
        },
        "iis_score": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Iis Score",
          "description": "Information-strength score for the signal at this horizon."
        },
        "normalized_iis": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Normalized Iis",
          "description": "IIS score normalized for cross-ticker comparison."
        },
        "percent_positive_pnl": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Percent Positive Pnl",
          "description": "Percentage of recent signal-following outcomes with positive PnL (0-100)."
        }
      },
      "type": "object",
      "title": "quality_metrics",
      "description": "Signal quality metrics for one signal row. Only populated when the request\nsets include_quality=true; otherwise the parent `quality` key is null.\nIndividual metrics are null when unavailable for that row."
    }
  }
}