kontoo

package module
v0.0.0-...-27188e6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2024 License: MIT Imports: 26 Imported by: 0

README

kontoo -- accounting helper

Log transactions of your financial assets and generate reports.

Installation

Make sure you have NodeJS and npm installed. Then run

npm install
npm run build
go run ./cmd/kontoo serve -debug -ledger ./ledger.json

Development

Run

npx webpack --watch

to automatically update .js and .css resources (still requires a browser refresh).

Notes

For equities and bonds, ledger entries are simple:

  • AssetPurchase with Price, Quantity, and Cost.
  • AssetSale with the same.
  • AssetHolding to assert a specific position holding, with Price, Quantity, and optional Cost.
  • AssetPrice to assert a specific (market) price for a single unit of the asset.

Bonds have an additional entry type signifying their maturity:

  • AssetMaturity to assert that the asset has matured. Its position will be zero afterwards.

For checking and savings accounts, things are different, but also simple:

  • AccountBalance to assert the balance (value) of an account.
  • AccountCredit to add to the balance.
  • AccountDebit to subtract from the balance.

Only the Value of the asset matters. These account types have neither Cost, Price, nor Quantity. AccountCredit and AccountDebit are rare and are mostly allowed here "for completeness" (they are more common for other asset types like TaxPayment). Most checking and savings accounts will only have AccountBalance entries.

Fixed deposit accounts are a bit weirder. They are maturing and yield interest just like bonds. However, since they are not traded on an exchange, they have no Price or Cost. Their value tends to increase over time (in the case of accumulating interest).

The "natural" entry types are:

  • AccountCredit to add to the balance.
  • AccountBalance to assert the balance (value) of the fixed deposit account.
  • AssetMaturity when the fixed deposit account has matured.

To calculate the total earnings of the investment, we need to sum up the individual account credits (typically a single one at the beginning, since each new investment results in a new fixed deposit account) and subtract them from the final balance at maturity.

We should therefore enforce the following protocol for fixed deposit accounts:

  • AccountCredit to add to the balance. In particular, this entry type MUST be used as the initial entry type when the deposit account is opened.
  • AccountBalance to assert the balance (value) of the fixed deposit account at any point in time after the initial AccountCredit.
  • AssetMaturity at maturity. A Value MUST be specified, which specifies the final account balance.

Documentation

Overview

Install go-enum by `go get -u github.com/searKing/golang/tools/go-enum`

Install go-enum by `go get -u github.com/searKing/golang/tools/go-enum`

Index

Constants

View Source
const (
	Millis    = 1_000
	UnitValue = 1_000_000
)
View Source
const (
	MoneyAmountArg argType = iota
	StringArg
	DecimalArg
	DateArg
	EntryTypeArg
)

Variables

View Source
var (
	ErrCookiesExpired = errors.New("cookies in cookie jar expired")
	ErrTickerNotFound = errors.New("ticker symbol not found")
	ErrNotCached      = errors.New("requested entry not found in cache")
)

Functions

func LenientParseDate

func LenientParseDate(args []string, d *Date) error

func ListEmbeddedResources

func ListEmbeddedResources() (files []string, err error)

func NewArgSpec

func NewArgSpec() *argSpec

func ParseAssetType

func ParseAssetType(args []string, e *AssetType) error

func ParseCurrency

func ParseCurrency(args []string, c *Currency) error

func ParseDecimal

func ParseDecimal(args []string, m *Micros) error

func ParseDecimalAsMicros

func ParseDecimalAsMicros(decimal string, m *Micros) error

func ParseDecimalOrPercent

func ParseDecimalOrPercent(args []string, m *Micros) error

func ParseEntryType

func ParseEntryType(args []string, e *EntryType) error

func ParseString

func ParseString(args []string, s *string) error

func PrintQuote

func PrintQuote(client *http.Client, ticker string, jar *CookieJar) error

This is the second API that might be useful. Currently not used.

func ValidCurrency

func ValidCurrency(c Currency) bool

Reports whether c is a valid and known currency.

Types

type AddExchangeRateItem

type AddExchangeRateItem struct {
	BaseCurrency  Currency `json:"baseCurrency"`
	QuoteCurrency Currency `json:"quoteCurrency"`
	Date          Date     `json:"date"`
	PriceMicros   Micros   `json:"priceMicros"`
}

type AddQuoteItem

