-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathportfolio.py
72 lines (59 loc) · 2.34 KB
/
portfolio.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from helpers import isclose
from assets import Assets
class Portfolio:
def __init__(self, allocation, value=1.0):
if type(allocation) is LinearRamp:
if not isclose(sum(allocation.start), 1.0):
raise RuntimeError("Start allocations need to add up to 1.0")
if not isclose(sum(allocation.end), 1.0):
raise RuntimeError("End allocations need to add up to 1.0")
self.allocation = allocation.start
self.ramp = allocation
else:
if not isclose(sum(allocation), 1.0):
raise RuntimeError("Allocations need to add up to 1.0")
self.allocation = allocation
self.ramp = None
self.value = value
def copy(self):
return Portfolio(self.ramp.copy() if self.ramp else self.allocation, self.value)
def withdraw(self, amt):
if amt < self.value:
self.value -= amt
return amt
else:
ret = self.value
self.value = 0.0
return ret
def grow(self, growBy):
self.value = sum(self.value * self.allocation * growBy)
if self.ramp:
self.allocation = self.ramp.__next__()
# actually, a geometric and exponential ramp sounds super interesting.
class LinearRamp():
def __init__(self, start, end, expectedIterations):
self.start = start
self.end = end
self.expectedIterations = expectedIterations
self.count = 0
def copy(self):
return LinearRamp(self.start, self.end, self.expectedIterations)
def __iter__(self):
return self
def __next__(self):
newAssets = self.interpolate()
if not isclose(sum(newAssets), 1.0):
raise RuntimeError("Allocations need to add up to 1.0")
self.count += 1
if self.count > self.expectedIterations:
raise StopIteration
return newAssets
def interpolate(self):
""" This is confusing enough just needing to know algebra...
You also need to realize that start, end, and the return value are all Assets classes
that represent collections of stocks, bonds, etc. Good luck.
"""
m = (-1.0 * (self.start - self.end))
b = self.start
x = self.count / (self.expectedIterations - 1)
return m * x + b