Drop `Symbol` / `.symbol` support from `.accounting`

Only stuff left was the allocator stuff. Drop the top level subpkg
exports and finally kill off the awkwardly named
`Symbol.lot_size_digits` properties XD

Expose a bunch more util funcs at subpkg top level, do some typing in
allocator method internals.
master
Tyler Goodlet 2023-05-24 15:26:51 -04:00
parent 738d0ca38b
commit 35f0520cb0
5 changed files with 51 additions and 37 deletions

View File

@ -38,23 +38,33 @@ from ._mktinfo import (
dec_digits,
digits_to_dec,
MktPair,
Symbol,
unpack_fqme,
)
from ._allocate import (
mk_allocator,
Allocator,
)
log = get_logger(__name__)
__all__ = [
'Allocator',
'Asset',
'dec_digits',
'digits_to_dec',
'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',
]

View File

@ -24,7 +24,7 @@ from typing import Optional
from bidict import bidict
from ._pos import Position
from ._mktinfo import Symbol
from . import MktPair
from ..data.types import Struct
@ -42,7 +42,7 @@ SizeUnit = Enum(
class Allocator(Struct):
symbol: Symbol
mkt: MktPair
# TODO: if we ever want ot support non-uniform entry-slot-proportion
# "sizes"
@ -114,8 +114,8 @@ class Allocator(Struct):
depending on position / order entry config.
'''
sym = self.symbol
ld = sym.lot_size_digits
mkt: MktPair = self.mkt
ld: int = mkt.size_tick_digits
size_unit = self.size_unit
live_size = live_pp.size
@ -125,13 +125,13 @@ class Allocator(Struct):
u_per_slot, currency_per_slot = self.step_sizes()
if size_unit == 'units':
slot_size = u_per_slot
l_sub_pp = self.units_limit - abs_live_size
slot_size: float = u_per_slot
l_sub_pp: float = self.units_limit - abs_live_size
elif size_unit == 'currency':
live_cost_basis = abs_live_size * live_pp.ppu
slot_size = currency_per_slot / price
l_sub_pp = (self.currency_limit - live_cost_basis) / price
live_cost_basis: float = abs_live_size * live_pp.ppu
slot_size: float = currency_per_slot / price
l_sub_pp: float = (self.currency_limit - live_cost_basis) / price
else:
raise ValueError(
@ -141,8 +141,14 @@ class Allocator(Struct):
# an entry (adding-to or starting a pp)
if (
live_size == 0
or (action == 'buy' and live_size > 0)
or action == 'sell' and live_size < 0
or (
action == 'buy'
and live_size > 0
)
or (
action == 'sell'
and live_size < 0
)
):
order_size = min(
slot_size,
@ -178,7 +184,7 @@ class Allocator(Struct):
order_size = max(slotted_pp, slot_size)
if (
abs_live_size < slot_size or
abs_live_size < slot_size
# NOTE: front/back "loading" heurstic:
# if the remaining pp is in between 0-1.5x a slot's
@ -187,14 +193,17 @@ class Allocator(Struct):
# **without** going past a net-zero pp. if the pp is
# > 1.5x a slot size, then front load: exit a slot's and
# expect net-zero to be acquired on the final exit.
slot_size < pp_size < round((1.5*slot_size), ndigits=ld) or
or slot_size < pp_size < round((1.5*slot_size), ndigits=ld)
or (
# underlying requires discrete (int) units (eg. stocks)
# and thus our slot size (based on our limit) would
# exit a fractional unit's worth so, presuming we aren't
# supporting a fractional-units-style broker, we need
# exit the final unit.
ld == 0 and abs_live_size == 1
# underlying requires discrete (int) units (eg. stocks)
# and thus our slot size (based on our limit) would
# exit a fractional unit's worth so, presuming we aren't
# supporting a fractional-units-style broker, we need
# exit the final unit.
ld == 0
and abs_live_size == 1
)
):
order_size = abs_live_size
@ -203,13 +212,14 @@ class Allocator(Struct):
# compute a fractional slots size to display
slots_used = self.slots_used(
Position(
mkt=sym,
mkt=mkt,
size=order_size,
ppu=price,
bs_mktid=sym,
bs_mktid=mkt.bs_mktid,
)
)
# TODO: render an actual ``Executable`` type here?
return {
'size': abs(round(order_size, ndigits=ld)),
'size_digits': ld,
@ -249,7 +259,7 @@ class Allocator(Struct):
def mk_allocator(
symbol: Symbol,
mkt: MktPair,
startup_pp: Position,
# default allocation settings
@ -276,6 +286,6 @@ def mk_allocator(
defaults.update(user_def)
return Allocator(
symbol=symbol,
mkt=mkt,
**defaults,
)

View File

@ -22,9 +22,9 @@ from __future__ import annotations
from collections import UserDict
from contextlib import contextmanager as cm
from pathlib import Path
import time
from typing import (
Any,
Callable,
Iterator,
Union,
Generator
@ -158,7 +158,7 @@ class TransactionLedger(UserDict):
for tid, txdict in self.data.items():
# special field handling for datetimes
# to ensure pendulum is used!
fqme = txdict.get('fqme', txdict['fqsn'])
fqme = txdict.get('fqme') or txdict['fqsn']
dt = parse(txdict['dt'])
expiry = txdict.get('expiry')
@ -242,8 +242,6 @@ def iter_by_dt(
datetime presumably set at the ``'dt'`` field in each entry.
'''
txs = records.items()
def dyn_parse_to_dt(
pair: tuple[str, dict],
) -> DateTime:

View File

@ -519,11 +519,11 @@ class MktPair(Struct, frozen=True):
return self._atype
@property
def tick_size_digits(self) -> int:
def price_tick_digits(self) -> int:
return float_digits(self.price_tick)
@property
def lot_size_digits(self) -> int:
def size_tick_digits(self) -> int:
return float_digits(self.size_tick)

View File

@ -44,7 +44,6 @@ from ._ledger import (
open_trade_ledger,
)
from ._mktinfo import (
Symbol,
MktPair,
Asset,
unpack_fqme,
@ -247,11 +246,8 @@ class Position(Struct):
# XXX: better place to do this?
mkt = self.mkt
# TODO: switch to new fields..?
# .size_tick_digits, .price_tick_digits
size_tick_digits = mkt.lot_size_digits
price_tick_digits = mkt.tick_size_digits
size_tick_digits = mkt.size_tick_digits
price_tick_digits = mkt.price_tick_digits
self.ppu = round(
# TODO: change this to ppu?