Skip to content

Commit 234f1ba

Browse files
committed
Remove main.py, add takahashi_alexander, add tests
1 parent db92284 commit 234f1ba

6 files changed

Lines changed: 321 additions & 7 deletions

File tree

main.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ authors = [
77
{ name = "fabianhe", email = "39628987+fabianhe@users.noreply.github.com" }
88
]
99
requires-python = ">=3.14"
10-
dependencies = []
10+
dependencies = [
11+
"pandas>=3.0.1",
12+
]
1113

1214
[dependency-groups]
1315
dev = [

src/privates/models.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import Sequence
2+
import pandas as pd
3+
4+
5+
def takahashi_alexander(
6+
cc: float = 1_000_000,
7+
rc: Sequence[float] = [0.29] + [0.3] * 19,
8+
b: float = 1.2,
9+
g: float | Sequence[float] = 0.2,
10+
y: float = 0.0,
11+
nav: float = 0.0,
12+
age: int = 0,
13+
pic: float = 0.0,
14+
) -> pd.DataFrame:
15+
if isinstance(g, Sequence):
16+
assert len(g) == len(rc)
17+
else:
18+
g = [g] * len(rc)
19+
df = pd.DataFrame(index=pd.RangeIndex(1, len(rc) + 1, name="Period"))
20+
df.index += age
21+
df["G"] = g
22+
df["RC"] = rc
23+
df["RD"] = (df.index / (len(rc) + age)) ** b
24+
df["RD"] = df["RD"].apply(lambda cell: max(y, cell))
25+
df["PIC"] = pic
26+
df["NAV"] = nav
27+
for idx, row in df.iterrows():
28+
assert isinstance(idx, int)
29+
df.loc[idx, "Capital Call"] = df.loc[idx, "RC"] * (cc - df.loc[idx, "PIC"])
30+
if idx < (len(rc) + age):
31+
df.loc[idx + 1, "PIC"] = df.loc[idx, "PIC"] + df.loc[idx, "Capital Call"]
32+
df.loc[idx, "Distribution"] = (
33+
(df.loc[idx, "NAV"] if idx == (age + 1) else df.loc[idx - 1, "NAV"])
34+
* (1 + df.loc[idx, "G"])
35+
* row["RD"]
36+
)
37+
df.loc[idx, "NAV"] = (
38+
(df.loc[idx, "NAV"] if idx == (age + 1) else df.loc[idx - 1, "NAV"])
39+
* (1 + df.loc[idx, "G"])
40+
+ df.loc[idx, "Capital Call"]
41+
- df.loc[idx, "Distribution"]
42+
)
43+
return df[["NAV", "Capital Call", "Distribution"]].astype(float)

test/test_models.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
from privates import models
2+
import pandas as pd
3+
import pandas.testing as pdt
4+
import pytest
5+
6+
test_cases = [
7+
(
8+
{
9+
"cc": 1_000_000.00,
10+
"rc": [0.25, 1 / 3, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 0.0],
11+
"b": 2.3,
12+
"g": 0.15,
13+
"y": 0.0,
14+
"nav": 0.0,
15+
"age": 0,
16+
"pic": 0.0,
17+
},
18+
pd.DataFrame(
19+
{
20+
"NAV": [
21+
250_000.00,
22+
532_834.59,
23+
837_492.86,
24+
1_011_150.58,
25+
1_070_074.53,
26+
1_011_949.16,
27+
842_494.34,
28+
595_391.41,
29+
335_308.27,
30+
134_030.04,
31+
29_908.90,
32+
0.00,
33+
],
34+
"Capital Call": [
35+
250_000.00,
36+
250_000.00,
37+
250_000.00,
38+
125_000.00,
39+
62_500.00,
40+
31_250.00,
41+
15_625.00,
42+
7_812.50,
43+
3_906.25,
44+
1_953.13,
45+
1_953.13,
46+
0.00,
47+
],
48+
"Distribution": [
49+
0.00,
50+
4_665.41,
51+
25_266.92,
52+
76_966.20,
53+
155_248.65,
54+
249_886.55,
55+
336_872.19,
56+
381_289.58,
57+
353_298.11,
58+
253_527.59,
59+
126_178.77,
60+
34_395.23,
61+
],
62+
},
63+
index=pd.Index(range(1, 13), name="Period"),
64+
),
65+
),
66+
(
67+
{
68+
"cc": 1_000_000.00,
69+
"rc": [0.25, 1 / 3, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 0.0],
70+
"b": 2.3,
71+
"g": 0.15,
72+
"y": 0.05,
73+
"nav": 0.0,
74+
"age": 0,
75+
"pic": 0.0,
76+
},
77+
pd.DataFrame(
78+
{
79+
"NAV": [
80+
250_000.00,
81+
523_125.00,
82+
821_514.06,
83+
994_243.43,
84+
1_053_227.17,
85+
996_508.93,
86+
829_878.05,
87+
586_592.46,
88+
330_410.66,
89+
132_100.89,
90+
29_506.52,
91+
0.00,
92+
],
93+
"Capital Call": [
94+
250_000.00,
95+
250_000.00,
96+
250_000.00,
97+
125_000.00,
98+
62_500.00,
99+
31_250.00,
100+
15_625.00,
101+
7_812.50,
102+
3_906.25,
103+
1_953.13,
104+
1_953.13,
105+
0.00,
106+
],
107+
"Distribution": [
108+
0.00,
109+
14_375.00,
110+
30_079.69,
111+
75_497.74,
112+
152_652.78,
113+
245_952.31,
114+
331_732.23,
115+
375_579.80,
116+
348_076.92,
117+
249_824.50,
118+
124_362.63,
119+
33_932.50,
120+
],
121+
},
122+
index=pd.Index(range(1, 13), name="Period"),
123+
),
124+
),
125+
(
126+
{
127+
"cc": 1_000_000.00,
128+
"rc": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 0.0],
129+
"b": 2.3,
130+
"g": 0.15,
131+
"y": 0.0,
132+
"nav": 1_011_150.58,
133+
"age": 4,
134+
"pic": 875_000.0,
135+
},
136+
pd.DataFrame(
137+
{
138+
"NAV": [
139+
1_070_074.52,
140+
1_011_949.15,
141+
842_494.34,
142+
595_391.41,
143+
335_308.26,
144+
134_030.04,
145+
29_908.90,
146+
0.00,
147+
],
148+
"Capital Call": [
149+
62_500.00,
150+
31_250.00,
151+
15_625.00,
152+
7_812.50,
153+
3_906.25,
154+
1_953.13,
155+
1_953.13,
156+
0.00,
157+
],
158+
"Distribution": [
159+
155_248.65,
160+
249_886.55,
161+
336_872.19,
162+
381_289.58,
163+
353_298.11,
164+
253_527.59,
165+
126_178.77,
166+
34_395.23,
167+
],
168+
},
169+
index=pd.Index(range(5, 13), name="Period"),
170+
),
171+
),
172+
]
173+
174+
175+
@pytest.mark.parametrize("inputs, expected_df", test_cases)
176+
def test_takahashi_alexander(inputs, expected_df):
177+
output = models.takahashi_alexander(**inputs)
178+
pdt.assert_frame_equal(output.round(2), expected_df, check_exact=False, atol=0.01)
File renamed without changes.

0 commit comments

Comments
 (0)