# Price Lines

A price line is a horizontal line drawn across a series at a specific price. Use price lines when you need to annotate fixed levels (entry, stop, target, strike) or track a live, table-driven value such as a moving threshold. Use [`tvl.price_line()`](#api-reference) for a static level (`price=100`) or for a Deephaven-extension column-driven level (`column="ThresholdCol"`) where the line tracks the last row of a named column as the table ticks. The returned `PriceLine` object goes onto a series via the `price_lines=` argument.

## What are price lines useful for?

- **Marking levels**: Entry, stop, and target levels on a trade can be drawn as static price lines so they sit alongside the candlestick body.
- **Showing thresholds**: A risk threshold or alert level becomes a single horizontal line on the chart pane.
- **Following live values**: A column-driven price line tracks the most recent row of a table, which works well for “current best bid” or “current VWAP” on a ticking stream.
- **Annotating with labels**: Each price line carries a `title` (drawn on the pane) and an axis label with its own colors, so the level can describe itself.

## Examples

### Add a simple horizontal line at a price

The minimal price line. Pass it to a series via `price_lines=[...]`.

```python order=simple_line,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

target = tvl.price_line(price=104.0, color="#2e7d32")

simple_line = tvl.candlestick(ohlc, price_lines=[target])
```

A green horizontal line sits at 104.0 across the entire chart.

### Style a price line

Most visual properties of a `PriceLine` are independent: color, width, dashing, and whether the line itself is drawn. The supported widths are `1`, `2`, `3`, `4`; styles come from `LineStyle` (`"solid"`, `"dotted"`, `"dashed"`, `"large_dashed"`, `"sparse_dotted"`).

```python order=styled_line,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

styled = tvl.price_line(
    price=104.0,
    color="#d32f2f",
    line_width=3,
    line_style="dashed",
    line_visible=True,
    id="stop-loss",
)

styled_line = tvl.candlestick(ohlc, price_lines=[styled])
```

A dashed red line at 104.0, three pixels wide.

### Add a title and an axis label

The `title` is drawn next to the line on the chart pane. The axis label (which sits on the price scale) is controlled by `axis_label_visible`, `axis_label_color`, and `axis_label_text_color`.

```python order=labeled_line,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

labeled = tvl.price_line(
    price=98.0,
    color="#1976d2",
    line_width=2,
    line_style="solid",
    title="Support",
    axis_label_visible=True,
    axis_label_color="#1976d2",
    axis_label_text_color="#ffffff",
)

labeled_line = tvl.candlestick(ohlc, price_lines=[labeled])
```

The line is labeled `Support` on the chart and `98.00` on the axis (with a blue background).

### Draw many price lines at once

A list of price lines can be attached to one series. This is the natural way to show a set of strikes, ladder levels, or stop placements.

```python order=ladder_chart,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

ladder = [
    tvl.price_line(price=p, color=c, line_style=style, title=label)
    for p, c, style, label in [
        (104.0, "#2e7d32", "solid",       "Target"),
        (102.0, "#558b2f", "dotted",      "Trim"),
        (100.0, "#1976d2", "dashed",      "Entry"),
        ( 98.0, "#ef6c00", "large_dashed","Trail stop"),
        ( 96.0, "#c62828", "sparse_dotted","Hard stop"),
    ]
]

ladder_chart = tvl.candlestick(ohlc, price_lines=ladder)
```

Five horizontal lines, each using a different `LineStyle` value, label the trading ladder. Notice the loop covers all five styles in `LineStyle`.

### Hide the line, keep the axis label

`line_visible=False` removes the horizontal stroke from the pane but keeps the axis label on the price scale. This is useful when you want a value annotation without cluttering the chart body.

```python order=labelonly_chart,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

invisible = tvl.price_line(
    price=100.0,
    line_visible=False,
    axis_label_visible=True,
    axis_label_color="#1976d2",
    axis_label_text_color="#ffffff",
    title="Par",
    id="par-level",
)

labelonly_chart = tvl.candlestick(ohlc, price_lines=[invisible])
```

The chart shows the axis tag for 100.00 with no line drawn through the pane.

### Track a live column value

This is the Deephaven extension to `price_line()`. Pass `column=` instead of `price=` and the line tracks the last row of that column. When the source table ticks, the price line moves automatically.

```python order=live_line,ohlc_w_avg,ohlc
import deephaven.plot.tradingview_lightweight as tvl
from deephaven.updateby import rolling_avg_tick

ohlc = tvl.data.ohlc()
# 20-period moving average — last row is the current value.
ohlc_w_avg = ohlc.update_by(
    ops=[rolling_avg_tick(cols=["AvgClose = Close"], rev_ticks=20)],
)

live = tvl.price_line(
    column="AvgClose",
    color="#ef6c00",
    line_width=2,
    line_style="solid",
    title="MA(20)",
)

live_line = tvl.candlestick(ohlc_w_avg, price_lines=[live])
```

The orange line tracks the 20-period moving average of `Close`. It is mutually exclusive with `price=`; setting both, or neither, raises `ValueError`.

### Pick the source for the built-in last-price line

Separate from user-added price lines, every series has an automatic “last price” horizontal line, styled with `last_price_line=tvl.last_price_line(...)` (returns a `LastPriceLine`). Its `source` (a `PriceLineSource` value) picks whether it follows the last bar or the last visible bar.

```python order=source_chart,ohlc
import deephaven.plot.tradingview_lightweight as tvl

ohlc = tvl.data.ohlc()

# Follow the last bar in the data, regardless of scroll position.
last_bar = tvl.line(
    ohlc, timestamp="Timestamp", value="Close",
    color="#1976d2",
    last_price_line=tvl.last_price_line(
        visible=True,
        source="last_bar",
        color="#1976d2",
        width=2,
        style="dotted",
    ),
)

# Follow the last visible bar — moves as you scroll.
last_visible = tvl.line(
    ohlc, timestamp="Timestamp", value="Open",
    color="#d32f2f",
    last_price_line=tvl.last_price_line(
        visible=True,
        source="last_visible",
        color="#d32f2f",
        width=2,
        style="dashed",
    ),
)

source_chart = tvl.chart(last_bar, last_visible)
```

Two series with different `source` values demonstrate both members of the `PriceLineSource` enum (`"last_bar"`, `"last_visible"`).

## API Reference

Provide either price (static value) or column (dynamic,
tracking the last-row value of the named column in the series'
table).

**Returns:** `PriceLine` A PriceLine instance.

**Raises:** ValueError -- If neither or both of price and column
    are supplied.

<ParamTable param={{"module_name": "deephaven.plot.tradingview_lightweight.", "name": "price_line", "parameters": [{"name": "price", "type": "Optional[float]", "description": "Static price level.  Mutually exclusive with column.", "default": "None"}, {"name": "color", "type": "Optional[Color]", "description": "Line color (CSS color string).", "default": "None"}, {"name": "line_width", "type": "Optional[LineWidth]", "description": "Line thickness in pixels (1\u20134).", "default": "None"}, {"name": "line_style", "type": "Optional[LineStyle]", "description": "Dash pattern; see LineStyle.", "default": "None"}, {"name": "line_visible", "type": "Optional[bool]", "description": "Whether the horizontal line rule is drawn (default True in TV-LW).  Set to False to show only the axis label.", "default": "None"}, {"name": "axis_label_visible", "type": "Optional[bool]", "description": "Whether the axis label is shown on the price scale.", "default": "None"}, {"name": "title", "type": "Optional[str]", "description": "Short text drawn on the chart pane next to the line.", "default": "None"}, {"name": "axis_label_color", "type": "Optional[Color]", "description": "Background color of the price-scale axis label.", "default": "None"}, {"name": "axis_label_text_color", "type": "Optional[Color]", "description": "Text color of the price-scale axis label.", "default": "None"}, {"name": "id", "type": "Optional[str]", "description": "Optional string identifier for the price line.", "default": "None"}, {"name": "column", "type": "Optional[str]", "description": "Deephaven extension \u2014 column name whose last-row value sets the price level dynamically. Mutually exclusive with price.", "default": "None"}]}} />
Create a LastPriceLine for a series' last_price_line= argument.

**Returns:** `LastPriceLine` A last-price-line config for last_price_line=.

<ParamTable param={{"module_name": "deephaven.plot.tradingview_lightweight.", "name": "last_price_line", "parameters": [{"name": "visible", "type": "bool | None", "description": "Show the last-price line (TVL default True).", "default": "None"}, {"name": "source", "type": "Literal['last_bar', 'last_visible'] | None", "description": "Which bar drives the line; see PriceLineSource.", "default": "None"}, {"name": "width", "type": "Literal[1, 2, 3, 4] | None", "description": "Stroke width in pixels; see LineWidth.", "default": "None"}, {"name": "color", "type": "Literal['gray-50', 'gray-75', 'gray-100', 'gray-200', 'gray-300', 'gray-400', 'gray-500', 'gray-600', 'gray-700', 'gray-800', 'gray-900', 'red-100', 'red-200', 'red-300', 'red-400', 'red-500', 'red-600', 'red-700', 'red-800', 'red-900', 'red-1000', 'red-1100', 'red-1200', 'red-1300', 'red-1400', 'orange-100', 'orange-200', 'orange-300', 'orange-400', 'orange-500', 'orange-600', 'orange-700', 'orange-800', 'orange-900', 'orange-1000', 'orange-1100', 'orange-1200', 'orange-1300', 'orange-1400', 'yellow-100', 'yellow-200', 'yellow-300', 'yellow-400', 'yellow-500', 'yellow-600', 'yellow-700', 'yellow-800', 'yellow-900', 'yellow-1000', 'yellow-1100', 'yellow-1200', 'yellow-1300', 'yellow-1400', 'chartreuse-100', 'chartreuse-200', 'chartreuse-300', 'chartreuse-400', 'chartreuse-500', 'chartreuse-600', 'chartreuse-700', 'chartreuse-800', 'chartreuse-900', 'chartreuse-1000', 'chartreuse-1100', 'chartreuse-1200', 'chartreuse-1300', 'chartreuse-1400', 'celery-100', 'celery-200', 'celery-300', 'celery-400', 'celery-500', 'celery-600', 'celery-700', 'celery-800', 'celery-900', 'celery-1000', 'celery-1100', 'celery-1200', 'celery-1300', 'celery-1400', 'green-100', 'green-200', 'green-300', 'green-400', 'green-500', 'green-600', 'green-700', 'green-800', 'green-900', 'green-1000', 'green-1100', 'green-1200', 'green-1300', 'green-1400', 'seafoam-100', 'seafoam-200', 'seafoam-300', 'seafoam-400', 'seafoam-500', 'seafoam-600', 'seafoam-700', 'seafoam-800', 'seafoam-900', 'seafoam-1000', 'seafoam-1100', 'seafoam-1200', 'seafoam-1300', 'seafoam-1400', 'cyan-100', 'cyan-200', 'cyan-300', 'cyan-400', 'cyan-500', 'cyan-600', 'cyan-700', 'cyan-800', 'cyan-900', 'cyan-1000', 'cyan-1100', 'cyan-1200', 'cyan-1300', 'cyan-1400', 'blue-100', 'blue-200', 'blue-300', 'blue-400', 'blue-500', 'blue-600', 'blue-700', 'blue-800', 'blue-900', 'blue-1000', 'blue-1100', 'blue-1200', 'blue-1300', 'blue-1400', 'indigo-100', 'indigo-200', 'indigo-300', 'indigo-400', 'indigo-500', 'indigo-600', 'indigo-700', 'indigo-800', 'indigo-900', 'indigo-1000', 'indigo-1100', 'indigo-1200', 'indigo-1300', 'indigo-1400', 'purple-100', 'purple-200', 'purple-300', 'purple-400', 'purple-500', 'purple-600', 'purple-700', 'purple-800', 'purple-900', 'purple-1000', 'purple-1100', 'purple-1200', 'purple-1300', 'purple-1400', 'fuchsia-100', 'fuchsia-200', 'fuchsia-300', 'fuchsia-400', 'fuchsia-500', 'fuchsia-600', 'fuchsia-700', 'fuchsia-800', 'fuchsia-900', 'fuchsia-1000', 'fuchsia-1100', 'fuchsia-1200', 'fuchsia-1300', 'fuchsia-1400', 'magenta-100', 'magenta-200', 'magenta-300', 'magenta-400', 'magenta-500', 'magenta-600', 'magenta-700', 'magenta-800', 'magenta-900', 'magenta-1000', 'magenta-1100', 'magenta-1200', 'magenta-1300', 'magenta-1400', 'negative', 'notice', 'positive', 'info', 'accent', 'accent-100', 'accent-200', 'accent-300', 'accent-400', 'accent-500', 'accent-600', 'accent-700', 'accent-800', 'accent-900', 'accent-1000', 'accent-1100', 'accent-1200', 'accent-1300', 'accent-1400', 'bg', 'content-bg', 'subdued-content-bg', 'surface-bg', 'fg'] | str | None", "description": "Line CSS color (empty string uses the series color).", "default": "None"}, {"name": "style", "type": "Literal['solid', 'dotted', 'dashed', 'large_dashed', 'sparse_dotted'] | None", "description": "Dash pattern; see LineStyle.", "default": "None"}]}} />
