piker/piker/accounting/__init__.py

116 lines
2.7 KiB
Python
Raw Normal View History

# piker: trading gear for hackers
# Copyright (C) Tyler Goodlet (in stewardship for pikers)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
"Accounting for degens": count dem numberz that tracks how much you got
for tendiez.
'''
from ..log import get_logger
from ._ledger import (
iter_by_dt,
Transaction,
TransactionLedger,
open_trade_ledger,
)
from ._pos import (
load_pps_from_ledger,
open_pps,
Position,
PpTable,
)
from ._mktinfo import (
Asset,
dec_digits,
digits_to_dec,
MktPair,
Symbol,
2023-05-17 20:43:31 +00:00
unpack_fqme,
)
from ._allocate import (
mk_allocator,
Allocator,
)
log = get_logger(__name__)
__all__ = [
'Allocator',
'Asset',
'MktPair',
'Position',
'PpTable',
'Symbol',
'Transaction',
'TransactionLedger',
'dec_digits',
'digits_to_dec',
'iter_by_dt',
'load_pps_from_ledger',
'mk_allocator',
'open_pps',
'open_trade_ledger',
'unpack_fqme',
]
def get_likely_pair(
src: str,
dst: str,
bs_mktid: str,
) -> str | None:
'''
Attempt to get the likely trading pair matching a given destination
asset `dst: str`.
'''
try:
src_name_start = bs_mktid.rindex(src)
except (
ValueError, # substr not found
):
# TODO: handle nested positions..(i.e.
# positions where the src fiat was used to
# buy some other dst which was furhter used
# to buy another dst..)
# log.warning(
# f'No src fiat {src} found in {bs_mktid}?'
# )
return
likely_dst = bs_mktid[:src_name_start]
if likely_dst == dst:
return bs_mktid
if __name__ == '__main__':
import sys
from pprint import pformat
args = sys.argv
assert len(args) > 1, 'Specifiy account(s) from `brokers.toml`'
args = args[1:]
for acctid in args:
broker, name = acctid.split('.')
Rework "breakeven" price as "price-per-uni": ppu The original implementation of `.calc_be_price()` wasn't correct since the real so called "price per unit" (ppu), is actually defined by a recurrence relation (which is why the original state-updated `.lifo_update()` approach worked well) and requires the previous ppu to be weighted by the new accumulated position size when considering a new clear event. The ppu is the price that above or below which the trader takes a win or loss on transacting one unit of the trading asset and thus it is the true "break even price" that determines making or losing money per fill. This patches fixes the implementation to use trailing windows of the accumulated size and ppu to compute the next ppu value for any new clear event as well as handle rare cases where the "direction" changes polarity (eg. long to short in a single order). The new method is `Position.calc_ppu()` and further details of the relation can be seen in the doc strings. This patch also includes a wack-ton of clean ups and removals in an effort to refine position management api for easier use in new backends: - drop `updaate_pps_conf()`, `load_pps_from_toml()` and rename `load_trands_from_ledger()` -> `load_pps_from_ledger()`. - extend `PpTable` to have a `.to_toml()` method which returns the active set of positions ready to be serialized to the `pps.toml` file which is collects from calling, - `PpTable.dump_active()` which now returns double dicts of the open/closed pp object maps. - make `Position.minimize_clears()` now iterate the clears table in chronological order (instead of reverse) and only drop fills prior to any zero-size state (the old reversed way can result incorrect history-size-retracement in cases where a position is lessened but not completely exited). - drop `Position.add_clear()` and instead just manually add entries inside `.update_from_trans()` and also add a `accum_size` and `ppu` field to ever entry thus creating a position "history" sequence of the ppu and accum size for every position and prepares for being and to show "position lifetimes" in the UI. - move fqsn getting into `Position.to_pretoml()`.
2022-07-26 15:27:38 +00:00
trans, updated_pps = load_pps_from_ledger(broker, name)
print(
f'Processing transactions into pps for {broker}:{acctid}\n'
f'{pformat(trans)}\n\n'
f'{pformat(updated_pps)}'
)