# Getting Started (/scripting-v2/getting-started)



Scripting V2 requires Python 3.9 or newer. Native jobs use your selected Python environment directly. Docker jobs reproduce it inside the daemon container.

## Create an environment [#create-an-environment]

Keep `.venv` beside the script so Market Lab discovers it automatically:

```bash
mkdir python-strategy
cd python-strategy
python3 -m venv .venv
.venv/bin/python -m pip install numpy pandas matplotlib
```

Market Lab resolves Python from `--python`, then an adjacent `.venv`, then `python3` or `python` from `PATH`.

## Write a script [#write-a-script]

Create `strategy.py`:

```python
CANDLES = "btc@candles@hyperliquidf:timeframe=60"

script = {
    "name": "print-close",
    "version": "2",
    "lookback": 2,
}


def on_data(ctx, history):
    candle = history.source(CANDLES, 0)
    if candle is not None:
        print(f"latest close: {candle['c']}")
```

A Python V2 file needs a module-level `script` dictionary, `"version": "2"`, and `on_data(ctx, history)`. It needs no Market Lab import or base class.

`history.source(...)` is also the source declaration. Market Lab discovers the selector and its options before the job starts, so V2 does not use `--source`, TOML `[sources]`, or `script.sources`.

Declare each feed with a literal string or a module-level string constant. A dynamic lookup may read an already-declared feed, but it cannot introduce a new subscription.

## Backtest it [#backtest-it]

```bash
mlab script backtest strategy.py \
  --from 2026-07-15 \
  --to 2026-07-16
```

Dates are UTC. A date without a time means `00:00:00`. Add an exact time when needed and quote it in the shell:

```bash
mlab script backtest strategy.py \
  --from "2026-07-15 09:30:00" \
  --to "2026-07-15 16:00:00"
```

Backtest execution uses Market Lab's simulator and never reaches an exchange.

## Deploy it live [#deploy-it-live]

```bash
mlab script run strategy.py --duration 3600
```

The command snapshots the Python file and returns a job ID:

```bash
mlab script jobs
mlab script status <JOB_ID>
mlab script logs <JOB_ID> --follow
mlab script stop <JOB_ID>
```

## Choose execution inside the script [#choose-execution-inside-the-script]

Python V2 does not take `--venue`. Every execution request names its exchange:

```python
ctx.trade(
    {
        "exchange": "hyperliquidf",
        "symbol": "BTC",
        "position": "open-long",
        "margin": 100,
        "leverage": 5,
        "order": {"type": "market"},
    }
)
```

Data and execution can use different exchanges. One job may also send requests to several execution exchanges.

BULK and Hyperliquid use mainnet by default. `--testnet` routes supported sources and execution requests in that job to testnet. HyperLink execution is mainnet-only.

## Use `marketlab.toml` [#use-marketlabtoml]

```toml
version = 1

[script]
path = "strategy.py"
python = ".venv/bin/python"
duration = 3600

[script.params]
fast_period = 5
slow_period = 20
margin = 100

[backtest]
from = "2026-07-15"
to = "2026-07-16"
```

The source remains in `history.source(...)` inside `strategy.py`:

```bash
mlab script backtest
mlab script run
```

Do not add `[execution].venue` for Python V2. Each execution request names its own exchange. JavaScript Scripting V1 keeps its existing `--source` and job-wide `--venue` behavior.

Next, read [Scripts](/scripting-v2/scripts) and [Sources](/scripting-v2/sources).
