Models#
Abstract base classes#
Three abstract Django models in richy.core.models are inherited
across the apps. They are abstract = True so they don’t produce
their own database table – subclasses do.
Base |
Subclasses |
Adds |
|---|---|---|
|
|
|
|
|
|
|
|
BaseItem#
Common fields shared by every asset type: symbol, type
(share / etf / index / coin), is_discontinued,
plus ItemManager on objects.
Inherited by Item (which itself is the
concrete parent of Share, Etf, Index, Coin) and
ItemWithPrices.
BaseDividend#
Common fields for dividend records: ex_date, payment_date,
record_date, yield_value, amount_value. Inherited by
richy.shares.models.Dividend and richy.etfs.models.Dividend.
See Models (or Models)
for the user-facing semantics of each field.
User#
The application uses a custom user model
(AUTH_USER_MODEL = "core.User") based on AbstractBaseUser and
PermissionsMixin. The login identifier is email – there is no
separate username field.
- class richy.core.models.User(*args, **kwargs)[source]#
Bases:
AbstractBaseUser,PermissionsMixinCustom user model
Convenience accessors used across the project:
- User.get_owned_items()[source]#
Returns currently held (open) items by the user.
- Returns:
List of owned Items.
- Return type:
Meta#
Application-wide key/value metadata. Each row stores a typed key
(type, currently only LAST_PRICE_UPDATE) and a Python value
serialized via PickledObjectField.
The LAST_PRICE_UPDATE entry holds the last datetime when share /
coin prices were refreshed – it’s surfaced as the tooltip on the
application name in the top bar.
Item#
Item is concrete (not abstract) and serves as the polymorphic
parent of every asset-type model. Each concrete asset type lives in
its own Django app and inherits from Item via Django’s
multi-table inheritance – so each subclass has its own table with
an implicit one-to-one back to core_item.
BaseItem (abstract)
├── Item (concrete; multi-table parent)
│ ├── richy.coins.models.Coin
│ ├── richy.etfs.models.Etf
│ ├── richy.indexes.models.Index
│ └── richy.shares.models.Share
└── ItemWithPrices (concrete; denormalized price cache)
Percentage change#
Percentage change from day 0 to day 1 – and also from day 0 to
day 5 – can be calculated with get_last_days_change(percents=True).
The method seeks for the last known price and a price that suits the
“days ago” criterion. If a price for “days ago” is missing (e.g.
because that date was a weekend), the method falls back to the nearest
prior price.
The result is cached.
Compounded change#
The same method can also calculate the compounded change based on all open deposit transactions. The calculation method is a weighted average.
- Item.get_last_days_change(days, no_cache=False, compounded=False, percents=False)[source]#
Calculates change in price in percents between last known price (today) and “today - days param” day.
In case of compounded change function works with open transactions. Takes the calculated percentage change and every found transaction and calculates it’s real gain/loss and it’s investment. Based on these 2 values for each transaction a weighted average is calculated.
- Parameters:
days (int) – Number of days to go in past.
no_cache (bool) – If true cache is not used (value is forced to be calculated).
compounded (bool) – If true calculates compounded change based on deposit transactions (only for precents=True).
percents (bool) – If true the method calculates percentage change.
- Returns:
Percentage diff since “past” (today - days param) to today.
- Return type:
int or None
ItemData#
A model where additional Item-related data is stored. Data is stored as a JSON object under specific keys:
basic_info– basic info for all items (displayed on the item detail page)holdings– list of ETF holdings (ETFs only)
Warning
ItemData should never be accessed directly. Use the accessors
on Item and its subclasses, e.g.:
Item.set_basic_info()Item.get_basic_info()
ItemWithPrices#
A read-only model backed by a PostgreSQL materialized view
(core_itemwithprices). It denormalizes the most recent price
plus historical price snapshots (1 day / 5 / 7 / 30 / 90 / 180 / 365
days ago, plus YTD) and the corresponding percentage changes onto a
single row per item – so list views can render rich tables without
joining Price for each row.
Because it’s a materialized view, ItemWithPrices is read-only
(Meta.managed = False) and must be refreshed whenever
underlying prices change:
For batch loading the view rows alongside UserItem instances:
- static ItemWithPrices.fetch_into_user_items(items)[source]#
Fetches (in a bulk/at once) ItemWithPrices model instance for all the given items and attaches them under “item_with_prices” property.
- Parameters:
items (list) – List of UserItem instances.
- class richy.core.models.ItemWithPrices(id, symbol, type, is_discontinued, last_price_id, last_price, price_1_day_ago, price_5_days_ago, price_7_days_ago, price_30_days_ago, price_90_days_ago, price_180_days_ago, price_365_days_ago, price_ytd, price_1_day_ago_change, price_5_days_ago_change, price_7_days_ago_change, price_30_days_ago_change, price_90_days_ago_change, price_180_days_ago_change, price_365_days_ago_change, price_ytd_days_ago_change)[source]#
Bases:
BaseItem
UserItem#
A per-user view of an Item. Inherits from
UserRelatedModel and adds display
preferences (show_in_overview, show_in_news,
show_on_dashboard), an archive flag (is_archived), a
free-form note, and a many-to-many to indexes.Index so users
can group items into custom indexes.
Uniqueness is enforced on (user, item) – a user has at most one
UserItem row per Item.
- class richy.core.models.UserItem(id, user, item, show_in_overview, show_in_news, show_on_dashboard, note, is_archived)[source]#
Bases:
UserRelatedModel
Price#
A single historical price record for an
Item. Each row stores
(item, datetime, price) and is uniquely keyed on
(item, datetime).
The model uses PandasManager so query
sets can be loaded directly into a pandas dataframe via
.to_pandas(...).
Asset#
Assets are generated or downloaded artefacts saved for further use.
The core.Asset model handles the data; each row can be related to
an Item or a Transaction.
Asset types:
EARNINGS_CHART– earnings chart downloaded from Yahoo!FINANCIALS_CHART– financial chart downloaded from Yahoo!TRENDS_CHART– trends chart downloaded from Yahoo!PERFORMANCE_CHART– performance chart, generatedRECOMMENDATIONS_CHART– recommendations chart, generatedTRENDS_TWITTER_CHART– Twitter trends chartTRANSACTION_GRAPH– transaction (dot) graph, generated
Manual uploading#
The Asset model has a convenient static method upload() for
new asset creation:
- classmethod Asset.upload(buffer, type, extension='png', item=None, transaction=None)[source]#
Creates/updates item asset and uploads file (param buffer) to the storage.
- Parameters:
buffer – File-like object.
type (int) – Item asset type - see Asset.TYPE_CHOICES.
extension – Extensions string i.e. “png”.
item (Item) – Item model instance.
Managers and querysets#
Custom Django ORM managers and querysets. Each pair adds project-wide
behaviour on top of the standard manager: dataframe export, user
scoping, item filtering, and – for ItemWithPrices – a small
identifier annotation used by batch-loading code.
The StakingManager /
StakingQuerySet pair follows the same
pattern and is documented in Models.
PandasManager / PandasQuerySet#
Adds a .to_pandas(*fields) method that returns the queryset as a
pandas.DataFrame. Used wherever the application reads data into
pandas for further analysis (charts, performance calculations,
historical pricing).
ItemManager / ItemQuerySet#
Adds .by_user(user) for items the user owns (joins through
UserItem). Wired in on BaseItem so
all four asset-type models inherit it.
- class richy.core.models.ItemQuerySet(model=None, query=None, using=None, hints=None)[source]#
Bases:
PandasQuerySet
ItemWithPricesQuerySet#
Adds .with_identifier(), an annotation that produces a synthetic
identifier = "<type>_<symbol>" column. Used by
fetch_into_user_items() to
join the materialized-view rows against a list of UserItem keys
in a single query.
- class richy.core.models.ItemWithPricesQuerySet(model=None, query=None, using=None, hints=None)[source]#
Bases:
QuerySet
Note
The corresponding manager (ItemWithPricesManager) is built at
runtime via models.Manager.from_queryset(ItemWithPricesQuerySet)
– there is no standalone class to autodoc.
CustomUserManager#
Custom manager for User. Provides
create_user() and create_superuser() matching the
email-as-username convention used by the custom user model.
- class richy.core.models.CustomUserManager(*args, **kwargs)[source]#
Bases:
UserManager
Utilities#
Non-model helpers that live in richy.core.models for historical
reasons. Listed here so the page covers everything in the file, even
though they aren’t models themselves.
JSON encoder#
Project-wide JSON encoder used by views that hand-roll JSON
responses. Extends DjangoJSONEncoder with extra type handling.
- class richy.core.models.RichyJSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]#
Bases:
DjangoJSONEncoderJSON encoder which handles
dataclasses
in additional to DjangoJSONEncoder which handles
datetime
date
time
timedelta
Decimal
Promise
UUID
Highcharts helpers#
Two small functions used when serializing data for Highcharts.
- richy.core.models.date_to_highcharts_timestamp(value)[source]#
- Parameters:
value (datetime.date or datetime.datetime) – Date(time) to be converted.