Skip to content

Instantly share code, notes, and snippets.

@marcelometal
Last active January 28, 2023 19:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcelometal/3ad69ac4bd557c140d10c66fbfffe30a to your computer and use it in GitHub Desktop.
Save marcelometal/3ad69ac4bd557c140d10c66fbfffe30a to your computer and use it in GitHub Desktop.
# Copyright (c) 2020, Marcelo Jorge Vieira
# License MIT
## fiis.yaml
## - portfolioSlug: default
## itemType: fiis
## symbol: TGAR11
## brokerSlug: easyinvest
## shares: 35
## price: 138.62
## commission: 0
## date: '2019-10-08T00:00:00Z'
## type: purchase
import asyncio
import yaml
from datetime import datetime
from aiohttp_client_cache import CachedSession, SQLiteBackend
from colorama import Fore
from tabulate import tabulate
# jq '.dividends[] | select ( .declaredDate > "2019-10-08T00:00:00Z" )'
MFINANCE_URL = "https://mfinance.com.br/api/v1"
FII_FILE = "fiis.yaml"
def _print_negative(value):
return f"{Fore.RED}{value}{Fore.RESET}"
def _print_positive(value):
return f"{Fore.GREEN}{value}{Fore.RESET}"
def _print(value):
if value > 0:
return _print_positive(value)
return _print_negative(value)
def _get_order_purchases():
with open(FII_FILE) as fii_file:
purchases = yaml.load(fii_file, Loader=yaml.FullLoader)
data = {}
for purchase in purchases:
symbol = purchase.get("symbol")
if symbol in data:
data[symbol].append(purchase)
else:
data[symbol] = [purchase]
for symbol, purchases in data.items():
data[symbol] = sorted(purchases, key=lambda d: d["date"])
return data
def _process_purchases(data, dividends):
perFII = []
result = {}
all_cost_basis = 0
all_position = 0
all_gain = 0
all_dividends = 0
order_purchases = _get_order_purchases()
for symbol, purchases in order_purchases.items():
# print(f"Processing {symbol}...")
fii_data = data.get(symbol)
fii_dividends = dividends.get(symbol).get("dividends")
cost_basis = 0
position = 0
total_dividends = 0
total_dividends = 0
shares = 0
# months = 0
for purchase in purchases:
cost_basis += purchase.get("price") * purchase.get("shares")
position += fii_data.get("lastPrice") * purchase.get("shares")
shares += purchase.get("shares")
for dividend in fii_dividends:
declaredDate = datetime.strptime(
dividend.get("declaredDate"), "%Y-%m-%dT%H:%M:%SZ"
)
fii_purchase_date = datetime.strptime(
purchase.get("date"), "%Y-%m-%dT%H:%M:%SZ"
)
if declaredDate > fii_purchase_date:
total_dividends += dividend.get("value") * purchase.get(
"shares"
)
# months += 1
gain = position - cost_basis
gain_percentage = (gain * 100) / cost_basis
total_dividends_percentage = (total_dividends * 100) / cost_basis
average_value = cost_basis / shares
perFII.append(
{
"Symbol": symbol,
"Last price": fii_data.get("lastPrice"),
"Dividend Yield %": fii_data.get("dividendYield"),
"Avg value": average_value,
"Shares": shares,
"Cost basis": cost_basis,
"Position": position,
"Gain": _print(gain),
"Gain %": _print(gain_percentage),
"Dividends": total_dividends,
"Dividends %": total_dividends_percentage,
# "months": months,
"Overall return %": _print(
gain_percentage + total_dividends_percentage
),
}
)
all_cost_basis += cost_basis
all_position += position
all_gain += gain
all_dividends += total_dividends
result["Cost basis"] = all_cost_basis
result["Position"] = all_position
result["Gain"] = _print(all_gain)
all_gain_percentage = (all_gain * 100) / all_cost_basis
result["Gain %"] = _print(all_gain_percentage)
result["Dividends"] = all_dividends
all_dividends_percentage = (all_dividends * 100) / all_cost_basis
result["Dividends %"] = all_dividends_percentage
result["Overall return %"] = _print(
all_gain_percentage + all_dividends_percentage
)
tabulate_params = {
"tablefmt": "github",
"headers": "keys",
"numalign": "right",
"floatfmt": "9,.2f",
}
print("\n")
print(
tabulate(sorted(perFII, key=lambda d: d["Symbol"]), **tabulate_params)
)
print("\n")
print(tabulate([result], **tabulate_params))
print("\n\n")
async def get(url, session):
# print(f"Processing {url}...")
try:
async with session.get(url=url, ssl=False) as response:
return await response.json()
except Exception as e:
print(f"Unable to get URL {url} due to {e.__class__}.")
async def main(urls_data, urls_dividends):
print("Running...")
async with CachedSession(cache=SQLiteBackend('mfinance_fii_cache')) as session:
data = await asyncio.gather(*[get(url, session) for url in urls_data])
data = {item["symbol"]: item for item in data}
dividends = await asyncio.gather(
*[get(url, session) for url in urls_dividends]
)
dividends = {item["symbol"]: item for item in dividends}
_process_purchases(data, dividends)
def _get_urls():
urls_data = set()
urls_dividends = set()
with open("fiis.yaml") as fii_file:
purchases = yaml.load(fii_file, Loader=yaml.FullLoader)
for purchase in purchases:
symbol = purchase.get("symbol")
fii_url = f"{MFINANCE_URL}/fiis/{symbol}"
urls_data.add(fii_url)
dividends_url = f"{MFINANCE_URL}/fiis/dividends/{symbol}"
urls_dividends.add(dividends_url)
return urls_data, urls_dividends
if __name__ == "__main__":
data, dividends = _get_urls()
asyncio.run(main(data, dividends))
@marcelometal
Copy link
Author

marcelometal commented May 26, 2021

Output:

python dividends_fiis.py

| Symbol   |   Last price |   Avg value |   Shares |   Cost basis |   Position |       Gain |    Gain % |   Dividends |   Dividends % |   Overall return % |
|----------|--------------|-------------|----------|--------------|------------|------------|-----------|-------------|---------------|--------------------|
| GTWR11   |        72.83 |       84.75 |      300 |    25,425.00 |  21,849.00 |  -3,576.00 |    -14.06 |    2,259.00 |          8.88 |              -5.18 |
| HGLG11   |       161.26 |      153.92 |       65 |    10,004.69 |  10,481.90 |     477.21 |      4.77 |    2,609.10 |         26.08 |              30.85 |



|   Cost basis |   Position |       Gain |    Gain % |   Dividends |   Dividends % |   Overall return % |
|--------------|------------|------------|-----------|-------------|---------------|--------------------|
|   999,999.06 | 292,999.00 | -34,894.39 |    -11.36 |   33,686.04 |         10.96 |              -0.39 |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment