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, dec_digits,
digits_to_dec, digits_to_dec,
MktPair, MktPair,
Symbol,
unpack_fqme, unpack_fqme,
) )
from ._allocate import (
mk_allocator,
Allocator,
)
log = get_logger(__name__) log = get_logger(__name__)
__all__ = [ __all__ = [
'Allocator',
'Asset', 'Asset',
'dec_digits',
'digits_to_dec',
'MktPair', 'MktPair',
'Position', 'Position',
'PpTable', 'PpTable',
'Symbol',
'Transaction', 'Transaction',
'TransactionLedger', 'TransactionLedger',
'dec_digits',
'digits_to_dec',
'iter_by_dt',
'load_pps_from_ledger', 'load_pps_from_ledger',
'mk_allocator',
'open_pps', 'open_pps',
'open_trade_ledger', 'open_trade_ledger',
'unpack_fqme',
] ]

View File

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

View File

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

View File

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

View File

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