Metadata-Version: 2.4
Name: vates
Version: 0.1.10
Summary: Python actuarial model
Author-email: Shanya Shi <shanyashi2025@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/shanyashi2025/vates
Keywords: actuarial model,asset-liability model,alm
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dotenv
Requires-Dist: numpy
Requires-Dist: pandas
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

### About

`vates` is an open-source Python package for actuarial models.

### Installation

```powershell
pip install vates
```

### Quick Start

#### 1. Projection Model

The `ProjModelEngine` class is the projection model engine.

- step 1: `ProjModelEngine`: initialize a model instance
- step 2: `model.configure_run`: configure a run
- step 3: `def < my_projection >`: define a function to perform projection calculations
- step 4: `model.bind_projection`: bind it to the model
- step 5: `model.run`: run the model

```python
from vates import ProjModelEngine

model = ProjModelEngine(slug='my_model', description='example model')
model.configure_run(start_year=2025, end_year=2026)

@model.bind_projection
def my_projection(m: ProjModelEngine):
    t = m.time
    p = m.period
    if t == 0:
        print(f"Projection started, START_DATE={m.START_DATE}")
    else:
        print(f"time: {t}, period: {p}")
    if t == m.MAX_T:
        print(f"Projection ended, END_DATE={m.END_DATE}")

model.run()
```

Following information will display in the terminal:
```text
Projection started, START_DATE=2025-12
time: 1, period: 2026-01
time: 2, period: 2026-02
...
time: 12, period: 2026-12
Projection ended, END_DATE=2026-12
```

The runlog can be found in `results\my_model.runlog.json` file.


#### 2. Add Variables for Model Output

You can set up instances of `TDimVariable` and/or `ConstVariable`, and the `@` operator tells `model` to output the 
projected results, which can be read by `model.proj_result`.

```python
from vates import ProjModelEngine, ConstVariable, TDimVariable

model = ProjModelEngine(slug='my_model', description='example model')
model.configure_run(start_year=2025, end_year=2026)

const_var = ConstVariable('const_var', owner="owner", group="group") @ model
tdim_var = TDimVariable('tdim_var', owner="owner", group="group",
                        max_t=model.MAX_T, start_date=model.START_DATE) @ model

@model.bind_projection
def my_projection(m: ProjModelEngine):
    t = m.time
    p = m.period
    if t == 0:
        const_var[...] = m.START_YEAR * 100 + m.START_MONTH
    tdim_var[t] = p.year * 100 + p.month + t / 100

model.run()

# 1. read the entire results 
df = model.proj_result()
print(df)

# 2. read value of a specific cell (group + owner + variable + date)
val = model.proj_result(
    group="group",
    owner="owner",
    variable="tdim_var",
    date="202602",
)
print(f"{val:.4f}")  # 202602.0200
```

The projected results are saved on disk as a `.proj.csv` file - `results\my_model.proj.csv`, which can be read by 
the function `proj_result`.

```python
from vates import proj_result

# 1. Get the entire results 
df = proj_result(
    results_directory=r"results",
    slug="my_model",
)
print(df)

# 2. Get value of a specific cell (group + owner + variable + date)
val = proj_result(
    results_directory=r"results",
    slug="my_model",
    group="group",
    owner="owner",
    variable="tdim_var",
    date="202602",
)
print(f"{val:.4f}")  # 202602.0200
```

#### 3. Time Synchronization

If a class needs the model's `time` and/or `period`, you can use `@time_synchronized` to decorate it. The decorator 
wires the class to the model's `time_synchronizer` so the objects are automatically kept in sync.

```python
from vates import ProjModelEngine, time_synchronized

@time_synchronized("m.time_synchronizer")
class MyClass:

    def __init__(self, m, name):
        self.name = name

    def speak(self):
        print(f"{self.name}: my `time` and `period` are up-to-date: {self.time=}, {self.period=}")

model = ProjModelEngine(slug='my_model', description='example model')
model.configure_run(start_year=2025, end_year=2026)

obj = MyClass(model, "my_obj")

@model.bind_projection
def my_projection():
    obj.speak()

model.run()
```

Following will be printed:
```text
my_obj: my `time` and `period` are up-to-date: self.time=0, self.period=Period('2025-12', 'M')
my_obj: my `time` and `period` are up-to-date: self.time=1, self.period=Period('2026-01', 'M')
...
my_obj: my `time` and `period` are up-to-date: self.time=12, self.period=Period('2026-12', 'M')
```

#### 4. Stochastic Model

The `StochExecutor` class is for stochastic model, multiprocessing is supported.

Similarly,
- step 1: `StochExecutor`: initialize a stochastic model instance
- step 2: `model.configure_run`: configure a run
- step 3: `def < my_projection >`: define a function to perform projection calculations (the bound function is executed 
  in worker processes, so it must be top-level/picklable)
- step 4: `model.bind_projection`: bind it to the model
- step 5: `model.run`: run the model

```python
from vates import ProjModelEngine, StochExecutor

def my_projection(m: ProjModelEngine):
    t = m.time
    if t == 0:
        print(f"simulation: {m.SIMULATION}")

def stoch_model():
    model = StochExecutor(slug='my_stoch_model', description='example stochastic model')
    model.configure_run(start_year=2025, end_year=2026, simulations="1-10", max_workers=2)
    model.bind_projection(my_projection)
    model.run()

if __name__ == '__main__':
    stoch_model()
```

Following information will display in the terminal:
```text
simulation: 1
simulation: 2
...
simulation: 10
```

#### 5. ALM Package

The `vates.alm` is the subpackage for asset-liability model.

There are building blocks for model developments:

- assets: `Cash`, `Equity`, `BondFixed`, `EquityOption`
- econs: `YieldCurve`, `CreditBand`, `EquityIndex`
- funds: `Fund`
- liabs: `ExtProjLiab`


### See

GitHub repository: https://github.com/shanyashi2025/vates

Example workspace: https://github.com/shanyashi2025/vates/tree/main/example_ws