type AddQuoteItem struct {
	AssetID     string `json:"assetID"`
	Date        Date   `json:"date"`
	PriceMicros Micros `json:"priceMicros"`
}

type AddQuotesRequest

type AddQuotesRequest struct {
	Quotes        []*AddQuoteItem        `json:"quotes"`
	ExchangeRates []*AddExchangeRateItem `json:"exchangeRates"`
}

type AddQuotesResponse

type AddQuotesResponse struct {
	Status        StatusCode `json:"status"`
	Error         string     `json:"error,omitempty"`
	ItemsImported int        `json:"itemsImported"`
}

type Asset

type Asset struct {
	Created         time.Time
	Modified        time.Time
	Type            AssetType
	Name            string
	ShortName       string                  `json:",omitempty"`
	IssueDate       *Date                   `json:",omitempty"`
	MaturityDate    *Date                   `json:",omitempty"`
	InterestMicros  Micros                  `json:"Interest,omitempty"`
	InterestPayment InterestPaymentSchedule `json:",omitempty"`
	IBAN            string                  `json:",omitempty"`
	AccountNumber   string                  `json:",omitempty"`
	ISIN            string                  `json:",omitempty"`
	WKN             string                  `json:",omitempty"`
	TickerSymbol    string                  `json:",omitempty"`
	// More ticker symbols, to get stock quotes online.
	// Keyed by quote service. Not used as ID.
	QuoteServiceSymbols map[string]string `json:",omitempty"`
	CustomID            string            `json:",omitempty"`
	Currency            Currency
	Comment             string `json:",omitempty"`
}

func ParseAsset

func ParseAsset(args []string) (*Asset, error)

func (*Asset) Category

func (a *Asset) Category() AssetCategory

func (*Asset) ID

func (a *Asset) ID() string

type AssetCategory

type AssetCategory int
const (
	UnspecfiedAssetCategory AssetCategory = iota
	Equity
	FixedIncome
	CashEquivalents
	RetirementSavings
	Commodities
	Taxes
	Debt
)

func (AssetCategory) String

func (ac AssetCategory) String() string

type AssetGroup

type AssetGroup struct {
	ID   string
	Name string
}

type AssetPosition

type AssetPosition struct {
	Asset *Asset
	// Last value date of any ledger entry seen for this position.
	LastUpdated    Date
	ValueMicros    Micros
	QuantityMicros Micros
	PriceMicros    Micros
	PriceDate      Date
	// Items are the constituent parts of the accumulated asset position.
	// The are stored in chronological order (latest comes last) and can
	// be used to determine profits and losses (P&L) and to update the
	// accumulated values when an asset is partially sold.
	Items []AssetPositionItem
}

AssetPosition represents the "current" asset position. It is typically calculated from ledger entries for the given asset.

func (*AssetPosition) Copy

func (p *AssetPosition) Copy() *AssetPosition

Copy returns a semi-deep copy of p: It shares the pointer to the asset, but all position-specific values (including Items) are copied.

func (*AssetPosition) CostMicros

func (p *AssetPosition) CostMicros() Micros

func (*AssetPosition) Currency

func (p *AssetPosition) Currency() Currency

func (*AssetPosition) MarketValue

func (p *AssetPosition) MarketValue() Micros

func (*AssetPosition) Name

func (p *AssetPosition) Name() string

func (*AssetPosition) PurchasePrice

func (p *AssetPosition) PurchasePrice() Micros

func (*AssetPosition) SetPrice

func (p *AssetPosition) SetPrice(price Micros, date Date)

func (*AssetPosition) Update

func (p *AssetPosition) Update(e *LedgerEntry)

type AssetPositionItem

type AssetPositionItem struct {
	ValueDate      Date
	QuantityMicros Micros
	PriceMicros    Micros
	CostMicros     Micros
}

AssetPositionItem tracks an individual purchase that is part of the accumulated asset position.

func (*AssetPositionItem) PurchasePrice

func (a *AssetPositionItem) PurchasePrice() Micros

type AssetType

