Add sym registry to PaperBoi as well as a sym ref on Transaction
Add decimal quantize API to Symbol to simplify by-broker truncation Add symbol info to `pps.toml` Move _assert call to outside the _async_main context manager Minor indentation and styling changes, also convert a few prints to log calls Fix multi write / race condition on open_pps call Switch open_pps to not write by default Fix integer math kraken syminfo _tick_size initializationdecimalization_take_2
parent
dc78994dcf
commit
f5b8b9a14f
|
@ -469,8 +469,7 @@ async def trades_dialogue(
|
|||
with (
|
||||
open_pps(
|
||||
'kraken',
|
||||
acctid,
|
||||
write_on_exit=True,
|
||||
acctid
|
||||
) as table,
|
||||
|
||||
open_trade_ledger(
|
||||
|
|
|
@ -345,8 +345,8 @@ async def stream_quotes(
|
|||
f'Missing msg fields {fields_diff}'
|
||||
)
|
||||
syminfo = si.to_dict()
|
||||
syminfo['price_tick_size'] = 1 / 10**si.pair_decimals
|
||||
syminfo['lot_tick_size'] = 1 / 10**si.lot_decimals
|
||||
syminfo['price_tick_size'] = 1. / 10**si.pair_decimals
|
||||
syminfo['lot_tick_size'] = 1. / 10**si.lot_decimals
|
||||
syminfo['asset_type'] = 'crypto'
|
||||
sym_infos[sym] = syminfo
|
||||
ws_pairs[sym] = si.wsname
|
||||
|
|
|
@ -38,6 +38,7 @@ import tractor
|
|||
|
||||
from .. import data
|
||||
from ..data.types import Struct
|
||||
from ..data._source import Symbol
|
||||
from ..pp import (
|
||||
Position,
|
||||
Transaction,
|
||||
|
@ -81,6 +82,7 @@ class PaperBoi(Struct):
|
|||
_reqids: bidict
|
||||
_positions: dict[str, Position]
|
||||
_trade_ledger: dict[str, Any]
|
||||
_syms: dict[str, Symbol] = {}
|
||||
|
||||
# init edge case L1 spread
|
||||
last_ask: tuple[float, float] = (float('inf'), 0) # price, size
|
||||
|
@ -252,6 +254,7 @@ class PaperBoi(Struct):
|
|||
key = fqsn.rstrip(f'.{self.broker}')
|
||||
t = Transaction(
|
||||
fqsn=fqsn,
|
||||
sym=self._syms[fqsn],
|
||||
tid=oid,
|
||||
size=size,
|
||||
price=price,
|
||||
|
@ -262,9 +265,11 @@ class PaperBoi(Struct):
|
|||
|
||||
with (
|
||||
open_trade_ledger(self.broker, 'paper') as ledger,
|
||||
open_pps(self.broker, 'paper', True) as table
|
||||
open_pps(self.broker, 'paper', write_on_exit=True) as table
|
||||
):
|
||||
ledger.update({oid: t.to_dict()})
|
||||
tx = t.to_dict()
|
||||
tx.pop('sym')
|
||||
ledger.update({oid: tx})
|
||||
# Write to pps toml right now
|
||||
table.update_from_trans({oid: t})
|
||||
|
||||
|
@ -567,6 +572,10 @@ async def trades_dialogue(
|
|||
|
||||
# TODO: load postions from ledger file
|
||||
_trade_ledger={},
|
||||
_syms={
|
||||
fqsn: flume.symbol
|
||||
for fqsn, flume in feed.flumes.items()
|
||||
}
|
||||
)
|
||||
|
||||
n.start_soon(
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
numpy data source coversion helpers.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from decimal import Decimal, ROUND_HALF_EVEN
|
||||
from typing import Any
|
||||
import decimal
|
||||
|
||||
from bidict import bidict
|
||||
import numpy as np
|
||||
|
@ -80,7 +80,7 @@ def float_digits(
|
|||
if value == 0:
|
||||
return 0
|
||||
|
||||
return int(-decimal.Decimal(str(value)).as_tuple().exponent)
|
||||
return int(-Decimal(str(value)).as_tuple().exponent)
|
||||
|
||||
|
||||
def ohlc_zeros(length: int) -> np.ndarray:
|
||||
|
@ -156,14 +156,14 @@ class Symbol(Struct):
|
|||
) -> Symbol:
|
||||
|
||||
tick_size = info.get('price_tick_size', 0.01)
|
||||
lot_tick_size = info.get('lot_tick_size', 0.0)
|
||||
lot_size = info.get('lot_tick_size', 0.0)
|
||||
|
||||
return Symbol(
|
||||
key=symbol,
|
||||
tick_size=tick_size,
|
||||
lot_tick_size=lot_tick_size,
|
||||
lot_tick_size=lot_size,
|
||||
tick_size_digits=float_digits(tick_size),
|
||||
lot_size_digits=float_digits(lot_tick_size),
|
||||
lot_size_digits=float_digits(lot_size),
|
||||
suffix=suffix,
|
||||
broker_info={broker: info},
|
||||
)
|
||||
|
@ -254,6 +254,12 @@ class Symbol(Struct):
|
|||
|
||||
return keys
|
||||
|
||||
def decimal_quant(self, d: Decimal):
|
||||
digits = self.lot_size_digits
|
||||
return d.quantize(
|
||||
Decimal(f'1.{"0".ljust(digits, "0")}'),
|
||||
rounding=ROUND_HALF_EVEN
|
||||
)
|
||||
|
||||
def _nan_to_closest_num(array: np.ndarray):
|
||||
"""Return interpolated values instead of NaN.
|
||||
|
|
41
piker/pp.py
41
piker/pp.py
|
@ -45,7 +45,7 @@ import toml
|
|||
from . import config
|
||||
from .brokers import get_brokermod
|
||||
from .clearing._messages import BrokerdPosition, Status
|
||||
from .data._source import Symbol
|
||||
from .data._source import Symbol, unpack_fqsn
|
||||
from .log import get_logger
|
||||
from .data.types import Struct
|
||||
|
||||
|
@ -83,7 +83,7 @@ def open_trade_ledger(
|
|||
with open(tradesfile, 'rb') as cf:
|
||||
start = time.time()
|
||||
ledger = tomli.load(cf)
|
||||
print(f'Ledger load took {time.time() - start}s')
|
||||
log.info(f'Ledger load took {time.time() - start}s')
|
||||
cpy = ledger.copy()
|
||||
|
||||
try:
|
||||
|
@ -92,7 +92,7 @@ def open_trade_ledger(
|
|||
if cpy != ledger:
|
||||
# TODO: show diff output?
|
||||
# https://stackoverflow.com/questions/12956957/print-diff-of-python-dictionaries
|
||||
print(f'Updating ledger for {tradesfile}:\n')
|
||||
log.info(f'Updating ledger for {tradesfile}:\n')
|
||||
ledger.update(cpy)
|
||||
# we write on close the mutated ledger data
|
||||
with open(tradesfile, 'w') as cf:
|
||||
|
@ -103,17 +103,18 @@ class Transaction(Struct, frozen=True):
|
|||
# TODO: should this be ``.to`` (see below)?
|
||||
fqsn: str
|
||||
|
||||
sym: Symbol
|
||||
tid: Union[str, int] # unique transaction id
|
||||
size: float
|
||||
price: float
|
||||
cost: float # commisions or other additional costs
|
||||
dt: datetime
|
||||
expiry: Optional[datetime] = None
|
||||
expiry: datetime | None = None
|
||||
|
||||
# optional key normally derived from the broker
|
||||
# backend which ensures the instrument-symbol this record
|
||||
# is for is truly unique.
|
||||
bsuid: Optional[Union[str, int]] = None
|
||||
bsuid: Union[str, int] | None = None
|
||||
|
||||
# optional fqsn for the source "asset"/money symbol?
|
||||
# from: Optional[str] = None
|
||||
|
@ -190,9 +191,20 @@ class Position(Struct):
|
|||
# listing venue here even when the backend isn't providing
|
||||
# it via the trades ledger..
|
||||
# drop symbol obj in serialized form
|
||||
s = d.pop('symbol')
|
||||
s = d.get('symbol')
|
||||
fqsn = s.front_fqsn()
|
||||
|
||||
broker, key, suffix = unpack_fqsn(fqsn)
|
||||
sym_info = s.broker_info[broker]
|
||||
|
||||
d['symbol'] = {
|
||||
'info': {
|
||||
'asset_type': sym_info['asset_type'],
|
||||
'price_tick_size': sym_info['price_tick_size'],
|
||||
'lot_tick_size': sym_info['lot_tick_size']
|
||||
}
|
||||
}
|
||||
|
||||
if self.expiry is None:
|
||||
d.pop('expiry', None)
|
||||
elif expiry:
|
||||
|
@ -467,8 +479,7 @@ class Position(Struct):
|
|||
if self.split_ratio is not None:
|
||||
size = round(size * self.split_ratio)
|
||||
|
||||
return float(Decimal(size).quantize(
|
||||
Decimal('1.0000'), rounding=ROUND_HALF_EVEN))
|
||||
return float(self.symbol.decimal_quant(Decimal(size)))
|
||||
|
||||
def minimize_clears(
|
||||
self,
|
||||
|
@ -512,7 +523,7 @@ class Position(Struct):
|
|||
'cost': t.cost,
|
||||
'price': t.price,
|
||||
'size': t.size,
|
||||
'dt': t.dt,
|
||||
'dt': t.dt
|
||||
}
|
||||
|
||||
# TODO: compute these incrementally instead
|
||||
|
@ -559,7 +570,7 @@ class PpTable(Struct):
|
|||
Symbol.from_fqsn(
|
||||
t.fqsn,
|
||||
info={},
|
||||
),
|
||||
) if not t.sym else t.sym,
|
||||
size=0.0,
|
||||
ppu=0.0,
|
||||
bsuid=t.bsuid,
|
||||
|
@ -620,7 +631,7 @@ class PpTable(Struct):
|
|||
# XXX: debug hook for size mismatches
|
||||
# qqqbsuid = 320227571
|
||||
# if bsuid == qqqbsuid:
|
||||
# breakpoint()
|
||||
# xbreakpoint()
|
||||
|
||||
pp.ensure_state()
|
||||
|
||||
|
@ -682,10 +693,10 @@ class PpTable(Struct):
|
|||
'''
|
||||
# TODO: show diff output?
|
||||
# https://stackoverflow.com/questions/12956957/print-diff-of-python-dictionaries
|
||||
print(f'Updating ``pps.toml`` for {path}:\n')
|
||||
|
||||
log.info(f'Updating ``pps.toml`` for {path}:\n')
|
||||
# active, closed_pp_objs = table.dump_active()
|
||||
pp_entries = self.to_toml()
|
||||
log.info(pp_entries)
|
||||
self.conf[self.brokername][self.acctid] = pp_entries
|
||||
|
||||
# TODO: why tf haven't they already done this for inline
|
||||
|
@ -883,7 +894,6 @@ def open_pps(
|
|||
brokername: str,
|
||||
acctid: str,
|
||||
write_on_exit: bool = False,
|
||||
|
||||
) -> Generator[PpTable, None, None]:
|
||||
'''
|
||||
Read out broker-specific position entries from
|
||||
|
@ -937,8 +947,11 @@ def open_pps(
|
|||
dtstr = clears_table['dt']
|
||||
dt = pendulum.parse(dtstr)
|
||||
clears_table['dt'] = dt
|
||||
|
||||
trans.append(Transaction(
|
||||
fqsn=bsuid,
|
||||
sym=Symbol.from_fqsn(
|
||||
fqsn, entry['symbol']),
|
||||
bsuid=bsuid,
|
||||
tid=tid,
|
||||
size=clears_table['size'],
|
||||
|
|
|
@ -84,12 +84,10 @@ async def _async_main(
|
|||
case {'name': 'position'}:
|
||||
break
|
||||
|
||||
if (
|
||||
assert_entries
|
||||
or assert_pps
|
||||
or assert_zeroed_pps
|
||||
or assert_msg
|
||||
):
|
||||
# Teardown piker like a user would
|
||||
raise KeyboardInterrupt
|
||||
|
||||
if assert_entries or assert_pps or assert_zeroed_pps or assert_msg:
|
||||
_assert(
|
||||
assert_entries,
|
||||
assert_pps,
|
||||
|
@ -100,9 +98,6 @@ async def _async_main(
|
|||
executions,
|
||||
)
|
||||
|
||||
# Teardown piker like a user would
|
||||
raise KeyboardInterrupt
|
||||
|
||||
|
||||
def _assert(
|
||||
assert_entries,
|
||||
|
|
Loading…
Reference in New Issue