# How to Access the Underlying Data Array in a BanTA Series

> Learn how to access the underlying data array in a BanTA Series. Use Get Range or RangeValid exported methods for safe data retrieval in your Go applications.

- Repository: [banbox/banta](https://github.com/banbox/banta)
- Tags: how-to-guide
- Published: 2026-02-26

---

**To access the underlying data array in a BanTA Series, use the exported accessor methods `Get()`, `Range()`, or `RangeValid()` defined in [`core.go`](https://github.com/banbox/banta/blob/main/core.go), as the raw `Data` slice is unexported for encapsulation.**

The `banbox/banta` library provides a `Series` type for handling time-series financial data in algorithmic trading applications. While the raw numeric values are stored internally in a private slice, the library exposes several safe methods to read this data. Understanding how to access the underlying data array in a BanTA Series is essential for building custom indicators or analyzing price history without breaking the library's encapsulation.

## Understanding the Series Data Structure

In [`types.go`](https://github.com/banbox/banta/blob/main/types.go), the `Series` struct defines an unexported field `Data []float64` that stores the actual numeric values. Because this field is lowercase (private), external packages cannot access it directly. This design prevents accidental modification of the internal state while allowing the library to maintain data integrity and handle memory management internally.

## Accessor Methods for Reading Series Data

The [`core.go`](https://github.com/banbox/banta/blob/main/core.go) file implements three primary methods for reading the underlying data without breaking encapsulation. These functions operate on the private `Data` slice internally while providing safe, read-only access to external callers.

### Get(): Retrieve a Single Value

The `Get(i int) float64` method returns the *i*-th most recent value, where index `0` represents the latest bar. This is the fastest way to access a single data point when you only need the current or a specific historical value by position.

### Range(): Extract a Window of Values

The `Range(start, stop int) []float64` method returns a slice containing values from `start` (most recent) up to but not including `stop`. The returned slice is ordered from newest to oldest, making it ideal for calculations requiring a sliding window of recent bars.

### RangeValid(): Filter Out NaN Values

The `RangeValid(start, stop int) ([]float64, []int)` method functions like `Range()` but excludes `NaN` (Not a Number) values. It returns two slices: the valid values and their corresponding original indices. Use this when your calculations require only defined data points and cannot handle missing values, such as when calculating averages on sparse data.

## Modifying Series Data

While the question focuses on reading data, the `Append(obj interface{})` method in [`core.go`](https://github.com/banbox/banta/blob/main/core.go) allows you to add new values to the series. This accepts either a single `float64` or a slice of values, enabling dynamic updates to the underlying array when processing live market feeds.

## Practical Code Examples

The following examples demonstrate how to access the underlying data array in real trading scenarios using the `banta` package API.

### Accessing the Last 10 Bars

```go
// Assume env is a *banta.BarEnv that has been populated with market data.
last10 := env.Close.Range(0, 10) // Returns newest → oldest
fmt.Println("Close prices of the last 10 bars:", last10)

```

### Retrieving the Latest Value

```go
// Get the most recent close price using index 0.
latestClose := env.Close.Get(0)
fmt.Printf("Latest close: %.2f\n", latestClose)

```

### Handling Missing Data

```go
// Get valid volume data for the last 20 bars, skipping NaN entries.
vals, idxs := env.Volume.RangeValid(0, 20)
for i, v := range vals {
    fmt.Printf("Bar %d (original index %d) volume: %.2f\n",
        i, idxs[i], v)
}

```

## Package-Internal Access

If you are contributing to the `banta` repository or writing code inside the package directory, Go permits direct access to the unexported `Data` field. The internal indicators in [`sta_inds.go`](https://github.com/banbox/banta/blob/main/sta_inds.go) demonstrate this pattern, accessing `s.Data` directly for performance-critical calculations that require tight loops over the raw array. However, external code must always use the public API methods described above to maintain proper encapsulation.

## Summary

- The underlying data array in a BanTA Series is stored in the unexported `Data []float64` field defined in [`types.go`](https://github.com/banbox/banta/blob/main/types.go).
- External packages must use `Get()`, `Range()`, or `RangeValid()` from [`core.go`](https://github.com/banbox/banta/blob/main/core.go) to access values safely.
- `RangeValid()` automatically filters out `NaN` values and returns the corresponding original indices for reference.
- Package-internal code can access `Data` directly when necessary, as demonstrated in [`sta_inds.go`](https://github.com/banbox/banta/blob/main/sta_inds.go).

## Frequently Asked Questions

### Can I access the Data field directly from my application?

No. The `Data` field is unexported (lowercase), meaning only code within the `banta` package can reference it. Your application must use the exported accessor methods like `Get()` and `Range()` to read values safely from outside the package.

### What is the difference between Range() and RangeValid()?

`Range()` returns all values in the specified window including any `NaN` entries, preserving the exact index positions. `RangeValid()` filters out `NaN` values and returns a second slice containing the original indices, which is useful when you need to know where valid data exists within the full series timeline.

### How do I get the most recent value in a Series?

Call `Get(0)` on your Series object. Index `0` always represents the latest (most recent) bar in the series, with higher indices representing progressively older data points ordered from newest to oldest.

### Is there a performance difference between these methods?

`Get()` provides the fastest access for single-value lookups as it performs a direct index calculation on the underlying slice. `Range()` involves creating a new slice copy, while `RangeValid()` incurs additional overhead due to the logic required to filter `NaN` values and construct the index mapping array.