-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
69 lines (54 loc) · 2.16 KB
/
main.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
import pandas
import datetime
import math
from scipy.optimize import fsolve
import yaml
CONSIDER_COMMISSIONS = True
def main():
with open("conf.yaml", 'r') as stream:
try:
conf = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
df = pandas.read_csv('transactions.csv', sep=';', header=0, decimal=',',
converters={'amount':convertToFloat, 'quote':convertToFloat, 'commission':convertToFloat, 'date':convertToDate},
names=['date', 'account', 'transactionType', 'description', 'qty', 'quote', 'amount', 'commission', 'curr', 'isin'])
print('******** IRR of positions ********\n')
for pos in conf.get('positions'):
print_position(pos, df)
print('\n************************')
def print_position(pos, df):
ts = df[(df.description.str.match(pos.get('regex'))) & (df.amount.notna())]
irr = calc_irr(ts, pos.get('quantity') * pos.get('price', 0), irr_to_date(pos, ts))
print(pos.get('name') + ':', str(round(100 * irr, 2)) + '%', special_greeting(irr))
def irr_to_date(pos, ts):
if pos.get('quantity') == 0:
return ts['date'].max()
else:
return datetime.date.today()
def special_greeting(irr):
if irr > 0.20:
return " ---- Great job Mr. Buffett"
if irr < -0.4:
return " ---- Ouch... that's gonna hurt your overall portfolio performance"
return ""
def calc_irr(transactions, market_price, to_date):
def target(r):
return present_value(r, transactions, to_date) - market_price
return fsolve(target, 0)[0]
def present_value(r, transactions, to_date):
pv = 0
for i, t in transactions.iterrows():
pv += t.amount * capitalization_factor(r, t.date, to_date)
if CONSIDER_COMMISSIONS & (not math.isnan(t.commission)):
pv += -t.commission * capitalization_factor(r, t.date, to_date)
return -pv
def capitalization_factor(r, t0, t1):
dt = (t1 - t0).days / 360
return math.exp(dt*r)
def convertToFloat(s):
return float(s.replace(',','.')) if s != '-' else float('nan')
def convertToDate(s):
return datetime.date.fromisoformat(s)
if __name__ == "__main__":
main()