type AssetType int32
const (
	UnspecifiedAssetType AssetType = iota

	Stock                   // Aktie
	StockExchangeTradedFund // Aktienfonds (ETF)
	StockMutualFund         // Aktienfonds (Investment)
	BondExchangeTradedFund  // Rentenfonds (ETF)
	BondMutualFund          // Rentenfonds (Investment)
	CorporateBond           // Unternehmensanleihe
	GovernmentBond          // Staatsanleihe
	FixedDepositAccount     // Festgeldkonto
	MoneyMarketAccount      // Tagesgeldkonto
	SavingsAccount          // Sparkonto
	CheckingAccount         // Girokonto
	BrokerageAccount        // Verrechnungskonto
	PensionAccount          // Altersvorsorgekonten (z.B. Säule 3a)
	Commodity               // Edelmetalle, Rohstoffe
	Cash                    // Bargeld
	TaxLiability            // Steuerschuld
	TaxPayment              // Steuer(voraus)zahlung
	CreditCardDebt          // Schulden auf Kreditkarte
	OtherDebt               // allg. Schulden
)

Values for AssetType constants may change over time. Only the name should be assumed constant (and persisted in the JSON ledger).

func AssetTypeValues

func AssetTypeValues() []AssetType

AssetTypeValues returns all values of the enum

func ParseAssetTypeString

func ParseAssetTypeString(s string) (AssetType, error)

ParseAssetTypeString retrieves an enum value from the enum constants string name. Throws an error if the param is not part of the enum.

func (AssetType) DisplayName

func (t AssetType) DisplayName() string

func (AssetType) MarshalJSON

func (i AssetType) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface for AssetType

func (AssetType) Registered

func (i AssetType) Registered() bool

IsAAssetType returns "true" if the value is listed in the enum definition. "false" otherwise

func (AssetType) String

func (i AssetType) String() string

func (*AssetType) UnmarshalJSON

func (i *AssetType) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for AssetType

func (AssetType) UseTransactionTracking

func (t AssetType) UseTransactionTracking() bool

func (AssetType) ValidEntryTypes

func (t AssetType) ValidEntryTypes() []EntryType

type CommandArgs

type CommandArgs struct {
	Args        []string
	KeywordArgs map[string][]string
}

func ParseArgs

func ParseArgs(args []string) (CommandArgs, error)

type CookieJar

type CookieJar struct {
	Crumb   string
	Cookies []SimpleCookie
}

func (*CookieJar) AddCookies

func (j *CookieJar) AddCookies(req *http.Request)

type CsvUploadResponse

type CsvUploadResponse struct {
	Status     StatusCode `json:"status"`
	Error      string     `json:"error,omitempty"`
	NumEntries int        `json:"numEntries"`
	InnerHTML  string     `json:"innerHTML"`
}

type Currency

type Currency string

Three-letter code, e.g. CHF, EUR, USD.

type DailyExchangeRate

type DailyExchangeRate struct {
	BaseCurrency  Currency
	QuoteCurrency Currency
	Timestamp     time.Time // Timestamp for the ClosingPrice as received from the quote service.
	ClosingPrice  Micros    // Expressed as a multiple of the QuoteCurrency: 1.30 means for 1 BaseCurrency you get 1.30 QuoteCurrency.
}

type DailyQuote

type DailyQuote struct {
	Symbol       string
	Currency     Currency
	Timestamp    time.Time // Timestamp for the ClosingPrice as received from the quote service.
	ClosingPrice Micros
}

type Date

type Date struct {
	time.Time
}

Dates without a time component.

func DateVal

func DateVal(year int, month time.Month, day int) Date

func ParseDate

func ParseDate(s string) (Date, error)

func ToDate

func ToDate(t time.Time) Date

func (Date) AddDays

func (d Date) AddDays(n int) Date

func (Date) Between

func (d Date) Between(start, end Date) bool

func (Date) Compare

func (d Date) Compare(other Date) int

func (Date) Equal

func (d Date) Equal(e Date) bool

func (Date) MarshalJSON

func (d Date) MarshalJSON() ([]byte, error)

func (Date) String

func (d Date) String() string

func (*Date) UnmarshalJSON

func (d *Date) UnmarshalJSON(data []byte) error

type DeleteLedgerEntryRequest

type DeleteLedgerEntryRequest struct {
	// We use a pointer to detect if the field was explicitly set.
	SequenceNum *int64 `json:"sequenceNum"`
}

type DeleteLedgerEntryResponse

type DeleteLedgerEntryResponse struct {
	Status      StatusCode `json:"status"`
	Error       string     `json:"error,omitempty"`
	SequenceNum int64      `json:"sequenceNum"`
}

type DepotExportItem

type DepotExportItem struct {
	QuantityMicros Micros   `json:"quantity"`
	WKN            string   `json:"wkn"`
	Currency       Currency `json:"currency"`
	PriceMicros    Micros   `json:"price"`
	ValueMicros    Micros   `json:"value"`
	ValueDate      Date     `json:"valueDate"`
}

