> ## Documentation Index
> Fetch the complete documentation index at: https://takeprofit.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data types in Indie

> Technical guide to Indie's data types including generics, series containers, and context classes. Detailed explanation of type system constraints and usage.

This section is an overview of core data types of the Indie language.

## Basic data types

They are:

* `float` — type of double precision (64-bit) floating point numbers
* `int` — integer numbers
* `bool` — boolean values `True` or `False`
* `str` — string data type

## `indie.Optional[T]` class

In Indie (unlike in Python) it is not allowed to assign `None` value to a variable of any arbitrary type (e.g. basic
data types). But it is allowed to do so with the help of `indie.Optional[T]` class.

`indie.Optional[T]` is similar to Python's `typing.Optional[T]` with a few significant differences:

* `None` can be assigned to values which have `indie.Optional[T]` type only. `None` cannot be assigned to values of some
  `T` type which is not an optional type
* to write some value to an optional variable just simple assignment operator should be used
* to access the `T` value which is stored in `indie.Optional[T]` it is required to explicitly call `value()` or `value_or()` method
* if `value()` method is called on an optional variable which is `None` it raises runtime error
* to test if an optional variable has some value stored inside `is None` and `is not None` constructs should be used
* if variable was declared as `indie.Optional[T]` then `T` cannot be changed for that variable to some other type `U`

For example this will not work in Indie:

```py theme={null}
a = None  # compilation error
# ...
a = 42
```

Indie compiler cannot infer `T` type for `a` in this example. Yes, it may guess that `a` is of `indie.Optional` type,
but it is unclear how to guess that `T` will be an `int` for it.

This will not work too:

```py theme={null}
a: int = None  # compilation error
# ...
a = 42
```

In this case, since `a` is explicitly declared as a non-optional type, `None` cannot be assigned to it.

That is why type of `a` must be declared explicitly as an optional type:

```py theme={null}
a: indie.Optional[int] = None
a = 42
# ...
a = 'foobar'  # compilation error
```

Once variable `a` is declared as optional of `int` value, it cannot at some point start to store `str` values.

By the way if you do not assign any value to an optional variable it will be `None` too:

```py theme={null}
a: indie.Optional[int] = None
b: indie.Optional[int]
```

Both `a ` and `b` in this example are `None`.

To check if optional variable `a` is `None` or not we use:

```py theme={null}
if a is None:
    # ...
if a is not None:
    # ...
```

To access value stored in optional variable `a`, the `value()` method should be explicitly called:

```py theme={null}
if a is not None:
    b = a.value()
```

If an optional variable has no value stored inside then `value()` method call raises a runtime error. For example:

```py theme={null}
s: indie.Optional[str]
t = s.value()  # runtime error, because `s is None == True`
```

But this works fine:

```py theme={null}
s: indie.Optional[str] = 'foobar'
t = s.value()
```

because in this case string `'foobar'` is stored in optional variable `s`.

## Built-in container types

Indie supports typed `list[T]` and `dict[K, V]` containers. Container types can be nested, so a dictionary value may
contain another dictionary, a list, an `Optional`, or a tuple pair.

`dict` keys can be `str`, `int`, `bool`, or finite `float` values. `0.0` and `-0.0` are the same key; `NaN` and
infinite float values are not supported as keys. `keys()` and `values()` return independent snapshot lists: later
changes to the dictionary do not change a snapshot, and items with the same index in both snapshots belong together.

```py theme={null}
prices: dict[str, Optional[dict[str, list[tuple[int, float]]]]] = {
    'active': {'levels': [(1, 101.5), (2, 102.0)]},
    'previous': None,
}

if prices['active'] is not None:
    levels = prices['active'].value()['levels']
    first_level = levels[0]
    level_number = first_level[0]
    level_price = first_level[1]

keys = prices.keys()
values = prices.values()
```

For values that are saved in indicator state (including dictionary/list values and dataclass fields), only a pair
`tuple[A, B]` is supported. Tuples with three or more items remain valid for temporary multi-return values and
unpacking, but cannot be stored in a serializable container or dataclass field. `set`, `queue`, and `deque` are not
supported containers.

## Series data types

* `indie.Series[T]` and an alias `indie.SeriesF` for `indie.Series[float]`
* `indie.MutSeries[T]` and an alias `indie.MutSeriesF` for `indie.MutSeries[float]`

`Series[T]` is a read-only container which stores series of `T` values. `MutSeries[T]` extends `Series[T]` with only
`__setitem__` method, which allows writing to the last element of the container (which syntactically looks like
`some_mut_series[0] = some_value`).

Type `T` can be (almost) any type in Indie, not just `float`, but also `int`, `bool`, `str`, etc.

## Context data types

There are three context classes:

* `indie.Context` is a base class that represents a context of a chart instrument
* `indie.MainContext` is a class that represents main context, extends `indie.Context`
* `indie.SecContext` is a class that represents secondary context, extends `indie.Context`

## Algorithm base class

There is a `indie.Algorithm` base class. All algorithms from `indie.algorithms` package are inherited from it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.