---
title: "Configuration"
description: "Environment variables, exchange credentials, hot-reload parameters, and logging configuration."
icon: "sliders"
---

Horizon reads credentials and configuration from environment variables as a fallback when not passed explicitly to constructors.

## Horizon API Key

| Variable | Description |
|----------|-------------|
| `HORIZON_API_KEY` | Your Horizon SDK API key (required) |

```bash
export HORIZON_API_KEY="hz_live_abc123..."
```

Get your key at [api.mathematicalcompany.com](https://api.mathematicalcompany.com). See the [Authentication](/authentication) page for details.

## Polymarket

| Variable | Description |
|----------|-------------|
| `POLYMARKET_PRIVATE_KEY` | Ethereum private key (hex, with or without `0x` prefix) |
| `POLYMARKET_API_KEY` | CLOB API key |
| `POLYMARKET_API_SECRET` | CLOB API secret |
| `POLYMARKET_API_PASSPHRASE` | CLOB API passphrase |

```bash
export POLYMARKET_PRIVATE_KEY="0x..."
export POLYMARKET_API_KEY="..."
export POLYMARKET_API_SECRET="..."
export POLYMARKET_API_PASSPHRASE="..."
```

```python
hz.Polymarket()  # reads from env automatically
```

## Kalshi

| Variable | Description |
|----------|-------------|
| `KALSHI_EMAIL` | Kalshi account email |
| `KALSHI_PASSWORD` | Kalshi account password |
| `KALSHI_API_KEY` | Kalshi API key |
| `KALSHI_API_URL` | Kalshi API base URL (override for demo/staging) |

```bash
export KALSHI_API_KEY="..."
# or
export KALSHI_EMAIL="..."
export KALSHI_PASSWORD="..."
```

```python
hz.Kalshi()  # reads from env automatically
```

## Database

| Variable | Description | Default |
|----------|-------------|---------|
| `HORIZON_DB` | SQLite database path | `./{strategy_name}.db` |

```bash
export HORIZON_DB="/data/horizon.db"
```

## Logging

| Variable | Description | Default |
|----------|-------------|---------|
| `HORIZON_LOG` | Rust tracing filter level | `warn` |

Valid levels: `debug`, `info`, `warn`, `error`

### Python Logging

Horizon uses Python's `logging` module for the Python layer:

```python
import logging
logging.basicConfig(level=logging.DEBUG)
```

### Rust Logging

Set the Rust tracing level via environment variable:

```bash
HORIZON_LOG=debug python my_strategy.py
```

### CLI Log Level

The `--log-level` flag sets both Python logging and the `HORIZON_LOG` environment variable:

```bash
python -m horizon run strategy.py --log-level=debug
```

## Credential Resolution Order

Both `Polymarket` and `Kalshi` resolve credentials in this order:

<Steps>
  <Step title="Explicit constructor arguments">
    ```python
    hz.Polymarket(private_key="0x...", api_key="...")
    ```
  </Step>
  <Step title="Environment variables">
    ```python
    hz.Polymarket()  # reads POLYMARKET_PRIVATE_KEY, etc.
    ```
  </Step>
</Steps>

Explicit arguments always take priority over environment variables.

## Hot-Reload Parameters

Update strategy parameters at runtime without restarting. Three approaches: pipeline function, standalone `ParamReloader`, or engine runtime params.

### Pipeline Function

Drop `hz.hot_reload()` into your pipeline to inject parameters into `ctx.params` every cycle.

**File-based:**
```python
import horizon as hz

hz.run(
    pipeline=[
        hz.hot_reload(source="params.json"),
        my_strategy,  # access via ctx.params["spread"]
    ],
    ...
)
```

Write new parameters (takes effect next cycle):
```python
hz.write_params("params.json", {"spread": 0.05, "gamma": 0.3})
```

**Dict-based:**
```python
live_params = {"spread": 0.04}
hz.run(
    pipeline=[
        hz.hot_reload(source=live_params),
        my_strategy,
    ],
    ...
)
# Update at runtime:
live_params["spread"] = 0.06  # Takes effect next cycle
```

### ParamReloader

Standalone class for watching a JSON parameter file. Useful outside of `hz.run()`.

```python
import horizon as hz

reloader = hz.ParamReloader(
    path="params.json",     # Path to JSON file
    poll_interval=1.0,      # Seconds between file stat checks (default: 1.0)
)

# Get initial parameters (always returns a dict, never None)
params = reloader.current()
print(params)  # {"spread": 0.04, "gamma": 0.3}

# Check for updates (returns new dict if file changed, None otherwise)
updated = reloader.check()
if updated is not None:
    print(f"Params changed: {updated}")
```

| Method | Returns | Description |
|--------|---------|-------------|
| `current()` | `dict[str, float]` | Most recently loaded parameters (never None) |
| `check()` | `dict[str, float] or None` | New params if file changed, else None |

<Note>
  `check()` returns `None` on the first call if the file hasn't changed since construction. Use `current()` to get the initial values.
</Note>

### Engine Runtime Params

Set and retrieve parameters directly on the Engine.

```python
engine = hz.Engine()
engine.update_param("spread", 0.05)
engine.update_params_batch({"spread": 0.05, "gamma": 0.3})
params = engine.get_all_params()  # {"spread": 0.05, "gamma": 0.3}
val = engine.get_param("spread")  # 0.05
engine.remove_param("gamma")
```

These are injected into `ctx.params` every cycle when using `hz.run()`.