func ReadDepotExportCSV

func ReadDepotExportCSV(reader io.Reader) ([]*DepotExportItem, error)

ReadDepotExportCSV is designed to read CSV exports of account positions provided by a specific German bank. It expects a set of headers to be present (in any order) and ignores all other headers. It also expects German formats for decimal numbers and dates as well as the use of ; as the column separator.

func ReadDepotExportCSVFile

func ReadDepotExportCSVFile(path string) ([]*DepotExportItem, error)
type DropdownOptions struct {
	Selected *NamedOption
	Options  []NamedOption
}

type EntryType

type EntryType int32
const (
	UnspecifiedEntryType EntryType = iota

	AssetPurchase
	AssetSale
	AssetPrice
	AssetHolding
	AccountCredit
	AccountDebit
	AccountBalance
	AssetMaturity
	DividendPayment
	InterestPayment
	ExchangeRate
)

func EntryTypeValues

func EntryTypeValues() []EntryType

EntryTypeValues returns all values of the enum

func ParseEntryTypeString

func ParseEntryTypeString(s string) (EntryType, error)

ParseEntryTypeString retrieves an enum value from the enum constants string name. Throws an error if the param is not part of the enum.

func (EntryType) MarshalJSON

func (i EntryType) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface for EntryType

func (EntryType) NeedsAssetID

func (t EntryType) NeedsAssetID() bool

func (EntryType) Registered

func (i EntryType) Registered() bool

IsAEntryType returns "true" if the value is listed in the enum definition. "false" otherwise

func (EntryType) String

func (i EntryType) String() string

func (*EntryType) UnmarshalJSON

func (i *EntryType) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for EntryType

type InterestPaymentSchedule

type InterestPaymentSchedule string
const (
	UnspecifiedPayment InterestPaymentSchedule = ""
	AccruedPayment     InterestPaymentSchedule = "accrued" // Interest paid at maturity
	AnnualPayment      InterestPaymentSchedule = "annual"  // Interest paid yearly
)

type Ledger

type Ledger struct {
	Header  *LedgerHeader  `json:",omitempty"`
	Assets  []*Asset       `json:",omitempty"`
	Entries []*LedgerEntry `json:",omitempty"`
}

func NewLedger

func NewLedger(baseCurrency Currency) *Ledger

NewLedger returns an empty ledger that uses the given base currency.

type LedgerAssetInfoRequest

type LedgerAssetInfoRequest struct {
	AssetID string `json:"assetId"`
	Date    *Date  `json:"date"` // Optional
}

type LedgerAssetInfoResponse

type LedgerAssetInfoResponse struct {
	Status    StatusCode `json:"status"`
	Error     string     `json:"error,omitempty"`
	InnerHTML string     `json:"innerHTML"`
}

type LedgerEntry

type LedgerEntry struct {
	Created     time.Time
	SequenceNum int64
	ValueDate   Date      `json:",omitempty"`
	Type        EntryType `json:",omitempty"`
	AssetRef    string    `json:",omitempty"`
	AssetID     string    `json:",omitempty"`

	Currency Currency `json:",omitempty"`

	// Only set for ExchangeRate type entries. Currency represents the base currency in that case.
	QuoteCurrency Currency `json:",omitempty"`

	// Value in micros of the currency. For currency CHF, 1'000'000 ValueMicros equals 1 CHF.
	// Except for accounts, ValueMicros is only informational. The current value of other asset positions
	// is calculated from its QuantityMicros and its PriceMicros.
	ValueMicros    Micros `json:"Value,omitempty"`    // Account balance or asset value as calculated from quantity and price.
	QuantityMicros Micros `json:"Quantity,omitempty"` // Number of stocks, oz of gold, nominal value of a bond
	PriceMicros    Micros `json:"Price,omitempty"`    // Price of a single quantity of the asset. (1 * UnitValue) means 100% for prices specified in percent.
	CostMicros     Micros `json:"Cost,omitempty"`     // Cost incurred by the transaction.

	Comment string `json:",omitempty"`
}

func ParseLedgerEntry

func ParseLedgerEntry(args []string) (*LedgerEntry, error)

type LedgerEntryRow

type LedgerEntryRow struct {
	E *LedgerEntry
	A *Asset
	// contains filtered or unexported fields
}

