Skip to main content

Tool to keep balance a portfolio of securities while investing.

Project description

foliotrack Logo

foliotrack is a Python package to manage, optimize and rebalance securities, including Exchange-Traded Funds (ETFs). Given a set of securities and their target allocation weights, the packages methods compute the optimal investment adjustments required to align the portfolio with the desired strategy.

Key Features

  • Mathematical Optimization: Uses Mixed-Integer Quadratic Programming (MIQP) to determine the most efficient asset allocation while respecting constraints (e.g., lot sizes, transaction costs).
  • Solver Integration: Leverages CVXPY for convex optimization modeling and PySCIPOpt as the underlying solver.
  • Real-Time Data Fetching:
    • Security prices via yfinance (Yahoo Finance API).
    • Currency conversion via ecbdata (European Central bank data) for multi-currency portfolios.
  • Export Compatibility: Generates output in a format compatible with Wealthfolio for seamless portfolio tracking.
  • Security Contract Comparator tool: Simulate and compare the evolution of multiple securities investment contracts with customizable fees and taxes, and visualize results interactively.

Use Case

Ideal for investors, financial advisors, and algorithmic traders seeking to:

✅ Automated Rebalancing – Maintains target asset allocations with minimal manual intervention, ensuring alignment with investment strategies.

✅ Multi-Currency Support – Dynamically adjusts for exchange rate fluctuations, enabling accurate valuation and rebalancing of global portfolios.

✅ User-Friendly GUI – Accelerates workflow with an intuitive interface, reducing complexity for faster decision-making and execution.

✅ Wealthfolio Integration – Exports optimized allocations in a compatible format for seamless tracking via Wealthfolio.

Project Structure

  • main.py: Example usage and entry point.
  • gradio-app.py: Gradio interface.
  • foliotrack/Currency.py: Defines the Currency class to get currencies informations like symbol and exchange rate.
  • foliotrack/Security.py: Defines the Security class for representing individual securities.
  • foliotrack/Portfolio.py: Defines the Portfolio class.
  • foliotrack/Equilibrate.py: Defines the Equilibrate class which contains the portfolio optimization algorithm.
  • Tools/Contract_security_comparator.py: Interactive command-line tool to compare security investment contracts with fees and capital gains tax.
  • pyproject.toml: Project metadata and dependencies.

Installation

Clone the repository from Github

git clone git@github.com:PhDFlo/foliotrack.git

In the foliotrack folder create the python environment using uv:

uv sync
source .venv/bin/activate

Gradio interface Usage

To facilitate the use of the foliotrack tool a Gradio interface is available by running python gradio-app.py. The app will be running locally and should display something like:

* Running on local URL:  http://127.0.0.1:7860
* To create a public link, set `share=True` in `launch()`.

Open the url in any browser.

Gradio interface image

  • To create your securities portfolio, add in the Inputs directory a .csv based on the investment.csv file.
  • Refresh the list of available files by clicking on the Refresh available files button and select your file.
  • Fill the table by clicking on the Fill Table from CSV button. This step is optionnal as you may want to fill the table directly on the web page.
  • Select the investment amount you want to add to your portfolio and click on the New Investment Amount (€) button. Default is 500€.
  • Choose the minimum amount to be invested, default is 99%. Ex: with an investment of 500€, at least 495€ will be placed in the portfolio.
  • Finally, compute the optimization to get as close as possible to the target share.

Python Example Usage

import logging
from foliotrack.Security import Security
from foliotrack.Portfolio import Portfolio
from foliotrack.Equilibrate import Equilibrate

logging.basicConfig(level=logging.INFO)

def main():
    # Create security instances
    security1 = Security(
        name="Amundi MSCI World UCITS Security",
        ticker="AMDW",
        currency="EUR",
        price_in_security_currency=500.0,
        yearly_charge=0.2,
        target_share=0.5,
        number_held=20.0,
    )
    security2 = Security(
        name="Vanguard S&P 500 UCITS Security",
        ticker="VUSA.AS",
        currency="USD",
        price_in_security_currency=300.0,
        yearly_charge=0.1,
        target_share=0.2,
        number_held=1.0,
    )
    security3 = Security(
        name="iShares Core MSCI Emerging Markets IMI UCITS Security",
        ticker="EIMI.L",
        currency="EUR",
        price_in_security_currency=200.0,
        yearly_charge=0.25,
        target_share=0.3,
        number_held=3.0,
    )

    # Create a Portfolio instance
    portfolio = Portfolio()
    portfolio.add_security(security1)
    portfolio.add_security(security2)
    portfolio.add_security(security3)

    portfolio.to_json("Portfolios/investment_example.json")

    portfolio.update_security_prices()  # Update prices from yfinance
    portfolio.compute_actual_shares()

    # Solve for equilibrium
    Equilibrate.solve_equilibrium(
        portfolio.securities, investment_amount=1000.0, min_percent_to_invest=0.99
    )

    # Log portfolio info
    info = portfolio.get_portfolio_info()
    logging.info("Portfolio info:")
    for security_info in info:
        logging.info(f"Security:")
        for k, v in security_info.items():
            logging.info(f"  {k}: {v}")

if __name__ == "__main__":
    main()

Python Example Output

