POptimizer Portfolio Optimization

repository·master·Indexed 41 days ago

https://github.com/wlm1ke/poptimizer

A Python-based tool for automating long-term stock portfolio management of MOEX shares and ETFs. It utilizes Modern Portfolio Theory, Ledoit-Wolf shrinkage, and an ensemble of neural networks evolved via evolutionary algorithms to provide risk-adjusted buy/sell recommendations. Features include Tinkoff account integration, Gmail notifications, a built-in secret keychain, and a web interface built with htmx.

Tokens
7.2K
Snippets
29
Records
38
Agent score
50%

What's inside POptimizer

  1. Technical Stack and Architecture

    master

    The project is built using the following technologies:

    • Frontend: htmx
    • Backend: asyncio Python
      • HTTP Client/Server: aiohttp
      • Data Storage: async PyMongo
      • Validation/Serialization: Pydantic
      • Model Training: PyTorch
      • Statistics & Optimization: SciPy

    Core Methodology:

    • Based on Modern Portfolio Theory (MPT), but uses forecast uncertainty instead of classical mean-variance optimization.
    • Uses Ledoit-Wolf shrinkage for correlation matrix estimation of large asset sets.
    • Uses an ensemble of neural networks formed via an evolutionary algorithm to predict risk and return.
  2. Managing Dividends

    master

    The Dividends section handles dividend data required for accurate modeling:

    • Initial Generation: On the first run, a dividend database is generated for the most liquid securities (suitable for portfolios of 200M+).
    • Manual Entry: If your portfolio is smaller than 200M, you must manually fill in dividend information for other stocks.
    • Updates: The system will send notifications to your configured Gmail account when dividend information needs updating. You can then edit this data in the Dividends section.
  3. How Forecast and Optimization work

    master

    The core intelligence of the system relies on evolutionary algorithms and portfolio theory:

    Forecasting

    Models are automatically formed using an evolutionary algorithm:

    • Models with higher returns and better statistical properties on a test set survive to create new models.
    • Models with lower returns or poor statistical properties are removed.
    • Test Sets: The system uses the most recent trading days as a test set. The number of days used varies based on market conditions.
    • Aggregation: Forecasts for all models are aggregated and displayed in the Forecast tab as annualized values. The system uses portfolio theory to calculate risk and return based on individual position characteristics.

    Optimization

    The Optimization tab provides buy/sell recommendations based on the following logic:

    • Confidence Intervals: Recommendations consider the spread in forecasts. A buy suggestion is only made if the lower bound of the confidence interval for buying is greater than the upper bound of the confidence interval for selling, accounting for transaction costs.
    • No Recommendations: You may see no optimization suggestions if:
      • There are too few forecasts or they diverge significantly (wide confidence intervals).
      • Transaction costs are too high due to high trade frequency.
      • The portfolio is already near-optimal (low-return/high-risk assets are sold, and remaining assets don't differ enough to cover costs).
    • Fallback: If no specific optimization is possible, the system displays a single security with the highest lower bound of its confidence interval as the best option for using available cash.
    • Outdated Status: Forecasts and optimizations are recalculated when enough new models appear or after portfolio changes. If calculations haven't finished after a change, the interface will display outdated.
  4. How Portfolio and Accounts management works

    master

    The application manages securities and accounts through several key mechanisms:

    • Available Securities: On the first run, the portfolio includes all stocks and funds traded on MOEX that have sufficient historical data for model construction. The list of available securities changes based on MOEX listings, minimum history requirements, and liquidity requirements (liquidity requirements scale with portfolio size).
    • Automatic Exclusion: Securities that fail to meet liquidity or history requirements are automatically removed during the daily update if they have no position across all accounts.
    • Transaction Frequency: The system tracks the characteristic frequency of trades at the portfolio level. This is used to build models and account for transaction costs in optimization suggestions. The initial frequency is set to 1 day.
    • Data Views:
      • Portfolio tab: Displays aggregated data from all accounts.
      • Accounts sections: Displays data for individual accounts with options for manual editing.
  5. Update or Revert POptimizer versions

    master

    Use the following commands to manage the application version without modifying the source code:

    • Update to the latest version: Ensure the latest version passes tests (check the GitHub Actions status), stop the running program with Ctrl-C, then run:
      task update_ver
    • Update dividend data: To update dividend data for the most liquid stocks:
      task reset_div
    • Revert to previous version: If an update fails or causes errors:
      task revert_ver
    task update_ver
    task reset_div
    task revert_ver
  6. First run and initial setup

    master

    To start using the application for the first time, follow these steps:

    1. Start MongoDB: Run the following command to register and start the MongoDB service. This only needs to be done once; it ensures MongoDB starts automatically upon system reboot.
      task mongo
    2. Run the application: Start the main program using the task runner.
      task run
    3. Access the UI: Open your browser and navigate to the address specified in your cfg.yaml file, or http://localhost:5000 by default.
    4. Configure Accounts: Create at least one brokerage account in the settings. If you have provided Tinkoff credentials in cfg.yaml, accounts will be created automatically.
    5. Populate Data: Fill in your accounts with current information regarding your existing stocks and cash balances.
    6. Set Exclusions (Optional): You can add specific tickers to an exclusion list in the settings (e.g., stocks unavailable at your broker or those expected to be delisted).
    7. Wait for Data Update: Wait for the first nightly data update (at 1:00 MSK). During this process, the program will automatically remove illiquid securities with short histories and zero positions across all accounts, as well as any tickers you added to the exclusion list.
    8. Follow Optimization: Once data is processed, follow the recommendations in the Optimization section.
    task mongo
    task run
  7. Manage secrets using the keychain

    master

    To avoid storing sensitive tokens (like Gmail passwords or Tinkoff tokens) in plain text in your configuration file, use the built-in keychain system. Secrets are stored in your operating system's secret storage for the poptimizer application.

    Store a secret

    uv run poptimizer keychain save YOUR_SECRET_KEY YOUR_SECRET_VALUE

    Retrieve or delete a secret

    • Get value: uv run poptimizer keychain get YOUR_SECRET_KEY
    • Delete: uv run poptimizer keychain delete YOUR_SECRET_KEY

    Use a secret in the configuration file

    In your cfg/cfg.yaml, use the placeholder syntax keychain:YOUR_SECRET_KEY. The application will automatically replace this placeholder with the actual value from the keychain during loading.

    uv run poptimizer keychain save MY_TOKEN my_actual_secret_value
    # In cfg/cfg.yaml:
    token: keychain:MY_TOKEN
  8. Integrate Tinkoff accounts

    master

    POptimizer can automatically update account positions from Tinkoff.

    1. Create a Read-only token from Tinkoff.
    2. Run the following command to retrieve your account IDs:
      uv run poptimizer tinkoff YOUR_TOKEN
    3. Save the token in the keychain.
    4. In `cfg/cfg.yaml`, add the token using the `keychain:YOUR_TOKEN_KEY` placeholder. You can assign a custom account name (alphanumeric) in the config, which will be used in the web interface. You can map multiple accounts to one token or use different tokens for different accounts.
    
    uv run poptimizer tinkoff YOUR_TOKEN
  9. Install POptimizer on MacOS

    master

    POptimizer is a Python application. Installation is currently documented for MacOS and requires Homebrew and Task.

    1. Clone the repository:
    git clone --filter=blob:none https://github.com/WLM1ke/poptimizer.git && cd poptimizer
    1. Install necessary tools and dependencies using Task:
    task install
    git clone --filter=blob:none https://github.com/WLM1ke/poptimizer.git && cd poptimizer
    task install
  10. Configure Gmail notifications

    master

    POptimizer can send error alerts, key event notifications, portfolio value changes, and optimization recommendations to a Gmail address.

    To set this up:

    1. Create a Google App Password.
    2. Save this password in the POptimizer keychain using the keychain save command.
    3. In cfg/cfg.yaml, add your email address and use the keychain:YOUR_KEY_NAME placeholder for the password.
  11. Configure POptimizer settings

    master

    Application settings are stored in cfg/cfg.yaml.

    • The file is optional; the application will run without it.
    • On the first run, an empty cfg/cfg.yaml is created automatically.
    • You can use cfg/cfg.yaml.template as a guide to populate the configuration file manually.
    • You can selectively fill in only the sections you need.
  12. Configure secrets using the Keychain

    master

    Poptimizer supports storing sensitive information (like passwords or tokens) in the system keychain instead of plain text in configuration files. To use a secret from the keychain, prefix the value in your cfg.yaml file with keychain: followed by the secret key name.

    When the application loads the configuration, it will look up the value in the system keychain using the poptimizer application identifier.

    # Example in cfg.yaml
    gmail:
      email: "user@example.com"
      password: "keychain:GMAIL_PASSWORD"
    
    brokers:
      tinkoff:
        - token: "keychain:TINKOFF_TOKEN"
          name: "MyAccount"
          id: "1234567890"