func (*LedgerEntryRow) AssetID

func (e *LedgerEntryRow) AssetID() string

func (*LedgerEntryRow) AssetName

func (e *LedgerEntryRow) AssetName() string

func (*LedgerEntryRow) AssetType

func (e *LedgerEntryRow) AssetType() AssetType

func (*LedgerEntryRow) Comment

func (e *LedgerEntryRow) Comment() string

func (*LedgerEntryRow) Cost

func (e *LedgerEntryRow) Cost() Micros

func (*LedgerEntryRow) Created

func (e *LedgerEntryRow) Created() time.Time

func (*LedgerEntryRow) Currency

func (e *LedgerEntryRow) Currency() string

func (*LedgerEntryRow) EntryType

func (e *LedgerEntryRow) EntryType() EntryType

func (*LedgerEntryRow) HasAsset

func (e *LedgerEntryRow) HasAsset() bool

func (*LedgerEntryRow) Label

func (e *LedgerEntryRow) Label() string

func (*LedgerEntryRow) MarketValue

func (e *LedgerEntryRow) MarketValue() Micros

func (*LedgerEntryRow) Price

func (e *LedgerEntryRow) Price() Micros

func (*LedgerEntryRow) Quantity

func (e *LedgerEntryRow) Quantity() Micros

func (*LedgerEntryRow) SequenceNum

func (e *LedgerEntryRow) SequenceNum() int64

func (*LedgerEntryRow) TotalCost

func (e *LedgerEntryRow) TotalCost() Micros

func (*LedgerEntryRow) TotalQuantity

func (e *LedgerEntryRow) TotalQuantity() Micros

func (*LedgerEntryRow) Value

func (e *LedgerEntryRow) Value() Micros

func (*LedgerEntryRow) ValueDate

func (e *LedgerEntryRow) ValueDate() Date

type LedgerHeader

type LedgerHeader struct {
	BaseCurrency Currency `json:",omitempty"`
}

type LedgerRecord

type LedgerRecord struct {
	Header *LedgerHeader `json:",omitempty"`
	Entry  *LedgerEntry  `json:",omitempty"`
	Asset  *Asset        `json:",omitempty"`
}

LedgerRecord is a wrapper for storing a ledger in a file, row by row, instead of as a single record. Only one of its fields may be set. Header must be the first entry in the file, assets and entries can then be mixed arbitrarily.

type MaturitiesChartData

type MaturitiesChartData struct {
	Currency     string                   `json:"currency"`
	BucketLabels []string                 `json:"bucketLabels"`
	Values       []*MaturitiesChartValues `json:"values"`
}

type MaturitiesChartValues

type MaturitiesChartValues struct {
	Label       string  `json:"label"`
	ValueMicros []int64 `json:"valueMicros"`
}

type Micros

type Micros int64

func FloatAsMicros

func FloatAsMicros(f float64) Micros

func (Micros) Div

func (a Micros) Div(b Micros) Micros

Calculates a divided by b, truncated towards zero.

func (Micros) Float

func (m Micros) Float() float64

func (Micros) Format

func (m Micros) Format(format string) string

func (Micros) Frac

func (a Micros) Frac(numer, denom Micros) Micros

Calculates a*numer/denom, truncated towards zero. The idea is that this function is defined for more inputs than a.Mul(numer).Div(denom) would be.

func (Micros) MarshalJSON

func (m Micros) MarshalJSON() ([]byte, error)

func (Micros) Mul

func (a Micros) Mul(b Micros) Micros

Returns the result of multiplying two values expressed in micros. E.g., a == 2_000_000, b == 3_000_000 ==> Mul(a, b) == 6_000_000.

func (Micros) SplitFrac

func (m Micros) SplitFrac() (int64, int)

SplitFrac splits m into its integer and fractional parts. If m is negative, both parts will have a negative sign, unless one of them is zero.

func (Micros) String

func (m Micros) String() string

func (Micros) String2

func (m Micros) String2() string

Faster, but uglier.

func (*Micros) UnmarshalJSON

func (m *Micros) UnmarshalJSON(data []byte) error

type NamedOption

type NamedOption struct {
	Name  string
	Value any
	Data  map[string]any
}

type PositionTableRow

