Skip to content

Instantly share code, notes, and snippets.

@idler921
Created August 28, 2019 10:28
Show Gist options
  • Save idler921/52815eebf37a6f73c8e781e4027816a0 to your computer and use it in GitHub Desktop.
Save idler921/52815eebf37a6f73c8e781e4027816a0 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 28 11:30:01 2019
@author: idler
"""
#import csv
import pandas
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
import datetime
import math
from scipy import optimize
def xnpv(rate,cashflows):
chron_order = sorted(cashflows, key = lambda x: x[0])
t0 = chron_order[0][0] #t0 is the date of the first cash flow
return sum([cf/(1+rate)**((t-t0).days/365.0) for (t,cf) in chron_order])
def xirr(cashflows,guess=0.1):
return optimize.newton(lambda r: xnpv(r,cashflows),guess)
def next_month(date):
try:
nextmonthdate = date.replace(month=date.month+1)
except ValueError:
if date.month == 12:
nextmonthdate = date.replace(year=date.year+1, month=1)
else:
nextmonthdate = date.replace(month=date.month+2,day=1) - datetime.timedelta(days=1)
# next month is too short to have "same date"
# pick your own heuristic, or re-raise the exception:
# raise
return nextmonthdate
code = "1888"
price_csv = f'C:/Users/idler/Downloads/{code}.HK.csv'
dividend_csv = f'C:/Users/idler/Downloads/{code}.HK (1).csv'
price_pd = pandas.read_csv(price_csv)
div = pandas.read_csv(dividend_csv)
start_date = parse("2011-09-01")
mi_amt = 5000
mi_fee = 50
next_buy = start_date
total_amt = 0
total_paid = 0
total_div = 0
last_close = 0
last_date = ""
cashflows = []
for i, row in price_pd.iterrows():
row_date = parse(row["Date"])
last_close = row["Close"]
last_date = row_date
df_div = div[div["Date"] == row["Date"]]["Dividends"]
if len(df_div) == 0:
div_date = 0
else:
div_date = df_div.sum()
if total_amt > 0:
div_given = div_date * total_amt
total_div += div_given
cashflows.append((row_date, -div_given))
print(i, row_date, "DIV ", div_given)
if row_date > next_buy and not math.isnan(row["Open"]):
price = row["Open"]
buy_amt = math.floor((5000-50)/price)
total_amt += buy_amt
paid = buy_amt * price
total_paid += paid
cashflows.append((row_date, paid))
print(i, next_buy, f"Buy {buy_amt} @ " + str(row["Open"]), f"= {round(paid,2)} Total {total_amt}" )
next_buy = next_month(next_buy)
total_value = total_amt * last_close
cashflows.append((last_date,-total_value))
print("\n%s\nStart date %s \nLast date %s" % (code,start_date,last_date))
print("Total value %.2f \nTotal paid %.2f \nTotal Div received %.2f" % (total_value, total_paid, total_div))
print("XIRR %.2f %%" %(round(xirr(cashflows)*100,2)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment