# Scripts (/scripting-v2/scripts)



A Python V2 script is a normal `.py` module. It needs a `script` dictionary and `on_data(ctx, history)`.

```python
script = {
    "name": "sma-crossover",
    "version": "2",
    "description": "Trade a moving-average crossover",
    "lookback": 100,
    "params": {
        "fast": {"type": "number", "default": 5},
        "slow": {"type": "number", "default": 20},
    },
}


def on_data(ctx, history):
    pass
```

No Market Lab import or base class is required.

## Manifest [#manifest]

| Field         | Required | Meaning                                               |
| ------------- | -------- | ----------------------------------------------------- |
| `name`        | Yes      | Script name shown in jobs and reports.                |
| `version`     | Yes      | Must be `"2"`.                                        |
| `description` | No       | Human-readable metadata.                              |
| `lookback`    | No       | Records retained per exact selector, from 2 to 5,000. |
| `params`      | No       | Runtime parameter definitions.                        |

V2 does not use `script.sources`, `--source`, or TOML `[sources]`. Calls to `history.source(...)` declare the job's sources.

## Parameters [#parameters]

```python
"params": {
    "window": {"type": "number", "required": True},
    "armed": {"type": "boolean", "default": False},
    "label": {"type": "string", "default": "baseline"},
}
```

```bash
--param window=20 --param armed=true --param label=experiment-a
```

Read resolved values from `ctx.params`:

```python
window = int(ctx.params["window"])
```

## `on_data(ctx, history)` [#on_datactx-history]

The required data hook runs once for every accepted source event. The new record is inserted into history before the hook runs.

```python
CANDLES = "btc@candles@binancef:timeframe=60"
SOURCE = "btc@candles@binancef"


def on_data(ctx, history):
    if ctx.source != SOURCE:
        return

    candle = history.source(CANDLES, 0)
```

## `on_execution(ctx)` [#on_executionctx]

The optional execution hook receives order, fill, position, and account lifecycle updates through `ctx.execution`:

```python
def on_execution(ctx):
    print(ctx.execution)
```

It may call `ctx.trade`, `ctx.order`, or `ctx.cancel`.

## `on_finish(ctx, history)` [#on_finishctx-history]

The optional finish hook runs after the final backtest event or when a live session stops normally. Use it for reports and artifacts:

```python
def on_finish(ctx, history):
    points = ctx.pnl()
    path = ctx.artifact_path("pnl.json")
```

Execution methods are disabled during `on_finish`.

## Process Lifecycle [#process-lifecycle]

One persistent Python process handles a session. Module globals survive between hook calls, and hooks run synchronously in event order.

Market Lab may import the module during CLI validation, daemon validation, and runtime startup. Keep import-time work limited to imports, constants, the manifest, and safe initialization.

Hooks may return `None` or a dictionary containing `metrics`, `meta`, or both. Returned values do not place orders.

See [API Reference](/scripting-v2/api-reference) for the complete contract.