type PositionTableRow struct {
	AssetID   string
	AssetName string
	AssetType AssetType
	Currency  Currency
	Value     Micros
	// BaseCurrency/Currency exchange rate. Used to calculate all monetary values
	// of this position in the base currency.
	ExchangeRate Micros
	// Notes about the position to be displayed to the user
	// (e.g. about old data being shown).
	Notes []string
	// Maximum age of the data on which the Value and ValueBaseCurrency
	// are calculated. Used to display warnings in the UI if the age is
	// above a threshold.
	DataAge time.Duration

	PurchasePrice Micros

	// Only populated for equities:
	Quantity          Micros
	Price             Micros
	PriceDate         Date
	ProfitLoss1Y      Micros
	ProfitLoss1YBasis Micros // the basis value relative to which the 1Y P&L ratio is calculated.
	Purchases1Y       Micros

	// Only populated for maturing assets:
	NominalValue            Micros
	InterestRate            Micros
	IssueDate               *Date
	MaturityDate            *Date
	TotalEarningsAtMaturity Micros
	InternalRateOfReturn    Micros
	YearsToMaturity         float64
}

func (*PositionTableRow) AssetCategory

func (r *PositionTableRow) AssetCategory() AssetCategory

func (*PositionTableRow) ProfitLoss

func (r *PositionTableRow) ProfitLoss() Micros

func (*PositionTableRow) ProfitLoss1YRatio

func (r *PositionTableRow) ProfitLoss1YRatio() Micros

func (*PositionTableRow) ProfitLossRatio

func (r *PositionTableRow) ProfitLossRatio() Micros

type PositionTableRowGroup

type PositionTableRowGroup struct {
	Category AssetCategory
	Rows     []*PositionTableRow
}

func (*PositionTableRowGroup) ValueBaseCurrency

func (g *PositionTableRowGroup) ValueBaseCurrency() Micros

type PositionTimeline

type PositionTimeline struct {
	AssetID    string  `json:"assetId"`
	AssetName  string  `json:"assetName"`
	Timestamps []int64 `json:"timestamps"`
	// Send values as int64 micros: the JSON marshalling of Micros
	// would send them as strings (e.g. "12.3").
	QuantityMicros []int64 `json:"quantityMicros"`
	ValueMicros    []int64 `json:"valueMicros"`
}

PositionTimeline contains time series data about an asset position.

type PositionTimelineRequest

type PositionTimelineRequest struct {
	AssetIDs     []string `json:"assetIds"`
	EndTimestamp int64    `json:"endTimestamp"`
	Period       string   `json:"period"`
}

type PositionTimelineResponse

type PositionTimelineResponse struct {
	Status    StatusCode          `json:"status"`
	Error     string              `json:"error,omitempty"`
	Timelines []*PositionTimeline `json:"timelines,omitempty"`
}

type PositionsMaturitiesRequest

type PositionsMaturitiesRequest struct {
	EndTimestamp int64 `json:"endTimestamp"`
}

type PositionsMaturitiesResponse

type PositionsMaturitiesResponse struct {
	Status     StatusCode           `json:"status"`
	Error      string               `json:"error,omitempty"`
	Maturities *MaturitiesChartData `json:"maturities,omitempty"`
}

type PriceHistoryCache

type PriceHistoryCache struct {
	// contains filtered or unexported fields
}

func NewPriceHistoryCache

func NewPriceHistoryCache() *PriceHistoryCache

func (*PriceHistoryCache) AddAll

func (c *PriceHistoryCache) AddAll(quotes []*DailyQuote, start, end time.Time) error

func (*PriceHistoryCache) Get

func (c *PriceHistoryCache) Get(symbol string, date time.Time) (*DailyQuote, error)

type Query

type Query struct {
	// contains filtered or unexported fields
}

func ParseQuery

func ParseQuery(rawQuery string) (*Query, error)

ParseQuery parses rawQuery as a query expression. A query expression consists of whitespace-separated query terms. A query term can be one of: foo ==> Any of the "main" fields must contain the substring "foo". f:foo ==> Field f must exist and contain the substring "foo" f~foo ==> Field f must regexp-match foo (which can be a full regexp, e.g. "bar|baz") Negations of the above: !f:foo, !f~foo

Supported field names are dependent on the entity being matched (ledger entry, asset position, ...). Well-known field names are: {id, type, name}

Date-related filters are special: date:2024 or date:2024-03 or date:2024-03-07 year:2024 from:2024-03-07 until:2024-12-31 (inclusive)

SequenceNum for ledger entries is also special: num:3 or num:10-100 or num:10-20,80-90,100 (all inclusive)

