Compare commits
No commits in common. "7c337bf948870e89ab675b0e60ee92553859a1b9" and "e4a68bdec992abb6b8be3f906e92802ca361ae90" have entirely different histories.
7c337bf948
...
e4a68bdec9
|
@ -1,40 +1,8 @@
|
||||||
piker.accounting
|
.accounting
|
||||||
________________
|
-----------
|
||||||
A subsystem for transaction processing, storage and historical
|
A subsystem for transaction processing, storage and historical
|
||||||
measurement.
|
measurement.
|
||||||
|
|
||||||
synopsis
|
|
||||||
--------
|
|
||||||
The big question for any trader is this:
|
|
||||||
|
|
||||||
*what is the price that determines whether i take a loss or a gain on my
|
|
||||||
trade?*
|
|
||||||
|
|
||||||
In other words, at any given state of accounting your current assets,
|
|
||||||
what is the price between any 2 assets you've transacted that determines
|
|
||||||
at which price you can conduct **the next** transaction and know if you
|
|
||||||
are making or losing more (or less) of the *source* asset versus the
|
|
||||||
*destination* asset?
|
|
||||||
|
|
||||||
Let's do a very simple example:
|
|
||||||
|
|
||||||
> Joe wants to buy some tacos bc they're super hungo.
|
|
||||||
> Joe has a friend who also likes tacos but doesn't mind if they're fresh; he doesn't mind having day old tacos.
|
|
||||||
> Inflation is rampant and taco prices are trending up for no good reason besides everyone thinks prices are going up.
|
|
||||||
> Joe goes to the taco stand and buys 4 tacos at 25 mxn.
|
|
||||||
> This makes Joe's net cost `4 * 25 = 200` mxn.
|
|
||||||
> Joe eats 3 tacos and realizes that he can't finish the last, so he puts it in the fridge to save for the next day (since he owns a comal).
|
|
||||||
> The next day the price of tacos goes up to 30 mxn (for no good reason > besides the taco stand noticing Joe is a tourist and that > "inflation" is some thing that's used as an excuse for price changes).
|
|
||||||
> Joe's friend from before got lit up (like he does every morning) and msgs Joe to buy him 2 tacos for when he shows up in the late morning.
|
|
||||||
> Joe says "sure, but i also have a leftover if you want it, and I'm fasting today so you can have my sobras and i'll buy you a new one".
|
|
||||||
> The friend coughs a couple times, and says "yee no problem man, just make sure you get them"
|
|
||||||
>
|
|
||||||
|
|
||||||
|
|
||||||
Prior *suit* definitions:
|
|
||||||
|
|
||||||
- the canucks equiv of the IRS call this idea ["Adjusted cost base"](https://www.canada.ca/en/revenue-agency/services/tax/individuals/topics/about-your-tax-return/tax-return/completing-a-tax-return/personal-income/line-12700-capital-gains/definitions-capital-gains.html#Adjustedcostbase)
|
|
||||||
|
|
||||||
|
|
||||||
.pnl
|
.pnl
|
||||||
----
|
----
|
||||||
|
|
|
@ -40,7 +40,7 @@ import tomli_w # for fast ledger writing
|
||||||
|
|
||||||
from piker.types import Struct
|
from piker.types import Struct
|
||||||
from piker import config
|
from piker import config
|
||||||
from piker.log import get_logger
|
from ..log import get_logger
|
||||||
from .calc import (
|
from .calc import (
|
||||||
iter_by_dt,
|
iter_by_dt,
|
||||||
)
|
)
|
||||||
|
@ -239,9 +239,7 @@ class TransactionLedger(UserDict):
|
||||||
|
|
||||||
symcache: SymbologyCache = self._symcache
|
symcache: SymbologyCache = self._symcache
|
||||||
towrite: dict[str, Any] = {}
|
towrite: dict[str, Any] = {}
|
||||||
for tid, txdict in self.tx_sort(
|
for tid, txdict in self.tx_sort(self.data.copy()):
|
||||||
self.data.copy()
|
|
||||||
):
|
|
||||||
# write blank-str expiry for non-expiring assets
|
# write blank-str expiry for non-expiring assets
|
||||||
if (
|
if (
|
||||||
'expiry' in txdict
|
'expiry' in txdict
|
||||||
|
@ -379,7 +377,7 @@ def open_trade_ledger(
|
||||||
account,
|
account,
|
||||||
dirpath=_fp,
|
dirpath=_fp,
|
||||||
)
|
)
|
||||||
cpy: dict = ledger_dict.copy()
|
cpy = ledger_dict.copy()
|
||||||
|
|
||||||
# XXX NOTE: if not provided presume we are being called from
|
# XXX NOTE: if not provided presume we are being called from
|
||||||
# sync code and need to maybe run `trio` to generate..
|
# sync code and need to maybe run `trio` to generate..
|
||||||
|
@ -408,13 +406,7 @@ def open_trade_ledger(
|
||||||
account=account,
|
account=account,
|
||||||
mod=mod,
|
mod=mod,
|
||||||
symcache=symcache,
|
symcache=symcache,
|
||||||
|
tx_sort=getattr(mod, 'tx_sort', tx_sort),
|
||||||
# NOTE: allow backends to provide custom ledger sorting
|
|
||||||
tx_sort=getattr(
|
|
||||||
mod,
|
|
||||||
'tx_sort',
|
|
||||||
tx_sort,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
yield ledger
|
yield ledger
|
||||||
|
|
|
@ -305,8 +305,8 @@ class MktPair(Struct, frozen=True):
|
||||||
# config right?
|
# config right?
|
||||||
# src_type: AssetTypeName
|
# src_type: AssetTypeName
|
||||||
|
|
||||||
# for derivs, info describing contract, egs. strike price, call
|
# for derivs, info describing contract, egs.
|
||||||
# or put, swap type, exercise model, etc.
|
# strike price, call or put, swap type, exercise model, etc.
|
||||||
contract_info: list[str] | None = None
|
contract_info: list[str] | None = None
|
||||||
|
|
||||||
# TODO: rename to sectype since all of these can
|
# TODO: rename to sectype since all of these can
|
||||||
|
|
|
@ -251,16 +251,10 @@ def iter_by_dt(
|
||||||
for k in parsers:
|
for k in parsers:
|
||||||
if (
|
if (
|
||||||
isdict and k in tx
|
isdict and k in tx
|
||||||
or
|
or getattr(tx, k, None)
|
||||||
getattr(tx, k, None)
|
|
||||||
):
|
):
|
||||||
v = (
|
v = tx[k] if isdict else tx.dt
|
||||||
tx[k] if isdict
|
assert v is not None, f'No valid value for `{k}`!?'
|
||||||
else tx.dt
|
|
||||||
)
|
|
||||||
assert v is not None, (
|
|
||||||
f'No valid value for `{k}`!?'
|
|
||||||
)
|
|
||||||
|
|
||||||
# only call parser on the value if not None from
|
# only call parser on the value if not None from
|
||||||
# the `parsers` table above (when NOT using
|
# the `parsers` table above (when NOT using
|
||||||
|
@ -275,21 +269,8 @@ def iter_by_dt(
|
||||||
return v
|
return v
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# TODO: move to top?
|
# XXX: should never get here..
|
||||||
from piker.log import get_logger
|
breakpoint()
|
||||||
log = get_logger(__name__)
|
|
||||||
|
|
||||||
# XXX: we should really never get here..
|
|
||||||
# only if a ledger record has no expected sort(able)
|
|
||||||
# field will we likely hit this.. like with ze IB.
|
|
||||||
# if no sortable field just deliver epoch?
|
|
||||||
log.warning(
|
|
||||||
'No (time) sortable field for TXN:\n'
|
|
||||||
f'{tx}\n'
|
|
||||||
)
|
|
||||||
return from_timestamp(0)
|
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
|
|
||||||
entry: tuple[str, dict] | Transaction
|
entry: tuple[str, dict] | Transaction
|
||||||
for entry in sorted(
|
for entry in sorted(
|
||||||
|
|
|
@ -300,8 +300,7 @@ def disect(
|
||||||
assert not df.is_empty()
|
assert not df.is_empty()
|
||||||
|
|
||||||
# muck around in pdbp REPL
|
# muck around in pdbp REPL
|
||||||
# tractor.devx.mk_pdb().set_trace()
|
breakpoint()
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
# TODO: we REALLY need a better console REPL for this
|
# TODO: we REALLY need a better console REPL for this
|
||||||
# kinda thing..
|
# kinda thing..
|
||||||
|
|
Loading…
Reference in New Issue