Files
docker-finance/README.md

947 lines
44 KiB
Markdown

[//]: # (docker-finance | modern accounting for the power-user)
[//]: # ()
[//]: # (Copyright [C] 2021-2024 Aaron Fiore [Founder, Evergreen Crypto LLC])
[//]: # ()
[//]: # (This program is free software: you can redistribute it and/or modify)
[//]: # (it under the terms of the GNU General Public License as published by)
[//]: # (the Free Software Foundation, either version 3 of the License, or)
[//]: # ([at your option] any later version.)
[//]: # ()
[//]: # (This program is distributed in the hope that it will be useful,)
[//]: # (but WITHOUT ANY WARRANTY; without even the implied warranty of)
[//]: # (MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the)
[//]: # (GNU General Public License for more details.)
[//]: # ()
[//]: # (You should have received a copy of the GNU General Public License)
[//]: # (along with this program. If not, see <https://www.gnu.org/licenses/>.)
# [<img src=".img/branding/evergreencrypto.png" width="25px" height="25px" />](https://evergreencrypto.co "docker-finance") *docker-finance*
**Modern accounting for the power-user** | *Crypto, banking, tax prep, meta analysis & more!*
> Looking for a Quickstart? Skip to [Installation](#installation).
1. **[What does it do?](#what-does-it-do)**
- [Overview](#overview)
- [Highlights](#highlights)
- [Screenshots](#screenshots)
2. **[What is supported?](#what-is-supported)**
- [CeFi (centralized custodians)](#cefi)
- [DeFi (decentralized ecosystems)](#defi)
- [TradFi (traditional institutions)](#trad-fi)
- [Prices (market price data)](#prices)
3. **[How do I get started?](#how-do-i-get-started)**
- [Installation](#installation)
- [Environment Generation](#environment-generation)
- [Configuration Files](#configuration-files)
4. **[How do I use it?](#how-do-i-use-it)**
- [Mostly-Unified CLI](#mostly-unified-cli)
- [Flow Layout](#flow-layout)
- [Caveats & Oddities](#caveats--oddities)
5. **[How do I contribute?](#how-do-i-contribute)**
- [Donate](#donate)
- [Development](#development)
6. **[How do I connect?](#how-do-i-connect)**
- [`#docker-finance:matrix.org`](#docker-financematrixorg)
- [Evergreen Crypto LLC](#evergreen-crypto-llc)
7. **[Where is the legalese?](#where-is-the-legalese)**
- [License and Disclaimer](#license-and-disclaimer)
## What does it do?
### Overview
`docker-finance` gives you the power of a privacy-focused, highly uniform system of financial management - but with a modern twist.
Cryptocurrencies & blockchain metadata are unified with legacy finance to create a world of best-practice accounting in a highly flexible, time-tested environment.
### Highlights
- [Highly granular plaintext accounting](#ledger-command)
- [Blockchain explorers](#defi)
- [Cryptocurrency wallets](#wallets)
- [Cryptocurrency exchanges](#cefi)
- [Traditional financial institutions](#tradfi)
- [Visualize your metadata with a high-powered physics framework](#meta-w-root-c-analysis)
- Privacy-aware instance generates (and stores) your visualizations locally
- [Interactive C++ interpreter](#root-cli-w-c-api) allows complex analysis with efficiency
- [Report generation](#reports) & [tax preparation](#taxes)
- Cryptocurrency income from interest and staking
- Cryptocurrency spending and network fees
- Capital gains/losses across all accounts
- Income statements, balance sheets and more
- [Automated data procurement & aggregation into meaningful journal entries](#fetch)
- Use network APIs for CSV data or drop-in your institutions' CSVs
- Import all CSV data with a single command to create a unified journal
- Enjoy using your client's (host's) `crontab` for the [container's suite of commands](#help-suite-of-commands)
- [Unique & customizable environments for your individual needs](#image-docker-finance)
- Versatile: create unlimited profiles for any number of groups and users
- Flexible: while automation is useful, so is the manual entry framework
- Private: all of your accounts are under your control; not a 3rd party
- Secure: all financial activity is managed within a Docker container
- [Developer-friendly environment that keeps you in the zone](#image-dev-tools)
- See the [Development](#development) section for details
### Screenshots
#### Client (Host)
The *docker* in `docker-finance`.
##### *image: docker-finance*
[<img src=".img/examples/client_00.png" width="239px" height="239px" />](.img/examples/client_00.png "") [<img src=".img/examples/client_01.png" width="239px" height="239px" />](.img/examples/client_01.png "") [<img src=".img/examples/client_02.png" width="239px" height="239px" />](.img/examples/client_02.png "") [<img src=".img/examples/client_03.png" width="239px" height="239px" />](.img/examples/client_03.png "") [<img src=".img/examples/client_04.png" width="239px" height="239px" />](.img/examples/client_04.png "")
##### *image: dev-tools*
[<img src=".img/examples/client_dev-tools_00.png" width="239px" height="239px" />](.img/examples/client_dev-tools_00.png "") [<img src=".img/examples/client_dev-tools_01.png" width="239px" height="239px" />](.img/examples/client_dev-tools_01.png "") [<img src=".img/examples/client_dev-tools_02.png" width="239px" height="239px" />](.img/examples/client_dev-tools_02.png "") [<img src=".img/examples/client_dev-tools_03.png" width="239px" height="239px" />](.img/examples/client_dev-tools_03.png "") [<img src=".img/examples/client_dev-tools_04.png" width="239px" height="239px" />](.img/examples/client_dev-tools_04.png "")
[<img src=".img/examples/client_dev-tools_05.png" width="239px" height="239px" />](.img/examples/client_dev-tools_05.png "") [<img src=".img/examples/client_dev-tools_06.png" width="239px" height="239px" />](.img/examples/client_dev-tools_06.png "") [<img src=".img/examples/client_dev-tools_07.png" width="239px" height="239px" />](.img/examples/client_dev-tools_07.png "") [<img src=".img/examples/client_dev-tools_08.png" width="239px" height="239px" />](.img/examples/client_dev-tools_08.png "") [<img src=".img/examples/client_dev-tools_09.png" width="239px" height="239px" />](.img/examples/client_dev-tools_09.png "")
#### Container
The *finance* in `docker-finance`.
##### *Fetch*
[<img src=".img/examples/fetch_00.png" width="239px" height="239px" />](.img/examples/fetch_00.png "") [<img src=".img/examples/fetch_01.png" width="239px" height="239px" />](.img/examples/fetch_01.png "") [<img src=".img/examples/fetch_02.png" width="239px" height="239px" />](.img/examples/fetch_02.png "") [<img src=".img/examples/fetch_03.png" width="239px" height="239px" />](.img/examples/fetch_03.png "") [<img src=".img/examples/fetch_04.png" width="239px" height="239px" />](.img/examples/fetch_04.png "")
##### *Ledger (command)*
[<img src=".img/examples/ledger_00.png" width="239px" height="239px" />](.img/examples/ledger_00.png "") [<img src=".img/examples/ledger_01.png" width="239px" height="239px" />](.img/examples/ledger_01.png "") [<img src=".img/examples/ledger_02.png" width="239px" height="239px" />](.img/examples/ledger_02.png "") [<img src=".img/examples/ledger_03.png" width="239px" height="239px" />](.img/examples/ledger_03.png "") [<img src=".img/examples/ledger_04.png" width="239px" height="239px" />](.img/examples/ledger_04.png "")
##### *Meta (w/ ROOT C++ analysis)*
[<img src=".img/examples/meta_00.png" width="239px" height="239px" />](.img/examples/meta_00.png "") [<img src=".img/examples/meta_01.png" width="239px" height="239px" />](.img/examples/meta_01.png "") [<img src=".img/examples/meta_02.png" width="239px" height="239px" />](.img/examples/meta_02.png "") [<img src=".img/examples/meta_03.png" width="239px" height="239px" />](.img/examples/meta_03.png "") [<img src=".img/examples/meta_04.png" width="239px" height="239px" />](.img/examples/meta_04.png "")
##### *ROOT (CLI w/ C++ API)*
[<img src=".img/examples/root_00.png" width="239px" height="239px" />](.img/examples/root_00.png "") [<img src=".img/examples/root_01.png" width="239px" height="239px" />](.img/examples/root_01.png "") [<img src=".img/examples/root_02.png" width="239px" height="239px" />](.img/examples/root_02.png "") [<img src=".img/examples/root_03.png" width="239px" height="239px" />](.img/examples/root_03.png "") [<img src=".img/examples/root_04.png" width="239px" height="239px" />](.img/examples/root_04.png "")
##### *Taxes*
[<img src=".img/examples/taxes_00.png" width="239px" height="239px" />](.img/examples/taxes_00.png "") [<img src=".img/examples/taxes_01.png" width="239px" height="239px" />](.img/examples/taxes_01.png "") [<img src=".img/examples/taxes_02.png" width="239px" height="239px" />](.img/examples/taxes_02.png "") [<img src=".img/examples/taxes_03.png" width="239px" height="239px" />](.img/examples/taxes_03.png "") [<img src=".img/examples/taxes_04.png" width="239px" height="239px" />](.img/examples/taxes_04.png "")
##### *Reports*
[<img src=".img/examples/reports_00.png" width="239px" height="239px" />](.img/examples/reports_00.png "") [<img src=".img/examples/reports_01.png" width="239px" height="239px" />](.img/examples/reports_01.png "") [<img src=".img/examples/reports_02.png" width="239px" height="239px" />](.img/examples/reports_02.png "") [<img src=".img/examples/reports_03.png" width="239px" height="239px" />](.img/examples/reports_03.png "") [<img src=".img/examples/reports_04.png" width="239px" height="239px" />](.img/examples/reports_04.png "")
##### *Help (suite of commands)*
[<img src=".img/examples/container_help_00.png" width="239px" height="239px" />](.img/examples/container_help_00.png "") [<img src=".img/examples/container_help_01.png" width="239px" height="239px" />](.img/examples/container_help_01.png "") [<img src=".img/examples/container_help_02.png" width="239px" height="239px" />](.img/examples/container_help_02.png "") [<img src=".img/examples/container_help_03.png" width="239px" height="239px" />](.img/examples/container_help_03.png "") [<img src=".img/examples/container_help_04.png" width="239px" height="239px" />](.img/examples/container_help_04.png "")
[<img src=".img/examples/container_help_05.png" width="239px" height="239px" />](.img/examples/container_help_05.png "") [<img src=".img/examples/container_help_06.png" width="239px" height="239px" />](.img/examples/container_help_06.png "") [<img src=".img/examples/container_help_07.png" width="239px" height="239px" />](.img/examples/container_help_07.png "") [<img src=".img/examples/container_help_08.png" width="239px" height="239px" />](.img/examples/container_help_08.png "") [<img src=".img/examples/container_help_09.png" width="239px" height="239px" />](.img/examples/container_help_09.png "")
## What is supported?
Plaintext accounting gives you the power to manage any number of assets or accounts.
However, for accounts that require fetch/import functionality, only the following are supported:
### CeFi
#### Regularly maintained
- [X] [Coinbase](https://coinbase.com/)
- [X] [Gemini](https://gemini.com/)
- [X] [PayPal](https://paypal.com/)
- [X] [Crypto](https://www.paypal.com/us/digital-wallet/manage-money/crypto/)
- [X] [Fiat](https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/)
#### Available but requires community maintenance
- [X] [Bittrex](https://bittrex.com/) *(non-US)*
- [X] [Changelly](https://changelly.com/)
- [X] [Coinbase Pro](https://pro.coinbase.com/) *("Sunsetted")*
- [X] [Kraken](https://kraken.com/) *(non-WA)*
- [X] [Lofty.ai](https://lofty.ai/)
- [X] [Nexo](https://nexo.com/) *(non-US)*
#### Available but no longer maintained
- [X] BlockFi *(bankrupt)*
- [X] Celsius Network *(bankrupt)*
### DeFi
#### Blockchain explorers / Ecosystems
Supported blockchains (independent of wallet type):
- [X] [Algorand](https://algorand.com/) *(powered by [AlgoNode.io](https://algonode.io/))*
- [ ] Cardano
- [X] Ethereum-based
- [ ] Arbitrum
- [X] [Ethereum](https://ethereum.org/) *(powered by [Etherscan.io APIs](https://etherscan.io/))*
- [X] [1inch](https://1inch.io/)
- [X] [Aave](https://aave.com/)
- [X] [AirSwap](https://about.airswap.io/)
- [X] [Compound](https://compound.finance/)
- [ ] Lido
- [X] [Rocket Pool](https://rocketpool.net/)
- [X] [Uniswap](https://uniswap.org/)
- [ ] Optimism
- [X] [Polygon](https://polygon.technology/) *(powered by [PolygonScan APIs](https://polygonscan.com/))*
- [X] [Tezos](https://tezos.com/) *(powered by [TzKT API](https://tzkt.io/))*
#### Self-hosting
- [X] [BTCPayServer](https://btcpayserver.org/)
#### Wallets
##### *Software*
- [X] [Coinbase Commerce (self-managed)](https://www.coinbase.com/commerce/)
- [X] [Coinbase Wallet](https://www.coinbase.com/wallet/)
- [X] [Coinomi](https://www.coinomi.com/)
- [X] [Electrum](https://electrum.org/)
- [X] [Metamask](https://metamask.io/)
- [X] [Pera Algo Wallet](https://perawallet.app/)
##### *Hardware*
- [X] [Ledger](https://www.ledger.com/)
- [X] [Trezor](https://trezor.io/)
##### *Web*
- [X] [AdaLite](https://adalite.io)
### TradFi
#### Regularly maintained
- [X] [Ally](https://www.ally.com/)
- [X] [Bank](https://www.ally.com/bank/)
- [X] [Capital One](https://www.capitalone.com/)
- [X] [Bank](https://www.capitalone.com/bank/online-banking/)
- [X] [Credit](https://www.capitalone.com/credit-cards/)
- [X] [Chase](https://www.chase.com/)
- [X] [Bank](https://personal.chase.com/personal/checking/)
- [X] [Credit](https://creditcards.chase.com/)
- [X] [Discover](https://www.discover.com/)
- [X] [Bank](https://www.discover.com/online-banking/)
- [X] [Credit](https://www.discover.com/credit-cards/)
- [X] [PayPal Business](https://business.paypal.com/)
- [X] [Fiat](https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/)
#### Requires community maintenance
- [X] [ETrade](https://www.etrade.com/)
- [X] [Brokerage](https://us.etrade.com/what-we-offer/our-accounts/brokerage-account)
### Prices
- [X] [Cryptocurrency](https://www.coingecko.com/)
- [X] [CoinGecko](https://www.coingecko.com/en/api)
- [X] [Mobula](https://docs.mobula.io/introduction)
- [ ] Traditional markets
## How do I get started?
### Installation
[//]: # (TODO: move step 3 to installation script, add `dfi` aliases, update README)
`docker-finance` is not your typical Docker image in which you simply pull and containerize, but rather it's an *image-based* accounting system that operates transparently between your client (host) and container; keeping your finances containerized, with all the benefits of containerization.
`docker-finance` *should* work out-of-the-box on any modern Linux system. For example, if your client (host) is Ubuntu, the default installation of `coreutils`, `shells` and `utils` that came with your system will satisfy requirements. However, you'll still need to manually install Docker (see below).
1. **Install dependencies**:
1. [Docker Engine](https://docs.docker.com/engine/install/#supported-platforms) with [post-install configuration](https://docs.docker.com/engine/install/linux-postinstall/)
- Latest version (or at least `27.1.1`)
2. [GNU Bash](https://www.gnu.org/software/bash/)
- Latest version (or at least `5.0.17`)
- Installed by *default* on most Linux distributions
2. **Install recommended**:
1. [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git/)
- Latest version (or at least `2.25.1`)
- Only needed for step 3 but should be kept in order to:
- Remain up-to-date with future `docker-finance` versions
- Safely track your workflow related data (journals, metadata, etc.)
2. Consider using a terminal multiplexer like [tmux](https://github.com/tmux/tmux/wiki) or [screen](https://www.gnu.org/software/screen/) for optimal workflow efficiency
3. **Copy/paste the following into your `bash` shell** (client preparation):
```bash
bashrc=~/.bashrc
aliases=~/.bash_aliases
function docker-finance::install()
{
# Environment expectations
_alias="alias docker-finance="
_client="$(pwd)/docker-finance/client"
# Remove previous alias
if grep "^${_alias}" "$aliases" &>/dev/null; then
sed -i "/^${_alias}/d" "$aliases"
unalias docker-finance
fi
# Set new alias
echo "${_alias}'${_client}/docker.bash'" >>"$aliases"
# Set bash completion
_completion="${_client}/src/docker/completion.bash"
if [ ! -f "$_completion" ]; then
echo "WARNING: bash completion not found" >&2
else
if ! grep "^source '${_completion}'" "$aliases" &>/dev/null; then
echo "source '${_completion}'" >>"$aliases"
fi
fi
# Make it so
source "$aliases" && echo "SUCCESS: installation complete"
}
if ! test -f "$bashrc" || ! hash bash &>/dev/null; then
echo "FATAL: unsupported bash installation" >&2
else
if [[ ! -z "$SHELL" && "$SHELL" =~ bash ]]; then
if [ ! -f "$aliases" ]; then
if ! grep -E "(\. ~/.bash_aliases|^source ~/.bash_aliases|^source ${aliases})" "$bashrc" &>/dev/null; then
aliases="$bashrc"
fi
fi
if hash git &>/dev/null; then
if [ -d docker-finance ]; then
if pushd docker-finance &>/dev/null; then
if ! git pull --tags; then
echo "FATAL: docker-finance repo not pulled" >&2
else
popd &>/dev/null
docker-finance::install
fi
popd &>/dev/null
else
echo "FATAL: docker-finance repo not found" >&2
fi
else
if ! git clone https://gitea.com/EvergreenCrypto/docker-finance; then
echo "FATAL: docker-finance repo not cloned" >&2
else
docker-finance::install
fi
fi
else
echo "FATAL: git not found" >&2
fi
else
echo "FATAL: unsupported bash environment" >&2
fi
fi
```
4. **Verify your repository** (recommended):
```bash
if pushd docker-finance/ 1>/dev/null; then
gpg --keyserver hkp://keyserver.ubuntu.com --recv-key 518A22F85BEFD32BCC99C48603F90C4F35E0213E \
&& git verify-commit $(git log -n1 --pretty=format:"%H") \
&& echo -e "\nSUCCESS: now confirm matching key = 518A22F85BEFD32BCC99C48603F90C4F35E0213E" \
|| echo -e "\nFATAL: no key available or possible MITM - do not use!"
popd 1>/dev/null
fi
```
5. **Generate client/container environment** (see [Environment Generation](#environment-generation) for details):
```bash
docker-finance archlinux/${USER}:default gen
```
6. **Build the image**:
```bash
docker-finance archlinux/${USER}:default build type=default
```
> See `docker-finance archlinux/${USER}:default build help` for build options (such as smaller, faster builds)
7. **Bring up the container**:
```bash
docker-finance archlinux/${USER}:default up
```
> You can use tab completion for all commands available to this built image
8. **You're inside!** See [How do I use it?](#how-do-i-use-it) for next steps.
### Environment Generation
`docker-finance`'s environment consists of two scopes: `client` and `container`. The client (host) view is confined to the host while the container view confined to the container (though the client *can*, at times, view from *within* the container's perspective).
In terms of configuration, the client (host) has the following files:
1. The [Client (Host) Configuration File](#client-host-configuration) (client only)
2. The [Client (Host) Custom Dockerfile](#client-host-custom-dockerfile) (client only)
3. The [Client/Container Superscript](#clientcontainer-superscript) (client/container)
You'll create these files (and more) when running client (host) command `gen`, as seen below.
> Tip: client scope can be considered an OOP class which inherits the container as a protected class, with the [Client/Container Superscript](#clientcontainer-superscript) binding them.
---
#### Client Generation
When running `gen`, you'll see the following:
> *Client-side environment found, backup then generate new one?*
Generates the client (host) configuration file (see the [Client (Host) Configuration File](#client-host-configuration) for details).
- You can use the generated defaults but make sure your directory layout matches accordingly
- To easily edit this configuration file after `gen` is complete, run client (host) command `edit type=env`
> *Generating new custom (optional) Dockerfile*
Generates custom Dockerfile. Do as you wish; install your own container packages, etc. (see the [Client (Host) Custom Dockerfile](#client-host-custom-dockerfile) for details).
- To easily edit this configuration file after `gen` is complete, run client (host) command `edit type=build`
---
#### Container Generation
After the previous client environment is generated, the following will prepare the container environment (everything you'll need while inside `docker-finance`).
> *Generate (or update) container profile configs and/or accounts?*
Although the container environment is a minimum requirement, here you'll have the option to continue generating or to backup a previous install.
> *Will this profile be used for development and/or demonstration?*
If you're a developer or wish to see the mockup test profile, select 'y' here.
> *Enter profile name (e.g., family in 'family/alice')*
> *Enter subprofile name (e.g., alice in 'family/alice')*
Container generation will always be for a specific `profile` with `subprofile`, and here is where you input that information. For example, you could have a `family` profile with subprofiles of various family members or a `business` profile with subprofiles of all the various businesses you own.
It should be noted that:
- all subsequent questions and container generation will relate to this `profile/subprofile` pairing
- all output will be sent to the `${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/profile/subprofile` path
> *Generate (or update) joint client/container shell script (superscript)? [Y/n]*
Select 'y' if this a first-run. If this is not a first-run but you need to regenerate the file, then select 'y' (see [Superscript](#clientcontainer-superscript) for details).
> *Generate (or update) container hledger-flow configs and/or accounts?*
Not limited to `hledger-flow` data, this option leads to generating *all* `docker-finance` journal data (and configurations).
> *Generate (or update) subprofile's shell script?*
The container's subprofile's shell script is where all subprofile commands and aliases exist.
This file is generated on a per-subprofile basis and all custom code *on a per-subprofile basis* should go here (see [Subprofile](#subprofile) for details).
> *Generate (or update) subprofile's fetch configuration?*
The container's fetch configuration is what all remote fetching relies on: prices, exchanges, blockchain explorers; all are configured here (see [Fetch](#fetch-1) for details).
> *Generate (or update) subprofile's financial metadata?*
The container's *per-subprofile* metadata file.
This file contains all your custom metadata and can edited with the `edit` and analyzed with the `meta` or `root` command (see [Meta](#meta) for details).
> *Generate (or update) subprofile's hledger-flow accounts?*
The container's `hledger-flow` accounts to be installed. These are the accounts described in [What is supported?](#what-is-supported).
> *Generate individual subprofile accounts instead of generating them all at once?*
If you intend to only use a few accounts, you can do so here. Otherwise, generate all accounts (recommended).
**WARNING**: if you plan to use blockchain-based wallets (coinbase-wallet, pera-wallet, ledger, metamask, etc.), you **MUST** generate their respective chains, as seen during generation (`algorand`, `ethereum-based`, `tezos`, etc).
### Configuration Files
#### Client (Host) Configuration
The client (host) configuration file:
- is located in the `${DOCKER_FINANCE_CLIENT_CONF}/client/env/` directory, with subdirectory format of `kernel-machine/platform/tag`
- format consists of `username@hostname` where `username` is your host username and `hostname` is your machine's hostname
- client/container configurations can be stored on shared NFS/CIFS or related network storage (with applicable user permissions)
- allows for customizable locations of *all* container data on any mountable filesystem (as a replacement for Docker Volumes)
- consists solely of variables in the format `DOCKER_FINANCE_VARIABLE=value` and is used by both Docker and `docker-finance`
- default template variables can be found in [gen.bash](client/docker-finance.d/client/env/gen.bash), as described below
After `gen` is complete, you can edit this file with the client (host) command: `edit type=env` (see [Client (Host) Command Format](#client-host-command-format)).
> DOCKER_FINANCE_CLIENT_CONF
Client (host) configuration path. Parent directory for client configuration files.
- Example: `DOCKER_FINANCE_CLIENT_CONF=/home/${USER}/.config/docker-finance.d`
> DOCKER_FINANCE_CLIENT_FLOW
Client (host) hledger-flow path. Parent directory for all profiles.
- Example: `DOCKER_FINANCE_CLIENT_FLOW=/net/nfs4/hledger-flow`
> DOCKER_FINANCE_CLIENT_REPO
Client (host) path for the `docker-finance` code repository (from the host's perspective).
This parent directory is where the `client` and `container` directories are located.
- Example: `DOCKER_FINANCE_CLIENT_REPO=/net/nfs4/git/docker-finance`
> DOCKER_FINANCE_CLIENT_SHARED
Client (host) path for the client/container shared directory.
The bind-mount is used exclusively for non-essential file sharing (custom scripts or any file you wish).
- Example: `DOCKER_FINANCE_CLIENT_SHARED=/mnt/share.d`
> DOCKER_FINANCE_CONTAINER_CMD
The container's `finance` command (useful for experimental implementations).
Default: `finance.bash` (internally aliased to `finance`)
- Example: `DOCKER_FINANCE_CONTAINER_CMD=finance.bash`
> DOCKER_FINANCE_CONTAINER_CONF
The container's configuration path (bind-mounted to client's (host's) configuration path).
- Example: `DOCKER_FINANCE_CONTAINER_CONF=/home/${USER}/.config/docker-finance.d`
> DOCKER_FINANCE_CONTAINER_EDITOR
The container's default text editor.
- Example: `DOCKER_FINANCE_CONTAINER_EDITOR=vim`
> DOCKER_FINANCE_CONTAINER_FLOW
The container's hledger-flow path from the container's perspective.
This path is bind-mounted to the client's (host's) hledger-flow path.
- Example: `DOCKER_FINANCE_CONTAINER_FLOW=/home/${USER}/hledger-flow`
> DOCKER_FINANCE_CONTAINER_REPO
The container's `docker-finance` code repository path (as viewed from the container).
This path is bind-mounted to the client's (host's) `docker-finance/container` path.
- Example: `DOCKER_FINANCE_CONTAINER_REPO=/home/${USER}/docker-finance`
> DOCKER_FINANCE_CONTAINER_SHARED
The container's `share.d` path, bind-mounted to client's (host's) `share.d` path.
- Example: `DOCKER_FINANCE_CONTAINER_FLOW=/home/${USER}/share.d`
> DOCKER_FINANCE_CPUS
Docker daemon/container setting: number of CPUs to use.
- Example: `DOCKER_FINANCE_CPUS=2`
> DOCKER_FINANCE_DEBUG
Enable/disable debugging code paths (e.g., debug logging)
- Example: `DOCKER_FINANCE_DEBUG=true`
> DOCKER_FINANCE_PORT_HLEDGER
`hledger-web` client-side (host) port
- Example: `DOCKER_FINANCE_PORT_HLEDGER=5000`
> DOCKER_FINANCE_PORT_ROOT
`root` client-side (host) port for web interface
- Example: `DOCKER_FINANCE_PORT_ROOT=8080`
> DOCKER_FINANCE_MEMORY
`docker-finance` container memory limit (see Docker documentation).
- Example: `5G`
> DOCKER_FINANCE_GID
Group ID for bind mount. **MUST** have write permissions to rw bind-mounts.
- Example: `DOCKER_FINANCE_GID=998`
> DOCKER_FINANCE_UID
User ID for bind mount. **MUST** have write permissions to rw bind-mounts.
- Example: `DOCKER_FINANCE_UID=1001`
> DOCKER_FINANCE_USER
`docker-finance` container user.
Container user's UID/GID **SHOULD** match `DOCKER_FINANCE_UID` and `DOCKER_FINANCE_GID`. This is automatically determined during [Environment Generation](#environment-generation).
User **MUST** have write permissions to rw bind-mounts.
- Example: `DOCKER_FINANCE_USER=alice`
---
#### Client (Host) Custom Dockerfile
The client (host) custom Dockerfile:
- is appended to the final generated Dockerfile
- allows you to append any Dockerfile command to a generated build
- is located in the `${DOCKER_FINANCE_CLIENT_CONF}/client/Dockerfiles/` directory
- format consists of `username@hostname` where `username` is your host username and `hostname` is your machine's hostname
- default generated templates can be found [here](client/docker-finance.d/client/Dockerfiles)
After `gen` is complete, you can edit this file with the client (host) command: `edit type=build` (see [Client (Host) Command Format](#client-host-command-format)).
---
#### Client/Container Superscript
The client/container shell script (Superscript) is a bind-mounted (by directory) script that:
- is the intermediary between client and container
- is unique to each client (host) user (/home/alice, /home/bob, etc.)
- is the glue that ties together **all** container [Subprofile](#subprofile) scripts
- is generated on a per-client basis: all custom code on a **per-client basis** should go here
See the in-file comments for further documentation:
- [superscript.bash.in](client/docker-finance.d/container/shell/superscript.bash.in)
After `gen` is complete, you can edit this file with the client (host) command: `edit type=shell` (see [Client (Host) Command Format](#client-host-command-format)).
---
#### Container Configurations
These configurations are confined solely to the container.
##### *Subprofile*
The Subprofile script is unique to each subprofile for each `profile/subprofile` within the `profiles` parent directory.
By default, this file will contain user aliases for all container commands. These aliases are mostly useful for small setups or setups with uniquely named subprofiles among all profiles.
See the in-file comments for further documentation:
- [subprofile.bash.in](client/docker-finance.d/container/shell/subprofile.bash.in)
After `gen` is complete, from within the container, you can edit this file with: `finance profile/subprofile edit type=shell` (see [Container Command Format](#container-command-format)).
##### *Fetch*
The source of all remote API fetching configurations (exchanges, blockchains, market prices). This file is used by both the `fetch` and `edit type=fetch` commands.
See the in-file comments for further documentation:
- [fetch.yaml.in](client/docker-finance.d/container/fetch/fetch.yaml.in)
After `gen` is complete, from within the container, you can edit this file with: `finance profile/subprofile edit type=fetch` (see [Container Command Format](#container-command-format)).
##### *Meta*
The source of all custom metadata information (typically used to store cryptocurrency metadata information). This file is used by the `meta`, `edit type=meta` and `root` commands, as seen in [Meta (w/ ROOT C++ analysis)](#meta-w-root-c-analysis).
See the in-file comments for further documentation:
- [meta.csv.in](client/docker-finance.d/container/meta/meta.csv.in)
After `gen` is complete, from within the container, you can edit this file with: `finance profile/subprofile edit type=meta` (see [Container Command Format](#container-command-format)).
## How do I use it?
### Mostly-Unified CLI
You'll only need to call two different scripts throughout your time using `docker-finance`:
1. The client script which handles the client-side system: `docker.bash`
2. The container script which handles the container-side system: `finance.bash`
These two scripts can be rationalized by the following format:
<script> <super/sub> <command> [args]
> Note: for your convenience, command arguments [args] can be arranged in any order.
For example, these [Screenshots](#screenshots) describe a setup with mockup data where the client (host) user named `personal`, along with container `$DOCKER_FINANCE_USER` named `personal`, engage in client/container activity. The container profile named `testprofile` and its subprofile named `testuser` can be described as `<super/sub>` portion of the format (`testprofile/testuser`).
> Note: mockup data can be found in the `mockup` directories within this repository.
---
#### Client (Host) Command Format
The client (host) command format consists of:
docker.bash <platform/username:tag> <command> [args]
Where:
- `docker.bash` is located in `${DOCKER_FINANCE_CLIENT_REPO}/client`
- `<platform/username:tag>`
- `platform` is the image platform (archlinux, ubuntu)
- `username` is the client (host) username with read/write permissions to the container (see [Configuration Files](#configuration-files))
- `tag` is a custom tag you can use to delineate any number of images that you wish you create (`latest`, `dev`, etc.)
- `<command>` is the command to pass to `docker.bash`
- `[args]` are the (optional) arguments to pass to `<command>`
For a complete list of commands and usage help:
```bash
${DOCKER_FINANCE_CLIENT_REPO}/client/docker.bash archlinux/${USER}:default help
```
Or, if the [Installation](#installation) alias was properly created:
```bash
docker-finance archlinux/${USER}:default help
```
You can also view the help usage of, for example, the `edit` command:
```bash
docker-finance archlinux/${USER}:default edit help
```
---
#### Container Command Format
The container command format consists of:
finance.bash <profile/subprofile> <command> [args]
Where:
- `finance.bash` is located in `${DOCKER_FINANCE_CLIENT_REPO}/container`
- `<profile/subprofile>`
- `profile` is the profile, as defined during [Environment Generation](#environment-generation)
- `subprofile` is the subprofile (user), as defined during [Environment Generation](#environment-generation)
- `<command>` is the command to pass to `finance.bash`
- `[args]` are the (optional) arguments to pass to `<command>`
By default, `finance.bash` is aliased to `finance` (so, either can be used).
For a complete list of commands (no `<profile/subprofile>` needed):
```bash
finance help
```
You can also view the help usage of, for example, the `fetch` command (notice the need for `<profile/subprofile>`).
Assuming `<profile/subprofile>` is `testprofile/testuser`:
```bash
finance testprofile/testuser fetch help
```
Or, use a subprofile alias, as described in [Subprofile](#subprofile):
```bash
testuser_fetch help
```
> Note: the `finance` alias is named to avoid confusion with the client (host) command `docker-finance`, but you can still use the alias `docker-finance` *within* the container in place of all `finance` commands.
### Flow Layout
A primary read through of [hledger](https://hledger.org) and [hledger-flow](https://github.com/apauley/hledger-flow/blob/master/README.org) documentation should bring you up to speed on the essentials.
As for `docker-finance` specifics, you can create a *test profile* during [Environment Generation](#environment-generation) to see what your flow's layout should look like.
> Note: be sure to select 'y' when asked if this will be a development profile, and then go on to create account(s).
Once inside the container, assuming you created a profile named `testprofile` and subprofile named `testuser`, issue the following commands:
```bash
finance testprofile/testuser fetch all=price year=all && finance testprofile/testuser import year=2018
```
> Note: for this *test profile* with developer mockups, you **MUST** import from `2018` as there are accounts that begin from that year
After experimenting with a *test profile*, you can re-run `gen` again to create your own normal profile.
---
All profiles/subprofiles are installed into the parent directory `${DOCKER_FINANCE_CONTAINER_FLOW}/profiles`.
Peeking inside `${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/profile/subprofile`, you'll see the following:
- `all-years.journal` and `directives.journal`
- These top-level journals are generated by `hledger-flow`. Ignore these and use the `edit` command for journal editing.
- `docker-finance.d`
- Location of all `docker-finance` configuration files (see `edit help` for details).
- `import`
- Location of all CSV data and *real* journals. This is where you'll place CSV files and custom account/subaccount changes (see `edit help` for details).
- `prices`
- Location of all market price data, by year, as acquired by `fetch price` (see `fetch help` for details).
- `reports`
- Location of all generated reports, by year, as generated by `reports` (see `reports help` for details).
- `taxes`
- Location of all generated taxes, by year, as generated by `taxes` (see `taxes help` for details).
---
Regarding any profile you create:
- For manual CSV downloads, place you CSV file into your `${DOCKER_FINANCE_CONTAINER_FLOW}/profiles/profile/subprofile/import/subprofile/account/subaccount/1-in/year` directory (replacing `year` with the year of data that the file/data represents). See `import help` for details.
- When you want to edit custom settings for an account or a subaccount, use the `edit` command. See `edit help` for details.
- Your `hledger-flow` will contain a symlink called `src` which links to all the internal mechanics that process your data. **Do not delete this link**.
### Caveats & Oddities
#### Flow Layout
##### *Prices*
Before you try to infer market prices, be sure to fetch prices *before* you do your first import (or first import of the year). If you do not fetch, the prices journal will **not** be included within the import and, if you have a previous year of prices, **you will unwittingly infer against that previous year instead of your expected year!**
##### *Accounts: Trezor*
In the "Trezor Suite" app, change your wallet name to your subaccount(s). For example, to delineate between your Trezor One from several Trezor T devices, and to delineate between their separate wallets *within* every device, follow these steps:
Example, using your #2 Trezor T device and one of its BTC "storage" wallets:
1. Change wallet name in app to `t-2:storage-1` as it's your Trezor T device #2, 1st bitcoin wallet named `storage-1` (versus your 2nd bitcoin wallet named `storage-2`, etc.)
2. Export the CSV file to the appropriate directory. It will be in the format of `t_2_storage_1_20230629T230013.csv` (timestamp will be different)
3. Rename the file to `t-2:storage-1_BTC.csv` (be sure to append the currency ticker to the file. So, `_BTC` if bitcoin or `_LTC` if litecoin, etc).
> Note: see Trezor `mockup` data within this repository, for a working example.
`docker-finance` relies on `Amount unit` within the file for the actual symbol/currency so, this file naming convention serves at least two purposes:
1. This allows you to maintain device continuity by reusing wallet names for different currencies.
2. This allows you to export, in the future, to the correct file from the associated hardware wallet because each hardware wallet exports its own unique CSV.
#### Taxes
- If you have a wallets designated for `SPEND`ing/`GIFT`ing or `INCOME`, you can use custom rules to mark all outgoing/incoming transactions as such (ex., using tags `taxed_as:SPEND`/`taxed_as:GIFT`/`taxed_as:INCOME`/etc.). See implementation for details.
- **WARNING**: *all* `GIFTIN` cost-basis must be manually entered from the corresponding `GIFT` results/calculations (as gifted from another).
- For blockchain-related transactions, you can easily add cost-basis of a gift received (`GIFTIN`) by TXID in your custom rules
- Example: despite Electrum providing `fiat_value`, you'll need to manually enter in your custom rules the correct `GIFT` value (if divergent)
## How do I contribute?
### Donate
#### Time
Your input is valuable and appreciated. Come, make this project your own!
#### Funding
&#8594; **100% of your donations go to the `docker-finance` funding pool.** &#8592;
> This pool is reserved for the `docker-finance` ecosystem (developers & operating costs).
##### *Cryptocurrency*
[Donate with Coinbase Commerce](https://commerce.coinbase.com/checkout/8831f2a9-1797-4aff-8cc3-bdbf97136a97)
[<img src=".img/donation/coinbase-commerce.png" width="25%" height="25%" />](https://commerce.coinbase.com/checkout/8831f2a9-1797-4aff-8cc3-bdbf97136a97 "Donate with Coinbase Commerce")
##### *Legacy*
[Donate with PayPal](https://www.paypal.com/donate/?hosted_button_id=2RESHZY8U37EJ)
[<img src=".img/donation/paypal-business.png" width="25%" height="25%" />](https://www.paypal.com/donate/?hosted_button_id=2RESHZY8U37EJ "Donate with PayPal")
##### *Alternative*
For alternative donation methods, including your crypto/token of choice, please open a request in the [issue tracker](https://gitea.com/EvergreenCrypto/docker-finance/issues) or reach out to [Evergreen Crypto LLC](#evergreen-crypto-llc).
---
##### *Dependencies*
To donate to the wonderful projects that `docker-finance` gratefully depends upon, please donate to them directly:
- [Docker](https://www.docker.com/blog/get-involved-with-docker/)
- [hledger](https://hledger.org/sponsor.html)
- [hledger-flow](https://github.com/apauley/hledger-flow)
- [ROOT.cern](https://root.cern/contribute/)
For other dependencies, please see their individual contributing guidelines.
### Development
You'll greatly benefit from building the [`dev-tools` image](#image-dev-tools), as seen in `docker-finance help`.
Additionally, when developing with the [`docker-finance` image](#image-docker-finance), please test your work with mockups as described in [Environment Generation](#environment-generation) and [Flow Layout](#flow-layout).
> Note: mockup CSVs will *intentionally* have multiple years within in a `1-in/year` directory in order to test for year parsing.
#### Pull Request
The following assumes that the command `dev-tools` has been properly aliased, per `docker-finance help`.
Before sending a pull request:
1. If you created a new file, please run `dev-tools license file=/path/to/new/file.ext` and update the copyright date and author.
2. For any work that utilizes Bash/C++/PHP, please run the linter for your respective language (e.g., `dev-tools linter type=bash`).
- See `dev-tools linter help` for details.
3. As for style guidelines, these are recommended:
- [Bash](https://google.github.io/styleguide/shellguide.html)
- [C++](https://google.github.io/styleguide/cppguide.html)
- [PHP](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/ruleSets/PhpCsFixer.rst)
4. If you can, please document the code in Doxygen style where applicable and run `dev-tools doxygen gen` to see your code documentation.
#### Notes
- Regarding client configuration, Docker volumes aren't used because of chicken-or-the-egg problem (among other reasons). `docker-finance` needs the client environment *before* building the Docker image and spawning the subsequent container (which would rely on volumes).
- As described in [Mostly-Unified CLI](#mostly-unified-cli), to use a developer version of the `finance` image (not a `dev-tools` image), simply build and tag a new `finance` image with `dev` (or whatever you see fit), and reset the `docker-finance` alias at your discretion.
- Run `DOCKER_FINANCE_DEBUG=true docker-finance <platform/user:tag> <cmd> [args]` to debug *before* the [Client (Host) Configuration File](#client-host-configuration) file is read.
- The `.C` files you see in the repository are ROOT.cern macro files, not C-language files.
## How do I connect?
### `#docker-finance:matrix.org`
Join the [`docker-finance` Matrix](https://matrix.to/#/#docker-finance:matrix.org) community.
[<img src=".img/contacts/matrix.png" width="25%" height="25%" />](https://matrix.to/#/#docker-finance:matrix.org "#docker-finance:matrix.org")
### Evergreen Crypto LLC
- For general communications, please visit the [contact section of the website](https://evergreencrypto.co/#contact).
- For security-related concerns, please [contact the Founder directly with PGP encrypted email](https://keyserver2.gnupg.org/pks/lookup?op=vindex&search=0x04fb3888ff3eb841).
## Where is the legalese?
### License and Disclaimer
`docker-finance`:
- is **not** a Docker product
- is **not** a Docker trademark
- is **not** an endorsement of [what is supported](#what-is-supported)
- is **not** a tax-advising product (consult your tax adviser)
- is **not** a financial-advising product (consult your financial adviser)
- **is** licensed under the [GPLv3](LICENSE.md) but...
- I highly suggest that you **consider refraining from the use of AI modeling against `docker-finance`** and also refrain from mirroring (or archiving) `docker-finance` on GitHub, GitLab or any other service that uses AI against its hosted code, [until the court make its final ruling on litigation against GitHub/Microsoft and OpenAI](https://githubcopilotlitigation.com/) (and after any possible appeal).
[//]: # (vim: sw=2 sts=2 si ai et)