func (*Query) Empty

func (q *Query) Empty() bool

func (*Query) LimitGroups

func (q *Query) LimitGroups(rows []*LedgerEntryRow) []*LedgerEntryRow

Returns only the first N entries from rows for each "group" (asset or exchange rate).

func (*Query) Match

func (q *Query) Match(e *LedgerEntryRow) bool

func (*Query) Sort

func (q *Query) Sort(rows []*LedgerEntryRow)

Sort ledger rows by (ValueDate, SequenceNum), ascending or descending.

type Server

type Server struct {
	// contains filtered or unexported fields
}

func NewServer

func NewServer(addr, ledgerPath, baseDir string) (*Server, error)

func (*Server) DebugMode

func (s *Server) DebugMode(enabled bool)

func (*Server) ReloadStore

func (s *Server) ReloadStore() error

func (*Server) Serve

func (s *Server) Serve() error

func (*Server) Store

func (s *Server) Store() *Store

type SimpleCookie

type SimpleCookie struct {
	Name    string
	Value   string
	Expires time.Time
}

type StatusCode

type StatusCode string
const (
	StatusOK              StatusCode = "OK"
	StatusPartialSuccess  StatusCode = "PARTIAL_SUCCESS"
	StatusInvalidArgument StatusCode = "INVALID_ARGUMENT"
)

type Store

type Store struct {
	// contains filtered or unexported fields
}

func LoadStore

func LoadStore(path string) (*Store, error)

func NewStore

func NewStore(ledger *Ledger, path string) (*Store, error)

func (*Store) Add

func (s *Store) Add(e *LedgerEntry) error

Add validates the given entry e and, on successful validation, inserts the entry into the store.

func (*Store) AddAsset

func (s *Store) AddAsset(a *Asset) error

func (*Store) AssetPositionAt

func (s *Store) AssetPositionAt(assetId string, date Date) *AssetPosition

AssetPositionAt returns the given asset's position at date.

func (*Store) AssetPositionsAt

func (s *Store) AssetPositionsAt(date Date) []*AssetPosition

AssetPositionsAt returns the asset positions for each non-zero asset position at t.

func (*Store) AssetPositionsBetween

func (s *Store) AssetPositionsBetween(assetID string, start, end Date) []*AssetPosition

AssetPositionsBetween returns all asset positions for assetID on days with ledger entries between start and end.

func (*Store) AssetPurchases

func (s *Store) AssetPurchases(assetId string, startDate, endDate Date) Micros

AssetPurchases returns the difference between asset positions bought and sold in the given period.

func (*Store) BaseCurrency

func (s *Store) BaseCurrency() Currency

func (*Store) Delete

func (s *Store) Delete(sequenceNum int64) error

func (*Store) EntriesAround

func (s *Store) EntriesAround(assetID string, date Date, n int) (before, after []*LedgerEntry)

EntriesAround returns n ledger entries before date and n entries after date for assetID. If there are less than n entries before or after, guess what, only those are returned.

func (*Store) EntriesInRange

func (s *Store) EntriesInRange(assetId string, start, end Date) []*LedgerEntry

EntriesInRange returns all ledger entries for the given asset in the (inclusive) range [start, end].

func (*Store) ExchangeRateAt

func (s *Store) ExchangeRateAt(c Currency, t Date) (Micros, Date, bool)

ExchangeRateAt returns the BaseCurrency/QuoteCurrency exchange rate at the given time. A value of 1.50 means that for 1 BaseCurrency you get 1.50 QuoteCurrency c. The rate is derived from ExchangeRate entries in the ledger; the most recent rate before t is used and its date is returned as the second return value. If no exchange rate between the given currency c and the base currency is known at t, the result is zero and the third return value is false.

func (*Store) FindAssetByRef

func (s *Store) FindAssetByRef(ref string) *Asset

func (*Store) FindAssetByWKN

func (s *Store) FindAssetByWKN(wkn string) *Asset

func (*Store) FindAssetsForQuoteService

func (s *Store) FindAssetsForQuoteService(quoteService string) []*Asset

func (*Store) FindEntryBySequenceNum

func (s *Store) FindEntryBySequenceNum(sequenceNum int64) *LedgerEntry

func (*Store) LedgerEntryRows

func (s *Store) LedgerEntryRows(query *Query) []*LedgerEntryRow

LedgerEntryRows returns all ledger entries matching the given query.

func (*Store) PriceAt