INFO:root:Security 'Amundi MSCI World UCITS Security' added to portfolio with share 0.5 and number held 20.0.
INFO:root:Security 'NVIDIA Corporation' added to portfolio with share 0.2 and number held 1.0.
INFO:root:Security 'iShares Core MSCI Emerging Markets IMI UCITS Security' added to portfolio with share 0.3 and number held 3.0.
INFO:root:Portfolio shares sum equal to 1. Portfolio is complete.
INFO:root:Portfolio saved to Portfolios/investment_example.json
INFO:root:Portfolio shares sum equal to 1. Portfolio is complete.
INFO:root:Optimisation status: optimal
INFO:root:Number of each Security to buy:
INFO:root:  Amundi MSCI World UCITS Security: 1 units
INFO:root:  NVIDIA Corporation: 1 units
INFO:root:  iShares Core MSCI Emerging Markets IMI UCITS Security: 7 units
INFO:root:Amount to spend and final share of each Security:
INFO:root:  Amundi MSCI World UCITS Security: 45.61€, Final share = 0.5678
INFO:root:  NVIDIA Corporation: 151.75€, Final share = 0.1799
INFO:root:  iShares Core MSCI Emerging Markets IMI UCITS Security: 297.99€, Final share = 0.2523
INFO:root:Total amount to invest: 495.35€
INFO:root:Portfolio info:
INFO:root:Security:
INFO:root:  name: Amundi MSCI World UCITS Security
INFO:root:  ticker: AMDW
INFO:root:  currency: EUR
INFO:root:  symbol: €
INFO:root:  exchange_rate: 1.0
INFO:root:  price_in_security_currency: 45.61
INFO:root:  price_in_portfolio_currency: 45.61
INFO:root:  yearly_charge: 0.2
INFO:root:  number_held: 20.0
INFO:root:  number_to_buy: 1
INFO:root:  amount_to_invest: 45.61
INFO:root:  amount_invested: 912.2
INFO:root:  target_share: 0.5
INFO:root:  actual_share: 0.77
INFO:root:  final_share: 0.5678
INFO:root:Security:
INFO:root:  name: NVIDIA Corporation
INFO:root:  ticker: NVDA
INFO:root:  currency: USD
INFO:root:  symbol: $
INFO:root:  exchange_rate: 0.8533879501621437
INFO:root:  price_in_security_currency: 177.82
INFO:root:  price_in_portfolio_currency: 151.7494452978324
INFO:root:  yearly_charge: 0.1
INFO:root:  number_held: 1.0
INFO:root:  number_to_buy: 1
INFO:root:  amount_to_invest: 151.75
INFO:root:  amount_invested: 151.7494452978324
INFO:root:  target_share: 0.2
INFO:root:  actual_share: 0.13
INFO:root:  final_share: 0.1799
INFO:root:Security:
INFO:root:  name: iShares Core MSCI Emerging Markets IMI UCITS Security
INFO:root:  ticker: EIMI.L
INFO:root:  currency: EUR
INFO:root:  symbol: €
INFO:root:  exchange_rate: 1.0
INFO:root:  price_in_security_currency: 42.57
INFO:root:  price_in_portfolio_currency: 42.57
INFO:root:  yearly_charge: 0.25
INFO:root:  number_held: 3.0
INFO:root:  number_to_buy: 7
INFO:root:  amount_to_invest: 297.99
INFO:root:  amount_invested: 127.71000000000001
INFO:root:  target_share: 0.3
INFO:root:  actual_share: 0.11
INFO:root:  final_share: 0.2523

Tools

Security Contract Comparator Usage

The Contract_security_comparator.py script allows you to simulate and compare the evolution of multiple securities investment contracts, each with its own fees and capital gains tax. You can define any number of contracts directly from the command line. It provides quantitative information to choose the best contract for investing on a particular security.

Example usage:

python Contract_security_comparator.py --initial 20000 --annual-return 0.06 --years 25 --yearly_contribution 1000 \
  --contract "A,0.0059,0.006,0.172" \
  --contract "B,0.0012,0.00,0.30"
  • --contract "Label,Security_fee,Bank_fee,CapitalGainsTax": Add as many contracts as you want, each with its own parameters.
  • All values for fees and taxes are expressed as decimals (e.g., 0.0059 for 0.59%).

The script will print the results for each contract and plot a graph comparing their evolution and final after-tax values.

Requirements

  • Python 3.12+
  • numpy
  • cvxpy
  • pyscipopt
  • gradio
  • pandas
  • matplotlib
  • pyQt6
  • yfinance
  • ecbdata

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

foliotrack-0.0.3.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

foliotrack-0.0.3-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file foliotrack-0.0.3.tar.gz.

File metadata

  • Download URL: foliotrack-0.0.3.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.8.22

File hashes

Hashes for foliotrack-0.0.3.tar.gz
Algorithm Hash digest
SHA256 47c21a477448ddf4a1aa1441729be5fb2ac7ad822bf0e0a2ce2c54c9cbadedd4
MD5 b1085cb6c9f429d44e37525a0f934287
BLAKE2b-256 20365eb0e039f361c2dbdb34ad5de9117e8dfbc3477e80339134bd948173fd30

See more details on using hashes here.

File details

Details for the file foliotrack-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: foliotrack-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.8.22

File hashes

Hashes for foliotrack-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 da2583b51464b6f1809c3c54c744182f22d66f3212d46e1e323162c20c17233c
MD5 9ede16bbb66a87bc8e2fdddf9ea08dc4
BLAKE2b-256 1d05da3c07cba54a3d7892574ccb63a314d4e86e8d49d45e509eaad5cae5e2f6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page