func (s *Store) PriceAt(assetID string, t Date) (Micros, Date, bool)

func (*Store) ProfitLossInPeriod

func (s *Store) ProfitLossInPeriod(assetId string, startDate, endDate Date) (profitLoss, referenceValue Micros, err error)

ProfitLossInPeriod calculates the P&L for the given asset in the given period.

As asset quantities might have been bought and sold during the period, there are a few cases to consider:

  • The qty was owned throughout the period: P&L is just the difference between the market value at the beginning and end of the period.
  • The qty was bought during the period: P&L is the difference of its purchasing price (including costs) and its market value at the end of the period.
  • The qty was owned at the beginning, but sold during the period: P&L is the difference between market value at the beginning of the period and sale price (minus costs).
  • The qty was purchased and sold during the period: P&L is the diff of purchasing price (including costs) and sale price (minus costs).

func (*Store) QuoteCurrencies

func (s *Store) QuoteCurrencies() []Currency

func (*Store) Save

func (s *Store) Save() error

func (*Store) Update

func (s *Store) Update(e *LedgerEntry) error

Updates replaces the ledger entry sequenceNum with the given entry e. In contrast to Add, Update expects e to be entirely valid; it will only lookup assets by ID, the currency must be set, etc.

func (*Store) UpdateAsset

func (s *Store) UpdateAsset(assetID string, a *Asset) error

func (*Store) ValueDateRange

func (s *Store) ValueDateRange() (min, max Date)

ValueDateRange returns the minimum and maximum value date of any ledger entry in the store.

type UpsertAssetRequest

type UpsertAssetRequest struct {
	AssetID string `json:"assetId,omitempty"`
	Asset   *Asset `json:"asset"`
}

type UpsertAssetResponse

type UpsertAssetResponse struct {
	Status  StatusCode `json:"status"`
	Error   string     `json:"error,omitempty"`
	AssetID string     `json:"assetId,omitempty"`
}

type UpsertLedgerEntryRequest

type UpsertLedgerEntryRequest struct {
	// Optional. If set, it is an update request, otherwise an add.
	UpdateExisting bool         `json:"updateExisting"`
	Entry          *LedgerEntry `json:"entry"`
}

JSON API for server requests and responses.

type UpsertLedgerEntryResponse

type UpsertLedgerEntryResponse struct {
	Status      StatusCode `json:"status"`
	Error       string     `json:"error,omitempty"`
	SequenceNum int64      `json:"sequenceNum"`
}

type YFChart

type YFChart struct {
	Result []*YFChartResult `json:"result"`
	Error  *YFError         `json:"error"`
}

type YFChartResponse

type YFChartResponse struct {
	Chart *YFChart `json:"chart"`
}

Y! Finance API

type YFChartResult

type YFChartResult struct {
	Meta       *YFMeta       `json:"meta"`
	Indicators *YFIndicators `json:"indicators"`
	Timestamps []float64     `json:"timestamp"`
}

type YFError

type YFError struct {
	Code        string `json:"code"`
	Description string `json:"description"`
}

type YFIndicators

type YFIndicators struct {
	Quote []*YFQuote `json:"quote"`
}

type YFMeta

type YFMeta struct {
	ExchangeTimezoneName string `json:"exchangeTimezoneName"`
	Currency             string `json:"currency"`
	Symbol               string `json:"symbol"`
}

type YFQuote

type YFQuote struct {
	Close []float64 `json:"close"`
}

type YFinance

type YFinance struct {
	// contains filtered or unexported fields
}

func NewYFinance

func NewYFinance() (*YFinance, error)

func (*YFinance) FetchPriceHistory

func (yf *YFinance) FetchPriceHistory(symbol string, start, end time.Time) ([]*DailyQuote, error)

func (*YFinance) GetDailyExchangeRates

func (yf *YFinance) GetDailyExchangeRates(baseCurrency Currency, quoteCurrencies []Currency, date time.Time) ([]*DailyExchangeRate, error)

Get closing exchange rates of multiple currencies for a single day.

func (*YFinance) GetDailyQuotes

func (yf *YFinance) GetDailyQuotes(symbols []string, date time.Time) ([]*DailyQuote, error)

Get closing prices of multiple stocks for a single day.

func (*YFinance) LoadCookieJar

func (yf *YFinance) LoadCookieJar() error

func (*YFinance) RefreshCookieJar

func (yf *YFinance) RefreshCookieJar() error

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL